Skip to content

Commit 27909ff

Browse files
fix(examples): migrate SafeDOMExample.affine to current AffineScript grammar (Refs gitbot-fleet#148, #208) (#30)
Replaces the pre-stabilization-dialect copy with the current-grammar canonical (byte-identical to hyperpolymath/gitbot-fleet#210). Previous content pre-dated ADR-014 / ADR-016 / ADR-215; parse-failed at line 1 of `affinescript check`. The example references the SafeDOM stdlib surface targeted by affinescript#56; `affinescript check` reports Resolve.UndefinedModule SafeDOM — the expected residual. Refs hyperpolymath/gitbot-fleet#148 Refs hyperpolymath/gitbot-fleet#208 Refs hyperpolymath/gitbot-fleet#210 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6dd6114 commit 27909ff

1 file changed

Lines changed: 111 additions & 107 deletions

File tree

examples/SafeDOMExample.affine

Lines changed: 111 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,129 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Example: Using SafeDOM for formally verified DOM mounting
2+
// SafeDOMExample.affine — formally-verified DOM mounting (aspirational).
3+
//
4+
// This example shows the *shape* of SafeDOM consumer code in current
5+
// AffineScript syntax. The `SafeDOM` stdlib surface it references
6+
// (`mount_safe`, `mount_when_ready`, `mount_batch`,
7+
// `proven_selector_validate`, `proven_html_validate`, `mount`) is the
8+
// target of `affinescript#56` (DOM+Pixi binding survey) and does not
9+
// yet exist in the published stdlib. The file is therefore
10+
// parse-checked but not type-checked end-to-end until #56 lands the
11+
// bindings; `affinescript check` reports `Resolve.UndefinedModule
12+
// SafeDOM` which is expected.
13+
//
14+
// Previous versions of this file (estate-wide, 5 dialect variants)
15+
// pre-dated ADR-014 (qualified paths), ADR-016 (effect rows), and the
16+
// `#{`-record-literal sigil (ADR-215). They were retired in favour of
17+
// this canonical via the gitbot-fleet#208 sweep (2026-05-26).
18+
19+
module SafeDOMExample;
20+
21+
use prelude::{Option, Some, None, Result, Ok, Err};
22+
23+
// `Element` and friends are nominal extern types for now — the real
24+
// shape lands with affinescript#56.
25+
extern type Element;
26+
extern type Selector;
27+
extern type ValidHTML;
28+
29+
// Single-mount status, lifted from the host into a typed tag union.
30+
enum MountStatus {
31+
Mounted(Element),
32+
MountPointNotFound(String),
33+
InvalidSelector(String),
34+
InvalidHTML(String)
35+
}
36+
37+
// Batch-mount result.
38+
enum MountResult {
39+
Mounted([Element]),
40+
Failed(String)
41+
}
342

4-
import SafeDOM
43+
// Spec for one element in a batch mount.
44+
struct MountSpec {
45+
selector: String,
46+
html: String
47+
}
548

6-
// Example 1: Basic mounting with error handling
7-
fn mount_app() {
8-
SafeDOM::mount_safe(
49+
// SafeDOM's host-side surface, all IO-effecting. Callbacks are passed
50+
// as separate parameters (rather than a `MountCallbacks` record)
51+
// because fn-typed struct fields are not currently parser-supported.
52+
extern fn mount_safe(
53+
selector: ref String,
54+
html: ref String,
55+
on_success: fn(Element) -> (),
56+
on_error: fn(String) -> (),
57+
) -{IO}-> ();
58+
59+
extern fn mount_when_ready(
60+
selector: ref String,
61+
html: ref String,
62+
on_success: fn(Element) -> (),
63+
on_error: fn(String) -> (),
64+
) -{IO}-> ();
65+
66+
extern fn mount_batch(specs: ref [MountSpec]) -{IO}-> MountResult;
67+
68+
extern fn proven_selector_validate(s: ref String) -{IO}-> Result<Selector, String>;
69+
extern fn proven_html_validate(s: ref String) -{IO}-> Result<ValidHTML, String>;
70+
extern fn mount(sel: ref Selector, html: ref ValidHTML) -{IO}-> MountStatus;
71+
72+
extern fn array_for_each(xs: ref [Element], f: fn(Element) -> ()) -{IO}-> ();
73+
extern fn array_len(xs: ref [Element]) -> Int;
74+
75+
// Example 1 — basic mount with success/error branches.
76+
pub fn mount_app() -{IO}-> () {
77+
mount_safe(
978
"#app",
1079
"<div><h1>Hello, World!</h1><p>Mounted safely with proofs.</p></div>",
11-
on_success: fn(el) {
12-
Console::log("✓ App mounted successfully!")
13-
Console::log("Element: ", el)
14-
},
15-
on_error: fn(err) {
16-
Console::error("✗ Mount failed: ", err)
17-
}
18-
)
80+
fn(el) -> () { Console::log("App mounted successfully"); },
81+
fn(err) -> () { Console::error("Mount failed: " ++ err); },
82+
);
1983
}
2084

21-
// Example 2: Wait for DOM ready before mounting
22-
fn mount_when_dom_ready() {
23-
SafeDOM::mount_when_ready(
85+
// Example 2 — defer until DOM ready.
86+
pub fn mount_when_dom_ready() -{IO}-> () {
87+
mount_when_ready(
2488
"#app",
2589
"<div class='container'><h1>App Title</h1></div>",
26-
on_success: fn(_) { Console::log("Mounted after DOM ready") },
27-
on_error: fn(err) { Console::error("Failed: ", err) }
28-
)
90+
fn(_el) -> () { Console::log("Mounted after DOM ready"); },
91+
fn(err) -> () { Console::error("Failed: " ++ err); },
92+
);
2993
}
3094

31-
// Example 3: Batch mounting (atomic - all or nothing)
32-
fn mount_multiple() {
95+
// Example 3atomic batch mount.
96+
pub fn mount_multiple() -{IO}-> () {
3397
let specs = [
34-
{selector: "#header", html: "<header><h1>Site Title</h1></header>"},
35-
{selector: "#nav", html: "<nav><a href='/'>Home</a></nav>"},
36-
{selector: "#main", html: "<main><p>Content here</p></main>"},
37-
{selector: "#footer", html: "<footer>© 2026</footer>"}
38-
]
39-
40-
match SafeDOM::mount_batch(specs) {
41-
Ok(elements) => {
42-
Console::log("✓ Successfully mounted ", len(elements), " elements")
43-
for el in elements {
44-
Console::log(" -", el)
45-
}
46-
}
47-
Error(err) => {
48-
Console::error("✗ Batch mount failed: ", err)
49-
Console::error(" (None were mounted - atomic operation)")
50-
}
51-
}
52-
}
53-
54-
// Example 4: Explicit validation before mounting
55-
fn mount_with_validation() {
56-
// Validate selector first
57-
match ProvenSelector::validate("#my-app") {
58-
Error(e) => Console::error("Invalid selector: ", e)
59-
Ok(valid_selector) => {
60-
// Validate HTML
61-
match ProvenHTML::validate("<div>Content</div>") {
62-
Error(e) => Console::error("Invalid HTML: ", e)
63-
Ok(valid_html) => {
64-
// Now mount with proven safety
65-
match SafeDOM::mount(valid_selector, valid_html) {
66-
Mounted(el) => Console::log("✓ Mounted with validated inputs: ", el)
67-
MountPointNotFound(s) => Console::error("✗ Element not found: ", s)
68-
InvalidSelector(_) => Console::error("Impossible - already validated")
69-
InvalidHTML(_) => Console::error("Impossible - already validated")
70-
}
71-
}
72-
}
98+
MountSpec #{ selector: "#header", html: "<header><h1>Site Title</h1></header>" },
99+
MountSpec #{ selector: "#nav", html: "<nav><a href='/'>Home</a></nav>" },
100+
MountSpec #{ selector: "#main", html: "<main><p>Content here</p></main>" },
101+
MountSpec #{ selector: "#footer", html: "<footer>2026</footer>" },
102+
];
103+
104+
match mount_batch(specs) {
105+
Mounted(elements) => {
106+
Console::log("Batch mount succeeded");
107+
array_for_each(elements, fn(_el) -> () { Console::log(" element"); });
108+
},
109+
Failed(err) => {
110+
Console::error("Batch mount failed (atomic — none mounted): " ++ err);
73111
}
74112
}
75113
}
76114

77-
// Example 5: Integration with TEA
78-
namespace MyApp {
79-
struct Model {
80-
message: String
81-
}
82-
83-
enum Msg {
84-
NoOp
85-
}
86-
87-
fn init() -> Model {
88-
Model{message: "Hello from TEA"}
89-
}
90-
91-
fn update(_model: Model, _msg: Msg) -> Model {
92-
_model
93-
}
94-
95-
fn view(model: Model) -> String {
96-
"<div><h1>" + model.message + "</h1></div>"
97-
}
98-
}
99-
100-
fn mount_tea_app() {
101-
let model = MyApp::init()
102-
let html = MyApp::view(model)
103-
104-
SafeDOM::mount_when_ready(
105-
"#tea-app",
106-
html,
107-
on_success: fn(el) {
108-
Console::log("✓ TEA app mounted")
109-
// Set up event handlers, subscriptions here
115+
// Example 4 — explicit two-stage validation before mounting.
116+
pub fn mount_with_validation() -{IO}-> () {
117+
match proven_selector_validate("#my-app") {
118+
Err(e) => Console::error("Invalid selector: " ++ e),
119+
Ok(valid_selector) => match proven_html_validate("<div>Content</div>") {
120+
Err(e) => Console::error("Invalid HTML: " ++ e),
121+
Ok(valid_html) => match mount(valid_selector, valid_html) {
122+
Mounted(_el) => Console::log("Mounted with validated inputs"),
123+
MountPointNotFound(s) => Console::error("Element not found: " ++ s),
124+
InvalidSelector(_) => Console::error("impossible — already validated"),
125+
InvalidHTML(_) => Console::error("impossible — already validated"),
126+
},
110127
},
111-
on_error: fn(err) { Console::error("✗ TEA mount failed: ", err) }
112-
)
113-
}
114-
115-
// Entry point
116-
fn main() {
117-
Console::log("SafeDOM Examples")
118-
Console::log("================\n")
119-
120-
// Choose which example to run
121-
mount_when_dom_ready() // Run on DOM ready
128+
}
122129
}
123-
124-
// Auto-execute when module loads
125-
main()

0 commit comments

Comments
 (0)