Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ jobs:
fail-fast: false
matrix:
include:
- language: javascript-typescript
# Repo source is not JS/TS; scan workflow files via the
# actions extractor (every repo has those). See hypatia rule
# codeql_language_matrix_mismatch.
- language: actions
build-mode: none

steps:
Expand Down
66 changes: 15 additions & 51 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,20 @@
# SPDX-License-Identifier: MPL-2.0
permissions:
contents: read

# Rust CI — thin wrapper calling the shared estate reusable in
# hyperpolymath/standards. Configure once, propagate everywhere.
# See: docs/CI-REUSABLE-WORKFLOWS.adoc in standards.
name: Rust CI
on: [push, pull_request]
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2

- name: Check formatting
run: cargo fmt --all -- --check

- name: Clippy lints
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Run tests
run: cargo test --all-features

- name: Build release
run: cargo build --release
on:
push:
branches: [main, master]
pull_request:

security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Security audit
run: cargo audit
- name: Check for outdated deps
run: cargo install cargo-outdated && cargo outdated --exit-code 1 || true
permissions:
contents: read

coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
- name: Install tarpaulin
run: cargo install cargo-tarpaulin
- name: Generate coverage
run: cargo tarpaulin --out Xml
- uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457 # v3
with:
files: cobertura.xml
jobs:
rust-ci:
uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4fdf4314b4ab54269adbaff10e30e483b5e86845
with:
enable_audit: true
enable_coverage: true
129 changes: 129 additions & 0 deletions examples/SafeDOMExample.affine
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// SPDX-License-Identifier: MPL-2.0
// SafeDOMExample.affine — formally-verified DOM mounting (aspirational).
//
// This example shows the *shape* of SafeDOM consumer code in current
// AffineScript syntax. The `SafeDOM` stdlib surface it references
// (`mount_safe`, `mount_when_ready`, `mount_batch`,
// `proven_selector_validate`, `proven_html_validate`, `mount`) is the
// target of `affinescript#56` (DOM+Pixi binding survey) and does not
// yet exist in the published stdlib. The file is therefore
// parse-checked but not type-checked end-to-end until #56 lands the
// bindings; `affinescript check` reports `Resolve.UndefinedModule
// SafeDOM` which is expected.
//
// Previous versions of this file (estate-wide, 5 dialect variants)
// pre-dated ADR-014 (qualified paths), ADR-016 (effect rows), and the
// `#{`-record-literal sigil (ADR-215). They were retired in favour of
// this canonical via the gitbot-fleet#208 sweep (2026-05-26).

module SafeDOMExample;

use prelude::{Option, Some, None, Result, Ok, Err};

// `Element` and friends are nominal extern types for now — the real
// shape lands with affinescript#56.
extern type Element;
extern type Selector;
extern type ValidHTML;

// Single-mount status, lifted from the host into a typed tag union.
enum MountStatus {
Mounted(Element),
MountPointNotFound(String),
InvalidSelector(String),
InvalidHTML(String)
}

// Batch-mount result.
enum MountResult {
Mounted([Element]),
Failed(String)
}

// Spec for one element in a batch mount.
struct MountSpec {
selector: String,
html: String
}

// SafeDOM's host-side surface, all IO-effecting. Callbacks are passed
// as separate parameters (rather than a `MountCallbacks` record)
// because fn-typed struct fields are not currently parser-supported.
extern fn mount_safe(
selector: ref String,
html: ref String,
on_success: fn(Element) -> (),
on_error: fn(String) -> (),
) -{IO}-> ();

extern fn mount_when_ready(
selector: ref String,
html: ref String,
on_success: fn(Element) -> (),
on_error: fn(String) -> (),
) -{IO}-> ();

extern fn mount_batch(specs: ref [MountSpec]) -{IO}-> MountResult;

extern fn proven_selector_validate(s: ref String) -{IO}-> Result<Selector, String>;
extern fn proven_html_validate(s: ref String) -{IO}-> Result<ValidHTML, String>;
extern fn mount(sel: ref Selector, html: ref ValidHTML) -{IO}-> MountStatus;

extern fn array_for_each(xs: ref [Element], f: fn(Element) -> ()) -{IO}-> ();
extern fn array_len(xs: ref [Element]) -> Int;

// Example 1 — basic mount with success/error branches.
pub fn mount_app() -{IO}-> () {
mount_safe(
"#app",
"<div><h1>Hello, World!</h1><p>Mounted safely with proofs.</p></div>",
fn(el) -> () { Console::log("App mounted successfully"); },
fn(err) -> () { Console::error("Mount failed: " ++ err); },
);
}

// Example 2 — defer until DOM ready.
pub fn mount_when_dom_ready() -{IO}-> () {
mount_when_ready(
"#app",
"<div class='container'><h1>App Title</h1></div>",
fn(_el) -> () { Console::log("Mounted after DOM ready"); },
fn(err) -> () { Console::error("Failed: " ++ err); },
);
}

// Example 3 — atomic batch mount.
pub fn mount_multiple() -{IO}-> () {
let specs = [
MountSpec #{ selector: "#header", html: "<header><h1>Site Title</h1></header>" },
MountSpec #{ selector: "#nav", html: "<nav><a href='/'>Home</a></nav>" },
MountSpec #{ selector: "#main", html: "<main><p>Content here</p></main>" },
MountSpec #{ selector: "#footer", html: "<footer>2026</footer>" },
];

match mount_batch(specs) {
Mounted(elements) => {
Console::log("Batch mount succeeded");
array_for_each(elements, fn(_el) -> () { Console::log(" element"); });
},
Failed(err) => {
Console::error("Batch mount failed (atomic — none mounted): " ++ err);
}
}
}

// Example 4 — explicit two-stage validation before mounting.
pub fn mount_with_validation() -{IO}-> () {
match proven_selector_validate("#my-app") {
Err(e) => Console::error("Invalid selector: " ++ e),
Ok(valid_selector) => match proven_html_validate("<div>Content</div>") {
Err(e) => Console::error("Invalid HTML: " ++ e),
Ok(valid_html) => match mount(valid_selector, valid_html) {
Mounted(_el) => Console::log("Mounted with validated inputs"),
MountPointNotFound(s) => Console::error("Element not found: " ++ s),
InvalidSelector(_) => Console::error("impossible — already validated"),
InvalidHTML(_) => Console::error("impossible — already validated"),
},
},
}
}
109 changes: 0 additions & 109 deletions examples/SafeDOMExample.res

This file was deleted.