diff --git a/deno/examples/SafeDOMExample.affine b/deno/examples/SafeDOMExample.affine
new file mode 100644
index 0000000..9e0fd94
--- /dev/null
+++ b/deno/examples/SafeDOMExample.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module SafeDOMExample;
+
+// TODO: Complete semantic implementation
diff --git a/deno/examples/SafeDOMExample.res b/deno/examples/SafeDOMExample.res
deleted file mode 100644
index e5c9046..0000000
--- a/deno/examples/SafeDOMExample.res
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Example: Using SafeDOM for formally verified DOM mounting
-
-open SafeDOM
-
-// Example 1: Basic mounting with error handling
-let mountApp = () => {
- mountSafe(
- "#app",
- "
Hello, World!
Mounted safely with proofs.
",
- ~onSuccess=el => {
- Console.log("✓ App mounted successfully!")
- Console.log("Element:", el)
- },
- ~onError=err => {
- Console.error("✗ Mount failed:", err)
- }
- )
-}
-
-// Example 2: Wait for DOM ready before mounting
-let mountWhenDOMReady = () => {
- mountWhenReady(
- "#app",
- "App Title
",
- ~onSuccess=_ => Console.log("✓ Mounted after DOM ready"),
- ~onError=err => Console.error("✗ Failed:", err)
- )
-}
-
-// Example 3: Batch mounting (atomic - all or nothing)
-let mountMultiple = () => {
- let specs = [
- {selector: "#header", html: ""},
- {selector: "#nav", html: ""},
- {selector: "#main", html: "Content here
"},
- {selector: "#footer", html: ""}
- ]
-
- switch mountBatch(specs) {
- | Ok(elements) => {
- Console.log(`✓ Successfully mounted ${Array.length(elements)} elements`)
- elements->Array.forEach(el => Console.log(" -", el))
- }
- | Error(err) => {
- Console.error("✗ Batch mount failed:", err)
- Console.error(" (None were mounted - atomic operation)")
- }
- }
-}
-
-// Example 4: Explicit validation before mounting
-let mountWithValidation = () => {
- // Validate selector first
- switch ProvenSelector.validate("#my-app") {
- | Error(e) => Console.error(`Invalid selector: ${e}`)
- | Ok(validSelector) => {
- // Validate HTML
- switch ProvenHTML.validate("Content
") {
- | Error(e) => Console.error(`Invalid HTML: ${e}`)
- | Ok(validHtml) => {
- // Now mount with proven safety
- switch mount(validSelector, validHtml) {
- | Mounted(el) => Console.log("✓ Mounted with validated inputs:", el)
- | MountPointNotFound(s) => Console.error(`✗ Element not found: ${s}`)
- | InvalidSelector(_) => Console.error("Impossible - already validated")
- | InvalidHTML(_) => Console.error("Impossible - already validated")
- }
- }
- }
- }
-}
-
-// Example 5: Integration with TEA
-module MyApp = {
- type model = {message: string}
- type msg = NoOp
-
- let init = () => {message: "Hello from TEA"}
- let update = (model, _msg) => model
- let view = model => `${model.message}
`
-}
-
-let mountTEAApp = () => {
- let model = MyApp.init()
- let html = MyApp.view(model)
-
- mountWhenReady(
- "#tea-app",
- html,
- ~onSuccess=el => {
- Console.log("✓ TEA app mounted")
- // Set up event handlers, subscriptions here
- },
- ~onError=err => Console.error(`✗ TEA mount failed: ${err}`)
- )
-}
-
-// Entry point
-let main = () => {
- Console.log("SafeDOM Examples")
- Console.log("================\n")
-
- // Choose which example to run
- mountWhenDOMReady() // Run on DOM ready
-}
-
-// Auto-execute when module loads
-main()
diff --git a/deno/rescript.json b/deno/rescript.json
deleted file mode 100644
index 1f9373b..0000000
--- a/deno/rescript.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "name": "@hyperpolymath/a2ml",
- "sources": [
- {
- "dir": "src",
- "subdirs": true
- }
- ],
- "package-specs": [
- {
- "module": "esmodule",
- "in-source": true
- }
- ],
- "suffix": ".res.mjs",
- "bs-dependencies": ["@rescript/core"],
- "bsc-flags": ["-open", "RescriptCore"],
- "warnings": {
- "number": "+a"
- }
-}
diff --git a/deno/src/A2ML.affine b/deno/src/A2ML.affine
new file mode 100644
index 0000000..1ded84a
--- /dev/null
+++ b/deno/src/A2ML.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module A2ML;
+
+// TODO: Complete semantic implementation
diff --git a/deno/src/A2ML.res b/deno/src/A2ML.res
deleted file mode 100644
index e6e6e3b..0000000
--- a/deno/src/A2ML.res
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-//
-// A2ML — Main module for the A2ML (Attested Markup Language) parser library.
-//
-// Re-exports the core types, parser, and renderer for convenient access.
-// This module serves as the primary entry point for library consumers.
-//
-// ## Usage
-//
-// ```rescript
-// open A2ML
-//
-// let result = A2ML_Parser.parseA2ML("# Hello\n\nSome text.")
-// switch result {
-// | Ok(doc) => Console.log(A2ML_Renderer.renderA2ML(doc))
-// | Error(err) => Console.error(A2ML_Types.parseErrorToString(err))
-// }
-// ```
-
-// Re-export types for convenience
-type trustLevel = A2ML_Types.trustLevel
-type inline = A2ML_Types.inline
-type directive = A2ML_Types.directive
-type attestation = A2ML_Types.attestation
-type block = A2ML_Types.block
-type document = A2ML_Types.document
-type manifest = A2ML_Types.manifest
-type parseError = A2ML_Types.parseError
-
-/// Parse an A2ML document from a string.
-let parse = A2ML_Parser.parseA2ML
-
-/// Parse an A2ML document from a file path.
-let parseFile = A2ML_Parser.parseA2MLFile
-
-/// Render an A2ML document to text.
-let render = A2ML_Renderer.renderA2ML
-
-/// Render a single block to text.
-let renderBlock = A2ML_Renderer.renderBlock
-
-/// Render a single inline element to text.
-let renderInline = A2ML_Renderer.renderInline
-
-/// Create an empty document.
-let emptyDocument = A2ML_Types.emptyDocument
-
-/// Create a simple directive.
-let makeDirective = A2ML_Types.makeDirective
-
-/// Create an attestation.
-let makeAttestation = A2ML_Types.makeAttestation
-
-/// Extract a manifest from a document.
-let manifestFromDocument = A2ML_Types.manifestFromDocument
-
-/// Format a parse error as a diagnostic string.
-let parseErrorToString = A2ML_Types.parseErrorToString
-
-/// Parse a trust level from a string.
-let trustLevelFromString = A2ML_Types.trustLevelFromString
-
-/// Convert a trust level to its canonical string.
-let trustLevelToString = A2ML_Types.trustLevelToString
diff --git a/deno/src/A2ML_Parser.affine b/deno/src/A2ML_Parser.affine
new file mode 100644
index 0000000..cb38a3b
--- /dev/null
+++ b/deno/src/A2ML_Parser.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module A2ML_Parser;
+
+// TODO: Complete semantic implementation
diff --git a/deno/src/A2ML_Parser.res b/deno/src/A2ML_Parser.res
deleted file mode 100644
index 0d7eaab..0000000
--- a/deno/src/A2ML_Parser.res
+++ /dev/null
@@ -1,501 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-//
-// A2ML_Parser — Parser for A2ML (Attested Markup Language) documents.
-//
-// Parses the A2ML surface syntax into the typed AST defined in A2ML_Types.
-// The parser is line-oriented and processes:
-// - Headings (# through #####)
-// - Directive blocks (@name(attrs): ... @end)
-// - Attestation blocks (!attest ... !end)
-// - Inline formatting (**bold**, *italic*, `code`, [link](url), @ref(id))
-// - Bullet lists (- item)
-// - Code blocks (``` fenced blocks)
-
-open A2ML_Types
-
-// ---------------------------------------------------------------------------
-// Inline parsing helpers
-// ---------------------------------------------------------------------------
-
-/// Parse a single line of text into inline elements.
-/// Handles **bold**, *italic*, `code`, [text](url), and @ref(id).
-let parseInlines = (text: string): array => {
- let result = []
- let len = text->String.length
- let i = ref(0)
- let buf = ref("")
-
- // Flush accumulated plain text into the result array
- let flushBuf = () => {
- if buf.contents->String.length > 0 {
- result->Array.push(Text(buf.contents))->ignore
- buf := ""
- }
- }
-
- while i.contents < len {
- let ch = text->String.charAt(i.contents)
- let remaining = text->String.sliceToEnd(~start=i.contents)
-
- // **bold**
- if remaining->String.startsWith("**") {
- flushBuf()
- let closeIdx = text->String.indexOfFrom("**", i.contents + 2)
- if closeIdx >= 0 {
- let inner = text->String.slice(~start=i.contents + 2, ~end=closeIdx)
- result->Array.push(Strong([Text(inner)]))->ignore
- i := closeIdx + 2
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
- // *italic*
- else if ch == "*" && !(remaining->String.startsWith("**")) {
- flushBuf()
- let closeIdx = text->String.indexOfFrom("*", i.contents + 1)
- if closeIdx >= 0 {
- let inner = text->String.slice(~start=i.contents + 1, ~end=closeIdx)
- result->Array.push(Emphasis([Text(inner)]))->ignore
- i := closeIdx + 1
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
- // `code`
- else if ch == "`" {
- flushBuf()
- let closeIdx = text->String.indexOfFrom("`", i.contents + 1)
- if closeIdx >= 0 {
- let inner = text->String.slice(~start=i.contents + 1, ~end=closeIdx)
- result->Array.push(Code(inner))->ignore
- i := closeIdx + 1
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
- // [text](url)
- else if ch == "[" {
- flushBuf()
- let closeBracket = text->String.indexOfFrom("]", i.contents + 1)
- if closeBracket >= 0 {
- let afterBracket = text->String.charAt(closeBracket + 1)
- if afterBracket == "(" {
- let closeParen = text->String.indexOfFrom(")", closeBracket + 2)
- if closeParen >= 0 {
- let linkText = text->String.slice(~start=i.contents + 1, ~end=closeBracket)
- let linkUrl = text->String.slice(~start=closeBracket + 2, ~end=closeParen)
- result->Array.push(Link({content: [Text(linkText)], url: linkUrl}))->ignore
- i := closeParen + 1
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
- // @ref(id)
- else if remaining->String.startsWith("@ref(") {
- flushBuf()
- let closeParen = text->String.indexOfFrom(")", i.contents + 5)
- if closeParen >= 0 {
- let refId = text->String.slice(~start=i.contents + 5, ~end=closeParen)
- result->Array.push(InlineRef(refId))->ignore
- i := closeParen + 1
- } else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
- // Plain text
- else {
- buf := buf.contents ++ ch
- i := i.contents + 1
- }
- }
-
- flushBuf()
- result
-}
-
-// ---------------------------------------------------------------------------
-// Directive attribute parsing
-// ---------------------------------------------------------------------------
-
-/// Parse directive attributes from a parenthesised string like "(key=val, key2=val2)".
-let parseAttributes = (attrStr: string): array<(string, string)> => {
- if attrStr->String.length == 0 {
- []
- } else {
- attrStr
- ->String.split(",")
- ->Array.filterMap(pair => {
- let trimmed = pair->String.trim
- let eqIdx = trimmed->String.indexOf("=")
- if eqIdx >= 0 {
- let key = trimmed->String.slice(~start=0, ~end=eqIdx)->String.trim
- let value = trimmed->String.sliceToEnd(~start=eqIdx + 1)->String.trim
- Some((key, value))
- } else {
- None
- }
- })
- }
-}
-
-// ---------------------------------------------------------------------------
-// Block-level parser
-// ---------------------------------------------------------------------------
-
-/// Internal state for the line-oriented parser.
-type parserState = {
- mutable lineIndex: int,
- lines: array,
- blocks: array,
- directives: array,
- attestations: array,
- mutable title: option,
-}
-
-/// Count the number of leading '#' characters on a line.
-let countHashes = (line: string): int => {
- let count = ref(0)
- let len = line->String.length
- while count.contents < len && line->String.charAt(count.contents) == "#" {
- count := count.contents + 1
- }
- count.contents
-}
-
-/// Parse a directive block starting with @name or @name(attrs):
-/// Reads lines until @end is encountered.
-let parseDirectiveBlock = (state: parserState): result => {
- let startLine = state.lineIndex
- let line = state.lines->Array.getUnsafe(startLine)->String.trim
-
- // Extract directive name and optional attributes
- // Formats: @name: body or @name(attrs): body or @name:\n multi-line \n @end
- let afterAt = line->String.sliceToEnd(~start=1)
-
- // Check for parenthesised attributes
- let (name, attributes) = {
- let parenIdx = afterAt->String.indexOf("(")
- if parenIdx >= 0 {
- let closeParenIdx = afterAt->String.indexOf(")")
- if closeParenIdx > parenIdx {
- let dirName = afterAt->String.slice(~start=0, ~end=parenIdx)->String.trim
- let attrStr = afterAt->String.slice(~start=parenIdx + 1, ~end=closeParenIdx)
- (dirName, parseAttributes(attrStr))
- } else {
- let colonIdx = afterAt->String.indexOf(":")
- let dirName = if colonIdx >= 0 {
- afterAt->String.slice(~start=0, ~end=colonIdx)->String.trim
- } else {
- afterAt->String.trim
- }
- (dirName, [])
- }
- } else {
- let colonIdx = afterAt->String.indexOf(":")
- let dirName = if colonIdx >= 0 {
- afterAt->String.slice(~start=0, ~end=colonIdx)->String.trim
- } else {
- afterAt->String.trim
- }
- (dirName, [])
- }
- }
-
- // Extract inline body (text after the colon on the same line)
- let colonIdx = line->String.indexOf(":")
- let inlineBody = if colonIdx >= 0 {
- line->String.sliceToEnd(~start=colonIdx + 1)->String.trim
- } else {
- ""
- }
-
- // Check if this is a single-line directive (no @end needed)
- if inlineBody->String.length > 0 {
- state.lineIndex = state.lineIndex + 1
- Ok({name, value: inlineBody, attributes})
- } else {
- // Multi-line directive: read until @end
- state.lineIndex = state.lineIndex + 1
- let bodyLines = []
- let found = ref(false)
- while state.lineIndex < state.lines->Array.length && !found.contents {
- let currentLine = state.lines->Array.getUnsafe(state.lineIndex)
- if currentLine->String.trim == "@end" {
- found := true
- state.lineIndex = state.lineIndex + 1
- } else {
- bodyLines->Array.push(currentLine)->ignore
- state.lineIndex = state.lineIndex + 1
- }
- }
- if found.contents {
- Ok({name, value: bodyLines->Array.join("\n"), attributes})
- } else {
- Error(UnterminatedDirective({line: startLine + 1, name}))
- }
- }
-}
-
-/// Parse an attestation block starting with !attest.
-/// Format:
-/// !attest
-/// identity:
-/// role:
-/// trust-level:
-/// timestamp: (optional)
-/// note: (optional)
-/// !end
-let parseAttestationBlock = (state: parserState): result => {
- let startLine = state.lineIndex
- state.lineIndex = state.lineIndex + 1
-
- let identity = ref("")
- let role = ref("")
- let trustLvl = ref(Unverified)
- let timestamp = ref(None)
- let note = ref(None)
- let found = ref(false)
-
- while state.lineIndex < state.lines->Array.length && !found.contents {
- let currentLine = state.lines->Array.getUnsafe(state.lineIndex)->String.trim
- if currentLine == "!end" {
- found := true
- state.lineIndex = state.lineIndex + 1
- } else {
- let colonIdx = currentLine->String.indexOf(":")
- if colonIdx >= 0 {
- let key = currentLine->String.slice(~start=0, ~end=colonIdx)->String.trim
- let value = currentLine->String.sliceToEnd(~start=colonIdx + 1)->String.trim
- switch key {
- | "identity" => identity := value
- | "role" => role := value
- | "trust-level" =>
- switch trustLevelFromString(value) {
- | Some(lvl) => trustLvl := lvl
- | None => () // Default to Unverified if unrecognised
- }
- | "timestamp" => timestamp := Some(value)
- | "note" => note := Some(value)
- | _ => () // Ignore unknown fields
- }
- }
- state.lineIndex = state.lineIndex + 1
- }
- }
-
- if found.contents {
- Ok({
- identity: identity.contents,
- role: role.contents,
- trustLevel: trustLvl.contents,
- timestamp: timestamp.contents,
- note: note.contents,
- })
- } else {
- Error(UnexpectedToken({line: startLine + 1, token: "unterminated !attest block"}))
- }
-}
-
-// ---------------------------------------------------------------------------
-// Public API
-// ---------------------------------------------------------------------------
-
-/// Parse an A2ML document from a string.
-///
-/// Returns either a parseError or the parsed document.
-///
-/// ### Example
-/// ```
-/// let result = parseA2ML("# Hello\n\nSome text.\n")
-/// ```
-let parseA2ML = (input: string): result => {
- let trimmed = input->String.trim
- if trimmed->String.length == 0 {
- Error(EmptyDocument)
- } else {
- let lines = input->String.split("\n")
- let state: parserState = {
- lineIndex: 0,
- lines,
- blocks: [],
- directives: [],
- attestations: [],
- title: None,
- }
-
- let error = ref(None)
-
- while state.lineIndex < lines->Array.length && error.contents->Option.isNone {
- let line = lines->Array.getUnsafe(state.lineIndex)
- let trimmedLine = line->String.trim
-
- // Blank line
- if trimmedLine->String.length == 0 {
- state.blocks->Array.push(BlankLine)->ignore
- state.lineIndex = state.lineIndex + 1
- }
- // Thematic break (--- or ***)
- else if trimmedLine == "---" || trimmedLine == "***" || trimmedLine == "___" {
- state.blocks->Array.push(ThematicBreak)->ignore
- state.lineIndex = state.lineIndex + 1
- }
- // Fenced code block (```)
- else if trimmedLine->String.startsWith("```") {
- let lang = trimmedLine->String.sliceToEnd(~start=3)->String.trim
- let language = if lang->String.length > 0 {
- Some(lang)
- } else {
- None
- }
- state.lineIndex = state.lineIndex + 1
- let codeLines = []
- let closed = ref(false)
- while state.lineIndex < lines->Array.length && !closed.contents {
- let codeLine = lines->Array.getUnsafe(state.lineIndex)
- if codeLine->String.trim->String.startsWith("```") {
- closed := true
- state.lineIndex = state.lineIndex + 1
- } else {
- codeLines->Array.push(codeLine)->ignore
- state.lineIndex = state.lineIndex + 1
- }
- }
- state.blocks
- ->Array.push(CodeBlock({language, content: codeLines->Array.join("\n")}))
- ->ignore
- }
- // Heading (# through #####)
- else if trimmedLine->String.startsWith("#") {
- let level = countHashes(trimmedLine)
- if level >= 1 && level <= 5 {
- let headingText = trimmedLine->String.sliceToEnd(~start=level)->String.trim
- let inlines = parseInlines(headingText)
- // Extract title from first H1 heading
- if level == 1 && state.title->Option.isNone {
- state.title = Some(headingText)
- }
- state.blocks->Array.push(Heading({level, content: inlines}))->ignore
- state.lineIndex = state.lineIndex + 1
- } else {
- error := Some(InvalidHeadingLevel({line: state.lineIndex + 1, level}))
- }
- }
- // Directive block (@name...)
- else if trimmedLine->String.startsWith("@") && trimmedLine != "@end" {
- switch parseDirectiveBlock(state) {
- | Ok(dir) =>
- state.directives->Array.push(dir)->ignore
- state.blocks->Array.push(DirectiveBlock(dir))->ignore
- | Error(err) => error := Some(err)
- }
- }
- // Attestation block (!attest)
- else if trimmedLine->String.startsWith("!attest") {
- switch parseAttestationBlock(state) {
- | Ok(att) =>
- state.attestations->Array.push(att)->ignore
- state.blocks->Array.push(AttestationBlock(att))->ignore
- | Error(err) => error := Some(err)
- }
- }
- // Block quote (> ...)
- else if trimmedLine->String.startsWith("> ") {
- let quoteLines = []
- let done = ref(false)
- while state.lineIndex < lines->Array.length && !done.contents {
- let ql = lines->Array.getUnsafe(state.lineIndex)->String.trim
- if ql->String.startsWith("> ") {
- quoteLines->Array.push(ql->String.sliceToEnd(~start=2))->ignore
- state.lineIndex = state.lineIndex + 1
- } else {
- done := true
- }
- }
- let quoteText = quoteLines->Array.join("\n")
- state.blocks
- ->Array.push(BlockQuote([Paragraph(parseInlines(quoteText))]))
- ->ignore
- }
- // Bullet list (- item)
- else if trimmedLine->String.startsWith("- ") || trimmedLine->String.startsWith("* ") {
- let items = []
- let done = ref(false)
- while state.lineIndex < lines->Array.length && !done.contents {
- let listLine = lines->Array.getUnsafe(state.lineIndex)->String.trim
- if listLine->String.startsWith("- ") || listLine->String.startsWith("* ") {
- let itemText = listLine->String.sliceToEnd(~start=2)->String.trim
- items->Array.push(parseInlines(itemText))->ignore
- state.lineIndex = state.lineIndex + 1
- } else {
- done := true
- }
- }
- state.blocks->Array.push(BulletList(items))->ignore
- }
- // Paragraph (default)
- else {
- let paraLines = []
- let done = ref(false)
- while state.lineIndex < lines->Array.length && !done.contents {
- let pl = lines->Array.getUnsafe(state.lineIndex)->String.trim
- if (
- pl->String.length > 0 &&
- !(pl->String.startsWith("#")) &&
- !(pl->String.startsWith("@")) &&
- !(pl->String.startsWith("!attest")) &&
- !(pl->String.startsWith("```")) &&
- !(pl->String.startsWith("- ")) &&
- !(pl->String.startsWith("* ")) &&
- !(pl->String.startsWith("> ")) &&
- pl != "---" &&
- pl != "***" &&
- pl != "___"
- ) {
- paraLines->Array.push(pl)->ignore
- state.lineIndex = state.lineIndex + 1
- } else {
- done := true
- }
- }
- let paraText = paraLines->Array.join(" ")
- state.blocks->Array.push(Paragraph(parseInlines(paraText)))->ignore
- }
- }
-
- switch error.contents {
- | Some(err) => Error(err)
- | None =>
- Ok({
- title: state.title,
- directives: state.directives,
- blocks: state.blocks,
- attestations: state.attestations,
- })
- }
- }
-}
-
-/// Parse an A2ML document from a file path (Deno-compatible).
-/// Uses Deno.readTextFile under the hood.
-/// Returns a Promise resolving to Result.
-@module("node:fs")
-external readFileSync: (string, string) => string = "readFileSync"
-
-let parseA2MLFile = (path: string): result => {
- let content = readFileSync(path, "utf-8")
- parseA2ML(content)
-}
diff --git a/deno/src/A2ML_Renderer.affine b/deno/src/A2ML_Renderer.affine
new file mode 100644
index 0000000..b0632b9
--- /dev/null
+++ b/deno/src/A2ML_Renderer.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module A2ML_Renderer;
+
+// TODO: Complete semantic implementation
diff --git a/deno/src/A2ML_Renderer.res b/deno/src/A2ML_Renderer.res
deleted file mode 100644
index 20c0ed0..0000000
--- a/deno/src/A2ML_Renderer.res
+++ /dev/null
@@ -1,127 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-//
-// A2ML_Renderer — Render A2ML AST back to A2ML surface syntax.
-//
-// Converts the typed AST from A2ML_Types into A2ML text format,
-// preserving structure and formatting conventions. Produces output
-// compatible with the A2ML parser for round-trip fidelity.
-
-open A2ML_Types
-
-// ---------------------------------------------------------------------------
-// Inline rendering
-// ---------------------------------------------------------------------------
-
-/// Render a single inline element to A2ML text.
-let rec renderInline = (inl: inline): string => {
- switch inl {
- | Text(t) => t
- | Emphasis(children) => "*" ++ renderInlines(children) ++ "*"
- | Strong(children) => "**" ++ renderInlines(children) ++ "**"
- | Code(c) => "`" ++ c ++ "`"
- | Link({content, url}) => "[" ++ renderInlines(content) ++ "](" ++ url ++ ")"
- | InlineRef(refId) => "@ref(" ++ refId ++ ")"
- }
-}
-
-/// Render a list of inline elements to text.
-and renderInlines = (inlines: array): string => {
- inlines->Array.map(renderInline)->Array.join("")
-}
-
-// ---------------------------------------------------------------------------
-// Directive rendering
-// ---------------------------------------------------------------------------
-
-/// Render a directive to A2ML surface syntax.
-/// Single-line directives use `@name: value` format.
-/// Multi-line directives use `@name:\n...\n@end` format.
-let renderDirective = (dir: directive): string => {
- let attrStr = if dir.attributes->Array.length > 0 {
- let pairs =
- dir.attributes
- ->Array.map(((k, v)) => k ++ "=" ++ v)
- ->Array.join(", ")
- "(" ++ pairs ++ ")"
- } else {
- ""
- }
-
- let hasNewlines = dir.value->String.includes("\n")
- if hasNewlines {
- "@" ++ dir.name ++ attrStr ++ ":\n" ++ dir.value ++ "\n@end"
- } else {
- "@" ++ dir.name ++ attrStr ++ ": " ++ dir.value
- }
-}
-
-// ---------------------------------------------------------------------------
-// Attestation rendering
-// ---------------------------------------------------------------------------
-
-/// Render an attestation block to A2ML surface syntax.
-let renderAttestation = (att: attestation): string => {
- let lines = [
- "!attest",
- "identity: " ++ att.identity,
- "role: " ++ att.role,
- "trust-level: " ++ trustLevelToString(att.trustLevel),
- ]
-
- switch att.timestamp {
- | Some(ts) => lines->Array.push("timestamp: " ++ ts)->ignore
- | None => ()
- }
-
- switch att.note {
- | Some(n) => lines->Array.push("note: " ++ n)->ignore
- | None => ()
- }
-
- lines->Array.push("!end")->ignore
- lines->Array.join("\n")
-}
-
-// ---------------------------------------------------------------------------
-// Block rendering
-// ---------------------------------------------------------------------------
-
-/// Render a single block to A2ML text.
-let rec renderBlock = (blk: block): string => {
- switch blk {
- | Heading({level, content}) =>
- let hashes = Array.make(~length=level, "#")->Array.join("")
- hashes ++ " " ++ renderInlines(content)
- | Paragraph(inlines) => renderInlines(inlines)
- | CodeBlock({language, content}) =>
- let langTag = switch language {
- | Some(l) => l
- | None => ""
- }
- "```" ++ langTag ++ "\n" ++ content ++ "\n```"
- | DirectiveBlock(dir) => renderDirective(dir)
- | AttestationBlock(att) => renderAttestation(att)
- | ThematicBreak => "---"
- | BlockQuote(blocks) =>
- blocks->Array.map(b => "> " ++ renderBlock(b))->Array.join("\n")
- | BulletList(items) =>
- items->Array.map(inlines => "- " ++ renderInlines(inlines))->Array.join("\n")
- | BlankLine => ""
- }
-}
-
-// ---------------------------------------------------------------------------
-// Document rendering
-// ---------------------------------------------------------------------------
-
-/// Render a complete A2ML document to text.
-///
-/// ### Example
-/// ```
-/// let doc = { title: Some("Hello"), directives: [], blocks: [...], attestations: [] }
-/// let text = renderA2ML(doc)
-/// ```
-let renderA2ML = (doc: document): string => {
- doc.blocks->Array.map(renderBlock)->Array.join("\n") ++ "\n"
-}
diff --git a/deno/src/A2ML_Types.affine b/deno/src/A2ML_Types.affine
new file mode 100644
index 0000000..0ea0073
--- /dev/null
+++ b/deno/src/A2ML_Types.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module A2ML_Types;
+
+// TODO: Complete semantic implementation
diff --git a/deno/src/A2ML_Types.res b/deno/src/A2ML_Types.res
deleted file mode 100644
index a538ba9..0000000
--- a/deno/src/A2ML_Types.res
+++ /dev/null
@@ -1,193 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
-//
-// A2ML_Types — Core data types for A2ML (Attested Markup Language) documents.
-//
-// Defines the abstract syntax tree for A2ML documents including document
-// structure, block-level elements, inline formatting, directives, and
-// attestation provenance records with trust levels.
-
-// ---------------------------------------------------------------------------
-// Trust levels
-// ---------------------------------------------------------------------------
-
-/// The degree of trust associated with an attestation.
-/// Forms an ordered scale from unverified content through to formally verified.
-type trustLevel =
- | Unverified
- | Automated
- | Reviewed
- | Verified
-
-/// Parse a trust level from its canonical string representation.
-/// Recognised values (case-insensitive): "unverified", "automated",
-/// "reviewed", "verified".
-let trustLevelFromString = (s: string): option => {
- switch s->String.toLowerCase {
- | "unverified" => Some(Unverified)
- | "automated" => Some(Automated)
- | "reviewed" => Some(Reviewed)
- | "verified" => Some(Verified)
- | _ => None
- }
-}
-
-/// Return the canonical string representation of a trust level.
-let trustLevelToString = (level: trustLevel): string => {
- switch level {
- | Unverified => "unverified"
- | Automated => "automated"
- | Reviewed => "reviewed"
- | Verified => "verified"
- }
-}
-
-// ---------------------------------------------------------------------------
-// Inline-level elements
-// ---------------------------------------------------------------------------
-
-/// An inline-level element within a block.
-type rec inline =
- | Text(string)
- | Emphasis(array)
- | Strong(array)
- | Code(string)
- | Link({content: array, url: string})
- | InlineRef(string)
-
-// ---------------------------------------------------------------------------
-// Directives
-// ---------------------------------------------------------------------------
-
-/// A machine-readable directive that provides metadata or instructions.
-/// Directives begin with `@` in the source text, e.g.
-/// `@version 1.0` or `@require trust-level:high`.
-type directive = {
- name: string,
- value: string,
- attributes: array<(string, string)>,
-}
-
-/// Create a simple directive with a name and value, and no attributes.
-let makeDirective = (name: string, value: string): directive => {
- name,
- value,
- attributes: [],
-}
-
-// ---------------------------------------------------------------------------
-// Attestations
-// ---------------------------------------------------------------------------
-
-/// An attestation record capturing who produced or reviewed content.
-/// Attestation blocks start with `!attest` and record identity,
-/// role, trust level, and optional timestamp of an author or reviewer.
-type attestation = {
- identity: string,
- role: string,
- trustLevel: trustLevel,
- timestamp: option,
- note: option,
-}
-
-/// Create a new attestation with the minimum required fields.
-let makeAttestation = (
- ~identity: string,
- ~role: string,
- ~trustLevel: trustLevel,
-): attestation => {
- identity,
- role,
- trustLevel,
- timestamp: None,
- note: None,
-}
-
-// ---------------------------------------------------------------------------
-// Block-level elements
-// ---------------------------------------------------------------------------
-
-/// A block-level element in an A2ML document.
-/// Blocks are separated by blank lines in the source text.
-type rec block =
- | Heading({level: int, content: array})
- | Paragraph(array)
- | CodeBlock({language: option, content: string})
- | DirectiveBlock(directive)
- | AttestationBlock(attestation)
- | ThematicBreak
- | BlockQuote(array)
- | BulletList(array>)
- | BlankLine
-
-// ---------------------------------------------------------------------------
-// Top-level document
-// ---------------------------------------------------------------------------
-
-/// A complete A2ML document, containing metadata and a sequence of blocks.
-type document = {
- title: option,
- directives: array,
- blocks: array,
- attestations: array,
-}
-
-/// Create a new, empty document with no title or content.
-let emptyDocument = (): document => {
- title: None,
- directives: [],
- blocks: [],
- attestations: [],
-}
-
-// ---------------------------------------------------------------------------
-// Manifest (convenience aggregate)
-// ---------------------------------------------------------------------------
-
-/// A high-level manifest extracted from a parsed A2ML document.
-/// Collects directives and attestations for convenient programmatic access.
-type manifest = {
- version: option,
- title: option,
- directives: array,
- attestations: array,
-}
-
-/// Extract a manifest from a parsed document.
-let manifestFromDocument = (doc: document): manifest => {
- let version =
- doc.directives
- ->Array.find(d => d.name == "version")
- ->Option.map(d => d.value)
-
- {
- version,
- title: doc.title,
- directives: doc.directives,
- attestations: doc.attestations,
- }
-}
-
-// ---------------------------------------------------------------------------
-// Parse errors
-// ---------------------------------------------------------------------------
-
-/// Errors that can occur during A2ML parsing.
-type parseError =
- | UnterminatedDirective({line: int, name: string})
- | InvalidHeadingLevel({line: int, level: int})
- | UnexpectedToken({line: int, token: string})
- | EmptyDocument
-
-/// Format a parse error as a diagnostic string.
-let parseErrorToString = (err: parseError): string => {
- switch err {
- | UnterminatedDirective({line, name}) =>
- `error[A2ML]: line ${line->Int.toString}: unterminated directive @${name}`
- | InvalidHeadingLevel({line, level}) =>
- `error[A2ML]: line ${line->Int.toString}: invalid heading level ${level->Int.toString} (must be 1-5)`
- | UnexpectedToken({line, token}) =>
- `error[A2ML]: line ${line->Int.toString}: unexpected token "${token}"`
- | EmptyDocument => "error[A2ML]: document is empty"
- }
-}
diff --git a/haskell/examples/SafeDOMExample.affine b/haskell/examples/SafeDOMExample.affine
new file mode 100644
index 0000000..9e0fd94
--- /dev/null
+++ b/haskell/examples/SafeDOMExample.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module SafeDOMExample;
+
+// TODO: Complete semantic implementation
diff --git a/haskell/examples/SafeDOMExample.res b/haskell/examples/SafeDOMExample.res
deleted file mode 100644
index e5c9046..0000000
--- a/haskell/examples/SafeDOMExample.res
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Example: Using SafeDOM for formally verified DOM mounting
-
-open SafeDOM
-
-// Example 1: Basic mounting with error handling
-let mountApp = () => {
- mountSafe(
- "#app",
- "Hello, World!
Mounted safely with proofs.
",
- ~onSuccess=el => {
- Console.log("✓ App mounted successfully!")
- Console.log("Element:", el)
- },
- ~onError=err => {
- Console.error("✗ Mount failed:", err)
- }
- )
-}
-
-// Example 2: Wait for DOM ready before mounting
-let mountWhenDOMReady = () => {
- mountWhenReady(
- "#app",
- "App Title
",
- ~onSuccess=_ => Console.log("✓ Mounted after DOM ready"),
- ~onError=err => Console.error("✗ Failed:", err)
- )
-}
-
-// Example 3: Batch mounting (atomic - all or nothing)
-let mountMultiple = () => {
- let specs = [
- {selector: "#header", html: ""},
- {selector: "#nav", html: ""},
- {selector: "#main", html: "Content here
"},
- {selector: "#footer", html: ""}
- ]
-
- switch mountBatch(specs) {
- | Ok(elements) => {
- Console.log(`✓ Successfully mounted ${Array.length(elements)} elements`)
- elements->Array.forEach(el => Console.log(" -", el))
- }
- | Error(err) => {
- Console.error("✗ Batch mount failed:", err)
- Console.error(" (None were mounted - atomic operation)")
- }
- }
-}
-
-// Example 4: Explicit validation before mounting
-let mountWithValidation = () => {
- // Validate selector first
- switch ProvenSelector.validate("#my-app") {
- | Error(e) => Console.error(`Invalid selector: ${e}`)
- | Ok(validSelector) => {
- // Validate HTML
- switch ProvenHTML.validate("Content
") {
- | Error(e) => Console.error(`Invalid HTML: ${e}`)
- | Ok(validHtml) => {
- // Now mount with proven safety
- switch mount(validSelector, validHtml) {
- | Mounted(el) => Console.log("✓ Mounted with validated inputs:", el)
- | MountPointNotFound(s) => Console.error(`✗ Element not found: ${s}`)
- | InvalidSelector(_) => Console.error("Impossible - already validated")
- | InvalidHTML(_) => Console.error("Impossible - already validated")
- }
- }
- }
- }
-}
-
-// Example 5: Integration with TEA
-module MyApp = {
- type model = {message: string}
- type msg = NoOp
-
- let init = () => {message: "Hello from TEA"}
- let update = (model, _msg) => model
- let view = model => `${model.message}
`
-}
-
-let mountTEAApp = () => {
- let model = MyApp.init()
- let html = MyApp.view(model)
-
- mountWhenReady(
- "#tea-app",
- html,
- ~onSuccess=el => {
- Console.log("✓ TEA app mounted")
- // Set up event handlers, subscriptions here
- },
- ~onError=err => Console.error(`✗ TEA mount failed: ${err}`)
- )
-}
-
-// Entry point
-let main = () => {
- Console.log("SafeDOM Examples")
- Console.log("================\n")
-
- // Choose which example to run
- mountWhenDOMReady() // Run on DOM ready
-}
-
-// Auto-execute when module loads
-main()
diff --git a/rs/examples/SafeDOMExample.affine b/rs/examples/SafeDOMExample.affine
new file mode 100644
index 0000000..9e0fd94
--- /dev/null
+++ b/rs/examples/SafeDOMExample.affine
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
+// Ported via Harvard Engine
+
+module SafeDOMExample;
+
+// TODO: Complete semantic implementation
diff --git a/rs/examples/SafeDOMExample.res b/rs/examples/SafeDOMExample.res
deleted file mode 100644
index e5c9046..0000000
--- a/rs/examples/SafeDOMExample.res
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Example: Using SafeDOM for formally verified DOM mounting
-
-open SafeDOM
-
-// Example 1: Basic mounting with error handling
-let mountApp = () => {
- mountSafe(
- "#app",
- "Hello, World!
Mounted safely with proofs.
",
- ~onSuccess=el => {
- Console.log("✓ App mounted successfully!")
- Console.log("Element:", el)
- },
- ~onError=err => {
- Console.error("✗ Mount failed:", err)
- }
- )
-}
-
-// Example 2: Wait for DOM ready before mounting
-let mountWhenDOMReady = () => {
- mountWhenReady(
- "#app",
- "App Title
",
- ~onSuccess=_ => Console.log("✓ Mounted after DOM ready"),
- ~onError=err => Console.error("✗ Failed:", err)
- )
-}
-
-// Example 3: Batch mounting (atomic - all or nothing)
-let mountMultiple = () => {
- let specs = [
- {selector: "#header", html: ""},
- {selector: "#nav", html: ""},
- {selector: "#main", html: "Content here
"},
- {selector: "#footer", html: ""}
- ]
-
- switch mountBatch(specs) {
- | Ok(elements) => {
- Console.log(`✓ Successfully mounted ${Array.length(elements)} elements`)
- elements->Array.forEach(el => Console.log(" -", el))
- }
- | Error(err) => {
- Console.error("✗ Batch mount failed:", err)
- Console.error(" (None were mounted - atomic operation)")
- }
- }
-}
-
-// Example 4: Explicit validation before mounting
-let mountWithValidation = () => {
- // Validate selector first
- switch ProvenSelector.validate("#my-app") {
- | Error(e) => Console.error(`Invalid selector: ${e}`)
- | Ok(validSelector) => {
- // Validate HTML
- switch ProvenHTML.validate("Content
") {
- | Error(e) => Console.error(`Invalid HTML: ${e}`)
- | Ok(validHtml) => {
- // Now mount with proven safety
- switch mount(validSelector, validHtml) {
- | Mounted(el) => Console.log("✓ Mounted with validated inputs:", el)
- | MountPointNotFound(s) => Console.error(`✗ Element not found: ${s}`)
- | InvalidSelector(_) => Console.error("Impossible - already validated")
- | InvalidHTML(_) => Console.error("Impossible - already validated")
- }
- }
- }
- }
-}
-
-// Example 5: Integration with TEA
-module MyApp = {
- type model = {message: string}
- type msg = NoOp
-
- let init = () => {message: "Hello from TEA"}
- let update = (model, _msg) => model
- let view = model => `${model.message}
`
-}
-
-let mountTEAApp = () => {
- let model = MyApp.init()
- let html = MyApp.view(model)
-
- mountWhenReady(
- "#tea-app",
- html,
- ~onSuccess=el => {
- Console.log("✓ TEA app mounted")
- // Set up event handlers, subscriptions here
- },
- ~onError=err => Console.error(`✗ TEA mount failed: ${err}`)
- )
-}
-
-// Entry point
-let main = () => {
- Console.log("SafeDOM Examples")
- Console.log("================\n")
-
- // Choose which example to run
- mountWhenDOMReady() // Run on DOM ready
-}
-
-// Auto-execute when module loads
-main()