@vielzeug/ore 26.10.17 → 26.10.18

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.
@@ -1,2 +1,2 @@
1
- const e=require("../errors.cjs");var t={ATTR:`attr`,BOOL_ATTR:`boolAttr`,EVENT:`event`,NODE:`node`,PROP:`prop`,REF:`ref`},n={capture:!0,once:!0,prevent:!0,stop:!0},r=(t,r)=>{if(r.length===0)return;let i={};for(let a of r){if(!(a in n))throw new e.OreApiError(e.ORE_ERRORS.eventModifierUnknown(t,a));i[a]=!0}return i},i=/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/,a=/\s+ref\s*=\s*["']?$/,o=/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,s=/\s+\.([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,c=/\s+([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,l=n=>{let l;if(l=i.exec(n)){let e=n.slice(0,-l[0].length),[i,...a]=l[1].split(`.`);return{eventModifiers:r(i,a),kind:t.EVENT,name:i,prefix:e}}if(l=a.exec(n))return{kind:t.REF,prefix:n.slice(0,-l[0].length)};if(l=o.exec(n))return{kind:t.BOOL_ATTR,name:l[1],prefix:n.slice(0,-l[0].length)};if(l=s.exec(n)){let r=l[1];if(r===`__proto__`||r===`constructor`||r===`prototype`)throw new e.OreApiError(e.ORE_ERRORS.propBindingForbiddenName(r));return{kind:t.PROP,name:r,prefix:n.slice(0,-l[0].length)}}if(l=c.exec(n))return{kind:t.ATTR,name:l[1],prefix:n.slice(0,-l[0].length)};let u=n.lastIndexOf(`<`);if(u>n.lastIndexOf(`>`)&&n[u+1]!==`/`)throw new e.OreApiError(e.ORE_ERRORS.templateInterpolationInTag);return{kind:t.NODE,prefix:n}},u=new WeakMap,d=/[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\s*=\s*$/,f=e=>{let t=Array.from(e),n=!1;for(let e=0;e<t.length-1;e++){let r=t[e],i=r[r.length-1];for(let e of r)e===`<`?n=!0:e===`>`&&(n=!1);if((i===`"`||i===`'`)&&n&&d.test(r.slice(0,-1))){t[e]=r.slice(0,-1);let n=t[e+1];n.startsWith(i)&&(t[e+1]=n.slice(1))}}return t},p=`data-ore-b`,m=/^ore:(\d+)$/,h=(e,t,n,r)=>{if(e.nodeType===Node.ELEMENT_NODE){let r=e,i=r.getAttribute(p);i!==null&&(n.set(Number(i),[...t]),r.removeAttribute(p))}else if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue,i=n===null?null:m.exec(n);i&&r.set(Number(i[1]),[...t])}let i=e.childNodes;for(let e=0;e<i.length;e++)h(i[e],[...t,e],n,r)},g=e=>{let n=f(e),r=``,i,a=0,o=0,s=[];for(let e=0;e<n.length-1;e++){let c=n[e],u=l(c);if(u.kind===t.NODE)r+=`${u.prefix}<!--ore:${o}-->`,s.push({commentId:o,kind:t.NODE}),o++,i=void 0;else{i===void 0||u.prefix.lastIndexOf(`<`)>u.prefix.lastIndexOf(`>`)?(i=a++,r+=`${u.prefix} ${p}="${i}"`):r+=u.prefix;let e=u.kind===t.BOOL_ATTR?`bool`:u.kind===t.ATTR?`attr`:void 0;s.push({elementId:i,eventModifiers:u.eventModifiers,kind:u.kind,mode:e,name:u.name})}}r+=n[n.length-1]??``;let c=document.createElement(`template`);c.innerHTML=r;let u=new Map,d=new Map,m=c.content.childNodes;for(let e=0;e<m.length;e++)h(m[e],[e],u,d);return{commentPaths:d,element:c,elementPaths:u,slots:s}},_=e=>{let t=u.get(e);return t||(t=g(e),u.set(e,t)),t},v=(e,t)=>{let n=e;for(let e of t)n=n.childNodes[e];return n};exports.SlotKind=t,exports.followPath=v,exports.getStaticTemplate=_;
1
+ const e=require("../errors.cjs");var t={ATTR:`attr`,BOOL_ATTR:`boolAttr`,EVENT:`event`,NODE:`node`,PROP:`prop`,REF:`ref`},n={capture:!0,once:!0,prevent:!0,stop:!0},r=(t,r)=>{if(r.length===0)return;let i={};for(let a of r){if(!(a in n))throw new e.OreApiError(e.ORE_ERRORS.eventModifierUnknown(t,a));i[a]=!0}return i},i=/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/,a=/\s+ref\s*=\s*["']?$/,o=/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,s=/\s+\.([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,c=/\s+([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,l=new Set([`innerhtml`,`outerhtml`,`srcdoc`]),u=n=>{let u;if(u=i.exec(n)){let e=n.slice(0,-u[0].length),[i,...a]=u[1].split(`.`);return{eventModifiers:r(i,a),kind:t.EVENT,name:i,prefix:e}}if(u=a.exec(n))return{kind:t.REF,prefix:n.slice(0,-u[0].length)};if(u=o.exec(n))return{kind:t.BOOL_ATTR,name:u[1],prefix:n.slice(0,-u[0].length)};if(u=s.exec(n)){let r=u[1];if(r===`__proto__`||r===`constructor`||r===`prototype`)throw new e.OreApiError(e.ORE_ERRORS.propBindingForbiddenName(r));if(l.has(r.toLowerCase()))throw new e.OreApiError(e.ORE_ERRORS.propBindingHtmlInjectionName(r));return{kind:t.PROP,name:r,prefix:n.slice(0,-u[0].length)}}if(u=c.exec(n))return{kind:t.ATTR,name:u[1],prefix:n.slice(0,-u[0].length)};let d=n.lastIndexOf(`<`);if(d>n.lastIndexOf(`>`)&&n[d+1]!==`/`)throw new e.OreApiError(e.ORE_ERRORS.templateInterpolationInTag);return{kind:t.NODE,prefix:n}},d=new WeakMap,f=/[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\s*=\s*$/,p=e=>{let t=Array.from(e),n=!1;for(let e=0;e<t.length-1;e++){let r=t[e],i=r[r.length-1];for(let e of r)e===`<`?n=!0:e===`>`&&(n=!1);if((i===`"`||i===`'`)&&n&&f.test(r.slice(0,-1))){t[e]=r.slice(0,-1);let n=t[e+1];n.startsWith(i)&&(t[e+1]=n.slice(1))}}return t},m=`data-ore-b`,h=/^ore:(\d+)$/,g=(e,t,n,r)=>{if(e.nodeType===Node.ELEMENT_NODE){let r=e,i=r.getAttribute(m);i!==null&&(n.set(Number(i),[...t]),r.removeAttribute(m))}else if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue,i=n===null?null:h.exec(n);i&&r.set(Number(i[1]),[...t])}let i=e.childNodes;for(let e=0;e<i.length;e++)g(i[e],[...t,e],n,r)},_=e=>{let n=p(e),r=``,i,a=0,o=0,s=[];for(let e=0;e<n.length-1;e++){let c=n[e],l=u(c);if(l.kind===t.NODE)r+=`${l.prefix}<!--ore:${o}-->`,s.push({commentId:o,kind:t.NODE}),o++,i=void 0;else{i===void 0||l.prefix.lastIndexOf(`<`)>l.prefix.lastIndexOf(`>`)?(i=a++,r+=`${l.prefix} ${m}="${i}"`):r+=l.prefix;let e=l.kind===t.BOOL_ATTR?`bool`:l.kind===t.ATTR?`attr`:void 0;s.push({elementId:i,eventModifiers:l.eventModifiers,kind:l.kind,mode:e,name:l.name})}}r+=n[n.length-1]??``;let c=document.createElement(`template`);c.innerHTML=r;let l=new Map,d=new Map,f=c.content.childNodes;for(let e=0;e<f.length;e++)g(f[e],[e],l,d);return{commentPaths:d,element:c,elementPaths:l,slots:s}},v=e=>{let t=d.get(e);return t||(t=_(e),d.set(e,t)),t},y=(e,t)=>{let n=e;for(let e of t)n=n.childNodes[e];return n};exports.SlotKind=t,exports.followPath=y,exports.getStaticTemplate=v;
2
2
  //# sourceMappingURL=compiler.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.cjs","names":["OreApiError","ORE_ERRORS","require_errors","SlotKind","EVENT_MODIFIERS","parseEventModifiers","modifiers","parsed","modifier","name","EVENT_RE","REF_RE","BOOL_ATTR_RE","PROP_RE","ATTR_RE","detectSlot","m","str","prefix","lastOpen","templateCache","ATTR_VALUE_CONTEXT_RE","normalizeTemplateStrings","out","strings","insideTag","i","s","lastChar","ch","next","ELEMENT_MARKER_ATTR","COMMENT_MARKER_RE","walkNode","node","el","marker","elementPaths","path","content","commentPaths","children","buildStaticTemplate","normalized","html","activeElementId","elementCounter","commentCounter","slots","raw","slot","mode","tpl","topChildren","getStaticTemplate","followPath","root"],"sources":["../../src/template/compiler.ts"],"sourcesContent":["/**\n * template/compiler.ts: HTML template string parser and static template cache.\n *\n * Responsibilities:\n * - Parse TemplateStringsArray into slot metadata (slot detection).\n * - Build a cached HTMLTemplateElement with path indices for efficient node lookup.\n * - Expose `getStaticTemplate()` for use by the instantiator.\n */\n\nimport { ORE_ERRORS, OreApiError } from '../errors';\n\n// ─── Slot kinds ───────────────────────────────────────────────────────────────\n// Const object + derived union, same pattern as `ComponentPhase`\n// in base-element.ts: used here (rather than plain string literals) because the kind\n// crosses a module boundary (compiler.ts produces it, instantiator.ts consumes\n// it): importing `SlotKind` gives autocomplete and a single rename point at the\n// consuming site, where a bare string literal wouldn't.\n\nexport const SlotKind = {\n ATTR: 'attr',\n BOOL_ATTR: 'boolAttr',\n EVENT: 'event',\n NODE: 'node',\n PROP: 'prop',\n REF: 'ref',\n} as const;\n\nexport type DetectedSlotKind = (typeof SlotKind)[keyof typeof SlotKind];\n\n/**\n * Event modifiers accepted after `@event.` in a template: `@click.stop.prevent`.\n * `stop`/`prevent` wrap the handler (stopPropagation/preventDefault); `once`/`capture`\n * map to the native addEventListener options of the same name.\n */\nexport type EventModifiers = {\n capture?: boolean;\n once?: boolean;\n prevent?: boolean;\n stop?: boolean;\n};\n\nconst EVENT_MODIFIERS: EventModifiers = { capture: true, once: true, prevent: true, stop: true };\n\nconst parseEventModifiers = (name: string, modifiers: string[]): EventModifiers | undefined => {\n if (modifiers.length === 0) return undefined;\n\n const parsed: EventModifiers = {};\n\n for (const modifier of modifiers) {\n if (!(modifier in EVENT_MODIFIERS)) throw new OreApiError(ORE_ERRORS.eventModifierUnknown(name, modifier));\n\n parsed[modifier as keyof EventModifiers] = true;\n }\n\n return parsed;\n};\n\ntype DetectedSlot = {\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n name?: string;\n prefix: string;\n};\n\n// ─── Static template types ────────────────────────────────────────────────────\n\nexport type NodePath = readonly number[];\n\nexport type SlotMeta = {\n commentId?: number;\n elementId?: number;\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n mode?: 'attr' | 'bool';\n name?: string;\n};\n\nexport type CompiledStaticTemplate = {\n commentPaths: ReadonlyMap<number, NodePath>;\n element: HTMLTemplateElement;\n elementPaths: ReadonlyMap<number, NodePath>;\n slots: SlotMeta[];\n};\n\n// ─── Slot detection regexes ───────────────────────────────────────────────────\n\nconst EVENT_RE = /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/;\nconst REF_RE = /\\s+ref\\s*=\\s*[\"']?$/;\nconst BOOL_ATTR_RE = /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst PROP_RE = /\\s+\\.([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst ATTR_RE = /\\s+([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\n\nconst detectSlot = (str: string): DetectedSlot => {\n let m: RegExpExecArray | null;\n\n if ((m = EVENT_RE.exec(str))) {\n const prefix = str.slice(0, -m[0].length);\n const [name, ...modifiers] = m[1].split('.');\n\n return { eventModifiers: parseEventModifiers(name, modifiers), kind: SlotKind.EVENT, name, prefix };\n }\n\n if ((m = REF_RE.exec(str))) {\n return { kind: SlotKind.REF, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = BOOL_ATTR_RE.exec(str))) {\n return { kind: SlotKind.BOOL_ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = PROP_RE.exec(str))) {\n const name = m[1];\n\n // Prototype-polluting property names are rejected at compile time: `.prop=`\n // writes the element property directly, so these names must never be writable.\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n throw new OreApiError(ORE_ERRORS.propBindingForbiddenName(name));\n }\n\n return { kind: SlotKind.PROP, name, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = ATTR_RE.exec(str))) {\n return { kind: SlotKind.ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n const lastOpen = str.lastIndexOf('<');\n const lastClose = str.lastIndexOf('>');\n\n if (lastOpen > lastClose && str[lastOpen + 1] !== '/') {\n throw new OreApiError(ORE_ERRORS.templateInterpolationInTag);\n }\n\n return { kind: SlotKind.NODE, prefix: str };\n};\n\n// ─── Static template cache ────────────────────────────────────────────────────\n\nconst templateCache = new WeakMap<TemplateStringsArray, CompiledStaticTemplate>();\n\n/**\n * Matches a string that ends in an attribute-assignment context, e.g. `...attr=`,\n * `...@click=`, `...?disabled=`. Used together with tag-context\n * tracking (see below) to decide whether a quote immediately before an\n * interpolation is an attribute-value quote (strip it) or a literal text quote\n * (keep it): previously every adjacent quote was stripped, so both\n * `` html`\"${value}\"` `` and prose like `area = \"${area}\"` lost their quotes.\n */\nconst ATTR_VALUE_CONTEXT_RE = /[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\\s*=\\s*$/;\n\n/**\n * Pre-process template strings to strip surrounding attribute quotes. This lets\n * the main loop operate on clean strings with no per-iteration state flags.\n *\n * Quote stripping requires BOTH an attr-assignment tail AND start-tag context\n * (tracked by replaying the raw strings): `class = \"${c}\"` inside a tag is\n * stripped; `area = \"${a}\"` in prose is not.\n */\nconst normalizeTemplateStrings = (strings: TemplateStringsArray): string[] => {\n const out = Array.from(strings);\n let insideTag = false;\n\n for (let i = 0; i < out.length - 1; i++) {\n const s = out[i];\n const lastChar = s[s.length - 1];\n\n // Tag context at the interpolation boundary is determined by all raw string\n // content up to it: including this string's own text before its final quote\n // (last angle bracket wins; attribute values containing '<'/'>' are outside\n // the supported syntax either way).\n for (const ch of s) {\n if (ch === '<') insideTag = true;\n else if (ch === '>') insideTag = false;\n }\n\n // Strip wrapping attribute quotes: attr=\"${value}\" → attr=${value}\n if ((lastChar === '\"' || lastChar === \"'\") && insideTag && ATTR_VALUE_CONTEXT_RE.test(s.slice(0, -1))) {\n out[i] = s.slice(0, -1);\n\n const next = out[i + 1];\n\n if (next.startsWith(lastChar)) out[i + 1] = next.slice(1);\n }\n }\n\n return out;\n};\n\n/**\n * Attribute names that mark a binding target element, and the comment prefix for\n * node-slot anchors. Namespaced (`data-ore-*` / `ore:N`) so user-authored markup in\n * static template regions can never collide with them: a plain `u` attribute or a\n * numeric comment was previously hijacked as a binding marker and stripped.\n */\nconst ELEMENT_MARKER_ATTR = 'data-ore-b';\nconst COMMENT_MARKER_RE = /^ore:(\\d+)$/;\n\nconst walkNode = (\n node: Node,\n path: number[],\n elementPaths: Map<number, NodePath>,\n commentPaths: Map<number, NodePath>,\n): void => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n const marker = el.getAttribute(ELEMENT_MARKER_ATTR);\n\n if (marker !== null) {\n elementPaths.set(Number(marker), [...path]);\n el.removeAttribute(ELEMENT_MARKER_ATTR);\n }\n } else if (node.nodeType === Node.COMMENT_NODE) {\n const content = (node as Comment).nodeValue;\n const m = content !== null ? COMMENT_MARKER_RE.exec(content) : null;\n\n if (m) {\n commentPaths.set(Number(m[1]), [...path]);\n }\n }\n\n const children = node.childNodes;\n\n for (let i = 0; i < children.length; i++) walkNode(children[i], [...path, i], elementPaths, commentPaths);\n};\n\nconst buildStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n const normalized = normalizeTemplateStrings(strings);\n let html = '';\n let activeElementId: number | undefined;\n let elementCounter = 0;\n let commentCounter = 0;\n const slots: SlotMeta[] = [];\n\n for (let i = 0; i < normalized.length - 1; i++) {\n const raw = normalized[i];\n const slot = detectSlot(raw);\n\n if (slot.kind === SlotKind.NODE) {\n html += `${slot.prefix}<!--ore:${commentCounter}-->`;\n slots.push({ commentId: commentCounter, kind: SlotKind.NODE });\n commentCounter++;\n activeElementId = undefined;\n } else {\n const needsNewMarker =\n activeElementId === undefined || slot.prefix.lastIndexOf('<') > slot.prefix.lastIndexOf('>');\n\n if (needsNewMarker) {\n activeElementId = elementCounter++;\n html += `${slot.prefix} ${ELEMENT_MARKER_ATTR}=\"${activeElementId}\"`;\n } else {\n html += slot.prefix;\n }\n\n const mode: 'attr' | 'bool' | undefined =\n slot.kind === SlotKind.BOOL_ATTR ? 'bool' : slot.kind === SlotKind.ATTR ? 'attr' : undefined;\n\n slots.push({\n elementId: activeElementId,\n eventModifiers: slot.eventModifiers,\n kind: slot.kind,\n mode,\n name: slot.name,\n });\n }\n }\n\n html += normalized[normalized.length - 1] ?? '';\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const elementPaths = new Map<number, NodePath>();\n const commentPaths = new Map<number, NodePath>();\n const topChildren = tpl.content.childNodes;\n\n for (let i = 0; i < topChildren.length; i++) walkNode(topChildren[i], [i], elementPaths, commentPaths);\n\n return { commentPaths, element: tpl, elementPaths, slots };\n};\n\nexport const getStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n let tpl = templateCache.get(strings);\n\n if (!tpl) {\n tpl = buildStaticTemplate(strings);\n templateCache.set(strings, tpl);\n }\n\n return tpl;\n};\n\n// ─── Path navigation (used by instantiator) ───────────────────────────────────\n\nexport const followPath = (root: Node, path: NodePath): Node => {\n let node: Node = root;\n\n for (const i of path) node = node.childNodes[i];\n\n return node;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"compiler.cjs","names":["OreApiError","ORE_ERRORS","require_errors","SlotKind","EVENT_MODIFIERS","parseEventModifiers","modifiers","parsed","modifier","name","EVENT_RE","REF_RE","BOOL_ATTR_RE","PROP_RE","ATTR_RE","HTML_INJECTION_PROPS","detectSlot","m","str","prefix","lastOpen","templateCache","ATTR_VALUE_CONTEXT_RE","normalizeTemplateStrings","out","strings","insideTag","i","s","lastChar","ch","next","ELEMENT_MARKER_ATTR","COMMENT_MARKER_RE","walkNode","node","el","marker","elementPaths","path","content","commentPaths","children","buildStaticTemplate","normalized","html","activeElementId","elementCounter","commentCounter","slots","raw","slot","mode","tpl","topChildren","getStaticTemplate","followPath","root"],"sources":["../../src/template/compiler.ts"],"sourcesContent":["/**\n * template/compiler.ts: HTML template string parser and static template cache.\n *\n * Responsibilities:\n * - Parse TemplateStringsArray into slot metadata (slot detection).\n * - Build a cached HTMLTemplateElement with path indices for efficient node lookup.\n * - Expose `getStaticTemplate()` for use by the instantiator.\n */\n\nimport { ORE_ERRORS, OreApiError } from '../errors';\n\n// ─── Slot kinds ───────────────────────────────────────────────────────────────\n// Const object + derived union, same pattern as `ComponentPhase`\n// in base-element.ts: used here (rather than plain string literals) because the kind\n// crosses a module boundary (compiler.ts produces it, instantiator.ts consumes\n// it): importing `SlotKind` gives autocomplete and a single rename point at the\n// consuming site, where a bare string literal wouldn't.\n\nexport const SlotKind = {\n ATTR: 'attr',\n BOOL_ATTR: 'boolAttr',\n EVENT: 'event',\n NODE: 'node',\n PROP: 'prop',\n REF: 'ref',\n} as const;\n\nexport type DetectedSlotKind = (typeof SlotKind)[keyof typeof SlotKind];\n\n/**\n * Event modifiers accepted after `@event.` in a template: `@click.stop.prevent`.\n * `stop`/`prevent` wrap the handler (stopPropagation/preventDefault); `once`/`capture`\n * map to the native addEventListener options of the same name.\n */\nexport type EventModifiers = {\n capture?: boolean;\n once?: boolean;\n prevent?: boolean;\n stop?: boolean;\n};\n\nconst EVENT_MODIFIERS: EventModifiers = { capture: true, once: true, prevent: true, stop: true };\n\nconst parseEventModifiers = (name: string, modifiers: string[]): EventModifiers | undefined => {\n if (modifiers.length === 0) return undefined;\n\n const parsed: EventModifiers = {};\n\n for (const modifier of modifiers) {\n if (!(modifier in EVENT_MODIFIERS)) throw new OreApiError(ORE_ERRORS.eventModifierUnknown(name, modifier));\n\n parsed[modifier as keyof EventModifiers] = true;\n }\n\n return parsed;\n};\n\ntype DetectedSlot = {\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n name?: string;\n prefix: string;\n};\n\n// ─── Static template types ────────────────────────────────────────────────────\n\nexport type NodePath = readonly number[];\n\nexport type SlotMeta = {\n commentId?: number;\n elementId?: number;\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n mode?: 'attr' | 'bool';\n name?: string;\n};\n\nexport type CompiledStaticTemplate = {\n commentPaths: ReadonlyMap<number, NodePath>;\n element: HTMLTemplateElement;\n elementPaths: ReadonlyMap<number, NodePath>;\n slots: SlotMeta[];\n};\n\n// ─── Slot detection regexes ───────────────────────────────────────────────────\n\nconst EVENT_RE = /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/;\nconst REF_RE = /\\s+ref\\s*=\\s*[\"']?$/;\nconst BOOL_ATTR_RE = /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst PROP_RE = /\\s+\\.([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst ATTR_RE = /\\s+([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\n\n// Element properties that parse their assigned value as raw HTML. Binding these\n// through `.prop=` would be an unlabeled HTML-injection sink; the named\n// unsafeHtml() directive is the only supported raw-HTML path. (innerText/textContent\n// are plain-text sinks and stay allowed.)\nconst HTML_INJECTION_PROPS = new Set(['innerhtml', 'outerhtml', 'srcdoc']);\n\nconst detectSlot = (str: string): DetectedSlot => {\n let m: RegExpExecArray | null;\n\n if ((m = EVENT_RE.exec(str))) {\n const prefix = str.slice(0, -m[0].length);\n const [name, ...modifiers] = m[1].split('.');\n\n return { eventModifiers: parseEventModifiers(name, modifiers), kind: SlotKind.EVENT, name, prefix };\n }\n\n if ((m = REF_RE.exec(str))) {\n return { kind: SlotKind.REF, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = BOOL_ATTR_RE.exec(str))) {\n return { kind: SlotKind.BOOL_ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = PROP_RE.exec(str))) {\n const name = m[1];\n\n // Prototype-polluting property names are rejected at compile time: `.prop=`\n // writes the element property directly, so these names must never be writable.\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n throw new OreApiError(ORE_ERRORS.propBindingForbiddenName(name));\n }\n\n // HTML-parsing properties are rejected for the same reason `srcdoc` and `on*`\n // attributes are blocked in setAttr(): `.prop=` writes the property directly,\n // so `.innerHTML=` would be an unlabeled raw-HTML sink that bypasses the\n // named unsafeHtml() escape hatch. Sanitized HTML injection must go through it.\n if (HTML_INJECTION_PROPS.has(name.toLowerCase())) {\n throw new OreApiError(ORE_ERRORS.propBindingHtmlInjectionName(name));\n }\n\n return { kind: SlotKind.PROP, name, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = ATTR_RE.exec(str))) {\n return { kind: SlotKind.ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n const lastOpen = str.lastIndexOf('<');\n const lastClose = str.lastIndexOf('>');\n\n if (lastOpen > lastClose && str[lastOpen + 1] !== '/') {\n throw new OreApiError(ORE_ERRORS.templateInterpolationInTag);\n }\n\n return { kind: SlotKind.NODE, prefix: str };\n};\n\n// ─── Static template cache ────────────────────────────────────────────────────\n\nconst templateCache = new WeakMap<TemplateStringsArray, CompiledStaticTemplate>();\n\n/**\n * Matches a string that ends in an attribute-assignment context, e.g. `...attr=`,\n * `...@click=`, `...?disabled=`. Used together with tag-context\n * tracking (see below) to decide whether a quote immediately before an\n * interpolation is an attribute-value quote (strip it) or a literal text quote\n * (keep it): previously every adjacent quote was stripped, so both\n * `` html`\"${value}\"` `` and prose like `area = \"${area}\"` lost their quotes.\n */\nconst ATTR_VALUE_CONTEXT_RE = /[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\\s*=\\s*$/;\n\n/**\n * Pre-process template strings to strip surrounding attribute quotes. This lets\n * the main loop operate on clean strings with no per-iteration state flags.\n *\n * Quote stripping requires BOTH an attr-assignment tail AND start-tag context\n * (tracked by replaying the raw strings): `class = \"${c}\"` inside a tag is\n * stripped; `area = \"${a}\"` in prose is not.\n */\nconst normalizeTemplateStrings = (strings: TemplateStringsArray): string[] => {\n const out = Array.from(strings);\n let insideTag = false;\n\n for (let i = 0; i < out.length - 1; i++) {\n const s = out[i];\n const lastChar = s[s.length - 1];\n\n // Tag context at the interpolation boundary is determined by all raw string\n // content up to it: including this string's own text before its final quote\n // (last angle bracket wins; attribute values containing '<'/'>' are outside\n // the supported syntax either way).\n for (const ch of s) {\n if (ch === '<') insideTag = true;\n else if (ch === '>') insideTag = false;\n }\n\n // Strip wrapping attribute quotes: attr=\"${value}\" → attr=${value}\n if ((lastChar === '\"' || lastChar === \"'\") && insideTag && ATTR_VALUE_CONTEXT_RE.test(s.slice(0, -1))) {\n out[i] = s.slice(0, -1);\n\n const next = out[i + 1];\n\n if (next.startsWith(lastChar)) out[i + 1] = next.slice(1);\n }\n }\n\n return out;\n};\n\n/**\n * Attribute names that mark a binding target element, and the comment prefix for\n * node-slot anchors. Namespaced (`data-ore-*` / `ore:N`) so user-authored markup in\n * static template regions can never collide with them: a plain `u` attribute or a\n * numeric comment was previously hijacked as a binding marker and stripped.\n */\nconst ELEMENT_MARKER_ATTR = 'data-ore-b';\nconst COMMENT_MARKER_RE = /^ore:(\\d+)$/;\n\nconst walkNode = (\n node: Node,\n path: number[],\n elementPaths: Map<number, NodePath>,\n commentPaths: Map<number, NodePath>,\n): void => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n const marker = el.getAttribute(ELEMENT_MARKER_ATTR);\n\n if (marker !== null) {\n elementPaths.set(Number(marker), [...path]);\n el.removeAttribute(ELEMENT_MARKER_ATTR);\n }\n } else if (node.nodeType === Node.COMMENT_NODE) {\n const content = (node as Comment).nodeValue;\n const m = content !== null ? COMMENT_MARKER_RE.exec(content) : null;\n\n if (m) {\n commentPaths.set(Number(m[1]), [...path]);\n }\n }\n\n const children = node.childNodes;\n\n for (let i = 0; i < children.length; i++) walkNode(children[i], [...path, i], elementPaths, commentPaths);\n};\n\nconst buildStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n const normalized = normalizeTemplateStrings(strings);\n let html = '';\n let activeElementId: number | undefined;\n let elementCounter = 0;\n let commentCounter = 0;\n const slots: SlotMeta[] = [];\n\n for (let i = 0; i < normalized.length - 1; i++) {\n const raw = normalized[i];\n const slot = detectSlot(raw);\n\n if (slot.kind === SlotKind.NODE) {\n html += `${slot.prefix}<!--ore:${commentCounter}-->`;\n slots.push({ commentId: commentCounter, kind: SlotKind.NODE });\n commentCounter++;\n activeElementId = undefined;\n } else {\n const needsNewMarker =\n activeElementId === undefined || slot.prefix.lastIndexOf('<') > slot.prefix.lastIndexOf('>');\n\n if (needsNewMarker) {\n activeElementId = elementCounter++;\n html += `${slot.prefix} ${ELEMENT_MARKER_ATTR}=\"${activeElementId}\"`;\n } else {\n html += slot.prefix;\n }\n\n const mode: 'attr' | 'bool' | undefined =\n slot.kind === SlotKind.BOOL_ATTR ? 'bool' : slot.kind === SlotKind.ATTR ? 'attr' : undefined;\n\n slots.push({\n elementId: activeElementId,\n eventModifiers: slot.eventModifiers,\n kind: slot.kind,\n mode,\n name: slot.name,\n });\n }\n }\n\n html += normalized[normalized.length - 1] ?? '';\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const elementPaths = new Map<number, NodePath>();\n const commentPaths = new Map<number, NodePath>();\n const topChildren = tpl.content.childNodes;\n\n for (let i = 0; i < topChildren.length; i++) walkNode(topChildren[i], [i], elementPaths, commentPaths);\n\n return { commentPaths, element: tpl, elementPaths, slots };\n};\n\nexport const getStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n let tpl = templateCache.get(strings);\n\n if (!tpl) {\n tpl = buildStaticTemplate(strings);\n templateCache.set(strings, tpl);\n }\n\n return tpl;\n};\n\n// ─── Path navigation (used by instantiator) ───────────────────────────────────\n\nexport const followPath = (root: Node, path: NodePath): Node => {\n let node: Node = root;\n\n for (const i of path) node = node.childNodes[i];\n\n return node;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/template/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,eAAO,MAAM,QAAQ;;;;;;;CAOX,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AA2BF,MAAM,MAAM,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5C,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAuMF,eAAO,MAAM,iBAAiB,GAAI,SAAS,oBAAoB,KAAG,sBASjE,CAAC;AAIF,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,EAAE,MAAM,QAAQ,KAAG,IAMvD,CAAC"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/template/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,eAAO,MAAM,QAAQ;;;;;;;CAOX,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AA2BF,MAAM,MAAM,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5C,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAqNF,eAAO,MAAM,iBAAiB,GAAI,SAAS,oBAAoB,KAAG,sBASjE,CAAC;AAIF,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,EAAE,MAAM,QAAQ,KAAG,IAMvD,CAAC"}
@@ -1,2 +1,2 @@
1
- import{ORE_ERRORS as e,OreApiError as t}from"../errors.js";var n={ATTR:`attr`,BOOL_ATTR:`boolAttr`,EVENT:`event`,NODE:`node`,PROP:`prop`,REF:`ref`},r={capture:!0,once:!0,prevent:!0,stop:!0},i=(n,i)=>{if(i.length===0)return;let a={};for(let o of i){if(!(o in r))throw new t(e.eventModifierUnknown(n,o));a[o]=!0}return a},a=/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/,o=/\s+ref\s*=\s*["']?$/,s=/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,c=/\s+\.([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,l=/\s+([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,u=r=>{let u;if(u=a.exec(r)){let e=r.slice(0,-u[0].length),[t,...a]=u[1].split(`.`);return{eventModifiers:i(t,a),kind:n.EVENT,name:t,prefix:e}}if(u=o.exec(r))return{kind:n.REF,prefix:r.slice(0,-u[0].length)};if(u=s.exec(r))return{kind:n.BOOL_ATTR,name:u[1],prefix:r.slice(0,-u[0].length)};if(u=c.exec(r)){let i=u[1];if(i===`__proto__`||i===`constructor`||i===`prototype`)throw new t(e.propBindingForbiddenName(i));return{kind:n.PROP,name:i,prefix:r.slice(0,-u[0].length)}}if(u=l.exec(r))return{kind:n.ATTR,name:u[1],prefix:r.slice(0,-u[0].length)};let d=r.lastIndexOf(`<`);if(d>r.lastIndexOf(`>`)&&r[d+1]!==`/`)throw new t(e.templateInterpolationInTag);return{kind:n.NODE,prefix:r}},d=/* @__PURE__ */ new WeakMap,f=/[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\s*=\s*$/,p=e=>{let t=Array.from(e),n=!1;for(let e=0;e<t.length-1;e++){let r=t[e],i=r[r.length-1];for(let e of r)e===`<`?n=!0:e===`>`&&(n=!1);if((i===`"`||i===`'`)&&n&&f.test(r.slice(0,-1))){t[e]=r.slice(0,-1);let n=t[e+1];n.startsWith(i)&&(t[e+1]=n.slice(1))}}return t},m=`data-ore-b`,h=/^ore:(\d+)$/,g=(e,t,n,r)=>{if(e.nodeType===Node.ELEMENT_NODE){let r=e,i=r.getAttribute(m);i!==null&&(n.set(Number(i),[...t]),r.removeAttribute(m))}else if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue,i=n===null?null:h.exec(n);i&&r.set(Number(i[1]),[...t])}let i=e.childNodes;for(let e=0;e<i.length;e++)g(i[e],[...t,e],n,r)},_=e=>{let t=p(e),r=``,i,a=0,o=0,s=[];for(let e=0;e<t.length-1;e++){let c=t[e],l=u(c);if(l.kind===n.NODE)r+=`${l.prefix}<!--ore:${o}-->`,s.push({commentId:o,kind:n.NODE}),o++,i=void 0;else{i===void 0||l.prefix.lastIndexOf(`<`)>l.prefix.lastIndexOf(`>`)?(i=a++,r+=`${l.prefix} ${m}="${i}"`):r+=l.prefix;let e=l.kind===n.BOOL_ATTR?`bool`:l.kind===n.ATTR?`attr`:void 0;s.push({elementId:i,eventModifiers:l.eventModifiers,kind:l.kind,mode:e,name:l.name})}}r+=t[t.length-1]??``;let c=document.createElement(`template`);c.innerHTML=r;let l=/* @__PURE__ */ new Map,d=/* @__PURE__ */ new Map,f=c.content.childNodes;for(let e=0;e<f.length;e++)g(f[e],[e],l,d);return{commentPaths:d,element:c,elementPaths:l,slots:s}},v=e=>{let t=d.get(e);return t||(t=_(e),d.set(e,t)),t},y=(e,t)=>{let n=e;for(let e of t)n=n.childNodes[e];return n};export{n as SlotKind,y as followPath,v as getStaticTemplate};
1
+ import{ORE_ERRORS as e,OreApiError as t}from"../errors.js";var n={ATTR:`attr`,BOOL_ATTR:`boolAttr`,EVENT:`event`,NODE:`node`,PROP:`prop`,REF:`ref`},r={capture:!0,once:!0,prevent:!0,stop:!0},i=(n,i)=>{if(i.length===0)return;let a={};for(let o of i){if(!(o in r))throw new t(e.eventModifierUnknown(n,o));a[o]=!0}return a},a=/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/,o=/\s+ref\s*=\s*["']?$/,s=/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,c=/\s+\.([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,l=/\s+([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/,u=/* @__PURE__ */ new Set([`innerhtml`,`outerhtml`,`srcdoc`]),d=r=>{let d;if(d=a.exec(r)){let e=r.slice(0,-d[0].length),[t,...a]=d[1].split(`.`);return{eventModifiers:i(t,a),kind:n.EVENT,name:t,prefix:e}}if(d=o.exec(r))return{kind:n.REF,prefix:r.slice(0,-d[0].length)};if(d=s.exec(r))return{kind:n.BOOL_ATTR,name:d[1],prefix:r.slice(0,-d[0].length)};if(d=c.exec(r)){let i=d[1];if(i===`__proto__`||i===`constructor`||i===`prototype`)throw new t(e.propBindingForbiddenName(i));if(u.has(i.toLowerCase()))throw new t(e.propBindingHtmlInjectionName(i));return{kind:n.PROP,name:i,prefix:r.slice(0,-d[0].length)}}if(d=l.exec(r))return{kind:n.ATTR,name:d[1],prefix:r.slice(0,-d[0].length)};let f=r.lastIndexOf(`<`);if(f>r.lastIndexOf(`>`)&&r[f+1]!==`/`)throw new t(e.templateInterpolationInTag);return{kind:n.NODE,prefix:r}},f=/* @__PURE__ */ new WeakMap,p=/[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\s*=\s*$/,m=e=>{let t=Array.from(e),n=!1;for(let e=0;e<t.length-1;e++){let r=t[e],i=r[r.length-1];for(let e of r)e===`<`?n=!0:e===`>`&&(n=!1);if((i===`"`||i===`'`)&&n&&p.test(r.slice(0,-1))){t[e]=r.slice(0,-1);let n=t[e+1];n.startsWith(i)&&(t[e+1]=n.slice(1))}}return t},h=`data-ore-b`,g=/^ore:(\d+)$/,_=(e,t,n,r)=>{if(e.nodeType===Node.ELEMENT_NODE){let r=e,i=r.getAttribute(h);i!==null&&(n.set(Number(i),[...t]),r.removeAttribute(h))}else if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue,i=n===null?null:g.exec(n);i&&r.set(Number(i[1]),[...t])}let i=e.childNodes;for(let e=0;e<i.length;e++)_(i[e],[...t,e],n,r)},v=e=>{let t=m(e),r=``,i,a=0,o=0,s=[];for(let e=0;e<t.length-1;e++){let c=t[e],l=d(c);if(l.kind===n.NODE)r+=`${l.prefix}<!--ore:${o}-->`,s.push({commentId:o,kind:n.NODE}),o++,i=void 0;else{i===void 0||l.prefix.lastIndexOf(`<`)>l.prefix.lastIndexOf(`>`)?(i=a++,r+=`${l.prefix} ${h}="${i}"`):r+=l.prefix;let e=l.kind===n.BOOL_ATTR?`bool`:l.kind===n.ATTR?`attr`:void 0;s.push({elementId:i,eventModifiers:l.eventModifiers,kind:l.kind,mode:e,name:l.name})}}r+=t[t.length-1]??``;let c=document.createElement(`template`);c.innerHTML=r;let l=/* @__PURE__ */ new Map,u=/* @__PURE__ */ new Map,f=c.content.childNodes;for(let e=0;e<f.length;e++)_(f[e],[e],l,u);return{commentPaths:u,element:c,elementPaths:l,slots:s}},y=e=>{let t=f.get(e);return t||(t=v(e),f.set(e,t)),t},b=(e,t)=>{let n=e;for(let e of t)n=n.childNodes[e];return n};export{n as SlotKind,b as followPath,y as getStaticTemplate};
2
2
  //# sourceMappingURL=compiler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.js","names":["SlotKind","EVENT_MODIFIERS","parseEventModifiers","modifiers","parsed","modifier","OreApiError","ORE_ERRORS","name","EVENT_RE","REF_RE","BOOL_ATTR_RE","PROP_RE","ATTR_RE","detectSlot","m","str","prefix","lastOpen","templateCache","ATTR_VALUE_CONTEXT_RE","normalizeTemplateStrings","out","strings","insideTag","i","s","lastChar","ch","next","ELEMENT_MARKER_ATTR","COMMENT_MARKER_RE","walkNode","node","el","marker","elementPaths","path","content","commentPaths","children","buildStaticTemplate","normalized","html","activeElementId","elementCounter","commentCounter","slots","raw","slot","mode","tpl","topChildren","getStaticTemplate","followPath","root"],"sources":["../../src/template/compiler.ts"],"sourcesContent":["/**\n * template/compiler.ts: HTML template string parser and static template cache.\n *\n * Responsibilities:\n * - Parse TemplateStringsArray into slot metadata (slot detection).\n * - Build a cached HTMLTemplateElement with path indices for efficient node lookup.\n * - Expose `getStaticTemplate()` for use by the instantiator.\n */\n\nimport { ORE_ERRORS, OreApiError } from '../errors';\n\n// ─── Slot kinds ───────────────────────────────────────────────────────────────\n// Const object + derived union, same pattern as `ComponentPhase`\n// in base-element.ts: used here (rather than plain string literals) because the kind\n// crosses a module boundary (compiler.ts produces it, instantiator.ts consumes\n// it): importing `SlotKind` gives autocomplete and a single rename point at the\n// consuming site, where a bare string literal wouldn't.\n\nexport const SlotKind = {\n ATTR: 'attr',\n BOOL_ATTR: 'boolAttr',\n EVENT: 'event',\n NODE: 'node',\n PROP: 'prop',\n REF: 'ref',\n} as const;\n\nexport type DetectedSlotKind = (typeof SlotKind)[keyof typeof SlotKind];\n\n/**\n * Event modifiers accepted after `@event.` in a template: `@click.stop.prevent`.\n * `stop`/`prevent` wrap the handler (stopPropagation/preventDefault); `once`/`capture`\n * map to the native addEventListener options of the same name.\n */\nexport type EventModifiers = {\n capture?: boolean;\n once?: boolean;\n prevent?: boolean;\n stop?: boolean;\n};\n\nconst EVENT_MODIFIERS: EventModifiers = { capture: true, once: true, prevent: true, stop: true };\n\nconst parseEventModifiers = (name: string, modifiers: string[]): EventModifiers | undefined => {\n if (modifiers.length === 0) return undefined;\n\n const parsed: EventModifiers = {};\n\n for (const modifier of modifiers) {\n if (!(modifier in EVENT_MODIFIERS)) throw new OreApiError(ORE_ERRORS.eventModifierUnknown(name, modifier));\n\n parsed[modifier as keyof EventModifiers] = true;\n }\n\n return parsed;\n};\n\ntype DetectedSlot = {\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n name?: string;\n prefix: string;\n};\n\n// ─── Static template types ────────────────────────────────────────────────────\n\nexport type NodePath = readonly number[];\n\nexport type SlotMeta = {\n commentId?: number;\n elementId?: number;\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n mode?: 'attr' | 'bool';\n name?: string;\n};\n\nexport type CompiledStaticTemplate = {\n commentPaths: ReadonlyMap<number, NodePath>;\n element: HTMLTemplateElement;\n elementPaths: ReadonlyMap<number, NodePath>;\n slots: SlotMeta[];\n};\n\n// ─── Slot detection regexes ───────────────────────────────────────────────────\n\nconst EVENT_RE = /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/;\nconst REF_RE = /\\s+ref\\s*=\\s*[\"']?$/;\nconst BOOL_ATTR_RE = /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst PROP_RE = /\\s+\\.([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst ATTR_RE = /\\s+([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\n\nconst detectSlot = (str: string): DetectedSlot => {\n let m: RegExpExecArray | null;\n\n if ((m = EVENT_RE.exec(str))) {\n const prefix = str.slice(0, -m[0].length);\n const [name, ...modifiers] = m[1].split('.');\n\n return { eventModifiers: parseEventModifiers(name, modifiers), kind: SlotKind.EVENT, name, prefix };\n }\n\n if ((m = REF_RE.exec(str))) {\n return { kind: SlotKind.REF, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = BOOL_ATTR_RE.exec(str))) {\n return { kind: SlotKind.BOOL_ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = PROP_RE.exec(str))) {\n const name = m[1];\n\n // Prototype-polluting property names are rejected at compile time: `.prop=`\n // writes the element property directly, so these names must never be writable.\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n throw new OreApiError(ORE_ERRORS.propBindingForbiddenName(name));\n }\n\n return { kind: SlotKind.PROP, name, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = ATTR_RE.exec(str))) {\n return { kind: SlotKind.ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n const lastOpen = str.lastIndexOf('<');\n const lastClose = str.lastIndexOf('>');\n\n if (lastOpen > lastClose && str[lastOpen + 1] !== '/') {\n throw new OreApiError(ORE_ERRORS.templateInterpolationInTag);\n }\n\n return { kind: SlotKind.NODE, prefix: str };\n};\n\n// ─── Static template cache ────────────────────────────────────────────────────\n\nconst templateCache = new WeakMap<TemplateStringsArray, CompiledStaticTemplate>();\n\n/**\n * Matches a string that ends in an attribute-assignment context, e.g. `...attr=`,\n * `...@click=`, `...?disabled=`. Used together with tag-context\n * tracking (see below) to decide whether a quote immediately before an\n * interpolation is an attribute-value quote (strip it) or a literal text quote\n * (keep it): previously every adjacent quote was stripped, so both\n * `` html`\"${value}\"` `` and prose like `area = \"${area}\"` lost their quotes.\n */\nconst ATTR_VALUE_CONTEXT_RE = /[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\\s*=\\s*$/;\n\n/**\n * Pre-process template strings to strip surrounding attribute quotes. This lets\n * the main loop operate on clean strings with no per-iteration state flags.\n *\n * Quote stripping requires BOTH an attr-assignment tail AND start-tag context\n * (tracked by replaying the raw strings): `class = \"${c}\"` inside a tag is\n * stripped; `area = \"${a}\"` in prose is not.\n */\nconst normalizeTemplateStrings = (strings: TemplateStringsArray): string[] => {\n const out = Array.from(strings);\n let insideTag = false;\n\n for (let i = 0; i < out.length - 1; i++) {\n const s = out[i];\n const lastChar = s[s.length - 1];\n\n // Tag context at the interpolation boundary is determined by all raw string\n // content up to it: including this string's own text before its final quote\n // (last angle bracket wins; attribute values containing '<'/'>' are outside\n // the supported syntax either way).\n for (const ch of s) {\n if (ch === '<') insideTag = true;\n else if (ch === '>') insideTag = false;\n }\n\n // Strip wrapping attribute quotes: attr=\"${value}\" → attr=${value}\n if ((lastChar === '\"' || lastChar === \"'\") && insideTag && ATTR_VALUE_CONTEXT_RE.test(s.slice(0, -1))) {\n out[i] = s.slice(0, -1);\n\n const next = out[i + 1];\n\n if (next.startsWith(lastChar)) out[i + 1] = next.slice(1);\n }\n }\n\n return out;\n};\n\n/**\n * Attribute names that mark a binding target element, and the comment prefix for\n * node-slot anchors. Namespaced (`data-ore-*` / `ore:N`) so user-authored markup in\n * static template regions can never collide with them: a plain `u` attribute or a\n * numeric comment was previously hijacked as a binding marker and stripped.\n */\nconst ELEMENT_MARKER_ATTR = 'data-ore-b';\nconst COMMENT_MARKER_RE = /^ore:(\\d+)$/;\n\nconst walkNode = (\n node: Node,\n path: number[],\n elementPaths: Map<number, NodePath>,\n commentPaths: Map<number, NodePath>,\n): void => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n const marker = el.getAttribute(ELEMENT_MARKER_ATTR);\n\n if (marker !== null) {\n elementPaths.set(Number(marker), [...path]);\n el.removeAttribute(ELEMENT_MARKER_ATTR);\n }\n } else if (node.nodeType === Node.COMMENT_NODE) {\n const content = (node as Comment).nodeValue;\n const m = content !== null ? COMMENT_MARKER_RE.exec(content) : null;\n\n if (m) {\n commentPaths.set(Number(m[1]), [...path]);\n }\n }\n\n const children = node.childNodes;\n\n for (let i = 0; i < children.length; i++) walkNode(children[i], [...path, i], elementPaths, commentPaths);\n};\n\nconst buildStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n const normalized = normalizeTemplateStrings(strings);\n let html = '';\n let activeElementId: number | undefined;\n let elementCounter = 0;\n let commentCounter = 0;\n const slots: SlotMeta[] = [];\n\n for (let i = 0; i < normalized.length - 1; i++) {\n const raw = normalized[i];\n const slot = detectSlot(raw);\n\n if (slot.kind === SlotKind.NODE) {\n html += `${slot.prefix}<!--ore:${commentCounter}-->`;\n slots.push({ commentId: commentCounter, kind: SlotKind.NODE });\n commentCounter++;\n activeElementId = undefined;\n } else {\n const needsNewMarker =\n activeElementId === undefined || slot.prefix.lastIndexOf('<') > slot.prefix.lastIndexOf('>');\n\n if (needsNewMarker) {\n activeElementId = elementCounter++;\n html += `${slot.prefix} ${ELEMENT_MARKER_ATTR}=\"${activeElementId}\"`;\n } else {\n html += slot.prefix;\n }\n\n const mode: 'attr' | 'bool' | undefined =\n slot.kind === SlotKind.BOOL_ATTR ? 'bool' : slot.kind === SlotKind.ATTR ? 'attr' : undefined;\n\n slots.push({\n elementId: activeElementId,\n eventModifiers: slot.eventModifiers,\n kind: slot.kind,\n mode,\n name: slot.name,\n });\n }\n }\n\n html += normalized[normalized.length - 1] ?? '';\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const elementPaths = new Map<number, NodePath>();\n const commentPaths = new Map<number, NodePath>();\n const topChildren = tpl.content.childNodes;\n\n for (let i = 0; i < topChildren.length; i++) walkNode(topChildren[i], [i], elementPaths, commentPaths);\n\n return { commentPaths, element: tpl, elementPaths, slots };\n};\n\nexport const getStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n let tpl = templateCache.get(strings);\n\n if (!tpl) {\n tpl = buildStaticTemplate(strings);\n templateCache.set(strings, tpl);\n }\n\n return tpl;\n};\n\n// ─── Path navigation (used by instantiator) ───────────────────────────────────\n\nexport const followPath = (root: Node, path: NodePath): Node => {\n let node: Node = root;\n\n for (const i of path) node = node.childNodes[i];\n\n return node;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"compiler.js","names":["SlotKind","EVENT_MODIFIERS","parseEventModifiers","modifiers","parsed","modifier","OreApiError","ORE_ERRORS","name","EVENT_RE","REF_RE","BOOL_ATTR_RE","PROP_RE","ATTR_RE","HTML_INJECTION_PROPS","detectSlot","m","str","prefix","lastOpen","templateCache","ATTR_VALUE_CONTEXT_RE","normalizeTemplateStrings","out","strings","insideTag","i","s","lastChar","ch","next","ELEMENT_MARKER_ATTR","COMMENT_MARKER_RE","walkNode","node","el","marker","elementPaths","path","content","commentPaths","children","buildStaticTemplate","normalized","html","activeElementId","elementCounter","commentCounter","slots","raw","slot","mode","tpl","topChildren","getStaticTemplate","followPath","root"],"sources":["../../src/template/compiler.ts"],"sourcesContent":["/**\n * template/compiler.ts: HTML template string parser and static template cache.\n *\n * Responsibilities:\n * - Parse TemplateStringsArray into slot metadata (slot detection).\n * - Build a cached HTMLTemplateElement with path indices for efficient node lookup.\n * - Expose `getStaticTemplate()` for use by the instantiator.\n */\n\nimport { ORE_ERRORS, OreApiError } from '../errors';\n\n// ─── Slot kinds ───────────────────────────────────────────────────────────────\n// Const object + derived union, same pattern as `ComponentPhase`\n// in base-element.ts: used here (rather than plain string literals) because the kind\n// crosses a module boundary (compiler.ts produces it, instantiator.ts consumes\n// it): importing `SlotKind` gives autocomplete and a single rename point at the\n// consuming site, where a bare string literal wouldn't.\n\nexport const SlotKind = {\n ATTR: 'attr',\n BOOL_ATTR: 'boolAttr',\n EVENT: 'event',\n NODE: 'node',\n PROP: 'prop',\n REF: 'ref',\n} as const;\n\nexport type DetectedSlotKind = (typeof SlotKind)[keyof typeof SlotKind];\n\n/**\n * Event modifiers accepted after `@event.` in a template: `@click.stop.prevent`.\n * `stop`/`prevent` wrap the handler (stopPropagation/preventDefault); `once`/`capture`\n * map to the native addEventListener options of the same name.\n */\nexport type EventModifiers = {\n capture?: boolean;\n once?: boolean;\n prevent?: boolean;\n stop?: boolean;\n};\n\nconst EVENT_MODIFIERS: EventModifiers = { capture: true, once: true, prevent: true, stop: true };\n\nconst parseEventModifiers = (name: string, modifiers: string[]): EventModifiers | undefined => {\n if (modifiers.length === 0) return undefined;\n\n const parsed: EventModifiers = {};\n\n for (const modifier of modifiers) {\n if (!(modifier in EVENT_MODIFIERS)) throw new OreApiError(ORE_ERRORS.eventModifierUnknown(name, modifier));\n\n parsed[modifier as keyof EventModifiers] = true;\n }\n\n return parsed;\n};\n\ntype DetectedSlot = {\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n name?: string;\n prefix: string;\n};\n\n// ─── Static template types ────────────────────────────────────────────────────\n\nexport type NodePath = readonly number[];\n\nexport type SlotMeta = {\n commentId?: number;\n elementId?: number;\n eventModifiers?: EventModifiers;\n kind: DetectedSlotKind;\n mode?: 'attr' | 'bool';\n name?: string;\n};\n\nexport type CompiledStaticTemplate = {\n commentPaths: ReadonlyMap<number, NodePath>;\n element: HTMLTemplateElement;\n elementPaths: ReadonlyMap<number, NodePath>;\n slots: SlotMeta[];\n};\n\n// ─── Slot detection regexes ───────────────────────────────────────────────────\n\nconst EVENT_RE = /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/;\nconst REF_RE = /\\s+ref\\s*=\\s*[\"']?$/;\nconst BOOL_ATTR_RE = /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst PROP_RE = /\\s+\\.([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\nconst ATTR_RE = /\\s+([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/;\n\n// Element properties that parse their assigned value as raw HTML. Binding these\n// through `.prop=` would be an unlabeled HTML-injection sink; the named\n// unsafeHtml() directive is the only supported raw-HTML path. (innerText/textContent\n// are plain-text sinks and stay allowed.)\nconst HTML_INJECTION_PROPS = new Set(['innerhtml', 'outerhtml', 'srcdoc']);\n\nconst detectSlot = (str: string): DetectedSlot => {\n let m: RegExpExecArray | null;\n\n if ((m = EVENT_RE.exec(str))) {\n const prefix = str.slice(0, -m[0].length);\n const [name, ...modifiers] = m[1].split('.');\n\n return { eventModifiers: parseEventModifiers(name, modifiers), kind: SlotKind.EVENT, name, prefix };\n }\n\n if ((m = REF_RE.exec(str))) {\n return { kind: SlotKind.REF, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = BOOL_ATTR_RE.exec(str))) {\n return { kind: SlotKind.BOOL_ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = PROP_RE.exec(str))) {\n const name = m[1];\n\n // Prototype-polluting property names are rejected at compile time: `.prop=`\n // writes the element property directly, so these names must never be writable.\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n throw new OreApiError(ORE_ERRORS.propBindingForbiddenName(name));\n }\n\n // HTML-parsing properties are rejected for the same reason `srcdoc` and `on*`\n // attributes are blocked in setAttr(): `.prop=` writes the property directly,\n // so `.innerHTML=` would be an unlabeled raw-HTML sink that bypasses the\n // named unsafeHtml() escape hatch. Sanitized HTML injection must go through it.\n if (HTML_INJECTION_PROPS.has(name.toLowerCase())) {\n throw new OreApiError(ORE_ERRORS.propBindingHtmlInjectionName(name));\n }\n\n return { kind: SlotKind.PROP, name, prefix: str.slice(0, -m[0].length) };\n }\n\n if ((m = ATTR_RE.exec(str))) {\n return { kind: SlotKind.ATTR, name: m[1], prefix: str.slice(0, -m[0].length) };\n }\n\n const lastOpen = str.lastIndexOf('<');\n const lastClose = str.lastIndexOf('>');\n\n if (lastOpen > lastClose && str[lastOpen + 1] !== '/') {\n throw new OreApiError(ORE_ERRORS.templateInterpolationInTag);\n }\n\n return { kind: SlotKind.NODE, prefix: str };\n};\n\n// ─── Static template cache ────────────────────────────────────────────────────\n\nconst templateCache = new WeakMap<TemplateStringsArray, CompiledStaticTemplate>();\n\n/**\n * Matches a string that ends in an attribute-assignment context, e.g. `...attr=`,\n * `...@click=`, `...?disabled=`. Used together with tag-context\n * tracking (see below) to decide whether a quote immediately before an\n * interpolation is an attribute-value quote (strip it) or a literal text quote\n * (keep it): previously every adjacent quote was stripped, so both\n * `` html`\"${value}\"` `` and prose like `area = \"${area}\"` lost their quotes.\n */\nconst ATTR_VALUE_CONTEXT_RE = /[@?]?[a-zA-Z_][-a-zA-Z0-9_.]*\\s*=\\s*$/;\n\n/**\n * Pre-process template strings to strip surrounding attribute quotes. This lets\n * the main loop operate on clean strings with no per-iteration state flags.\n *\n * Quote stripping requires BOTH an attr-assignment tail AND start-tag context\n * (tracked by replaying the raw strings): `class = \"${c}\"` inside a tag is\n * stripped; `area = \"${a}\"` in prose is not.\n */\nconst normalizeTemplateStrings = (strings: TemplateStringsArray): string[] => {\n const out = Array.from(strings);\n let insideTag = false;\n\n for (let i = 0; i < out.length - 1; i++) {\n const s = out[i];\n const lastChar = s[s.length - 1];\n\n // Tag context at the interpolation boundary is determined by all raw string\n // content up to it: including this string's own text before its final quote\n // (last angle bracket wins; attribute values containing '<'/'>' are outside\n // the supported syntax either way).\n for (const ch of s) {\n if (ch === '<') insideTag = true;\n else if (ch === '>') insideTag = false;\n }\n\n // Strip wrapping attribute quotes: attr=\"${value}\" → attr=${value}\n if ((lastChar === '\"' || lastChar === \"'\") && insideTag && ATTR_VALUE_CONTEXT_RE.test(s.slice(0, -1))) {\n out[i] = s.slice(0, -1);\n\n const next = out[i + 1];\n\n if (next.startsWith(lastChar)) out[i + 1] = next.slice(1);\n }\n }\n\n return out;\n};\n\n/**\n * Attribute names that mark a binding target element, and the comment prefix for\n * node-slot anchors. Namespaced (`data-ore-*` / `ore:N`) so user-authored markup in\n * static template regions can never collide with them: a plain `u` attribute or a\n * numeric comment was previously hijacked as a binding marker and stripped.\n */\nconst ELEMENT_MARKER_ATTR = 'data-ore-b';\nconst COMMENT_MARKER_RE = /^ore:(\\d+)$/;\n\nconst walkNode = (\n node: Node,\n path: number[],\n elementPaths: Map<number, NodePath>,\n commentPaths: Map<number, NodePath>,\n): void => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n const marker = el.getAttribute(ELEMENT_MARKER_ATTR);\n\n if (marker !== null) {\n elementPaths.set(Number(marker), [...path]);\n el.removeAttribute(ELEMENT_MARKER_ATTR);\n }\n } else if (node.nodeType === Node.COMMENT_NODE) {\n const content = (node as Comment).nodeValue;\n const m = content !== null ? COMMENT_MARKER_RE.exec(content) : null;\n\n if (m) {\n commentPaths.set(Number(m[1]), [...path]);\n }\n }\n\n const children = node.childNodes;\n\n for (let i = 0; i < children.length; i++) walkNode(children[i], [...path, i], elementPaths, commentPaths);\n};\n\nconst buildStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n const normalized = normalizeTemplateStrings(strings);\n let html = '';\n let activeElementId: number | undefined;\n let elementCounter = 0;\n let commentCounter = 0;\n const slots: SlotMeta[] = [];\n\n for (let i = 0; i < normalized.length - 1; i++) {\n const raw = normalized[i];\n const slot = detectSlot(raw);\n\n if (slot.kind === SlotKind.NODE) {\n html += `${slot.prefix}<!--ore:${commentCounter}-->`;\n slots.push({ commentId: commentCounter, kind: SlotKind.NODE });\n commentCounter++;\n activeElementId = undefined;\n } else {\n const needsNewMarker =\n activeElementId === undefined || slot.prefix.lastIndexOf('<') > slot.prefix.lastIndexOf('>');\n\n if (needsNewMarker) {\n activeElementId = elementCounter++;\n html += `${slot.prefix} ${ELEMENT_MARKER_ATTR}=\"${activeElementId}\"`;\n } else {\n html += slot.prefix;\n }\n\n const mode: 'attr' | 'bool' | undefined =\n slot.kind === SlotKind.BOOL_ATTR ? 'bool' : slot.kind === SlotKind.ATTR ? 'attr' : undefined;\n\n slots.push({\n elementId: activeElementId,\n eventModifiers: slot.eventModifiers,\n kind: slot.kind,\n mode,\n name: slot.name,\n });\n }\n }\n\n html += normalized[normalized.length - 1] ?? '';\n\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const elementPaths = new Map<number, NodePath>();\n const commentPaths = new Map<number, NodePath>();\n const topChildren = tpl.content.childNodes;\n\n for (let i = 0; i < topChildren.length; i++) walkNode(topChildren[i], [i], elementPaths, commentPaths);\n\n return { commentPaths, element: tpl, elementPaths, slots };\n};\n\nexport const getStaticTemplate = (strings: TemplateStringsArray): CompiledStaticTemplate => {\n let tpl = templateCache.get(strings);\n\n if (!tpl) {\n tpl = buildStaticTemplate(strings);\n templateCache.set(strings, tpl);\n }\n\n return tpl;\n};\n\n// ─── Path navigation (used by instantiator) ───────────────────────────────────\n\nexport const followPath = (root: Node, path: NodePath): Node => {\n let node: Node = root;\n\n for (const i of path) node = node.childNodes[i];\n\n return node;\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require("../_dev.cjs");const e=require("../errors.cjs");let t=require("@vielzeug/ripple");var n=e=>typeof e==`function`?e():(0,t.isReactive)(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]?.()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=(e,t,n)=>{let r=t.toLowerCase();if(/^on[a-z]/i.test(t)){`${t}${t.slice(2)}`,e.removeAttribute(t);return}if(r===`srcdoc`||n==null||n===!1){e.removeAttribute(t);return}let i=n===!0?`true`:String(n);c.has(r)&&l.test(i)?(`${t}`,e.removeAttribute(t)):e.setAttribute(t,i)},d=(t,n,r,i)=>{if(!t)return e.ORE_ERRORS.listenNullTarget(n),()=>{};let a=r;return t.addEventListener(n,a,i),()=>t.removeEventListener(n,a,i)},f=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=e=>i(e.startsWith(`--`)?e:f(e)),m=e=>{let t=n(e);return t==null||t===!1?``:i(String(t))},h=e=>{let t=new Set;for(let[r,i]of Object.entries(e)){if(!n(i))continue;let e=r.replace(/\s+/g,``);e&&t.add(e)}return t},g=e=>Array.isArray(e)||typeof e==`object`&&!!e;exports.UNSAFE_CSS_CHARS=r,exports.createReplaceableSlot=s,exports.cssDeclarationName=p,exports.cssDeclarationValue=m,exports.isStructuredValue=g,exports.listen=d,exports.removeNodes=o,exports.resolveClassTokens=h,exports.resolveMaybeReactive=n,exports.runAll=a,exports.sanitizeCssToken=i,exports.setAttr=u,exports.toKebab=f;
1
+ require("../_dev.cjs");const e=require("../errors.cjs");let t=require("@vielzeug/ripple");var n=e=>typeof e==`function`?e():(0,t.isReactive)(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]?.()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=/[\t\n\r]/g,d=/^[\s\p{C}]+|[\s\p{C}]+$/gu,f=e=>e.replace(u,``).replace(d,``),p=e=>l.test(f(e)),m=(e,t,n)=>{let r=t.toLowerCase();if(/^on[a-z]/i.test(t)){`${t}${t.slice(2)}`,e.removeAttribute(t);return}if(r===`srcdoc`||n==null||n===!1){e.removeAttribute(t);return}let i=n===!0?`true`:String(n);c.has(r)&&p(i)?(`${t}`,e.removeAttribute(t)):e.setAttribute(t,i)},h=(t,n,r,i)=>{if(!t)return e.ORE_ERRORS.listenNullTarget(n),()=>{};let a=r;return t.addEventListener(n,a,i),()=>t.removeEventListener(n,a,i)},g=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),_=e=>i(e.startsWith(`--`)?e:g(e)),v=e=>{let t=n(e);return t==null||t===!1?``:i(String(t))},y=e=>{let t=new Set;for(let[r,i]of Object.entries(e)){if(!n(i))continue;let e=r.replace(/\s+/g,``);e&&t.add(e)}return t},b=e=>Array.isArray(e)||typeof e==`object`&&!!e;exports.UNSAFE_CSS_CHARS=r,exports.createReplaceableSlot=s,exports.cssDeclarationName=_,exports.cssDeclarationValue=v,exports.isStructuredValue=b,exports.listen=h,exports.removeNodes=o,exports.resolveClassTokens=y,exports.resolveMaybeReactive=n,exports.runAll=a,exports.sanitizeCssToken=i,exports.setAttr=m,exports.toKebab=g;
2
2
  //# sourceMappingURL=dom.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.cjs","names":["isReactive","ORE_ERRORS","require_errors","_vielzeug_ripple","resolveMaybeReactive","value","UNSAFE_CSS_CHARS","sanitizeCssToken","runAll","i","fns","removeNodes","node","nodes","createReplaceableSlot","cleanups","fn","next","URL_ATTRS","DANGEROUS_SCHEME_RE","setAttr","lowerName","name","el","val","strVal","listen","listener","handler","options","toKebab","str","c","cssDeclarationName","cssDeclarationValue","resolved","resolveClassTokens","tokens","key","record","token","isStructuredValue"],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * A value that may be a plain value, a reactive signal, or a getter function :\n * the shape `when()`, `each()`, `classMap()`, and `bind()` accept.\n * Exported so consumers can annotate their own composable parameters with it.\n */\nexport type MaybeReactive<T> = T | Readable<T> | (() => T);\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal: the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: MaybeReactive<T>): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]?.();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\": a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping: this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes: read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply: it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...): inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...): \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\n/**\n * Normalize a CSS property name for use in a declaration (camelCase → kebab-case,\n * injection characters stripped). Custom properties (`--*`) are case-sensitive, so\n * they skip the kebab conversion. Shared by `styleMap()` (template side) and\n * `bind({ style })` (host side) so both sanitize identically.\n */\nexport const cssDeclarationName = (name: string): string =>\n sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n/**\n * Resolve a style value to its declaration text ('' for null/false/empty).\n * Shared by `styleMap()` and `bind({ style })`.\n */\nexport const cssDeclarationValue = (value: unknown): string => {\n const resolved = resolveMaybeReactive(value as MaybeReactive<string | number | null | undefined | false>);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Resolve a class map to the set of active class tokens: keys with truthy\n * (possibly reactive) values, whitespace stripped from each key (spaces would\n * inject extra class tokens). Shared by `classMap()` (joins the set into a\n * class attribute) and `bind({ class })` (diffs the set against classList).\n */\nexport const resolveClassTokens = (record: Record<string, MaybeReactive<boolean>>): Set<string> => {\n const tokens = new Set<string>();\n\n for (const [key, value] of Object.entries(record)) {\n if (!resolveMaybeReactive(value)) continue;\n\n const token = key.replace(/\\s+/g, '');\n\n if (token) tokens.add(token);\n }\n\n return tokens;\n};\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"A,0FAoBA,IAAaI,EAA2B,GACtC,OAAOC,GAAU,WAAcA,EAAkB,GAAA,EAAIL,EAAAA,WAAAA,CAAWK,CAAK,EAAIA,EAAM,MAAQA,EAO5EC,EAAmB,SAEnBC,EAAoB,GAA0BF,EAAM,QAAQC,EAAkB,EAAE,EAEhFE,EAAU,GAA8B,CACnD,IAAK,IAAIC,EAAIC,EAAI,OAAS,EAAGD,GAAK,EAAG,IAAKC,EAAID,EAAE,GAAG,CACrD,EAEaE,EAAe,GAAwB,CAClD,IAAK,IAAMC,KAAQC,EACjBD,EAAoB,OAAO,CAE/B,EAuBaE,MAA+C,CAC1D,IAAID,EAAgB,CAAC,EACjBE,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACNP,EAAOO,CAAQ,EACfJ,EAAYE,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAOA,CACT,EACA,gBAAgB,EAAI,CAClBE,EAAS,KAAKC,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQC,CACV,CACF,CACF,EASMC,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASKC,EACJ,sGAEWC,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAMC,EAAYC,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAKA,CAAI,EAAG,CAExB,GAAyBA,EAAzB,EAAiGA,EAAK,MAAM,CAAC,EAA7G,EAEFC,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAWA,GATID,IAAc,UASdG,GAAO,MAAQA,IAAQ,GAAO,CAChCD,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAEA,IAAMG,EAASD,IAAQ,GAAO,OAAS,OAAOA,CAAG,EAE7CN,EAAU,IAAIG,CAAS,GAAKF,EAAoB,KAAKM,CAAM,GAE3D,GAA8CH,EAA9C,EAEFC,EAAG,gBAAgBD,CAAI,GAKzBC,EAAG,aAAaD,EAAMG,CAAM,CAC9B,EAEaC,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAACH,EAGH,OAFKtB,EAAAA,WAAW,iBAAiBqB,CAAI,MAExB,CAAC,EAGhB,IAAMK,EAA0BC,EAIhC,OAFAL,EAAG,iBAAiBD,EAAMK,EAAUE,CAAO,MAE9BN,EAAG,oBAAoBD,EAAMK,EAAUE,CAAO,CAC7D,EAEaC,EAAW,GAAwBC,EAAI,QAAQ,SAAW,GAAM,IAAIC,EAAE,YAAY,GAAG,EAQrFC,EAAsB,GACjC1B,EAAiBe,EAAK,WAAW,IAAI,EAAIA,EAAOQ,EAAQR,CAAI,CAAC,EAMlDY,EAAuB,GAA2B,CAC7D,IAAMC,EAAW/B,EAAqBC,CAAkE,EAIxG,OAFI8B,GAAY,MAAQA,IAAa,GAAc,GAE5C5B,EAAiB,OAAO4B,CAAQ,CAAC,CAC1C,EAQaC,EAAsB,GAAgE,CACjG,IAAMC,EAAS,IAAI,IAEnB,IAAK,GAAM,CAACC,EAAKjC,KAAU,OAAO,QAAQkC,CAAM,EAAG,CACjD,GAAI,CAACnC,EAAqBC,CAAK,EAAG,SAElC,IAAMmC,EAAQF,EAAI,QAAQ,OAAQ,EAAE,EAEhCE,GAAOH,EAAO,IAAIG,CAAK,CAC7B,CAEA,OAAOH,CACT,EAEaI,EAAqB,GAChC,MAAM,QAAQpC,CAAK,GAAM,OAAOA,GAAU,YAAYA,E"}
1
+ {"version":3,"file":"dom.cjs","names":["isReactive","ORE_ERRORS","require_errors","_vielzeug_ripple","resolveMaybeReactive","value","UNSAFE_CSS_CHARS","sanitizeCssToken","runAll","i","fns","removeNodes","node","nodes","createReplaceableSlot","cleanups","fn","next","URL_ATTRS","DANGEROUS_SCHEME_RE","URL_REMOVE_RE","URL_TRIM_RE","normalizeUrlForSchemeCheck","isDangerousUrl","setAttr","lowerName","name","el","val","strVal","listen","listener","handler","options","toKebab","str","c","cssDeclarationName","cssDeclarationValue","resolved","resolveClassTokens","tokens","key","record","token","isStructuredValue"],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * A value that may be a plain value, a reactive signal, or a getter function :\n * the shape `when()`, `each()`, `classMap()`, and `bind()` accept.\n * Exported so consumers can annotate their own composable parameters with it.\n */\nexport type MaybeReactive<T> = T | Readable<T> | (() => T);\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal: the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: MaybeReactive<T>): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]?.();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\": a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping: this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes: read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply: it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\n/**\n * Control characters and spaces, normalized away before the scheme check to\n * mirror the WHATWG URL parser browsers use when resolving URL attributes: it\n * removes every ASCII tab/LF/CR anywhere in the input and trims C0 controls and\n * spaces from both ends. So `java\\tscript:alert(1)` executes even though the raw\n * string does not start with `javascript:`. Testing the normalized form closes\n * that gap while leaving benign URLs (e.g. one with an internal space) untouched.\n */\nconst URL_REMOVE_RE = /[\\t\\n\\r]/g;\nconst URL_TRIM_RE = /^[\\s\\p{C}]+|[\\s\\p{C}]+$/gu;\n\nconst normalizeUrlForSchemeCheck = (value: string): string => value.replace(URL_REMOVE_RE, '').replace(URL_TRIM_RE, '');\n\nconst isDangerousUrl = (value: string): boolean => DANGEROUS_SCHEME_RE.test(normalizeUrlForSchemeCheck(value));\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...): inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...): \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && isDangerousUrl(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\n/**\n * Normalize a CSS property name for use in a declaration (camelCase → kebab-case,\n * injection characters stripped). Custom properties (`--*`) are case-sensitive, so\n * they skip the kebab conversion. Shared by `styleMap()` (template side) and\n * `bind({ style })` (host side) so both sanitize identically.\n */\nexport const cssDeclarationName = (name: string): string =>\n sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n/**\n * Resolve a style value to its declaration text ('' for null/false/empty).\n * Shared by `styleMap()` and `bind({ style })`.\n */\nexport const cssDeclarationValue = (value: unknown): string => {\n const resolved = resolveMaybeReactive(value as MaybeReactive<string | number | null | undefined | false>);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Resolve a class map to the set of active class tokens: keys with truthy\n * (possibly reactive) values, whitespace stripped from each key (spaces would\n * inject extra class tokens). Shared by `classMap()` (joins the set into a\n * class attribute) and `bind({ class })` (diffs the set against classList).\n */\nexport const resolveClassTokens = (record: Record<string, MaybeReactive<boolean>>): Set<string> => {\n const tokens = new Set<string>();\n\n for (const [key, value] of Object.entries(record)) {\n if (!resolveMaybeReactive(value)) continue;\n\n const token = key.replace(/\\s+/g, '');\n\n if (token) tokens.add(token);\n }\n\n return tokens;\n};\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"A,0FAoBA,IAAaI,EAA2B,GACtC,OAAOC,GAAU,WAAcA,EAAkB,GAAA,EAAIL,EAAAA,WAAAA,CAAWK,CAAK,EAAIA,EAAM,MAAQA,EAO5EC,EAAmB,SAEnBC,EAAoB,GAA0BF,EAAM,QAAQC,EAAkB,EAAE,EAEhFE,EAAU,GAA8B,CACnD,IAAK,IAAIC,EAAIC,EAAI,OAAS,EAAGD,GAAK,EAAG,IAAKC,EAAID,EAAE,GAAG,CACrD,EAEaE,EAAe,GAAwB,CAClD,IAAK,IAAMC,KAAQC,EACjBD,EAAoB,OAAO,CAE/B,EAuBaE,MAA+C,CAC1D,IAAID,EAAgB,CAAC,EACjBE,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACNP,EAAOO,CAAQ,EACfJ,EAAYE,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAOA,CACT,EACA,gBAAgB,EAAI,CAClBE,EAAS,KAAKC,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQC,CACV,CACF,CACF,EASMC,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASKC,EACJ,sGAUIC,EAAgB,YAChBC,EAAc,4BAEdC,EAA8B,GAA0BjB,EAAM,QAAQe,EAAe,EAAE,CAAC,CAAC,QAAQC,EAAa,EAAE,EAEhHE,EAAkB,GAA2BJ,EAAoB,KAAKG,EAA2BjB,CAAK,CAAC,EAEhGmB,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAMC,EAAYC,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAKA,CAAI,EAAG,CAExB,GAAyBA,EAAzB,EAAiGA,EAAK,MAAM,CAAC,EAA7G,EAEFC,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAWA,GATID,IAAc,UASdG,GAAO,MAAQA,IAAQ,GAAO,CAChCD,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAEA,IAAMG,EAASD,IAAQ,GAAO,OAAS,OAAOA,CAAG,EAE7CV,EAAU,IAAIO,CAAS,GAAKF,EAAeM,CAAM,GAEjD,GAA8CH,EAA9C,EAEFC,EAAG,gBAAgBD,CAAI,GAKzBC,EAAG,aAAaD,EAAMG,CAAM,CAC9B,EAEaC,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAACH,EAGH,OAFK1B,EAAAA,WAAW,iBAAiByB,CAAI,MAExB,CAAC,EAGhB,IAAMK,EAA0BC,EAIhC,OAFAL,EAAG,iBAAiBD,EAAMK,EAAUE,CAAO,MAE9BN,EAAG,oBAAoBD,EAAMK,EAAUE,CAAO,CAC7D,EAEaC,EAAW,GAAwBC,EAAI,QAAQ,SAAW,GAAM,IAAIC,EAAE,YAAY,GAAG,EAQrFC,EAAsB,GACjC9B,EAAiBmB,EAAK,WAAW,IAAI,EAAIA,EAAOQ,EAAQR,CAAI,CAAC,EAMlDY,EAAuB,GAA2B,CAC7D,IAAMC,EAAWnC,EAAqBC,CAAkE,EAIxG,OAFIkC,GAAY,MAAQA,IAAa,GAAc,GAE5ChC,EAAiB,OAAOgC,CAAQ,CAAC,CAC1C,EAQaC,EAAsB,GAAgE,CACjG,IAAMC,EAAS,IAAI,IAEnB,IAAK,GAAM,CAACC,EAAKrC,KAAU,OAAO,QAAQsC,CAAM,EAAG,CACjD,GAAI,CAACvC,EAAqBC,CAAK,EAAG,SAElC,IAAMuC,EAAQF,EAAI,QAAQ,OAAQ,EAAE,EAEhCE,GAAOH,EAAO,IAAIG,CAAK,CAC7B,CAEA,OAAOH,CACT,EAEaI,EAAqB,GAChC,MAAM,QAAQxC,CAAK,GAAM,OAAOA,GAAU,YAAYA,E"}
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK7D;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,OAAO,aAAa,CAAC,CAAC,CAAC,KAAG,CAC4B,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAW,CAAC;AAEzC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAC;AAE/F,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,KAAK,IAAI,IAAI,CAAC;IACd,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,iFAAiF;IACjF,eAAe,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAqBxC,CAAC;AAiCF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAYb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MACc,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,OAAO,KAAG,MAMpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,KAAG,GAAG,CAAC,MAAM,CAY7F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK7D;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,OAAO,aAAa,CAAC,CAAC,CAAC,KAAG,CAC4B,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAW,CAAC;AAEzC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAC;AAE/F,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,KAAK,IAAI,IAAI,CAAC;IACd,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,iFAAiF;IACjF,eAAe,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAqBxC,CAAC;AAgDF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAYb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MACc,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,OAAO,KAAG,MAMpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,KAAG,GAAG,CAAC,MAAM,CAY7F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
package/dist/utils/dom.js CHANGED
@@ -1,2 +1,2 @@
1
- import"../_dev.js";import{ORE_ERRORS as e}from"../errors.js";import{isReactive as t}from"@vielzeug/ripple";var n=e=>typeof e==`function`?e():t(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]?.()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=/* @__PURE__ */ new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=(e,t,n)=>{let r=t.toLowerCase();if(/^on[a-z]/i.test(t)){`${t}${t.slice(2)}`,e.removeAttribute(t);return}if(r===`srcdoc`||n==null||n===!1){e.removeAttribute(t);return}let i=n===!0?`true`:String(n);c.has(r)&&l.test(i)?(`${t}`,e.removeAttribute(t)):e.setAttribute(t,i)},d=(t,n,r,i)=>{if(!t)return e.listenNullTarget(n),()=>{};let a=r;return t.addEventListener(n,a,i),()=>t.removeEventListener(n,a,i)},f=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=e=>i(e.startsWith(`--`)?e:f(e)),m=e=>{let t=n(e);return t==null||t===!1?``:i(String(t))},h=e=>{let t=/* @__PURE__ */ new Set;for(let[r,i]of Object.entries(e)){if(!n(i))continue;let e=r.replace(/\s+/g,``);e&&t.add(e)}return t},g=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{r as UNSAFE_CSS_CHARS,s as createReplaceableSlot,p as cssDeclarationName,m as cssDeclarationValue,g as isStructuredValue,d as listen,o as removeNodes,h as resolveClassTokens,n as resolveMaybeReactive,a as runAll,i as sanitizeCssToken,u as setAttr,f as toKebab};
1
+ import"../_dev.js";import{ORE_ERRORS as e}from"../errors.js";import{isReactive as t}from"@vielzeug/ripple";var n=e=>typeof e==`function`?e():t(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]?.()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=/* @__PURE__ */ new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=/[\t\n\r]/g,d=/^[\s\p{C}]+|[\s\p{C}]+$/gu,f=e=>e.replace(u,``).replace(d,``),p=e=>l.test(f(e)),m=(e,t,n)=>{let r=t.toLowerCase();if(/^on[a-z]/i.test(t)){`${t}${t.slice(2)}`,e.removeAttribute(t);return}if(r===`srcdoc`||n==null||n===!1){e.removeAttribute(t);return}let i=n===!0?`true`:String(n);c.has(r)&&p(i)?(`${t}`,e.removeAttribute(t)):e.setAttribute(t,i)},h=(t,n,r,i)=>{if(!t)return e.listenNullTarget(n),()=>{};let a=r;return t.addEventListener(n,a,i),()=>t.removeEventListener(n,a,i)},g=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),_=e=>i(e.startsWith(`--`)?e:g(e)),v=e=>{let t=n(e);return t==null||t===!1?``:i(String(t))},y=e=>{let t=/* @__PURE__ */ new Set;for(let[r,i]of Object.entries(e)){if(!n(i))continue;let e=r.replace(/\s+/g,``);e&&t.add(e)}return t},b=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{r as UNSAFE_CSS_CHARS,s as createReplaceableSlot,_ as cssDeclarationName,v as cssDeclarationValue,b as isStructuredValue,h as listen,o as removeNodes,y as resolveClassTokens,n as resolveMaybeReactive,a as runAll,i as sanitizeCssToken,m as setAttr,g as toKebab};
2
2
  //# sourceMappingURL=dom.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","names":["resolveMaybeReactive","value","isReactive","UNSAFE_CSS_CHARS","sanitizeCssToken","runAll","i","fns","removeNodes","node","nodes","createReplaceableSlot","cleanups","fn","next","URL_ATTRS","DANGEROUS_SCHEME_RE","setAttr","lowerName","name","el","val","strVal","listen","ORE_ERRORS","listener","handler","options","toKebab","str","c","cssDeclarationName","cssDeclarationValue","resolved","resolveClassTokens","tokens","key","record","token","isStructuredValue"],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * A value that may be a plain value, a reactive signal, or a getter function :\n * the shape `when()`, `each()`, `classMap()`, and `bind()` accept.\n * Exported so consumers can annotate their own composable parameters with it.\n */\nexport type MaybeReactive<T> = T | Readable<T> | (() => T);\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal: the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: MaybeReactive<T>): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]?.();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\": a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping: this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes: read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply: it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...): inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...): \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\n/**\n * Normalize a CSS property name for use in a declaration (camelCase → kebab-case,\n * injection characters stripped). Custom properties (`--*`) are case-sensitive, so\n * they skip the kebab conversion. Shared by `styleMap()` (template side) and\n * `bind({ style })` (host side) so both sanitize identically.\n */\nexport const cssDeclarationName = (name: string): string =>\n sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n/**\n * Resolve a style value to its declaration text ('' for null/false/empty).\n * Shared by `styleMap()` and `bind({ style })`.\n */\nexport const cssDeclarationValue = (value: unknown): string => {\n const resolved = resolveMaybeReactive(value as MaybeReactive<string | number | null | undefined | false>);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Resolve a class map to the set of active class tokens: keys with truthy\n * (possibly reactive) values, whitespace stripped from each key (spaces would\n * inject extra class tokens). Shared by `classMap()` (joins the set into a\n * class attribute) and `bind({ class })` (diffs the set against classList).\n */\nexport const resolveClassTokens = (record: Record<string, MaybeReactive<boolean>>): Set<string> => {\n const tokens = new Set<string>();\n\n for (const [key, value] of Object.entries(record)) {\n if (!resolveMaybeReactive(value)) continue;\n\n const token = key.replace(/\\s+/g, '');\n\n if (token) tokens.add(token);\n }\n\n return tokens;\n};\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"A,2GAoBA,IAAaA,EAA2B,GACtC,OAAOC,GAAU,WAAcA,EAAkB,EAAIC,EAAWD,CAAK,EAAIA,EAAM,MAAQA,EAO5EE,EAAmB,SAEnBC,EAAoB,GAA0BH,EAAM,QAAQE,EAAkB,EAAE,EAEhFE,EAAU,GAA8B,CACnD,IAAK,IAAIC,EAAIC,EAAI,OAAS,EAAGD,GAAK,EAAG,IAAKC,EAAID,EAAE,GAAG,CACrD,EAEaE,EAAe,GAAwB,CAClD,IAAK,IAAMC,KAAQC,EACjBD,EAAoB,OAAO,CAE/B,EAuBaE,MAA+C,CAC1D,IAAID,EAAgB,CAAC,EACjBE,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACNP,EAAOO,CAAQ,EACfJ,EAAYE,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAOA,CACT,EACA,gBAAgB,EAAI,CAClBE,EAAS,KAAKC,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQC,CACV,CACF,CACF,EASMC,kBAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASKC,EACJ,sGAEWC,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAMC,EAAYC,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAKA,CAAI,EAAG,CAExB,GAAyBA,EAAzB,EAAiGA,EAAK,MAAM,CAAC,EAA7G,EAEFC,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAWA,GATID,IAAc,UASdG,GAAO,MAAQA,IAAQ,GAAO,CAChCD,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAEA,IAAMG,EAASD,IAAQ,GAAO,OAAS,OAAOA,CAAG,EAE7CN,EAAU,IAAIG,CAAS,GAAKF,EAAoB,KAAKM,CAAM,GAE3D,GAA8CH,EAA9C,EAEFC,EAAG,gBAAgBD,CAAI,GAKzBC,EAAG,aAAaD,EAAMG,CAAM,CAC9B,EAEaC,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAACH,EAGH,OAFKI,EAAW,iBAAiBL,CAAI,MAExB,CAAC,EAGhB,IAAMM,EAA0BC,EAIhC,OAFAN,EAAG,iBAAiBD,EAAMM,EAAUE,CAAO,MAE9BP,EAAG,oBAAoBD,EAAMM,EAAUE,CAAO,CAC7D,EAEaC,EAAW,GAAwBC,EAAI,QAAQ,SAAW,GAAM,IAAIC,EAAE,YAAY,GAAG,EAQrFC,EAAsB,GACjC3B,EAAiBe,EAAK,WAAW,IAAI,EAAIA,EAAOS,EAAQT,CAAI,CAAC,EAMlDa,EAAuB,GAA2B,CAC7D,IAAMC,EAAWjC,EAAqBC,CAAkE,EAIxG,OAFIgC,GAAY,MAAQA,IAAa,GAAc,GAE5C7B,EAAiB,OAAO6B,CAAQ,CAAC,CAC1C,EAQaC,EAAsB,GAAgE,CACjG,IAAMC,kBAAS,IAAI,IAEnB,IAAK,GAAM,CAACC,EAAKnC,KAAU,OAAO,QAAQoC,CAAM,EAAG,CACjD,GAAI,CAACrC,EAAqBC,CAAK,EAAG,SAElC,IAAMqC,EAAQF,EAAI,QAAQ,OAAQ,EAAE,EAEhCE,GAAOH,EAAO,IAAIG,CAAK,CAC7B,CAEA,OAAOH,CACT,EAEaI,EAAqB,GAChC,MAAM,QAAQtC,CAAK,GAAM,OAAOA,GAAU,YAAYA,E"}
1
+ {"version":3,"file":"dom.js","names":["resolveMaybeReactive","value","isReactive","UNSAFE_CSS_CHARS","sanitizeCssToken","runAll","i","fns","removeNodes","node","nodes","createReplaceableSlot","cleanups","fn","next","URL_ATTRS","DANGEROUS_SCHEME_RE","URL_REMOVE_RE","URL_TRIM_RE","normalizeUrlForSchemeCheck","isDangerousUrl","setAttr","lowerName","name","el","val","strVal","listen","ORE_ERRORS","listener","handler","options","toKebab","str","c","cssDeclarationName","cssDeclarationValue","resolved","resolveClassTokens","tokens","key","record","token","isStructuredValue"],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * A value that may be a plain value, a reactive signal, or a getter function :\n * the shape `when()`, `each()`, `classMap()`, and `bind()` accept.\n * Exported so consumers can annotate their own composable parameters with it.\n */\nexport type MaybeReactive<T> = T | Readable<T> | (() => T);\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal: the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: MaybeReactive<T>): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]?.();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\": a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping: this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes: read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply: it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\n/**\n * Control characters and spaces, normalized away before the scheme check to\n * mirror the WHATWG URL parser browsers use when resolving URL attributes: it\n * removes every ASCII tab/LF/CR anywhere in the input and trims C0 controls and\n * spaces from both ends. So `java\\tscript:alert(1)` executes even though the raw\n * string does not start with `javascript:`. Testing the normalized form closes\n * that gap while leaving benign URLs (e.g. one with an internal space) untouched.\n */\nconst URL_REMOVE_RE = /[\\t\\n\\r]/g;\nconst URL_TRIM_RE = /^[\\s\\p{C}]+|[\\s\\p{C}]+$/gu;\n\nconst normalizeUrlForSchemeCheck = (value: string): string => value.replace(URL_REMOVE_RE, '').replace(URL_TRIM_RE, '');\n\nconst isDangerousUrl = (value: string): boolean => DANGEROUS_SCHEME_RE.test(normalizeUrlForSchemeCheck(value));\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...): inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...): \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && isDangerousUrl(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\n/**\n * Normalize a CSS property name for use in a declaration (camelCase → kebab-case,\n * injection characters stripped). Custom properties (`--*`) are case-sensitive, so\n * they skip the kebab conversion. Shared by `styleMap()` (template side) and\n * `bind({ style })` (host side) so both sanitize identically.\n */\nexport const cssDeclarationName = (name: string): string =>\n sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n/**\n * Resolve a style value to its declaration text ('' for null/false/empty).\n * Shared by `styleMap()` and `bind({ style })`.\n */\nexport const cssDeclarationValue = (value: unknown): string => {\n const resolved = resolveMaybeReactive(value as MaybeReactive<string | number | null | undefined | false>);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Resolve a class map to the set of active class tokens: keys with truthy\n * (possibly reactive) values, whitespace stripped from each key (spaces would\n * inject extra class tokens). Shared by `classMap()` (joins the set into a\n * class attribute) and `bind({ class })` (diffs the set against classList).\n */\nexport const resolveClassTokens = (record: Record<string, MaybeReactive<boolean>>): Set<string> => {\n const tokens = new Set<string>();\n\n for (const [key, value] of Object.entries(record)) {\n if (!resolveMaybeReactive(value)) continue;\n\n const token = key.replace(/\\s+/g, '');\n\n if (token) tokens.add(token);\n }\n\n return tokens;\n};\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"A,2GAoBA,IAAaA,EAA2B,GACtC,OAAOC,GAAU,WAAcA,EAAkB,EAAIC,EAAWD,CAAK,EAAIA,EAAM,MAAQA,EAO5EE,EAAmB,SAEnBC,EAAoB,GAA0BH,EAAM,QAAQE,EAAkB,EAAE,EAEhFE,EAAU,GAA8B,CACnD,IAAK,IAAIC,EAAIC,EAAI,OAAS,EAAGD,GAAK,EAAG,IAAKC,EAAID,EAAE,GAAG,CACrD,EAEaE,EAAe,GAAwB,CAClD,IAAK,IAAMC,KAAQC,EACjBD,EAAoB,OAAO,CAE/B,EAuBaE,MAA+C,CAC1D,IAAID,EAAgB,CAAC,EACjBE,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACNP,EAAOO,CAAQ,EACfJ,EAAYE,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAOA,CACT,EACA,gBAAgB,EAAI,CAClBE,EAAS,KAAKC,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQC,CACV,CACF,CACF,EASMC,kBAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASKC,EACJ,sGAUIC,EAAgB,YAChBC,EAAc,4BAEdC,EAA8B,GAA0BlB,EAAM,QAAQgB,EAAe,EAAE,CAAC,CAAC,QAAQC,EAAa,EAAE,EAEhHE,EAAkB,GAA2BJ,EAAoB,KAAKG,EAA2BlB,CAAK,CAAC,EAEhGoB,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAMC,EAAYC,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAKA,CAAI,EAAG,CAExB,GAAyBA,EAAzB,EAAiGA,EAAK,MAAM,CAAC,EAA7G,EAEFC,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAWA,GATID,IAAc,UASdG,GAAO,MAAQA,IAAQ,GAAO,CAChCD,EAAG,gBAAgBD,CAAI,EAEvB,MACF,CAEA,IAAMG,EAASD,IAAQ,GAAO,OAAS,OAAOA,CAAG,EAE7CV,EAAU,IAAIO,CAAS,GAAKF,EAAeM,CAAM,GAEjD,GAA8CH,EAA9C,EAEFC,EAAG,gBAAgBD,CAAI,GAKzBC,EAAG,aAAaD,EAAMG,CAAM,CAC9B,EAEaC,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAACH,EAGH,OAFKI,EAAW,iBAAiBL,CAAI,MAExB,CAAC,EAGhB,IAAMM,EAA0BC,EAIhC,OAFAN,EAAG,iBAAiBD,EAAMM,EAAUE,CAAO,MAE9BP,EAAG,oBAAoBD,EAAMM,EAAUE,CAAO,CAC7D,EAEaC,EAAW,GAAwBC,EAAI,QAAQ,SAAW,GAAM,IAAIC,EAAE,YAAY,GAAG,EAQrFC,EAAsB,GACjC/B,EAAiBmB,EAAK,WAAW,IAAI,EAAIA,EAAOS,EAAQT,CAAI,CAAC,EAMlDa,EAAuB,GAA2B,CAC7D,IAAMC,EAAWrC,EAAqBC,CAAkE,EAIxG,OAFIoC,GAAY,MAAQA,IAAa,GAAc,GAE5CjC,EAAiB,OAAOiC,CAAQ,CAAC,CAC1C,EAQaC,EAAsB,GAAgE,CACjG,IAAMC,kBAAS,IAAI,IAEnB,IAAK,GAAM,CAACC,EAAKvC,KAAU,OAAO,QAAQwC,CAAM,EAAG,CACjD,GAAI,CAACzC,EAAqBC,CAAK,EAAG,SAElC,IAAMyC,EAAQF,EAAI,QAAQ,OAAQ,EAAE,EAEhCE,GAAOH,EAAO,IAAIG,CAAK,CAC7B,CAEA,OAAOH,CACT,EAEaI,EAAqB,GAChC,MAAM,QAAQ1C,CAAK,GAAM,OAAOA,GAAU,YAAYA,E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/ore",
3
- "version": "26.10.17",
3
+ "version": "26.10.18",
4
4
  "description": "Functional web-component authoring on top of ripple",
5
5
  "repository": {
6
6
  "type": "git",
@@ -54,8 +54,8 @@
54
54
  "test:types": "tsc -p tsconfig.json --noEmit"
55
55
  },
56
56
  "peerDependencies": {
57
- "@vielzeug/assay": "^26.10.17",
58
- "@vielzeug/ripple": "^26.10.17"
57
+ "@vielzeug/assay": "^26.10.18",
58
+ "@vielzeug/ripple": "^26.10.18"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@vielzeug/assay": {
@@ -64,8 +64,8 @@
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/node": "^26.6.5",
67
- "@vielzeug/assay": "26.10.17",
68
- "@vielzeug/ripple": "26.10.17",
67
+ "@vielzeug/assay": "26.10.18",
68
+ "@vielzeug/ripple": "26.10.18",
69
69
  "axe-core": "^4.14.0",
70
70
  "jsdom": "^30.1.3",
71
71
  "typescript": "^6.0.3",