@hyperframes/parsers 0.8.75 → 0.8.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gsapParserAcorn.js +9 -0
- package/dist/gsapParserAcorn.js.map +1 -1
- package/dist/gsapParserExports.js +9 -0
- package/dist/gsapParserExports.js.map +1 -1
- package/dist/gsapWriterAcorn.js.map +1 -1
- package/dist/hfIds.d.ts +6 -6
- package/dist/hfIds.js.map +1 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/hfIds.d.ts
CHANGED
|
@@ -5,12 +5,12 @@ declare const EXCLUDED_TAGS: Set<string>;
|
|
|
5
5
|
* get different ids based on which comes first in the DOM. This is unavoidable:
|
|
6
6
|
* unique ids for byte-identical elements require a positional signal.
|
|
7
7
|
*
|
|
8
|
-
* Why this is safe in practice: once `
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* Why this is safe in practice: once `data-hf-id` is on disk (stamped at project open, or by the
|
|
9
|
+
* first save) it is bound to its element, so reordering identical siblings carries it along, and
|
|
10
|
+
* `ensureHfIds` skips pinned elements (`if (getContractAttribute(el, "data-hf-id")) continue`).
|
|
11
|
+
* Before that, an outside edit changes what is minted (an element's attributes or own text, or a
|
|
12
|
+
* twin added or removed), so a save carrying an id served before the edit misses or hits the other
|
|
13
|
+
* twin until the watcher reloads the preview.
|
|
14
14
|
*/
|
|
15
15
|
declare function mintHfId(el: Element, assigned: Set<string>): string;
|
|
16
16
|
declare function isCompositionTemplate(el: Element): boolean;
|
package/dist/hfIds.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hfIds.ts","../src/hfIdAssignment.ts"],"sourcesContent":["/**\n * Stable hf- element id minting (R1). Node-safe (linkedom only, not browser DOM).\n *\n * Two surfaces share these helpers:\n * - ensureHfIds(html): node-id surface — mints data-hf-id on every element.\n * - mintHfId(el, assigned): shared by htmlParser for clip ids.\n *\n * Hash is CONTENT ONLY (tag + sorted attrs + own text) — no sibling position,\n * so inserting a non-identical sibling never shifts another element's id.\n */\nimport { parseHTML } from \"linkedom\";\nimport { assignHfIds } from \"./hfIdAssignment.js\";\nexport {\n EXCLUDED_TAGS,\n mintHfId,\n isCompositionTemplate,\n walkCompositionDescendants,\n} from \"./hfIdAssignment.js\";\n\nexport function ensureHfIds(html: string): string {\n // Wrap fragments so every body element participates in stable ID assignment.\n const wrapped = !/<!doctype|<html[\\s>]/i.test(html);\n const { document } = wrapped\n ? parseHTML(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`)\n : parseHTML(html);\n if (!document.body) return html;\n assignHfIds(document.body);\n return wrapped ? document.body.innerHTML || \"\" : document.toString();\n}\n","// Non-editable / non-visual elements that should never receive a stable id.\nexport const EXCLUDED_TAGS = new Set([\n \"script\",\n \"style\",\n \"template\",\n \"meta\",\n \"link\",\n \"noscript\",\n \"base\",\n]);\n\n// 32-bit FNV-1a. Pure, deterministic, no crypto, no Math.random.\nfunction fnv1a(str: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n// 4 base-36 chars · 36^4 ≈ 1.68M ids per document. Birthday-paradox collision\n// ≈ N²/(2·36^4): well under 1% per document after dup rehash at realistic\n// clip-model sizes (≤ a few hundred elements). The dup-rehash in mintHfId\n// resolves the rare collision; width is deliberately small for readable ids.\nfunction toHfId(hash: number): string {\n const s = (hash >>> 0).toString(36);\n // Use suffix (most-avalanched bits) for better distribution within the 4-char window.\n const four = s.length >= 4 ? s.slice(-4) : s.padStart(4, \"0\");\n return `hf-${four}`;\n}\n\n// Element's own direct text (TEXT_NODE children), not descendants'.\nfunction ownText(el: Element): string {\n let text = \"\";\n el.childNodes.forEach((n) => {\n if (n.nodeType === 3) text += (n as Text).nodeValue ?? \"\";\n });\n return text.trim();\n}\n\nfunction getContractAttribute(el: Element, name: string): string | null {\n return Array.from(el.attributes).find((attr) => attr.name.toLowerCase() === name)?.value ?? null;\n}\n\nfunction contentKey(el: Element): string {\n // HTML parsers normalize foreign-content attribute names differently too.\n // Canonicalize only the hash input; retain actual SVG attribute spelling.\n // Exclude all data-hf-* attrs (ids, studio state) — they must not influence the hash.\n // Use \\x00 / \\x01 separators (invalid in HTML attrs) to prevent ambiguous serialization.\n const attrs = Array.from(el.attributes)\n .filter((a) => !a.name.toLowerCase().startsWith(\"data-hf-\"))\n .map((a) => `${a.name.toLowerCase()}\\x00${a.value}`)\n .sort()\n .join(\"\\x01\");\n return `${el.tagName.toLowerCase()}|${attrs}|${ownText(el)}`;\n}\n\n/**\n * Collision tiebreak for byte-identical siblings: document-order dup counter\n * (`hash(key#N)`). This IS order-dependent — two identical `<span></span>`\n * get different ids based on which comes first in the DOM. This is unavoidable:\n * unique ids for byte-identical elements require a positional signal.\n *\n * Why this is safe in practice: once `ensureHfIds` write-back persists\n * `data-hf-id` to source the attribute is physically bound to its element.\n * Reordering identical siblings carries the attribute along → zero\n * order-dependence post-persist. `ensureHfIds` skips pinned elements\n * (`if (getContractAttribute(el, \"data-hf-id\")) continue`), so normal operation\n * never re-exposes the ordering after first persist.\n */\n// WIRE CONTRACT: id minting is content-keyed (FNV1a of innerHTML + tag). R7's\n// preview route relies on mintHfId producing identical ids across mint contexts\n// (disk-persist pass vs. in-memory bundle pass) — see preview.test.ts\n// \"bundle returning untagged HTML gets same ids as disk\". Any change that adds\n// positional, session, or random input to the hash breaks that invariant and\n// makes hf- ids diverge between disk and served HTML, silently corrupting\n// drag-to-edit targeting.\nexport function mintHfId(el: Element, assigned: Set<string>): string {\n const key = contentKey(el);\n let id = toHfId(fnv1a(key));\n let dup = 0;\n while (assigned.has(id)) {\n dup += 1;\n // Graceful fallback instead of a hard throw: rehashing only fails to find a\n // free 4-char slot in a pathological document (~1.6M identical elements).\n // Rather than crash the whole parse, widen the id with the dup counter —\n // still deterministic and unique, just longer than the 4-char norm.\n if (dup > 10000) {\n id = `hf-${(fnv1a(key) >>> 0).toString(36)}-${dup}`;\n break;\n }\n id = toHfId(fnv1a(`${key}#${dup}`));\n }\n assigned.add(id);\n return id;\n}\n\n/**\n * True for a sub-composition authoring template whose content the studio preview\n * unwraps into the served body. Two accepted forms:\n * A) `<template data-composition-id=\"X\">…` — the id on the template itself.\n * B) `<template id=\"X-template\"><div data-composition-id=\"X\">…` — the id on the\n * wrapped root div (the form `hyperframes add` scaffolds and registry blocks use).\n * Only these are treated as transparent containers for hf-id purposes. A plain\n * `<template>` (runtime clone-source: list item, particle, etc.) must NOT get\n * inner ids — its content is cloned N times into the live DOM, so a persisted\n * inner id would be duplicated across every clone. Form B is distinguished from\n * a clone-source by the presence of a direct `[data-composition-id]` child.\n */\nfunction getChildElements(parent: Element): Element[] {\n const directChildren = Array.from(parent.children);\n if (directChildren.length || parent.tagName.toLowerCase() !== \"template\") return directChildren;\n const content = (parent as HTMLTemplateElement).content;\n if (content?.children.length) return Array.from(content.children);\n return directChildren;\n}\n\nexport function isCompositionTemplate(el: Element): boolean {\n if (el.tagName.toLowerCase() !== \"template\") return false;\n if (getContractAttribute(el, \"data-composition-id\") !== null) return true;\n for (const child of getChildElements(el)) {\n if (getContractAttribute(child, \"data-composition-id\") !== null) return true;\n }\n return false;\n}\n\n/**\n * Walk document-order descendants, descending through composition templates\n * while keeping plain templates inert. linkedom's querySelectorAll does not\n * expose template contents, so callers that model the served composition use\n * this traversal instead.\n */\nexport function walkCompositionDescendants(\n root: Document | Element,\n visit: (el: Element) => void,\n): void {\n const rootElement: Element | null =\n root.nodeType === 9 ? (root as Document).documentElement : (root as Element);\n if (!rootElement) return;\n\n const walk = (parent: Element): void => {\n for (const child of getChildElements(parent)) {\n const isTemplate = child.tagName.toLowerCase() === \"template\";\n if (isTemplate && !isCompositionTemplate(child)) continue;\n visit(child);\n walk(child);\n }\n };\n\n walk(rootElement);\n}\n\n// Internal DOM-only assignment: callers retain their parser and document identity.\nexport function assignHfIds(body: Element): void {\n const assigned = new Set<string>();\n walkCompositionDescendants(body, (el) => {\n const existing = getContractAttribute(el, \"data-hf-id\");\n if (existing) assigned.add(existing);\n });\n walkCompositionDescendants(body, (el) => {\n if (EXCLUDED_TAGS.has(el.tagName.toLowerCase())) return;\n if (getContractAttribute(el, \"data-hf-id\")) return;\n el.setAttribute(\"data-hf-id\", mintHfId(el, assigned));\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/hfIds.ts","../src/hfIdAssignment.ts"],"sourcesContent":["/**\n * Stable hf- element id minting (R1). Node-safe (linkedom only, not browser DOM).\n *\n * Two surfaces share these helpers:\n * - ensureHfIds(html): node-id surface — mints data-hf-id on every element.\n * - mintHfId(el, assigned): shared by htmlParser for clip ids.\n *\n * Hash is CONTENT ONLY (tag + sorted attrs + own text) — no sibling position,\n * so inserting a non-identical sibling never shifts another element's id.\n */\nimport { parseHTML } from \"linkedom\";\nimport { assignHfIds } from \"./hfIdAssignment.js\";\nexport {\n EXCLUDED_TAGS,\n mintHfId,\n isCompositionTemplate,\n walkCompositionDescendants,\n} from \"./hfIdAssignment.js\";\n\nexport function ensureHfIds(html: string): string {\n // Wrap fragments so every body element participates in stable ID assignment.\n const wrapped = !/<!doctype|<html[\\s>]/i.test(html);\n const { document } = wrapped\n ? parseHTML(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`)\n : parseHTML(html);\n if (!document.body) return html;\n assignHfIds(document.body);\n return wrapped ? document.body.innerHTML || \"\" : document.toString();\n}\n","// Non-editable / non-visual elements that should never receive a stable id.\nexport const EXCLUDED_TAGS = new Set([\n \"script\",\n \"style\",\n \"template\",\n \"meta\",\n \"link\",\n \"noscript\",\n \"base\",\n]);\n\n// 32-bit FNV-1a. Pure, deterministic, no crypto, no Math.random.\nfunction fnv1a(str: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n// 4 base-36 chars · 36^4 ≈ 1.68M ids per document. Birthday-paradox collision\n// ≈ N²/(2·36^4): well under 1% per document after dup rehash at realistic\n// clip-model sizes (≤ a few hundred elements). The dup-rehash in mintHfId\n// resolves the rare collision; width is deliberately small for readable ids.\nfunction toHfId(hash: number): string {\n const s = (hash >>> 0).toString(36);\n // Use suffix (most-avalanched bits) for better distribution within the 4-char window.\n const four = s.length >= 4 ? s.slice(-4) : s.padStart(4, \"0\");\n return `hf-${four}`;\n}\n\n// Element's own direct text (TEXT_NODE children), not descendants'.\nfunction ownText(el: Element): string {\n let text = \"\";\n el.childNodes.forEach((n) => {\n if (n.nodeType === 3) text += (n as Text).nodeValue ?? \"\";\n });\n return text.trim();\n}\n\nfunction getContractAttribute(el: Element, name: string): string | null {\n return Array.from(el.attributes).find((attr) => attr.name.toLowerCase() === name)?.value ?? null;\n}\n\nfunction contentKey(el: Element): string {\n // HTML parsers normalize foreign-content attribute names differently too.\n // Canonicalize only the hash input; retain actual SVG attribute spelling.\n // Exclude all data-hf-* attrs (ids, studio state) — they must not influence the hash.\n // Use \\x00 / \\x01 separators (invalid in HTML attrs) to prevent ambiguous serialization.\n const attrs = Array.from(el.attributes)\n .filter((a) => !a.name.toLowerCase().startsWith(\"data-hf-\"))\n .map((a) => `${a.name.toLowerCase()}\\x00${a.value}`)\n .sort()\n .join(\"\\x01\");\n return `${el.tagName.toLowerCase()}|${attrs}|${ownText(el)}`;\n}\n\n/**\n * Collision tiebreak for byte-identical siblings: document-order dup counter\n * (`hash(key#N)`). This IS order-dependent — two identical `<span></span>`\n * get different ids based on which comes first in the DOM. This is unavoidable:\n * unique ids for byte-identical elements require a positional signal.\n *\n * Why this is safe in practice: once `data-hf-id` is on disk (stamped at project open, or by the\n * first save) it is bound to its element, so reordering identical siblings carries it along, and\n * `ensureHfIds` skips pinned elements (`if (getContractAttribute(el, \"data-hf-id\")) continue`).\n * Before that, an outside edit changes what is minted (an element's attributes or own text, or a\n * twin added or removed), so a save carrying an id served before the edit misses or hits the other\n * twin until the watcher reloads the preview.\n */\n// WIRE CONTRACT: id minting is content-keyed (FNV1a of tag, sorted attrs, own text). R7's\n// preview route relies on mintHfId producing identical ids across mint contexts\n// (served copy vs. the source a save parses) — see preview.test.ts\n// \"bundle returning untagged HTML gets the ids minted from the source file\". Any change that adds\n// positional, session, or random input to the hash breaks that invariant and\n// makes hf- ids diverge between disk and served HTML, silently corrupting\n// drag-to-edit targeting.\nexport function mintHfId(el: Element, assigned: Set<string>): string {\n const key = contentKey(el);\n let id = toHfId(fnv1a(key));\n let dup = 0;\n while (assigned.has(id)) {\n dup += 1;\n // Graceful fallback instead of a hard throw: rehashing only fails to find a\n // free 4-char slot in a pathological document (~1.6M identical elements).\n // Rather than crash the whole parse, widen the id with the dup counter —\n // still deterministic and unique, just longer than the 4-char norm.\n if (dup > 10000) {\n id = `hf-${(fnv1a(key) >>> 0).toString(36)}-${dup}`;\n break;\n }\n id = toHfId(fnv1a(`${key}#${dup}`));\n }\n assigned.add(id);\n return id;\n}\n\n/**\n * True for a sub-composition authoring template whose content the studio preview\n * unwraps into the served body. Two accepted forms:\n * A) `<template data-composition-id=\"X\">…` — the id on the template itself.\n * B) `<template id=\"X-template\"><div data-composition-id=\"X\">…` — the id on the\n * wrapped root div (the form `hyperframes add` scaffolds and registry blocks use).\n * Only these are treated as transparent containers for hf-id purposes. A plain\n * `<template>` (runtime clone-source: list item, particle, etc.) must NOT get\n * inner ids — its content is cloned N times into the live DOM, so a persisted\n * inner id would be duplicated across every clone. Form B is distinguished from\n * a clone-source by the presence of a direct `[data-composition-id]` child.\n */\nfunction getChildElements(parent: Element): Element[] {\n const directChildren = Array.from(parent.children);\n if (directChildren.length || parent.tagName.toLowerCase() !== \"template\") return directChildren;\n const content = (parent as HTMLTemplateElement).content;\n if (content?.children.length) return Array.from(content.children);\n return directChildren;\n}\n\nexport function isCompositionTemplate(el: Element): boolean {\n if (el.tagName.toLowerCase() !== \"template\") return false;\n if (getContractAttribute(el, \"data-composition-id\") !== null) return true;\n for (const child of getChildElements(el)) {\n if (getContractAttribute(child, \"data-composition-id\") !== null) return true;\n }\n return false;\n}\n\n/**\n * Walk document-order descendants, descending through composition templates\n * while keeping plain templates inert. linkedom's querySelectorAll does not\n * expose template contents, so callers that model the served composition use\n * this traversal instead.\n */\nexport function walkCompositionDescendants(\n root: Document | Element,\n visit: (el: Element) => void,\n): void {\n const rootElement: Element | null =\n root.nodeType === 9 ? (root as Document).documentElement : (root as Element);\n if (!rootElement) return;\n\n const walk = (parent: Element): void => {\n for (const child of getChildElements(parent)) {\n const isTemplate = child.tagName.toLowerCase() === \"template\";\n if (isTemplate && !isCompositionTemplate(child)) continue;\n visit(child);\n walk(child);\n }\n };\n\n walk(rootElement);\n}\n\n// Internal DOM-only assignment: callers retain their parser and document identity.\nexport function assignHfIds(body: Element): void {\n const assigned = new Set<string>();\n walkCompositionDescendants(body, (el) => {\n const existing = getContractAttribute(el, \"data-hf-id\");\n if (existing) assigned.add(existing);\n });\n walkCompositionDescendants(body, (el) => {\n if (EXCLUDED_TAGS.has(el.tagName.toLowerCase())) return;\n if (getContractAttribute(el, \"data-hf-id\")) return;\n el.setAttribute(\"data-hf-id\", mintHfId(el, assigned));\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -2204,7 +2204,16 @@ function parseGsapScriptAcornForWrite(script) {
|
|
|
2204
2204
|
return null;
|
|
2205
2205
|
}
|
|
2206
2206
|
}
|
|
2207
|
+
var PARSE_MEMO_ENTRIES = 4;
|
|
2208
|
+
var parseMemo = /* @__PURE__ */ new Map();
|
|
2207
2209
|
function parseGsapScriptAcorn(script) {
|
|
2210
|
+
const parsed = parseMemo.get(script) ?? parseGsapScriptAcornUncached(script);
|
|
2211
|
+
parseMemo.delete(script);
|
|
2212
|
+
parseMemo.set(script, parsed);
|
|
2213
|
+
if (parseMemo.size > PARSE_MEMO_ENTRIES) parseMemo.delete(parseMemo.keys().next().value);
|
|
2214
|
+
return structuredClone(parsed);
|
|
2215
|
+
}
|
|
2216
|
+
function parseGsapScriptAcornUncached(script) {
|
|
2208
2217
|
try {
|
|
2209
2218
|
const ast = parseProgram(script);
|
|
2210
2219
|
const scope = collectScopeBindings(ast);
|
|
@@ -3292,7 +3301,17 @@ function extractCompositionMetadata(html) {
|
|
|
3292
3301
|
const compositionId = htmlEl.getAttribute("data-composition-id");
|
|
3293
3302
|
const durationStr = htmlEl.getAttribute("data-composition-duration");
|
|
3294
3303
|
const compositionDuration = durationStr ? parseFloat(durationStr) : null;
|
|
3295
|
-
const
|
|
3304
|
+
const root = (doc.querySelector("template")?.content ?? doc).querySelector(
|
|
3305
|
+
"[data-composition-id]"
|
|
3306
|
+
);
|
|
3307
|
+
const variables = [
|
|
3308
|
+
...new Map(
|
|
3309
|
+
[
|
|
3310
|
+
...parseCompositionVariables(htmlEl),
|
|
3311
|
+
...root && root !== htmlEl ? parseCompositionVariables(root) : []
|
|
3312
|
+
].map((v) => [v.id, v])
|
|
3313
|
+
).values()
|
|
3314
|
+
];
|
|
3296
3315
|
return {
|
|
3297
3316
|
compositionId,
|
|
3298
3317
|
compositionDuration: compositionDuration && isFinite(compositionDuration) ? compositionDuration : null,
|