@llui/compiler 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessor-resolver.d.ts +9 -1
- package/dist/accessor-resolver.d.ts.map +1 -1
- package/dist/accessor-resolver.js +68 -9
- package/dist/accessor-resolver.js.map +1 -1
- package/dist/collect-deps.d.ts +5 -1
- package/dist/collect-deps.d.ts.map +1 -1
- package/dist/collect-deps.js +117 -14
- package/dist/collect-deps.js.map +1 -1
- package/dist/cross-file-walker.d.ts +4 -1
- package/dist/cross-file-walker.d.ts.map +1 -1
- package/dist/cross-file-walker.js +72 -9
- package/dist/cross-file-walker.js.map +1 -1
- package/dist/lint-modules.d.ts.map +1 -1
- package/dist/lint-modules.js +2 -0
- package/dist/lint-modules.js.map +1 -1
- package/dist/module.d.ts +12 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +2 -1
- package/dist/module.js.map +1 -1
- package/dist/modules/bitmask-overflow.js +1 -1
- package/dist/modules/bitmask-overflow.js.map +1 -1
- package/dist/modules/core-synthesis.d.ts +7 -0
- package/dist/modules/core-synthesis.d.ts.map +1 -1
- package/dist/modules/core-synthesis.js +24 -12
- package/dist/modules/core-synthesis.js.map +1 -1
- package/dist/modules/opaque-state-flow.d.ts +3 -0
- package/dist/modules/opaque-state-flow.d.ts.map +1 -0
- package/dist/modules/opaque-state-flow.js +240 -0
- package/dist/modules/opaque-state-flow.js.map +1 -0
- package/dist/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +84 -6
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
package/dist/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"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","sourcesContent":["// CompilerModule + ModuleRegistry — v2c §2 visitor-registry primitive.\n//\n// Modules accumulate findings during a single AST walk per file and\n// contribute emissions after the walk completes. The walker visits each\n// node once; every module registered for that node's SyntaxKind sees it.\n//\n// This file defines the interfaces + the registry. The actual modules\n// (`compiler-core`, `compiler-agent`, `compiler-ssr`, `compiler-devtools`)\n// will consume them; for v2c-partial only the primitive lands, and one\n// proof-of-concept module exercises it.\n//\n// Design contract (v2c.md §2.1):\n// - Modules NEVER walk the AST themselves — only the registry walks.\n// This keeps the cost O(nodes), not O(modules × nodes).\n// - Visitor order for a given SyntaxKind is the declaration order in\n// `llui.config.ts`'s `modules: [...]` array. Observable to module\n// authors. Alphabetical-by-name was rejected (couples correctness\n// to package names).\n// - Emission conflicts (two modules writing to the same field) are\n// a hard error, not a silent overwrite. Each module owns disjoint\n// output fields.\n// - `runtimeImports` arrays merge by union (deduplicated). Multiple\n// modules requesting the same runtime helper collapse to one\n// import.\n\nimport ts from 'typescript'\nimport type { Diagnostic } from './diagnostic.js'\n\n// ── Module interface ────────────────────────────────────────────────\n\nexport interface DiagnosticDefinition {\n /** Stable id, e.g. `llui/opaque-view-call`. Per v2c §3 §8.2. */\n id: string\n /** One-line description; useful for adapter UIs that don't render the message. */\n description: string\n}\n\n/**\n * Per-file analysis output. Modules accumulate findings here during\n * visitor dispatch; emit consumes it. The shape is intentionally\n * open-ended — modules name their own slots and the umbrella's\n * orchestrator never inspects them, only forwards.\n */\nexport interface FileAnalysis {\n /** Source file the analysis ran over. */\n sourceFile: ts.SourceFile\n /** Per-module accumulator buckets, keyed by module name. */\n perModule: Map<string, unknown>\n /** Diagnostics emitted during the walk. */\n diagnostics: Diagnostic[]\n}\n\n/**\n * Context passed to every visitor invocation. Modules use it to record\n * findings, emit diagnostics, and consult shared state (the TS\n * Compiler-API checker, the project root, sibling-module findings if\n * dependencies allow).\n */\n/**\n * Resolved external type sources for the file under analysis. Same\n * shape as `transform.ts`'s `ExternalTypeSources`; declared here as a\n * structural minimum so the module registry doesn't import from the\n * umbrella. The host adapter (vite-plugin) supplies the values via\n * its async cross-file resolver (`findTypeSource`).\n *\n * Always undefined for test-only `transformLlui(source, fileName)`\n * invocations and for lint adapters without import resolution. Modules\n * that consume this should fall back to file-local behaviour when\n * absent.\n */\nexport interface ModuleExternalTypes {\n state?: { source: string; typeName: string }\n msg?: { source: string; typeName: string }\n effect?: { source: string; typeName: string }\n}\n\nexport interface AnalysisContext {\n sourceFile: ts.SourceFile\n /** TS TypeChecker, when the host adapter has built a Program. May be undefined for AST-only paths. */\n checker: ts.TypeChecker | undefined\n /**\n * Get the named module's accumulator slot (creating it lazily). The\n * slot is whatever shape the module wrote; type-safe access is the\n * module author's responsibility — typically via a typed `get<T>()`\n * wrapper exported alongside the module.\n */\n getSlot<T>(moduleName: string, init: () => T): T\n /** Record a diagnostic. The diagnostic's `id` should match one declared in `DiagnosticDefinition[]`. */\n reportDiagnostic(d: Diagnostic): void\n /**\n * External type sources from the host adapter's cross-file resolver.\n * Undefined when the host doesn't supply them (test path, lint-only\n * adapters without import resolution).\n */\n externalTypes?: ModuleExternalTypes\n}\n\nexport interface EmissionContribution {\n /** Module emitting this contribution — used for conflict reporting. */\n module: string\n /** Field name on the `ComponentDef` object literal (e.g. `__msgSchema`). */\n field: string\n /** AST expression to assign. The umbrella merges into the component()'s config arg. */\n value: ts.Expression\n /**\n * Optional per-call target. When set, this contribution applies only\n * to the named `component()` call expression; the umbrella's\n * emission-merger writes the field into that call's config-arg\n * object literal. When omitted, the contribution is *file-global*:\n * the merger writes the field into every `component()` call in the\n * file (the common case — `__msgSchema`, `__prefixes`, `__schemaHash`\n * are file-shape-derived).\n *\n * Per-call target is needed for `__componentMeta` (file + line vary\n * per call site) and any other field whose value depends on the\n * specific `component()` call location.\n *\n * Conflict-detection runs per-(field, target) tuple — two modules\n * may both contribute `__custom` if they target *different* call\n * expressions; same target on the same field is still an error.\n */\n target?: ts.CallExpression\n}\n\nexport interface EmissionContext {\n sourceFile: ts.SourceFile\n factory: ts.NodeFactory\n}\n\n/**\n * A compiler module declares:\n * - identification (name, compilerVersion semver against the umbrella);\n * - the diagnostics it can emit (stable IDs);\n * - per-`SyntaxKind` visitor handlers (the walker dispatches each AST\n * node once; every module with a handler for its kind sees it);\n * - optionally, an `emit` function that contributes ComponentDef fields\n * after the walk completes;\n * - optionally, `runtimeImports` declaring which `@llui/dom` symbols\n * its emissions reference.\n */\nexport interface CompilerModule {\n name: string\n /** Semver range against the compiler API. v2c §5. */\n compilerVersion: string\n /** Modules this one depends on. The registry verifies presence at activation. */\n dependsOn?: string[]\n diagnostics: DiagnosticDefinition[]\n /**\n * Optional AST pre-transform. Called once per file BEFORE the\n * visitor walk and emission phase. Returns a (possibly rewritten)\n * SourceFile; the result is threaded through subsequent modules'\n * pre-transforms (in declaration order) and then becomes the file\n * the visitor walks. Use for AST mutations the visitor model can't\n * cleanly express — adjacent statement insertion, wrapping arrow\n * expressions, etc. The agent's connect-pattern pass and the\n * universal handler-tagger are the canonical examples (MODULE-MAPPING.md\n * binding-descriptors entry).\n *\n * Most modules do NOT need this. Visitor + emit is the preferred\n * shape because it composes deterministically across modules without\n * threading a mutable SourceFile through each one. preTransform\n * exists for the cases where AST mutation is unavoidable.\n *\n * The §2.1 \"walker runs once per file\" invariant is preserved: the\n * VISITOR walk runs once. preTransform passes are additional, but\n * they're typically cheap (targeted call-site rewrites, not deep\n * recursive walks) and execute before the single visitor walk.\n */\n preTransform?(ctx: PreTransformContext, sf: ts.SourceFile): ts.SourceFile\n visitors: {\n [K in ts.SyntaxKind]?: (ctx: AnalysisContext, node: ts.Node) => void\n }\n /**\n * Optional per-call AST rewrite, BOTTOM-UP (after children visited).\n * Called once per `CallExpression` during the post-visitor transform\n * phase, AFTER analysis has accumulated findings in\n * `analysis.perModule` AND after `ts.visitEachChild` has recursively\n * rewritten the node's children. Returns either:\n * - `null` — node unchanged; chain continues with the next module's\n * transformCall (if any).\n * - a new `ts.CallExpression` — node replaced; subsequent modules'\n * transformCall hooks see the new node (composes in declaration\n * order, just like preTransform).\n *\n * Use for rewrites that depend on the rewritten children — e.g.\n * row-factory emission inspects the render body for an already-emitted\n * `elTemplate(...)` call, so element rewrites that produce\n * `elTemplate` MUST have fired first. Module authors should treat\n * transformCall as a pure function of its inputs (the node + analysis\n * findings).\n */\n transformCall?(ctx: TransformCallContext, node: ts.CallExpression): ts.CallExpression | null\n /**\n * Optional per-call AST rewrite, TOP-DOWN (before children visited).\n * Mirrors `transformCall` but fires BEFORE `ts.visitEachChild`\n * recurses into the call's children. Use when the rewrite must happen\n * before the children are visited — most commonly when the rewrite\n * changes the call's argument shape and the children's visitor would\n * misinterpret the original shape. Memo-wrapping the `items:`\n * accessor of an `each()` call is the canonical example: the wrapped\n * accessor is what subsequent passes (item-selector dedup, mask\n * injection) read.\n *\n * Both `transformCallEnter` and `transformCall` may be declared by\n * the same module; enter fires top-down before recursion, transformCall\n * fires bottom-up after. Ordering within each direction is declaration\n * order across modules; the two directions never interleave for a\n * given node.\n */\n transformCallEnter?(ctx: TransformCallContext, node: ts.CallExpression): ts.CallExpression | null\n /** Called once per file after the visitor pass completes. Returns this module's emission contributions. */\n emit?(ctx: EmissionContext, analysis: FileAnalysis): EmissionContribution[]\n /** Runtime symbol names this module's emissions reference (from `@llui/dom`). */\n runtimeImports?: string[]\n}\n\nexport interface PreTransformContext {\n factory: ts.NodeFactory\n /**\n * Shared per-file findings accumulator. preTransform passes that\n * need to communicate with their own emit step (e.g. \"this file\n * needed scope-variant registrations\") use this slot map. The same\n * `analysis.perModule` map is later passed to visitors and emit.\n */\n analysis: FileAnalysis\n}\n\n/**\n * Context passed to every `transformCall` invocation. Carries the\n * factory for building new AST nodes and a read-only view of analysis\n * findings (visitors have already completed and populated\n * `analysis.perModule` by the time transformCall fires).\n */\nexport interface TransformCallContext {\n factory: ts.NodeFactory\n /** Read-only access to visitor-phase findings. */\n analysis: FileAnalysis\n}\n\n// ── Registry ────────────────────────────────────────────────────────\n\nexport interface RegistryRunResult {\n analysis: FileAnalysis\n emissions: EmissionContribution[]\n /** Union of runtime imports from every active module. */\n runtimeImports: string[]\n}\n\n/**\n * The visitor registry. Built once per compiler boot from the user's\n * `llui.config.ts` `modules: [...]` array; the umbrella's per-file\n * pipeline calls `run(sourceFile, checker)` to drive a complete pass.\n */\nexport class ModuleRegistry {\n private readonly modules: ReadonlyArray<CompilerModule>\n /** Pre-indexed by SyntaxKind for O(1) dispatch. */\n private readonly visitorsByKind: Map<ts.SyntaxKind, Array<CompilerModule>>\n\n constructor(modules: ReadonlyArray<CompilerModule>) {\n this.modules = modules\n this.verifyDependencies()\n this.visitorsByKind = this.buildVisitorIndex()\n }\n\n private verifyDependencies(): void {\n const present = new Set(this.modules.map((m) => m.name))\n for (const m of this.modules) {\n for (const dep of m.dependsOn ?? []) {\n if (!present.has(dep)) {\n throw new Error(\n `[llui] module \"${m.name}\" depends on \"${dep}\", which is not in the active module list. ` +\n `Add ${dep}() to your llui.config.ts modules array (must appear before \"${m.name}\"). ` +\n `See docs/proposals/v2-compiler/v2c.md §2.4.`,\n )\n }\n }\n }\n }\n\n private buildVisitorIndex(): Map<ts.SyntaxKind, Array<CompilerModule>> {\n const index = new Map<ts.SyntaxKind, Array<CompilerModule>>()\n for (const m of this.modules) {\n for (const kindStr of Object.keys(m.visitors)) {\n const kind = Number(kindStr) as ts.SyntaxKind\n if (!index.has(kind)) index.set(kind, [])\n index.get(kind)!.push(m)\n }\n }\n return index\n }\n\n /**\n * Run a full analysis + emission pass over `sourceFile`. Phases:\n * 1. Pre-transform: each module's `preTransform?` fires in\n * declaration order; the (possibly rewritten) SourceFile flows\n * through subsequent passes.\n * 2. Visitor walk: a single AST walk dispatches each node to every\n * module's matching SyntaxKind handler. Read-only — visitors\n * accumulate findings in `analysis.perModule` but cannot rewrite.\n * 3. Transform: a `ts.transform`-style walk dispatches each\n * `CallExpression` to every module's `transformCallEnter?`\n * (top-down, before children recursion) and `transformCall?`\n * (bottom-up, after children recursion) hooks in declaration\n * order; each hook's return value (if non-null) feeds the next.\n * Composes call-site rewrites without each module paying a\n * whole-file walk cost.\n * 4. Emission: each module's `emit?` fires; the registry merges\n * contributions, detecting (field, target) conflicts.\n */\n run(\n sourceFile: ts.SourceFile,\n checker?: ts.TypeChecker,\n externalTypes?: ModuleExternalTypes,\n ): RegistryRunResult {\n const analysis: FileAnalysis = {\n sourceFile,\n perModule: new Map(),\n diagnostics: [],\n }\n\n // Phase 1: pre-transform passes. Threaded SourceFile flows through\n // each module's preTransform in declaration order. Modules without\n // a preTransform pass through.\n let currentSf = sourceFile\n for (const m of this.modules) {\n if (!m.preTransform) continue\n currentSf = m.preTransform(\n {\n factory: ts.factory,\n analysis,\n },\n currentSf,\n )\n }\n analysis.sourceFile = currentSf\n const ctx: AnalysisContext = {\n sourceFile: currentSf,\n checker,\n getSlot: <T>(name: string, init: () => T): T => {\n let slot = analysis.perModule.get(name) as T | undefined\n if (slot === undefined) {\n slot = init()\n analysis.perModule.set(name, slot)\n }\n return slot\n },\n reportDiagnostic: (d) => {\n analysis.diagnostics.push(d)\n },\n externalTypes,\n }\n\n // Phase 2: single-pass visitor walk over the (possibly\n // pre-transformed) SourceFile.\n const walk = (node: ts.Node): void => {\n const handlers = this.visitorsByKind.get(node.kind)\n if (handlers) {\n for (const m of handlers) {\n const handler = m.visitors[node.kind]\n if (handler) handler(ctx, node)\n }\n }\n ts.forEachChild(node, walk)\n }\n walk(currentSf)\n\n // Phase 2b: per-CallExpression transform. Modules with a\n // `transformCallEnter` (top-down) or `transformCall` (bottom-up)\n // hook get one chance to rewrite each call site per direction;\n // chained in declaration order. The phase is skipped entirely\n // when no module declares either hook (zero overhead for the\n // common case of metadata-only modules).\n //\n // Within a single CallExpression visit:\n // 1. transformCallEnter fires (declaration order) — rewrites\n // the node BEFORE children are recursed; subsequent\n // transformCallEnter hooks see the rewritten node.\n // 2. ts.visitEachChild recurses into the (possibly enter-rewritten)\n // node, visiting children.\n // 3. transformCall fires (declaration order) — rewrites the\n // now-children-rewritten node; subsequent transformCall hooks\n // see the result.\n //\n // The two directions never interleave for a given node: all enters\n // run, then all children visit, then all exits run.\n const enterModules = this.modules.filter((m) => m.transformCallEnter)\n const exitModules = this.modules.filter((m) => m.transformCall)\n if (enterModules.length > 0 || exitModules.length > 0) {\n const transformCtx: TransformCallContext = {\n factory: ts.factory,\n analysis,\n }\n const visit: ts.Visitor = (node) => {\n // Top-down (enter) — fires BEFORE children recursion. Chain\n // composes in declaration order; each enter hook sees the\n // output of the previous one.\n let current = node\n if (ts.isCallExpression(current)) {\n for (const m of enterModules) {\n const replaced = m.transformCallEnter!(transformCtx, current as ts.CallExpression)\n if (replaced) current = replaced\n }\n }\n // Recurse children of the (possibly enter-rewritten) node.\n const visited = ts.visitEachChild(current, visit, undefined!)\n // Bottom-up (exit) — fires AFTER children recursion. Chain\n // composes in declaration order; each exit hook sees the\n // output of the previous one.\n if (ts.isCallExpression(visited)) {\n let result = visited as ts.CallExpression\n for (const m of exitModules) {\n const replaced = m.transformCall!(transformCtx, result)\n if (replaced) result = replaced\n }\n return result\n }\n return visited\n }\n currentSf = ts.visitNode(currentSf, visit) as ts.SourceFile\n analysis.sourceFile = currentSf\n }\n\n // Phase 3: emission. Each module contributes after analysis\n // completes. Conflicts on (field, target) tuples are hard errors\n // per §2.1.\n const emissionCtx: EmissionContext = {\n sourceFile: currentSf,\n factory: ts.factory,\n }\n const emissions: EmissionContribution[] = []\n // Conflict detection keyed by `(field, target)` — two modules may\n // contribute distinct per-target emissions to the same field name\n // (e.g. component-meta for two different `component()` calls in\n // one file), but two emissions with the same target on the same\n // field is the hard error from §2.1.\n //\n // Targets are compared by object identity (not by `pos`/`end`) so\n // synthetic nodes (factory-created with pos=-1) compare correctly.\n // File-global emissions (target=undefined) share one bucket.\n const globalOwnerByField = new Map<string, string>()\n const targetOwnerByField = new Map<ts.CallExpression, Map<string, string>>()\n for (const m of this.modules) {\n if (!m.emit) continue\n const contributions = m.emit(emissionCtx, analysis)\n for (const c of contributions) {\n let owners: Map<string, string>\n if (c.target) {\n let existing = targetOwnerByField.get(c.target)\n if (!existing) {\n existing = new Map()\n targetOwnerByField.set(c.target, existing)\n }\n owners = existing\n } else {\n owners = globalOwnerByField\n }\n const other = owners.get(c.field)\n if (other !== undefined) {\n throw new Error(\n `[llui/module-emission-conflict] Modules \"${other}\" and \"${c.module}\" both ` +\n `contribute to ComponentDef field \"${c.field}\"${c.target ? ' for the same component() call site' : ''}. ` +\n `This is a hard error — each (field, target) pair must be owned by exactly one ` +\n `module. Either deduplicate, or move one emission to a distinct field. See ` +\n `docs/proposals/v2-compiler/v2c.md §2.1.`,\n )\n }\n owners.set(c.field, c.module)\n emissions.push(c)\n }\n }\n\n // Union runtime imports.\n const runtimeImports = new Set<string>()\n for (const m of this.modules) {\n for (const imp of m.runtimeImports ?? []) runtimeImports.add(imp)\n }\n\n return {\n analysis,\n emissions,\n runtimeImports: [...runtimeImports].sort(),\n }\n }\n\n /** Module names in declaration order. Adapters surface this for debug logs / config diagnostics. */\n listModules(): string[] {\n return this.modules.map((m) => m.name)\n }\n\n /** All diagnostic definitions across active modules. Used by adapters to enumerate stable IDs. */\n listDiagnostics(): DiagnosticDefinition[] {\n return this.modules.flatMap((m) => m.diagnostics)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"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","sourcesContent":["// CompilerModule + ModuleRegistry — v2c §2 visitor-registry primitive.\n//\n// Modules accumulate findings during a single AST walk per file and\n// contribute emissions after the walk completes. The walker visits each\n// node once; every module registered for that node's SyntaxKind sees it.\n//\n// This file defines the interfaces + the registry. The actual modules\n// (`compiler-core`, `compiler-agent`, `compiler-ssr`, `compiler-devtools`)\n// will consume them; for v2c-partial only the primitive lands, and one\n// proof-of-concept module exercises it.\n//\n// Design contract (v2c.md §2.1):\n// - Modules NEVER walk the AST themselves — only the registry walks.\n// This keeps the cost O(nodes), not O(modules × nodes).\n// - Visitor order for a given SyntaxKind is the declaration order in\n// `llui.config.ts`'s `modules: [...]` array. Observable to module\n// authors. Alphabetical-by-name was rejected (couples correctness\n// to package names).\n// - Emission conflicts (two modules writing to the same field) are\n// a hard error, not a silent overwrite. Each module owns disjoint\n// output fields.\n// - `runtimeImports` arrays merge by union (deduplicated). Multiple\n// modules requesting the same runtime helper collapse to one\n// import.\n\nimport ts from 'typescript'\nimport type { Diagnostic } from './diagnostic.js'\n\n// ── Module interface ────────────────────────────────────────────────\n\nexport interface DiagnosticDefinition {\n /** Stable id, e.g. `llui/opaque-view-call`. Per v2c §3 §8.2. */\n id: string\n /** One-line description; useful for adapter UIs that don't render the message. */\n description: string\n}\n\n/**\n * Per-file analysis output. Modules accumulate findings here during\n * visitor dispatch; emit consumes it. The shape is intentionally\n * open-ended — modules name their own slots and the umbrella's\n * orchestrator never inspects them, only forwards.\n */\nexport interface FileAnalysis {\n /** Source file the analysis ran over. */\n sourceFile: ts.SourceFile\n /** Per-module accumulator buckets, keyed by module name. */\n perModule: Map<string, unknown>\n /** Diagnostics emitted during the walk. */\n diagnostics: Diagnostic[]\n}\n\n/**\n * Context passed to every visitor invocation. Modules use it to record\n * findings, emit diagnostics, and consult shared state (the TS\n * Compiler-API checker, the project root, sibling-module findings if\n * dependencies allow).\n */\n/**\n * Resolved external type sources for the file under analysis. Same\n * shape as `transform.ts`'s `ExternalTypeSources`; declared here as a\n * structural minimum so the module registry doesn't import from the\n * umbrella. The host adapter (vite-plugin) supplies the values via\n * its async cross-file resolver (`findTypeSource`).\n *\n * Always undefined for test-only `transformLlui(source, fileName)`\n * invocations and for lint adapters without import resolution. Modules\n * that consume this should fall back to file-local behaviour when\n * absent.\n */\nexport interface ModuleExternalTypes {\n state?: { source: string; typeName: string }\n msg?: { source: string; typeName: string }\n effect?: { source: string; typeName: string }\n}\n\nexport interface AnalysisContext {\n sourceFile: ts.SourceFile\n /** TS TypeChecker, when the host adapter has built a Program. May be undefined for AST-only paths. */\n checker: ts.TypeChecker | undefined\n /**\n * The cross-file Program the checker is bound to, when available.\n * Modules that need to resolve identifiers across files (e.g. the\n * opaque-state-flow lint walking through imported helpers) must walk\n * Program-bound nodes — the file the registry hands them is a\n * locally-reparsed copy and its identifiers won't resolve through the\n * checker. Use `program.getSourceFile(sourceFile.fileName)` to fetch\n * the Program-bound counterpart. Undefined when the host doesn't\n * supply a Program (test path, lint adapters without cross-file).\n */\n program: ts.Program | undefined\n /**\n * Get the named module's accumulator slot (creating it lazily). The\n * slot is whatever shape the module wrote; type-safe access is the\n * module author's responsibility — typically via a typed `get<T>()`\n * wrapper exported alongside the module.\n */\n getSlot<T>(moduleName: string, init: () => T): T\n /** Record a diagnostic. The diagnostic's `id` should match one declared in `DiagnosticDefinition[]`. */\n reportDiagnostic(d: Diagnostic): void\n /**\n * External type sources from the host adapter's cross-file resolver.\n * Undefined when the host doesn't supply them (test path, lint-only\n * adapters without import resolution).\n */\n externalTypes?: ModuleExternalTypes\n}\n\nexport interface EmissionContribution {\n /** Module emitting this contribution — used for conflict reporting. */\n module: string\n /** Field name on the `ComponentDef` object literal (e.g. `__msgSchema`). */\n field: string\n /** AST expression to assign. The umbrella merges into the component()'s config arg. */\n value: ts.Expression\n /**\n * Optional per-call target. When set, this contribution applies only\n * to the named `component()` call expression; the umbrella's\n * emission-merger writes the field into that call's config-arg\n * object literal. When omitted, the contribution is *file-global*:\n * the merger writes the field into every `component()` call in the\n * file (the common case — `__msgSchema`, `__prefixes`, `__schemaHash`\n * are file-shape-derived).\n *\n * Per-call target is needed for `__componentMeta` (file + line vary\n * per call site) and any other field whose value depends on the\n * specific `component()` call location.\n *\n * Conflict-detection runs per-(field, target) tuple — two modules\n * may both contribute `__custom` if they target *different* call\n * expressions; same target on the same field is still an error.\n */\n target?: ts.CallExpression\n}\n\nexport interface EmissionContext {\n sourceFile: ts.SourceFile\n factory: ts.NodeFactory\n}\n\n/**\n * A compiler module declares:\n * - identification (name, compilerVersion semver against the umbrella);\n * - the diagnostics it can emit (stable IDs);\n * - per-`SyntaxKind` visitor handlers (the walker dispatches each AST\n * node once; every module with a handler for its kind sees it);\n * - optionally, an `emit` function that contributes ComponentDef fields\n * after the walk completes;\n * - optionally, `runtimeImports` declaring which `@llui/dom` symbols\n * its emissions reference.\n */\nexport interface CompilerModule {\n name: string\n /** Semver range against the compiler API. v2c §5. */\n compilerVersion: string\n /** Modules this one depends on. The registry verifies presence at activation. */\n dependsOn?: string[]\n diagnostics: DiagnosticDefinition[]\n /**\n * Optional AST pre-transform. Called once per file BEFORE the\n * visitor walk and emission phase. Returns a (possibly rewritten)\n * SourceFile; the result is threaded through subsequent modules'\n * pre-transforms (in declaration order) and then becomes the file\n * the visitor walks. Use for AST mutations the visitor model can't\n * cleanly express — adjacent statement insertion, wrapping arrow\n * expressions, etc. The agent's connect-pattern pass and the\n * universal handler-tagger are the canonical examples (MODULE-MAPPING.md\n * binding-descriptors entry).\n *\n * Most modules do NOT need this. Visitor + emit is the preferred\n * shape because it composes deterministically across modules without\n * threading a mutable SourceFile through each one. preTransform\n * exists for the cases where AST mutation is unavoidable.\n *\n * The §2.1 \"walker runs once per file\" invariant is preserved: the\n * VISITOR walk runs once. preTransform passes are additional, but\n * they're typically cheap (targeted call-site rewrites, not deep\n * recursive walks) and execute before the single visitor walk.\n */\n preTransform?(ctx: PreTransformContext, sf: ts.SourceFile): ts.SourceFile\n visitors: {\n [K in ts.SyntaxKind]?: (ctx: AnalysisContext, node: ts.Node) => void\n }\n /**\n * Optional per-call AST rewrite, BOTTOM-UP (after children visited).\n * Called once per `CallExpression` during the post-visitor transform\n * phase, AFTER analysis has accumulated findings in\n * `analysis.perModule` AND after `ts.visitEachChild` has recursively\n * rewritten the node's children. Returns either:\n * - `null` — node unchanged; chain continues with the next module's\n * transformCall (if any).\n * - a new `ts.CallExpression` — node replaced; subsequent modules'\n * transformCall hooks see the new node (composes in declaration\n * order, just like preTransform).\n *\n * Use for rewrites that depend on the rewritten children — e.g.\n * row-factory emission inspects the render body for an already-emitted\n * `elTemplate(...)` call, so element rewrites that produce\n * `elTemplate` MUST have fired first. Module authors should treat\n * transformCall as a pure function of its inputs (the node + analysis\n * findings).\n */\n transformCall?(ctx: TransformCallContext, node: ts.CallExpression): ts.CallExpression | null\n /**\n * Optional per-call AST rewrite, TOP-DOWN (before children visited).\n * Mirrors `transformCall` but fires BEFORE `ts.visitEachChild`\n * recurses into the call's children. Use when the rewrite must happen\n * before the children are visited — most commonly when the rewrite\n * changes the call's argument shape and the children's visitor would\n * misinterpret the original shape. Memo-wrapping the `items:`\n * accessor of an `each()` call is the canonical example: the wrapped\n * accessor is what subsequent passes (item-selector dedup, mask\n * injection) read.\n *\n * Both `transformCallEnter` and `transformCall` may be declared by\n * the same module; enter fires top-down before recursion, transformCall\n * fires bottom-up after. Ordering within each direction is declaration\n * order across modules; the two directions never interleave for a\n * given node.\n */\n transformCallEnter?(ctx: TransformCallContext, node: ts.CallExpression): ts.CallExpression | null\n /** Called once per file after the visitor pass completes. Returns this module's emission contributions. */\n emit?(ctx: EmissionContext, analysis: FileAnalysis): EmissionContribution[]\n /** Runtime symbol names this module's emissions reference (from `@llui/dom`). */\n runtimeImports?: string[]\n}\n\nexport interface PreTransformContext {\n factory: ts.NodeFactory\n /**\n * Shared per-file findings accumulator. preTransform passes that\n * need to communicate with their own emit step (e.g. \"this file\n * needed scope-variant registrations\") use this slot map. The same\n * `analysis.perModule` map is later passed to visitors and emit.\n */\n analysis: FileAnalysis\n}\n\n/**\n * Context passed to every `transformCall` invocation. Carries the\n * factory for building new AST nodes and a read-only view of analysis\n * findings (visitors have already completed and populated\n * `analysis.perModule` by the time transformCall fires).\n */\nexport interface TransformCallContext {\n factory: ts.NodeFactory\n /** Read-only access to visitor-phase findings. */\n analysis: FileAnalysis\n}\n\n// ── Registry ────────────────────────────────────────────────────────\n\nexport interface RegistryRunResult {\n analysis: FileAnalysis\n emissions: EmissionContribution[]\n /** Union of runtime imports from every active module. */\n runtimeImports: string[]\n}\n\n/**\n * The visitor registry. Built once per compiler boot from the user's\n * `llui.config.ts` `modules: [...]` array; the umbrella's per-file\n * pipeline calls `run(sourceFile, checker)` to drive a complete pass.\n */\nexport class ModuleRegistry {\n private readonly modules: ReadonlyArray<CompilerModule>\n /** Pre-indexed by SyntaxKind for O(1) dispatch. */\n private readonly visitorsByKind: Map<ts.SyntaxKind, Array<CompilerModule>>\n\n constructor(modules: ReadonlyArray<CompilerModule>) {\n this.modules = modules\n this.verifyDependencies()\n this.visitorsByKind = this.buildVisitorIndex()\n }\n\n private verifyDependencies(): void {\n const present = new Set(this.modules.map((m) => m.name))\n for (const m of this.modules) {\n for (const dep of m.dependsOn ?? []) {\n if (!present.has(dep)) {\n throw new Error(\n `[llui] module \"${m.name}\" depends on \"${dep}\", which is not in the active module list. ` +\n `Add ${dep}() to your llui.config.ts modules array (must appear before \"${m.name}\"). ` +\n `See docs/proposals/v2-compiler/v2c.md §2.4.`,\n )\n }\n }\n }\n }\n\n private buildVisitorIndex(): Map<ts.SyntaxKind, Array<CompilerModule>> {\n const index = new Map<ts.SyntaxKind, Array<CompilerModule>>()\n for (const m of this.modules) {\n for (const kindStr of Object.keys(m.visitors)) {\n const kind = Number(kindStr) as ts.SyntaxKind\n if (!index.has(kind)) index.set(kind, [])\n index.get(kind)!.push(m)\n }\n }\n return index\n }\n\n /**\n * Run a full analysis + emission pass over `sourceFile`. Phases:\n * 1. Pre-transform: each module's `preTransform?` fires in\n * declaration order; the (possibly rewritten) SourceFile flows\n * through subsequent passes.\n * 2. Visitor walk: a single AST walk dispatches each node to every\n * module's matching SyntaxKind handler. Read-only — visitors\n * accumulate findings in `analysis.perModule` but cannot rewrite.\n * 3. Transform: a `ts.transform`-style walk dispatches each\n * `CallExpression` to every module's `transformCallEnter?`\n * (top-down, before children recursion) and `transformCall?`\n * (bottom-up, after children recursion) hooks in declaration\n * order; each hook's return value (if non-null) feeds the next.\n * Composes call-site rewrites without each module paying a\n * whole-file walk cost.\n * 4. Emission: each module's `emit?` fires; the registry merges\n * contributions, detecting (field, target) conflicts.\n */\n run(\n sourceFile: ts.SourceFile,\n checker?: ts.TypeChecker,\n externalTypes?: ModuleExternalTypes,\n program?: ts.Program,\n ): RegistryRunResult {\n const analysis: FileAnalysis = {\n sourceFile,\n perModule: new Map(),\n diagnostics: [],\n }\n\n // Phase 1: pre-transform passes. Threaded SourceFile flows through\n // each module's preTransform in declaration order. Modules without\n // a preTransform pass through.\n let currentSf = sourceFile\n for (const m of this.modules) {\n if (!m.preTransform) continue\n currentSf = m.preTransform(\n {\n factory: ts.factory,\n analysis,\n },\n currentSf,\n )\n }\n analysis.sourceFile = currentSf\n const ctx: AnalysisContext = {\n sourceFile: currentSf,\n checker,\n program,\n getSlot: <T>(name: string, init: () => T): T => {\n let slot = analysis.perModule.get(name) as T | undefined\n if (slot === undefined) {\n slot = init()\n analysis.perModule.set(name, slot)\n }\n return slot\n },\n reportDiagnostic: (d) => {\n analysis.diagnostics.push(d)\n },\n externalTypes,\n }\n\n // Phase 2: single-pass visitor walk over the (possibly\n // pre-transformed) SourceFile.\n const walk = (node: ts.Node): void => {\n const handlers = this.visitorsByKind.get(node.kind)\n if (handlers) {\n for (const m of handlers) {\n const handler = m.visitors[node.kind]\n if (handler) handler(ctx, node)\n }\n }\n ts.forEachChild(node, walk)\n }\n walk(currentSf)\n\n // Phase 2b: per-CallExpression transform. Modules with a\n // `transformCallEnter` (top-down) or `transformCall` (bottom-up)\n // hook get one chance to rewrite each call site per direction;\n // chained in declaration order. The phase is skipped entirely\n // when no module declares either hook (zero overhead for the\n // common case of metadata-only modules).\n //\n // Within a single CallExpression visit:\n // 1. transformCallEnter fires (declaration order) — rewrites\n // the node BEFORE children are recursed; subsequent\n // transformCallEnter hooks see the rewritten node.\n // 2. ts.visitEachChild recurses into the (possibly enter-rewritten)\n // node, visiting children.\n // 3. transformCall fires (declaration order) — rewrites the\n // now-children-rewritten node; subsequent transformCall hooks\n // see the result.\n //\n // The two directions never interleave for a given node: all enters\n // run, then all children visit, then all exits run.\n const enterModules = this.modules.filter((m) => m.transformCallEnter)\n const exitModules = this.modules.filter((m) => m.transformCall)\n if (enterModules.length > 0 || exitModules.length > 0) {\n const transformCtx: TransformCallContext = {\n factory: ts.factory,\n analysis,\n }\n const visit: ts.Visitor = (node) => {\n // Top-down (enter) — fires BEFORE children recursion. Chain\n // composes in declaration order; each enter hook sees the\n // output of the previous one.\n let current = node\n if (ts.isCallExpression(current)) {\n for (const m of enterModules) {\n const replaced = m.transformCallEnter!(transformCtx, current as ts.CallExpression)\n if (replaced) current = replaced\n }\n }\n // Recurse children of the (possibly enter-rewritten) node.\n const visited = ts.visitEachChild(current, visit, undefined!)\n // Bottom-up (exit) — fires AFTER children recursion. Chain\n // composes in declaration order; each exit hook sees the\n // output of the previous one.\n if (ts.isCallExpression(visited)) {\n let result = visited as ts.CallExpression\n for (const m of exitModules) {\n const replaced = m.transformCall!(transformCtx, result)\n if (replaced) result = replaced\n }\n return result\n }\n return visited\n }\n currentSf = ts.visitNode(currentSf, visit) as ts.SourceFile\n analysis.sourceFile = currentSf\n }\n\n // Phase 3: emission. Each module contributes after analysis\n // completes. Conflicts on (field, target) tuples are hard errors\n // per §2.1.\n const emissionCtx: EmissionContext = {\n sourceFile: currentSf,\n factory: ts.factory,\n }\n const emissions: EmissionContribution[] = []\n // Conflict detection keyed by `(field, target)` — two modules may\n // contribute distinct per-target emissions to the same field name\n // (e.g. component-meta for two different `component()` calls in\n // one file), but two emissions with the same target on the same\n // field is the hard error from §2.1.\n //\n // Targets are compared by object identity (not by `pos`/`end`) so\n // synthetic nodes (factory-created with pos=-1) compare correctly.\n // File-global emissions (target=undefined) share one bucket.\n const globalOwnerByField = new Map<string, string>()\n const targetOwnerByField = new Map<ts.CallExpression, Map<string, string>>()\n for (const m of this.modules) {\n if (!m.emit) continue\n const contributions = m.emit(emissionCtx, analysis)\n for (const c of contributions) {\n let owners: Map<string, string>\n if (c.target) {\n let existing = targetOwnerByField.get(c.target)\n if (!existing) {\n existing = new Map()\n targetOwnerByField.set(c.target, existing)\n }\n owners = existing\n } else {\n owners = globalOwnerByField\n }\n const other = owners.get(c.field)\n if (other !== undefined) {\n throw new Error(\n `[llui/module-emission-conflict] Modules \"${other}\" and \"${c.module}\" both ` +\n `contribute to ComponentDef field \"${c.field}\"${c.target ? ' for the same component() call site' : ''}. ` +\n `This is a hard error — each (field, target) pair must be owned by exactly one ` +\n `module. Either deduplicate, or move one emission to a distinct field. See ` +\n `docs/proposals/v2-compiler/v2c.md §2.1.`,\n )\n }\n owners.set(c.field, c.module)\n emissions.push(c)\n }\n }\n\n // Union runtime imports.\n const runtimeImports = new Set<string>()\n for (const m of this.modules) {\n for (const imp of m.runtimeImports ?? []) runtimeImports.add(imp)\n }\n\n return {\n analysis,\n emissions,\n runtimeImports: [...runtimeImports].sort(),\n }\n }\n\n /** Module names in declaration order. Adapters surface this for debug logs / config diagnostics. */\n listModules(): string[] {\n return this.modules.map((m) => m.name)\n }\n\n /** All diagnostic definitions across active modules. Used by adapters to enumerate stable IDs. */\n listDiagnostics(): DiagnosticDefinition[] {\n return this.modules.flatMap((m) => m.diagnostics)\n }\n}\n"]}
|
|
@@ -96,7 +96,7 @@ export function bitmaskOverflowModule() {
|
|
|
96
96
|
if (componentCalls.length === 0)
|
|
97
97
|
return;
|
|
98
98
|
const componentCall = componentCalls[0];
|
|
99
|
-
const paths = collectStatePathsFromSource(sf);
|
|
99
|
+
const { paths } = collectStatePathsFromSource(sf);
|
|
100
100
|
const pathCount = paths.size;
|
|
101
101
|
if (pathCount <= PATH_LIMIT)
|
|
102
102
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitmask-overflow.js","sourceRoot":"","sources":["../../src/modules/bitmask-overflow.ts"],"names":[],"mappings":"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","sourcesContent":["// `bitmask-overflow` — errors when a component reads more than 62 unique\n// state paths. The runtime bitmask is two 31-bit words (`mask` 0..30,\n// `maskHi` 31..61); paths past the 62-path limit collapse to FULL_MASK\n// (-1) and re-evaluate every binding on change, negating the optimization.\n//\n// Migrated from `@llui/eslint-plugin`'s bitmask-overflow rule\n// (v0.x). Promoted to a compiler error (was an ESLint warning) so the\n// LLM-first authoring path cannot silently ship overflowing components.\n// LLMs ignore warnings; the compiler-error channel is non-bypassable.\n//\n// The diagnostic message includes:\n// - the per-top-level-field breakdown so authors know where to slice,\n// - a co-occurrence note for fields whose every sub-path always fires\n// in the same accessor sets (those collapse to one bit if the parent\n// object is read as a unit),\n// - a recommendation to restructure state so the most-read paths\n// collapse to fewer top-level prefixes, or to factor the offending\n// subtree into a subApp.\n//\n// Anchors the diagnostic on the file's first `component(...)` call so\n// the location is meaningful. Files without a `component()` call are\n// silent — utility modules that happen to read state-shaped accessors\n// don't trigger the rule.\n\nimport ts from 'typescript'\nimport { collectAccessorPathSets, collectStatePathsFromSource } from '../collect-deps.js'\nimport { rangeFromOffsets } from '../diagnostic.js'\nimport type { CompilerModule } from '../module.js'\nimport { findComponentCalls } from './_shared.js'\n\nconst PATH_LIMIT = 62\n\nfunction setsEqual<T>(a: Set<T>, b: Set<T>): boolean {\n if (a.size !== b.size) return false\n for (const x of a) if (!b.has(x)) return false\n return true\n}\n\nfunction findCooccurringFields(\n paths: Set<string>,\n accessorSets: Set<string>[],\n): Array<{ field: string; saved: number }> {\n const subPathsByTop = new Map<string, string[]>()\n for (const p of paths) {\n const dot = p.indexOf('.')\n if (dot < 0) continue\n const top = p.slice(0, dot)\n const arr = subPathsByTop.get(top) ?? []\n arr.push(p)\n subPathsByTop.set(top, arr)\n }\n const appearances = new Map<string, Set<number>>()\n for (let i = 0; i < accessorSets.length; i++) {\n for (const path of accessorSets[i]!) {\n if (!appearances.has(path)) appearances.set(path, new Set())\n appearances.get(path)!.add(i)\n }\n }\n const out: Array<{ field: string; saved: number }> = []\n for (const [field, subPaths] of subPathsByTop) {\n if (subPaths.length < 2) continue\n const first = appearances.get(subPaths[0]!) ?? new Set<number>()\n let uniform = true\n for (let i = 1; i < subPaths.length; i++) {\n const set = appearances.get(subPaths[i]!) ?? new Set<number>()\n if (!setsEqual(first, set)) {\n uniform = false\n break\n }\n }\n if (uniform) out.push({ field, saved: subPaths.length - 1 })\n }\n return out.sort((a, b) => b.saved - a.saved)\n}\n\nexport function bitmaskOverflowModule(): CompilerModule {\n return {\n name: 'bitmask-overflow',\n compilerVersion: '^0.3.0',\n diagnostics: [\n {\n id: 'llui/bitmask-overflow',\n description:\n 'Component reads more than 62 unique state paths — paths past the limit fall back to FULL_MASK.',\n },\n ],\n visitors: {\n [ts.SyntaxKind.SourceFile]: (ctx, node) => {\n const visited = node as ts.SourceFile\n // Re-parse from text. PreTransform passes (e.g.\n // `bindingDescriptorsModule` in agent mode) produce synthetic\n // AST nodes that lack parent pointers; `collectStatePathsFromSource`\n // walks parent chains and crashes on undefined. Re-parsing\n // guarantees a clean tree with `setParentNodes=true` — the\n // analysis is over the user's source, which is what we want\n // regardless of upstream rewrites.\n const sf = ts.createSourceFile(visited.fileName, visited.text, ts.ScriptTarget.Latest, true)\n const componentCalls = findComponentCalls(sf)\n if (componentCalls.length === 0) return\n const componentCall = componentCalls[0]!\n\n const paths = collectStatePathsFromSource(sf)\n const pathCount = paths.size\n if (pathCount <= PATH_LIMIT) return\n\n const overflow = pathCount - PATH_LIMIT\n const byTopLevel = new Map<string, number>()\n for (const p of paths) {\n const top = p.split('.', 1)[0]!\n byTopLevel.set(top, (byTopLevel.get(top) ?? 0) + 1)\n }\n const sorted = [...byTopLevel.entries()].sort((a, b) => b[1] - a[1])\n const candidates: string[] = []\n let saved = 0\n for (const [field, n] of sorted) {\n if (pathCount - saved <= 31) break\n candidates.push(field)\n saved += n\n }\n const breakdown = sorted.map(([field, n]) => `${field} (${n})`).join(', ')\n const candidateList = candidates.map((f) => `\\`${f}\\``).join(', ')\n\n const accessorSets = collectAccessorPathSets(sf)\n const cooccurring = findCooccurringFields(paths, accessorSets)\n const cooccurrenceNote =\n cooccurring.length > 0\n ? `\\n\\nCo-occurrence detected: ` +\n cooccurring\n .map(\n ({ field, saved: s }) =>\n `every sub-path under \\`${field}\\` always fires together; reading \\`s.${field}\\` as one unit saves ${s} bit${s === 1 ? '' : 's'}`,\n )\n .join('; ') +\n `. Bundle those reads into a single \\`s.${cooccurring[0]!.field}\\` access (e.g. \\`const ${cooccurring[0]!.field} = s.${cooccurring[0]!.field}\\`) before extraction — cheaper refactor, same budget relief.`\n : ''\n\n const message =\n `Component has ${pathCount} unique state access paths (${overflow} past the ${PATH_LIMIT}-path limit). ` +\n `Paths ${PATH_LIMIT + 1}..${pathCount} fall back to FULL_MASK — their changes re-evaluate every binding ` +\n `in the component, negating the bitmask optimization for those updates.\\n\\n` +\n `Top-level fields by path count: ${breakdown}.${cooccurrenceNote}\\n\\n` +\n `Recommended fix: restructure state so ${candidateList} are grouped under one or two ` +\n `reference-stable parents, or factor that subtree into a separate module that consumes ` +\n `the parent's state via the standard view-function \\`(props, send)\\` convention. ` +\n `Alternative: use \\`combine()\\` to split the reducer into slices when the parent's \\`update()\\` ` +\n `is mostly mechanical routing.`\n\n ctx.reportDiagnostic({\n id: 'llui/bitmask-overflow',\n severity: 'error',\n category: 'perf',\n message,\n location: {\n file: sf.fileName,\n range: rangeFromOffsets(sf.text, componentCall.getStart(sf), componentCall.getEnd()),\n },\n })\n },\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bitmask-overflow.js","sourceRoot":"","sources":["../../src/modules/bitmask-overflow.ts"],"names":[],"mappings":"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","sourcesContent":["// `bitmask-overflow` — errors when a component reads more than 62 unique\n// state paths. The runtime bitmask is two 31-bit words (`mask` 0..30,\n// `maskHi` 31..61); paths past the 62-path limit collapse to FULL_MASK\n// (-1) and re-evaluate every binding on change, negating the optimization.\n//\n// Migrated from `@llui/eslint-plugin`'s bitmask-overflow rule\n// (v0.x). Promoted to a compiler error (was an ESLint warning) so the\n// LLM-first authoring path cannot silently ship overflowing components.\n// LLMs ignore warnings; the compiler-error channel is non-bypassable.\n//\n// The diagnostic message includes:\n// - the per-top-level-field breakdown so authors know where to slice,\n// - a co-occurrence note for fields whose every sub-path always fires\n// in the same accessor sets (those collapse to one bit if the parent\n// object is read as a unit),\n// - a recommendation to restructure state so the most-read paths\n// collapse to fewer top-level prefixes, or to factor the offending\n// subtree into a subApp.\n//\n// Anchors the diagnostic on the file's first `component(...)` call so\n// the location is meaningful. Files without a `component()` call are\n// silent — utility modules that happen to read state-shaped accessors\n// don't trigger the rule.\n\nimport ts from 'typescript'\nimport { collectAccessorPathSets, collectStatePathsFromSource } from '../collect-deps.js'\nimport { rangeFromOffsets } from '../diagnostic.js'\nimport type { CompilerModule } from '../module.js'\nimport { findComponentCalls } from './_shared.js'\n\nconst PATH_LIMIT = 62\n\nfunction setsEqual<T>(a: Set<T>, b: Set<T>): boolean {\n if (a.size !== b.size) return false\n for (const x of a) if (!b.has(x)) return false\n return true\n}\n\nfunction findCooccurringFields(\n paths: Set<string>,\n accessorSets: Set<string>[],\n): Array<{ field: string; saved: number }> {\n const subPathsByTop = new Map<string, string[]>()\n for (const p of paths) {\n const dot = p.indexOf('.')\n if (dot < 0) continue\n const top = p.slice(0, dot)\n const arr = subPathsByTop.get(top) ?? []\n arr.push(p)\n subPathsByTop.set(top, arr)\n }\n const appearances = new Map<string, Set<number>>()\n for (let i = 0; i < accessorSets.length; i++) {\n for (const path of accessorSets[i]!) {\n if (!appearances.has(path)) appearances.set(path, new Set())\n appearances.get(path)!.add(i)\n }\n }\n const out: Array<{ field: string; saved: number }> = []\n for (const [field, subPaths] of subPathsByTop) {\n if (subPaths.length < 2) continue\n const first = appearances.get(subPaths[0]!) ?? new Set<number>()\n let uniform = true\n for (let i = 1; i < subPaths.length; i++) {\n const set = appearances.get(subPaths[i]!) ?? new Set<number>()\n if (!setsEqual(first, set)) {\n uniform = false\n break\n }\n }\n if (uniform) out.push({ field, saved: subPaths.length - 1 })\n }\n return out.sort((a, b) => b.saved - a.saved)\n}\n\nexport function bitmaskOverflowModule(): CompilerModule {\n return {\n name: 'bitmask-overflow',\n compilerVersion: '^0.3.0',\n diagnostics: [\n {\n id: 'llui/bitmask-overflow',\n description:\n 'Component reads more than 62 unique state paths — paths past the limit fall back to FULL_MASK.',\n },\n ],\n visitors: {\n [ts.SyntaxKind.SourceFile]: (ctx, node) => {\n const visited = node as ts.SourceFile\n // Re-parse from text. PreTransform passes (e.g.\n // `bindingDescriptorsModule` in agent mode) produce synthetic\n // AST nodes that lack parent pointers; `collectStatePathsFromSource`\n // walks parent chains and crashes on undefined. Re-parsing\n // guarantees a clean tree with `setParentNodes=true` — the\n // analysis is over the user's source, which is what we want\n // regardless of upstream rewrites.\n const sf = ts.createSourceFile(visited.fileName, visited.text, ts.ScriptTarget.Latest, true)\n const componentCalls = findComponentCalls(sf)\n if (componentCalls.length === 0) return\n const componentCall = componentCalls[0]!\n\n const { paths } = collectStatePathsFromSource(sf)\n const pathCount = paths.size\n if (pathCount <= PATH_LIMIT) return\n\n const overflow = pathCount - PATH_LIMIT\n const byTopLevel = new Map<string, number>()\n for (const p of paths) {\n const top = p.split('.', 1)[0]!\n byTopLevel.set(top, (byTopLevel.get(top) ?? 0) + 1)\n }\n const sorted = [...byTopLevel.entries()].sort((a, b) => b[1] - a[1])\n const candidates: string[] = []\n let saved = 0\n for (const [field, n] of sorted) {\n if (pathCount - saved <= 31) break\n candidates.push(field)\n saved += n\n }\n const breakdown = sorted.map(([field, n]) => `${field} (${n})`).join(', ')\n const candidateList = candidates.map((f) => `\\`${f}\\``).join(', ')\n\n const accessorSets = collectAccessorPathSets(sf)\n const cooccurring = findCooccurringFields(paths, accessorSets)\n const cooccurrenceNote =\n cooccurring.length > 0\n ? `\\n\\nCo-occurrence detected: ` +\n cooccurring\n .map(\n ({ field, saved: s }) =>\n `every sub-path under \\`${field}\\` always fires together; reading \\`s.${field}\\` as one unit saves ${s} bit${s === 1 ? '' : 's'}`,\n )\n .join('; ') +\n `. Bundle those reads into a single \\`s.${cooccurring[0]!.field}\\` access (e.g. \\`const ${cooccurring[0]!.field} = s.${cooccurring[0]!.field}\\`) before extraction — cheaper refactor, same budget relief.`\n : ''\n\n const message =\n `Component has ${pathCount} unique state access paths (${overflow} past the ${PATH_LIMIT}-path limit). ` +\n `Paths ${PATH_LIMIT + 1}..${pathCount} fall back to FULL_MASK — their changes re-evaluate every binding ` +\n `in the component, negating the bitmask optimization for those updates.\\n\\n` +\n `Top-level fields by path count: ${breakdown}.${cooccurrenceNote}\\n\\n` +\n `Recommended fix: restructure state so ${candidateList} are grouped under one or two ` +\n `reference-stable parents, or factor that subtree into a separate module that consumes ` +\n `the parent's state via the standard view-function \\`(props, send)\\` convention. ` +\n `Alternative: use \\`combine()\\` to split the reducer into slices when the parent's \\`update()\\` ` +\n `is mostly mechanical routing.`\n\n ctx.reportDiagnostic({\n id: 'llui/bitmask-overflow',\n severity: 'error',\n category: 'perf',\n message,\n location: {\n file: sf.fileName,\n range: rangeFromOffsets(sf.text, componentCall.getStart(sf), componentCall.getEnd()),\n },\n })\n },\n },\n }\n}\n"]}
|
|
@@ -6,6 +6,13 @@ export interface CoreSynthesisModuleOptions {
|
|
|
6
6
|
/** Component() call detection requires the @llui/dom import binding
|
|
7
7
|
* to disambiguate from user-local `component` identifiers. */
|
|
8
8
|
lluiImport: ts.ImportDeclaration;
|
|
9
|
+
/** At least one reactive accessor in the file flows the state
|
|
10
|
+
* identifier into an expression the walker can't trace (opaque
|
|
11
|
+
* callee, spread, ternary branch, dynamic key, …). Forces emission
|
|
12
|
+
* of a `(s) => s` whole-state sentinel at the tail of `__prefixes`
|
|
13
|
+
* so FULL_MASK bindings catch a dirty bit on every update,
|
|
14
|
+
* regardless of which fields the opaque expression actually reads. */
|
|
15
|
+
hasOpaqueAccessor?: boolean;
|
|
9
16
|
}
|
|
10
17
|
export interface CoreSynthesisSlot {
|
|
11
18
|
/** True when at least one component() call got the __update/__handlers/__prefixes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-synthesis.d.ts","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;mEAC+D;IAC/D,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"core-synthesis.d.ts","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;mEAC+D;IAC/D,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAA;IAChC;;;;;2EAKuE;IACvE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC;;2CAEuC;IACvC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,eAAO,MAAM,mBAAmB,yBAAyB,CAAA;AAEzD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,cAAc,CAqBpF"}
|
|
@@ -27,7 +27,7 @@ import ts from 'typescript';
|
|
|
27
27
|
import { computeAccessorMask, createMaskLiteral, isComponentCall } from '../transform.js';
|
|
28
28
|
export const CORE_SYNTHESIS_SLOT = 'core-synthesis:state';
|
|
29
29
|
export function coreSynthesisModule(opts) {
|
|
30
|
-
const { fieldBits, fieldBitsHi, lluiImport } = opts;
|
|
30
|
+
const { fieldBits, fieldBitsHi, lluiImport, hasOpaqueAccessor = false } = opts;
|
|
31
31
|
return {
|
|
32
32
|
name: 'core-synthesis',
|
|
33
33
|
compilerVersion: '^0.3.0',
|
|
@@ -36,7 +36,7 @@ export function coreSynthesisModule(opts) {
|
|
|
36
36
|
transformCallEnter(ctx, node) {
|
|
37
37
|
if (!isComponentCall(node, lluiImport))
|
|
38
38
|
return null;
|
|
39
|
-
const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi);
|
|
39
|
+
const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi, hasOpaqueAccessor);
|
|
40
40
|
if (!rewritten)
|
|
41
41
|
return null;
|
|
42
42
|
const slot = ctx.analysis.perModule.get(CORE_SYNTHESIS_SLOT);
|
|
@@ -51,8 +51,8 @@ export function coreSynthesisModule(opts) {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
// ─── Synthesis implementation (moved verbatim from transform.ts) ────
|
|
54
|
-
function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map()) {
|
|
55
|
-
if (fieldBits.size === 0 && fieldBitsHi.size === 0)
|
|
54
|
+
function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map(), hasOpaqueAccessor = false) {
|
|
55
|
+
if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor)
|
|
56
56
|
return null;
|
|
57
57
|
const configArg = node.arguments[0];
|
|
58
58
|
if (!configArg || !ts.isObjectLiteralExpression(configArg))
|
|
@@ -120,7 +120,7 @@ function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map()) {
|
|
|
120
120
|
// emit layer today, so high-position bindings still re-evaluate
|
|
121
121
|
// every cycle — but the dirty computation itself is now precise,
|
|
122
122
|
// which lets memo()'d aggregates short-circuit correctly.
|
|
123
|
-
const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f);
|
|
123
|
+
const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f, hasOpaqueAccessor);
|
|
124
124
|
if (prefixesProp)
|
|
125
125
|
extraProps.push(prefixesProp);
|
|
126
126
|
const newConfig = f.createObjectLiteralExpression([...configArg.properties, ...extraProps], true);
|
|
@@ -602,8 +602,8 @@ function computeStructuralMask(configArg, fieldBits) {
|
|
|
602
602
|
*
|
|
603
603
|
* Returns null if no paths are present.
|
|
604
604
|
*/
|
|
605
|
-
function buildPrefixesProp(fieldBits, fieldBitsHi, f) {
|
|
606
|
-
if (fieldBits.size === 0 && fieldBitsHi.size === 0)
|
|
605
|
+
function buildPrefixesProp(fieldBits, fieldBitsHi, f, hasOpaqueAccessor = false) {
|
|
606
|
+
if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor)
|
|
607
607
|
return null;
|
|
608
608
|
// Sort paths by bit value within each word. Bits are powers of two
|
|
609
609
|
// inside their word (1, 2, 4, …, 1<<30), so sorting numerically gives
|
|
@@ -613,15 +613,27 @@ function buildPrefixesProp(fieldBits, fieldBitsHi, f) {
|
|
|
613
613
|
.filter(([, bit]) => bit > 0)
|
|
614
614
|
.sort(([, a], [, b]) => a - b);
|
|
615
615
|
const orderedHi = [...fieldBitsHi.entries()].sort(([, a], [, b]) => a - b);
|
|
616
|
-
const buildArrow = (
|
|
617
|
-
|
|
618
|
-
|
|
616
|
+
const buildArrow = (parts) => {
|
|
617
|
+
// Empty parts → `(s) => s` (whole-state sentinel). Any other path
|
|
618
|
+
// builds the optional-chain access expression.
|
|
619
|
+
const body = parts.length === 0 ? f.createIdentifier('s') : buildAccess(f, 's', parts);
|
|
619
620
|
return f.createArrowFunction(undefined, undefined, [f.createParameterDeclaration(undefined, undefined, 's')], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), body);
|
|
620
621
|
};
|
|
621
622
|
const arrows = [
|
|
622
|
-
...orderedLo.map(([path]) => buildArrow(path)),
|
|
623
|
-
...orderedHi.map(([path]) => buildArrow(path)),
|
|
623
|
+
...orderedLo.map(([path]) => buildArrow(path.split('.'))),
|
|
624
|
+
...orderedHi.map(([path]) => buildArrow(path.split('.'))),
|
|
624
625
|
];
|
|
626
|
+
// Append the whole-state sentinel `(s) => s` when any accessor in
|
|
627
|
+
// the file flows state opaquely. Its prefix bit dirties on every
|
|
628
|
+
// update (immutable reducers always return a new object identity),
|
|
629
|
+
// so FULL_MASK bindings — whose mask covers every bit — fire even
|
|
630
|
+
// when the changed field has no traceable prefix entry. Without
|
|
631
|
+
// this, a field read ONLY through an opaque expression would
|
|
632
|
+
// disappear from `__prefixes`; computeDirtyFromPrefixes would
|
|
633
|
+
// return 0 for changes to it; (-1) & 0 = 0; the binding would
|
|
634
|
+
// silently never re-evaluate.
|
|
635
|
+
if (hasOpaqueAccessor)
|
|
636
|
+
arrows.push(buildArrow([]));
|
|
625
637
|
return f.createPropertyAssignment('__prefixes', f.createArrayLiteralExpression(arrows, false));
|
|
626
638
|
}
|
|
627
639
|
function buildAccess(f, root, parts) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-synthesis.js","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"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","sourcesContent":["// `core-synthesis` — owns the co-emitted core trio:\n// - `__update` — Phase 1/2 dispatcher; reads `structuralMask`\n// - `__handlers` — per-message-type specialized handlers\n// - `__prefixes` — array of path-keyed reference-stable closures\n//\n// The three are NOT decomposable into separate modules (per v2c §7.9.2\n// design decision (a) vs (b)): they share `topLevelBits` /\n// `structuralMask` / `fieldBits` intermediates, and `__prefixes`\n// ordering is bit-position-keyed (the array index *is* the bit position\n// used by every binding's mask). Producing them in three independent\n// emit passes would either duplicate the analysis or require a shared\n// scratchpad slot — both lose vs the function's existing single pass.\n//\n// So this module owns the entire synthesis: `tryInjectDirty` plus its\n// ~600 lines of supporting helpers (`tryBuildHandlers`,\n// `buildCaseHandler`, `buildUpdateBody`, `buildPrefixesProp`,\n// `computeStructuralMask`, `buildAccess`, plus the case-analysis\n// helpers `detectArrayOp`, `findReturnArray`, `detectStrideLoop`,\n// `hasSliceAssignment`, `analyzeModifiedFields`). Moved verbatim from\n// transform.ts in v2c/decomp-21.\n//\n// Side-effect: the inline call sets `usesApplyBinding = true` when\n// the rewrite fires (drives `__runPhase2` + `__handleMsg` imports in\n// `cleanupImports`). The module surfaces this via `CORE_SYNTHESIS_SLOT`\n// for the umbrella to read after `registry.run`.\n\nimport ts from 'typescript'\nimport type { CompilerModule } from '../module.js'\nimport { computeAccessorMask, createMaskLiteral, isComponentCall } from '../transform.js'\n\nexport interface CoreSynthesisModuleOptions {\n fieldBits: Map<string, number>\n fieldBitsHi: Map<string, number>\n /** Component() call detection requires the @llui/dom import binding\n * to disambiguate from user-local `component` identifiers. */\n lluiImport: ts.ImportDeclaration\n}\n\nexport interface CoreSynthesisSlot {\n /** True when at least one component() call got the __update/__handlers/__prefixes\n * trio injected — drives `cleanupImports`'s decision about `__runPhase2`\n * + `__handleMsg` runtime imports. */\n usesApplyBinding: boolean\n}\n\nexport const CORE_SYNTHESIS_SLOT = 'core-synthesis:state'\n\nexport function coreSynthesisModule(opts: CoreSynthesisModuleOptions): CompilerModule {\n const { fieldBits, fieldBitsHi, lluiImport } = opts\n return {\n name: 'core-synthesis',\n compilerVersion: '^0.3.0',\n diagnostics: [],\n visitors: {},\n\n transformCallEnter(ctx, node) {\n if (!isComponentCall(node, lluiImport)) return null\n const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi)\n if (!rewritten) return null\n const slot = ctx.analysis.perModule.get(CORE_SYNTHESIS_SLOT) as CoreSynthesisSlot | undefined\n if (slot) slot.usesApplyBinding = true\n else\n ctx.analysis.perModule.set(CORE_SYNTHESIS_SLOT, {\n usesApplyBinding: true,\n } as CoreSynthesisSlot)\n return rewritten\n },\n }\n}\n\n// ─── Synthesis implementation (moved verbatim from transform.ts) ────\n\nfunction tryInjectDirty(\n node: ts.CallExpression,\n fieldBits: Map<string, number>,\n f: ts.NodeFactory,\n fieldBitsHi: Map<string, number> = new Map(),\n): ts.CallExpression | null {\n if (fieldBits.size === 0 && fieldBitsHi.size === 0) return null\n const configArg = node.arguments[0]\n if (!configArg || !ts.isObjectLiteralExpression(configArg)) return null\n\n // Check if __dirty already exists\n for (const prop of configArg.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === '__dirty'\n ) {\n return null\n }\n }\n\n // Top-level field → aggregated bit mask. Sub-paths under one field\n // (`route.page`, `route.data`) collapse into a single entry so\n // `tryBuildHandlers` can reason per-field. Positions 0..30 live here;\n // 31..61 in the parallel high-word map below. `__maskLegend` itself\n // is now owned by `maskLegendModule` (v2c/decomp-9).\n const topLevelBits = new Map<string, number>()\n for (const [path, bit] of fieldBits) {\n const topField = path.split('.')[0]!\n topLevelBits.set(topField, (topLevelBits.get(topField) ?? 0) | bit)\n }\n const topLevelBitsHi = new Map<string, number>()\n for (const [path, bit] of fieldBitsHi) {\n const topField = path.split('.')[0]!\n topLevelBitsHi.set(topField, (topLevelBitsHi.get(topField) ?? 0) | bit)\n }\n\n // Structural mask — used by __handlers.\n const structuralMask = computeStructuralMask(configArg, fieldBits)\n\n // v0.4 size-cut (Tier 2.4): the `__update` fast-path emission was\n // removed. Empirically (see benchmarks/bundle-baseline.json + the\n // strategy comparison in earlier work) it provided only ~3% wall-time\n // improvement on a 200-binding sparse-update workload, but cost 200-400\n // bytes per compiled component plus the dispatch branch in\n // processMessages. The runtime always uses genericUpdate now.\n\n // __handlers: per-message-type specialized update functions.\n // Analyzes the update() switch/case and generates direct handlers\n // that bypass the generic Phase 1/2 pipeline for single-message updates.\n // Tier 5 (drop __handlers) was attempted and REVERTED — see\n // benchmarks/bundle-baseline.json#/abandoned. The 1.4 kB savings cost\n // 23-89% perf on jfb's swap/remove/update/select.\n const handlersProp = tryBuildHandlers(configArg, topLevelBits, topLevelBitsHi, structuralMask, f)\n\n // `__maskLegend` is emitted by `maskLegendModule` via the registry\n // bridge (v2c/decomp-9); the umbrella's `applyRegistryEmissions` step\n // splices it into the same config-arg literal we return here.\n const extraProps: ts.ObjectLiteralElementLike[] = []\n if (handlersProp) extraProps.push(handlersProp)\n\n // __prefixes: opt-in path-keyed reactivity (see\n // docs/proposals/unified-composition-model.md). One closure per\n // distinct path that an accessor reads, hoisted into a stable array;\n // the array position IS the bit position used by the path's bindings.\n // The runtime prefers __prefixes when present and computes the\n // combinedDirty mask by reference-comparing `prefix(prev)` vs\n // `prefix(next)` for each entry — strictly more precise than the\n // top-level-conflated __dirty (which always co-fires bindings sharing\n // a top-level field even when only one sub-path actually mutated).\n //\n // Emit `__prefixes` whenever any reactive paths are present. For\n // components with ≤31 paths, the runtime's\n // `computeDirtyFromPrefixes` returns a single `number`; for\n // 32..61-path components it returns a `[lo, hi]` tuple that the\n // runtime fans out into `combinedDirty` + `combinedDirtyHi`. The\n // binding-level mask gating is still single-word at the compiler\n // emit layer today, so high-position bindings still re-evaluate\n // every cycle — but the dirty computation itself is now precise,\n // which lets memo()'d aggregates short-circuit correctly.\n const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f)\n if (prefixesProp) extraProps.push(prefixesProp)\n\n const newConfig = f.createObjectLiteralExpression([...configArg.properties, ...extraProps], true)\n\n // `updateCallExpression` (not `createCallExpression`) so the new\n // node inherits `node.pos` / `node.end` from the original. Phase 2b\n // downstream consumers (componentMetaModule, etc.) read pos via\n // `getStart(sf)` for line info; a synthetic node (pos=-1) would\n // collapse every `component()` call's `__componentMeta.line` to 0.\n return f.updateCallExpression(node, node.expression, node.typeArguments, [\n newConfig,\n ...node.arguments.slice(1),\n ])\n}\n\n/**\n * Analyze update() switch/case and generate per-message-type handlers.\n *\n * Each handler receives (inst, msg) and returns [newState, effects].\n * The handler calls update() to get the new state, then directly invokes\n * the appropriate runtime primitives (reconcileItems, __directUpdate, etc.)\n * instead of going through the generic Phase 1/2 pipeline.\n *\n * Conservative: only generates handlers for cases where the field\n * modifications are statically determinable. Complex cases are skipped.\n */\nfunction tryBuildHandlers(\n configArg: ts.ObjectLiteralExpression,\n topLevelBits: Map<string, number>,\n topLevelBitsHi: Map<string, number>,\n structuralMask: number,\n f: ts.NodeFactory,\n): ts.PropertyAssignment | null {\n if (topLevelBits.size === 0 && topLevelBitsHi.size === 0) return null\n\n // Find the update function in the component config\n let updateFn: ts.ArrowFunction | ts.FunctionExpression | null = null\n for (const prop of configArg.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === 'update'\n ) {\n if (ts.isArrowFunction(prop.initializer) || ts.isFunctionExpression(prop.initializer)) {\n updateFn = prop.initializer\n }\n break\n }\n }\n if (!updateFn) return null\n\n // Find the switch statement in the update body\n const body = ts.isBlock(updateFn.body) ? updateFn.body : null\n if (!body) return null\n\n let switchStmt: ts.SwitchStatement | null = null\n for (const stmt of body.statements) {\n if (ts.isSwitchStatement(stmt)) {\n switchStmt = stmt\n break\n }\n }\n if (!switchStmt) return null\n\n // Check the switch discriminant is msg.type pattern\n const stateParam = updateFn.parameters[0]?.name\n const msgParam = updateFn.parameters[1]?.name\n if (!stateParam || !msgParam || !ts.isIdentifier(stateParam) || !ts.isIdentifier(msgParam))\n return null\n const stateName = stateParam.text\n\n // Analyze each case clause\n const handlers: ts.PropertyAssignment[] = []\n\n for (const clause of switchStmt.caseBlock.clauses) {\n if (!ts.isCaseClause(clause)) continue\n\n // Extract the case label — must be a string literal like 'select'\n if (!ts.isStringLiteral(clause.expression)) continue\n const msgType = clause.expression.text\n\n // Collect ALL return [newState, effects] statements recursively from the\n // case body. Multiple returns (from if/else branches) must all be analyzed\n // so the handler's dirty mask covers every possible modified field.\n const returnExprs: ts.ArrayLiteralExpression[] = []\n const collectReturns = (node: ts.Node): void => {\n if (\n ts.isReturnStatement(node) &&\n node.expression &&\n ts.isArrayLiteralExpression(node.expression) &&\n node.expression.elements.length >= 2\n ) {\n returnExprs.push(node.expression)\n return\n }\n // Don't descend into nested functions — their returns are unrelated.\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isFunctionExpression(node) ||\n ts.isArrowFunction(node) ||\n ts.isMethodDeclaration(node)\n ) {\n return\n }\n ts.forEachChild(node, collectReturns)\n }\n for (const stmt of clause.statements) {\n collectReturns(stmt)\n }\n if (returnExprs.length === 0) continue\n\n // Union modified fields across all return paths.\n const allModified = new Set<string>()\n let bailOut = false\n for (const returnExpr of returnExprs) {\n const stateExpr = returnExpr.elements[0]!\n const fields = analyzeModifiedFields(stateExpr, stateName, topLevelBits, topLevelBitsHi)\n if (!fields) {\n bailOut = true\n break\n }\n for (const f of fields) allModified.add(f)\n }\n if (bailOut) continue // at least one return path was too complex\n\n const modifiedFields = Array.from(allModified)\n\n // Compute the dirty mask for this case across both words. Fields\n // tracked in `topLevelBitsHi` contribute to `caseDirtyHi`; fields\n // tracked nowhere (`undefined` lookup in both) fall back to\n // FULL_MASK in the low word — same conservative behavior as\n // before, just preserved per-word now.\n let caseDirty = 0\n let caseDirtyHi = 0\n for (const field of modifiedFields) {\n const lo = topLevelBits.get(field)\n const hi = topLevelBitsHi.get(field)\n if (lo === undefined && hi === undefined) {\n caseDirty |= 0xffffffff | 0\n } else {\n if (lo !== undefined) caseDirty |= lo\n if (hi !== undefined) caseDirtyHi |= hi\n }\n }\n\n // Detect array operation pattern for structural block optimization\n const arrayOp = detectArrayOp(clause, modifiedFields, structuralMask, caseDirty)\n\n const handler = buildCaseHandler(f, caseDirty, caseDirtyHi, arrayOp)\n handlers.push(f.createPropertyAssignment(f.createStringLiteral(msgType), handler))\n }\n\n if (handlers.length === 0) return null\n\n return f.createPropertyAssignment('__handlers', f.createObjectLiteralExpression(handlers, true))\n}\n\ntype ArrayOp =\n | 'none'\n | 'clear'\n | 'mutate'\n | 'remove'\n | 'general'\n | { type: 'strided'; stride: number } // for (i = 0; i < len; i += stride) pattern\n\n/**\n * Detect the array operation pattern in a case body.\n * - 'none': no array field modified (e.g., only `selected` changes)\n * - 'clear': array set to empty literal `[]`\n * - 'mutate': array created via `.slice()` then mutated in place (same keys)\n * - 'general': unknown pattern, use generic reconcile\n */\nfunction detectArrayOp(\n clause: ts.CaseClause,\n modifiedFields: string[],\n _structuralMask?: number,\n _caseDirty?: number,\n): ArrayOp {\n // No fields modified → no Phase 1 needed (no bindings can care if no\n // state field changed). Safe to return 'none' here because it's a\n // tautology: every binding mask ANDed with zero is zero.\n if (modifiedFields.length === 0) return 'none'\n\n // The specialized methods (`reconcileClear`, `reconcileItems`,\n // `reconcileRemove`, `reconcileChanged`) only exist on `each` blocks.\n // Non-each blocks (`show`, `branch`, `scope`) leave them undefined,\n // so a method other than 0 (general reconcile) silently no-ops on\n // those blocks at runtime. If the case modifies fields BEYOND the\n // array op (e.g. `{ ...state, open: true, name: '', tags: [] }`),\n // any show/branch block whose mask intersects the case's dirty bits\n // would be selected for reconcile but then skipped by the no-op\n // method invocation — its `when`/`on` accessor never re-evaluates,\n // and the component appears structurally inert after mount.\n //\n // Conservative correctness: only emit a non-general method when the\n // array op is the SOLE field modification. With one modified field,\n // the only blocks selected by mask gating are ones that read that\n // single field — and the optimization is well-defined for that\n // narrow case (each blocks operating on the array). Multi-field\n // cases fall through to `'general'` (method=0), so every selected\n // block runs the standard `reconcile` path. We trade a niche\n // optimization (small benefit even when applicable) for guaranteed\n // structural reconciliation across the framework's primitive set.\n //\n // Sister of show-helper-reconcile.test.ts, which fixed the same\n // class of bug on the method=-1 path. Same architectural principle:\n // the compiler can't see every block in the view, so optimizations\n // that route around `reconcile` must be ironclad. When in doubt,\n // emit method=0 and let `_handleMsg`'s per-block mask gate filter.\n //\n // Previously: if `(structuralMask & caseDirty) === 0`, return 'none'\n // on the theory that no structural block's mask could intersect this\n // case's dirty bits. That optimization was UNSAFE: `computeStructuralMask`\n // only walks the view function's lexical AST and does not descend into\n // helper function calls. A view like\n //\n // view: () => [\n // ...show({ when: s => s.mode === 'signin', render: () => [signinFormBody()] }),\n // ]\n //\n // where `signinFormBody()` is a helper that internally does\n // ...show({ when: s => s.errors.email !== undefined, ... })\n //\n // produces a `structuralMask` that covers `mode` but MISSES\n // `errors.email`. At runtime the inner show block is still registered\n // in `inst.structuralBlocks`, and it legitimately needs to reconcile\n // when `errors` changes — but the compiler was emitting `method = -1`\n // (skip blocks entirely) for cases that only touch `errors`, and the\n // error paragraphs would never mount.\n if (modifiedFields.length !== 1) return 'general'\n const onlyField = modifiedFields[0]!\n\n // Look at the return expression's array field values\n for (const stmt of clause.statements) {\n const returnExpr = findReturnArray(stmt)\n if (!returnExpr) continue\n\n const stateExpr = returnExpr.elements[0]\n if (!stateExpr || !ts.isObjectLiteralExpression(stateExpr)) continue\n\n for (const prop of stateExpr.properties) {\n const name =\n ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)\n ? prop.name.text\n : ts.isShorthandPropertyAssignment(prop)\n ? prop.name.text\n : null\n if (!name) continue\n // The optimization only applies when the array op is on the\n // single tracked field. A `field: []` on a different field\n // (one not in modifiedFields, e.g. an untracked field) would\n // still no-op safely on each blocks via the mask gate, but to\n // keep the analysis tight we require an exact match.\n if (name !== onlyField) continue\n\n // Check for empty array literal: `field: []`\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isArrayLiteralExpression(prop.initializer) &&\n prop.initializer.elements.length === 0\n ) {\n return 'clear'\n }\n\n // Check for shorthand `field` where field was assigned via `.slice()` earlier\n // This catches: `const rows = state.rows.slice(); rows[i] = ...; return { ...state, rows }`\n if (ts.isShorthandPropertyAssignment(prop)) {\n const varName = prop.name.text\n if (hasSliceAssignment(clause, varName)) {\n // Check for strided for-loop: for (let i = 0; i < arr.length; i += STRIDE)\n const stride = detectStrideLoop(clause, varName)\n if (stride > 1) return { type: 'strided', stride }\n return 'mutate'\n }\n }\n\n // Check for property assignment with filter: `field: state.field.filter(...)`\n if (ts.isPropertyAssignment(prop) && ts.isCallExpression(prop.initializer)) {\n const call = prop.initializer\n if (\n ts.isPropertyAccessExpression(call.expression) &&\n call.expression.name.text === 'filter'\n ) {\n return 'remove'\n }\n }\n }\n }\n\n return 'general'\n}\n\nfunction findReturnArray(stmt: ts.Statement): ts.ArrayLiteralExpression | null {\n if (ts.isReturnStatement(stmt) && stmt.expression && ts.isArrayLiteralExpression(stmt.expression))\n return stmt.expression\n if (ts.isBlock(stmt)) {\n for (const inner of stmt.statements) {\n const result = findReturnArray(inner)\n if (result) return result\n }\n }\n return null\n}\n\n/**\n * Detect a strided for-loop: `for (let i = 0; i < arr.length; i += STRIDE)`\n * where `arr` is the named variable. Returns the stride or 0 if not found.\n */\nfunction detectStrideLoop(clause: ts.CaseClause, _arrName: string): number {\n function walk(node: ts.Node): number {\n if (ts.isForStatement(node) && node.incrementor) {\n // Check incrementor: i += STRIDE\n const inc = node.incrementor\n if (\n ts.isBinaryExpression(inc) &&\n inc.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken &&\n ts.isNumericLiteral(inc.right)\n ) {\n const stride = parseInt(inc.right.text, 10)\n if (stride > 1) return stride\n }\n }\n return ts.forEachChild(node, walk) ?? 0\n }\n for (const stmt of clause.statements) {\n const result = walk(stmt)\n if (result > 0) return result\n }\n return 0\n}\n\nfunction hasSliceAssignment(clause: ts.CaseClause, varName: string): boolean {\n function walk(node: ts.Node): boolean {\n // Look for: const varName = stateName.field.slice()\n if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === varName &&\n node.initializer\n ) {\n const init = node.initializer\n if (\n ts.isCallExpression(init) &&\n ts.isPropertyAccessExpression(init.expression) &&\n init.expression.name.text === 'slice'\n ) {\n return true\n }\n }\n return ts.forEachChild(node, walk) ?? false\n }\n for (const stmt of clause.statements) {\n if (walk(stmt)) return true\n }\n return false\n}\n\n/**\n * Analyze which top-level state fields are modified in a return expression.\n * Returns the set of field names, or null if too complex to determine.\n */\nfunction analyzeModifiedFields(\n stateExpr: ts.Expression,\n stateName: string,\n topLevelBits: Map<string, number>,\n topLevelBitsHi: Map<string, number> = new Map(),\n): string[] | null {\n // Recognize fields tracked in EITHER the low-word or high-word map.\n // 32..61-prefix components have their overflow paths in\n // `topLevelBitsHi`; the case handler's `caseDirty` / `caseDirtyHi`\n // logic depends on us recognizing those fields here.\n const isTracked = (name: string): boolean => topLevelBits.has(name) || topLevelBitsHi.has(name)\n // Pattern: { ...state, field1: ..., field2: ... } or { field1: ..., field2: ... }\n if (ts.isObjectLiteralExpression(stateExpr)) {\n const modified: string[] = []\n for (const prop of stateExpr.properties) {\n if (ts.isSpreadAssignment(prop)) {\n // Only `...state` is safe to ignore — re-spreading state back into\n // state doesn't change any field's identity. ANY other spread\n // (e.g. `...msg.props`, `...someObj`) can overwrite arbitrary\n // top-level fields with new references, and we cannot know which\n // ones statically. Bail out so the generic Phase 2 path runs\n // `__dirty` at runtime and produces a correct mask.\n if (ts.isIdentifier(prop.expression) && prop.expression.text === stateName) {\n continue\n }\n return null\n }\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {\n const fieldName = prop.name.text\n if (isTracked(fieldName)) {\n modified.push(fieldName)\n }\n }\n // Handle shorthand: { ...state, rows } where rows is a local variable\n if (ts.isShorthandPropertyAssignment(prop)) {\n const fieldName = prop.name.text\n if (isTracked(fieldName)) {\n modified.push(fieldName)\n }\n }\n }\n return modified.length > 0 ? modified : null\n }\n\n // Pattern: state (no change — early return)\n if (ts.isIdentifier(stateExpr) && stateExpr.text === stateName) {\n return [] // no fields modified\n }\n\n return null // too complex\n}\n\n/**\n * Build a handler function for a specific message type case.\n *\n * Generated: (inst, msg) => {\n * const [s, e] = inst.def.update(inst.state, msg)\n * inst.state = s\n * const bl = inst.structuralBlocks, b = inst.allBindings, p = b.length\n * // Phase 1: gated by caseDirty\n * for (let i = 0; i < bl.length; i++) {\n * if (bl[i].mask & caseDirty) bl[i].reconcile(s, caseDirty)\n * }\n * // Phase 2\n * __runPhase2(s, caseDirty, b, p)\n * return [s, e]\n * }\n */\n/**\n * Build a handler that delegates to __handleMsg(inst, msg, dirty, method).\n * method: 0=reconcile, 1=reconcileItems, 2=reconcileClear, 3=reconcileRemove, -1=skip blocks\n */\nfunction buildCaseHandler(\n f: ts.NodeFactory,\n caseDirty: number,\n caseDirtyHi: number,\n arrayOp: ArrayOp,\n): ts.ArrowFunction {\n const method =\n typeof arrayOp === 'object' && arrayOp.type === 'strided'\n ? 10 + arrayOp.stride // reconcileChanged with stride\n : arrayOp === 'none'\n ? -1\n : arrayOp === 'mutate'\n ? 1\n : arrayOp === 'clear'\n ? 2\n : arrayOp === 'remove'\n ? 3\n : 0 // general\n\n // (inst, msg) => __handleMsg(inst, msg, dirty, method, [dirtyHi])\n const args: ts.Expression[] = [\n f.createIdentifier('inst'),\n f.createIdentifier('msg'),\n createMaskLiteral(f, caseDirty),\n method >= 0\n ? f.createNumericLiteral(method)\n : f.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, f.createNumericLiteral(1)),\n ]\n // Emit the 5th positional arg only when the case touches a high-word\n // field. Stale runtime bundles' _handleMsg signatures ignored that\n // slot anyway; new ones (defaulted to 0) make it explicit when needed.\n if (caseDirtyHi !== 0) args.push(createMaskLiteral(f, caseDirtyHi))\n return f.createArrowFunction(\n undefined,\n undefined,\n [\n f.createParameterDeclaration(undefined, undefined, 'inst'),\n f.createParameterDeclaration(undefined, undefined, 'msg'),\n ],\n undefined,\n f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),\n f.createCallExpression(f.createIdentifier('__handleMsg'), undefined, args),\n )\n}\n\n/**\n * Compute the OR of all structural block masks found in the view function.\n * Returns FULL_MASK if any structural block uses FULL_MASK or if no blocks found.\n */\nfunction computeStructuralMask(\n configArg: ts.ObjectLiteralExpression,\n fieldBits: Map<string, number>,\n): number {\n const viewProp = configArg.properties.find(\n (p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'view',\n )\n if (!viewProp || !ts.isPropertyAssignment(viewProp)) return 0xffffffff | 0\n\n let mask = 0\n let foundStructural = false\n\n function walk(node: ts.Node): void {\n if (ts.isCallExpression(node)) {\n const name = ts.isIdentifier(node.expression) ? node.expression.text : ''\n if (['each', 'branch', 'scope', 'show'].includes(name) && node.arguments[0]) {\n foundStructural = true\n const opts = node.arguments[0]\n if (ts.isObjectLiteralExpression(opts)) {\n // Check for __mask property (already injected by tryInjectStructuralMask)\n for (const prop of opts.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === '__mask'\n ) {\n if (ts.isNumericLiteral(prop.initializer)) {\n mask |= parseInt(prop.initializer.text, 10)\n return\n }\n if (ts.isPrefixUnaryExpression(prop.initializer)) {\n // Handle negative literals like -1\n mask = 0xffffffff | 0\n return\n }\n }\n }\n // No __mask found — use driving accessor mask\n const driverProp = name === 'each' ? 'items' : name === 'branch' ? 'on' : 'when'\n for (const prop of opts.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === driverProp\n ) {\n if (\n ts.isArrowFunction(prop.initializer) ||\n ts.isFunctionExpression(prop.initializer)\n ) {\n const { mask: m } = computeAccessorMask(prop.initializer, fieldBits)\n mask |= m || 0xffffffff | 0\n }\n break\n }\n }\n }\n }\n }\n ts.forEachChild(node, walk)\n }\n\n walk(viewProp.initializer)\n return foundStructural ? mask || 0xffffffff | 0 : 0\n}\n\n/**\n * Build the `__prefixes` property assignment from path → bit maps.\n *\n * Emits one arrow `(s) => s.<path>` per distinct path. Array index =\n * the path's bit position: positions 0..30 come from `fieldBits` (low\n * word), positions 31..61 from `fieldBitsHi` (high word). The runtime\n * walks this array and reference-compares `prefix(prev)` vs\n * `prefix(next)` per entry, fanning bits into a `(lo, hi)` pair when\n * the array length exceeds 31.\n *\n * Returns null if no paths are present.\n */\nfunction buildPrefixesProp(\n fieldBits: Map<string, number>,\n fieldBitsHi: Map<string, number>,\n f: ts.NodeFactory,\n): ts.PropertyAssignment | null {\n if (fieldBits.size === 0 && fieldBitsHi.size === 0) return null\n // Sort paths by bit value within each word. Bits are powers of two\n // inside their word (1, 2, 4, …, 1<<30), so sorting numerically gives\n // ascending bit position. FULL_MASK (-1) entries from past-61\n // overflow shouldn't drive a prefix entry — defensively skip them.\n const orderedLo = [...fieldBits.entries()]\n .filter(([, bit]) => bit > 0)\n .sort(([, a], [, b]) => a - b)\n const orderedHi = [...fieldBitsHi.entries()].sort(([, a], [, b]) => a - b)\n const buildArrow = (path: string): ts.ArrowFunction => {\n const parts = path.split('.')\n const body = buildAccess(f, 's', parts)\n return f.createArrowFunction(\n undefined,\n undefined,\n [f.createParameterDeclaration(undefined, undefined, 's')],\n undefined,\n f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),\n body,\n )\n }\n const arrows = [\n ...orderedLo.map(([path]) => buildArrow(path)),\n ...orderedHi.map(([path]) => buildArrow(path)),\n ]\n return f.createPropertyAssignment('__prefixes', f.createArrayLiteralExpression(arrows, false))\n}\n\nfunction buildAccess(f: ts.NodeFactory, root: string, parts: string[]): ts.Expression {\n let expr: ts.Expression = f.createIdentifier(root)\n for (const part of parts) {\n // Use optional chaining for nested paths\n if (parts.length > 1) {\n expr = f.createPropertyAccessChain(expr, f.createToken(ts.SyntaxKind.QuestionDotToken), part)\n } else {\n expr = f.createPropertyAccessExpression(expr, part)\n }\n }\n return expr\n}\n"]}
|
|
1
|
+
{"version":3,"file":"core-synthesis.js","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"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","sourcesContent":["// `core-synthesis` — owns the co-emitted core trio:\n// - `__update` — Phase 1/2 dispatcher; reads `structuralMask`\n// - `__handlers` — per-message-type specialized handlers\n// - `__prefixes` — array of path-keyed reference-stable closures\n//\n// The three are NOT decomposable into separate modules (per v2c §7.9.2\n// design decision (a) vs (b)): they share `topLevelBits` /\n// `structuralMask` / `fieldBits` intermediates, and `__prefixes`\n// ordering is bit-position-keyed (the array index *is* the bit position\n// used by every binding's mask). Producing them in three independent\n// emit passes would either duplicate the analysis or require a shared\n// scratchpad slot — both lose vs the function's existing single pass.\n//\n// So this module owns the entire synthesis: `tryInjectDirty` plus its\n// ~600 lines of supporting helpers (`tryBuildHandlers`,\n// `buildCaseHandler`, `buildUpdateBody`, `buildPrefixesProp`,\n// `computeStructuralMask`, `buildAccess`, plus the case-analysis\n// helpers `detectArrayOp`, `findReturnArray`, `detectStrideLoop`,\n// `hasSliceAssignment`, `analyzeModifiedFields`). Moved verbatim from\n// transform.ts in v2c/decomp-21.\n//\n// Side-effect: the inline call sets `usesApplyBinding = true` when\n// the rewrite fires (drives `__runPhase2` + `__handleMsg` imports in\n// `cleanupImports`). The module surfaces this via `CORE_SYNTHESIS_SLOT`\n// for the umbrella to read after `registry.run`.\n\nimport ts from 'typescript'\nimport type { CompilerModule } from '../module.js'\nimport { computeAccessorMask, createMaskLiteral, isComponentCall } from '../transform.js'\n\nexport interface CoreSynthesisModuleOptions {\n fieldBits: Map<string, number>\n fieldBitsHi: Map<string, number>\n /** Component() call detection requires the @llui/dom import binding\n * to disambiguate from user-local `component` identifiers. */\n lluiImport: ts.ImportDeclaration\n /** At least one reactive accessor in the file flows the state\n * identifier into an expression the walker can't trace (opaque\n * callee, spread, ternary branch, dynamic key, …). Forces emission\n * of a `(s) => s` whole-state sentinel at the tail of `__prefixes`\n * so FULL_MASK bindings catch a dirty bit on every update,\n * regardless of which fields the opaque expression actually reads. */\n hasOpaqueAccessor?: boolean\n}\n\nexport interface CoreSynthesisSlot {\n /** True when at least one component() call got the __update/__handlers/__prefixes\n * trio injected — drives `cleanupImports`'s decision about `__runPhase2`\n * + `__handleMsg` runtime imports. */\n usesApplyBinding: boolean\n}\n\nexport const CORE_SYNTHESIS_SLOT = 'core-synthesis:state'\n\nexport function coreSynthesisModule(opts: CoreSynthesisModuleOptions): CompilerModule {\n const { fieldBits, fieldBitsHi, lluiImport, hasOpaqueAccessor = false } = opts\n return {\n name: 'core-synthesis',\n compilerVersion: '^0.3.0',\n diagnostics: [],\n visitors: {},\n\n transformCallEnter(ctx, node) {\n if (!isComponentCall(node, lluiImport)) return null\n const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi, hasOpaqueAccessor)\n if (!rewritten) return null\n const slot = ctx.analysis.perModule.get(CORE_SYNTHESIS_SLOT) as CoreSynthesisSlot | undefined\n if (slot) slot.usesApplyBinding = true\n else\n ctx.analysis.perModule.set(CORE_SYNTHESIS_SLOT, {\n usesApplyBinding: true,\n } as CoreSynthesisSlot)\n return rewritten\n },\n }\n}\n\n// ─── Synthesis implementation (moved verbatim from transform.ts) ────\n\nfunction tryInjectDirty(\n node: ts.CallExpression,\n fieldBits: Map<string, number>,\n f: ts.NodeFactory,\n fieldBitsHi: Map<string, number> = new Map(),\n hasOpaqueAccessor: boolean = false,\n): ts.CallExpression | null {\n if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor) return null\n const configArg = node.arguments[0]\n if (!configArg || !ts.isObjectLiteralExpression(configArg)) return null\n\n // Check if __dirty already exists\n for (const prop of configArg.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === '__dirty'\n ) {\n return null\n }\n }\n\n // Top-level field → aggregated bit mask. Sub-paths under one field\n // (`route.page`, `route.data`) collapse into a single entry so\n // `tryBuildHandlers` can reason per-field. Positions 0..30 live here;\n // 31..61 in the parallel high-word map below. `__maskLegend` itself\n // is now owned by `maskLegendModule` (v2c/decomp-9).\n const topLevelBits = new Map<string, number>()\n for (const [path, bit] of fieldBits) {\n const topField = path.split('.')[0]!\n topLevelBits.set(topField, (topLevelBits.get(topField) ?? 0) | bit)\n }\n const topLevelBitsHi = new Map<string, number>()\n for (const [path, bit] of fieldBitsHi) {\n const topField = path.split('.')[0]!\n topLevelBitsHi.set(topField, (topLevelBitsHi.get(topField) ?? 0) | bit)\n }\n\n // Structural mask — used by __handlers.\n const structuralMask = computeStructuralMask(configArg, fieldBits)\n\n // v0.4 size-cut (Tier 2.4): the `__update` fast-path emission was\n // removed. Empirically (see benchmarks/bundle-baseline.json + the\n // strategy comparison in earlier work) it provided only ~3% wall-time\n // improvement on a 200-binding sparse-update workload, but cost 200-400\n // bytes per compiled component plus the dispatch branch in\n // processMessages. The runtime always uses genericUpdate now.\n\n // __handlers: per-message-type specialized update functions.\n // Analyzes the update() switch/case and generates direct handlers\n // that bypass the generic Phase 1/2 pipeline for single-message updates.\n // Tier 5 (drop __handlers) was attempted and REVERTED — see\n // benchmarks/bundle-baseline.json#/abandoned. The 1.4 kB savings cost\n // 23-89% perf on jfb's swap/remove/update/select.\n const handlersProp = tryBuildHandlers(configArg, topLevelBits, topLevelBitsHi, structuralMask, f)\n\n // `__maskLegend` is emitted by `maskLegendModule` via the registry\n // bridge (v2c/decomp-9); the umbrella's `applyRegistryEmissions` step\n // splices it into the same config-arg literal we return here.\n const extraProps: ts.ObjectLiteralElementLike[] = []\n if (handlersProp) extraProps.push(handlersProp)\n\n // __prefixes: opt-in path-keyed reactivity (see\n // docs/proposals/unified-composition-model.md). One closure per\n // distinct path that an accessor reads, hoisted into a stable array;\n // the array position IS the bit position used by the path's bindings.\n // The runtime prefers __prefixes when present and computes the\n // combinedDirty mask by reference-comparing `prefix(prev)` vs\n // `prefix(next)` for each entry — strictly more precise than the\n // top-level-conflated __dirty (which always co-fires bindings sharing\n // a top-level field even when only one sub-path actually mutated).\n //\n // Emit `__prefixes` whenever any reactive paths are present. For\n // components with ≤31 paths, the runtime's\n // `computeDirtyFromPrefixes` returns a single `number`; for\n // 32..61-path components it returns a `[lo, hi]` tuple that the\n // runtime fans out into `combinedDirty` + `combinedDirtyHi`. The\n // binding-level mask gating is still single-word at the compiler\n // emit layer today, so high-position bindings still re-evaluate\n // every cycle — but the dirty computation itself is now precise,\n // which lets memo()'d aggregates short-circuit correctly.\n const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f, hasOpaqueAccessor)\n if (prefixesProp) extraProps.push(prefixesProp)\n\n const newConfig = f.createObjectLiteralExpression([...configArg.properties, ...extraProps], true)\n\n // `updateCallExpression` (not `createCallExpression`) so the new\n // node inherits `node.pos` / `node.end` from the original. Phase 2b\n // downstream consumers (componentMetaModule, etc.) read pos via\n // `getStart(sf)` for line info; a synthetic node (pos=-1) would\n // collapse every `component()` call's `__componentMeta.line` to 0.\n return f.updateCallExpression(node, node.expression, node.typeArguments, [\n newConfig,\n ...node.arguments.slice(1),\n ])\n}\n\n/**\n * Analyze update() switch/case and generate per-message-type handlers.\n *\n * Each handler receives (inst, msg) and returns [newState, effects].\n * The handler calls update() to get the new state, then directly invokes\n * the appropriate runtime primitives (reconcileItems, __directUpdate, etc.)\n * instead of going through the generic Phase 1/2 pipeline.\n *\n * Conservative: only generates handlers for cases where the field\n * modifications are statically determinable. Complex cases are skipped.\n */\nfunction tryBuildHandlers(\n configArg: ts.ObjectLiteralExpression,\n topLevelBits: Map<string, number>,\n topLevelBitsHi: Map<string, number>,\n structuralMask: number,\n f: ts.NodeFactory,\n): ts.PropertyAssignment | null {\n if (topLevelBits.size === 0 && topLevelBitsHi.size === 0) return null\n\n // Find the update function in the component config\n let updateFn: ts.ArrowFunction | ts.FunctionExpression | null = null\n for (const prop of configArg.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === 'update'\n ) {\n if (ts.isArrowFunction(prop.initializer) || ts.isFunctionExpression(prop.initializer)) {\n updateFn = prop.initializer\n }\n break\n }\n }\n if (!updateFn) return null\n\n // Find the switch statement in the update body\n const body = ts.isBlock(updateFn.body) ? updateFn.body : null\n if (!body) return null\n\n let switchStmt: ts.SwitchStatement | null = null\n for (const stmt of body.statements) {\n if (ts.isSwitchStatement(stmt)) {\n switchStmt = stmt\n break\n }\n }\n if (!switchStmt) return null\n\n // Check the switch discriminant is msg.type pattern\n const stateParam = updateFn.parameters[0]?.name\n const msgParam = updateFn.parameters[1]?.name\n if (!stateParam || !msgParam || !ts.isIdentifier(stateParam) || !ts.isIdentifier(msgParam))\n return null\n const stateName = stateParam.text\n\n // Analyze each case clause\n const handlers: ts.PropertyAssignment[] = []\n\n for (const clause of switchStmt.caseBlock.clauses) {\n if (!ts.isCaseClause(clause)) continue\n\n // Extract the case label — must be a string literal like 'select'\n if (!ts.isStringLiteral(clause.expression)) continue\n const msgType = clause.expression.text\n\n // Collect ALL return [newState, effects] statements recursively from the\n // case body. Multiple returns (from if/else branches) must all be analyzed\n // so the handler's dirty mask covers every possible modified field.\n const returnExprs: ts.ArrayLiteralExpression[] = []\n const collectReturns = (node: ts.Node): void => {\n if (\n ts.isReturnStatement(node) &&\n node.expression &&\n ts.isArrayLiteralExpression(node.expression) &&\n node.expression.elements.length >= 2\n ) {\n returnExprs.push(node.expression)\n return\n }\n // Don't descend into nested functions — their returns are unrelated.\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isFunctionExpression(node) ||\n ts.isArrowFunction(node) ||\n ts.isMethodDeclaration(node)\n ) {\n return\n }\n ts.forEachChild(node, collectReturns)\n }\n for (const stmt of clause.statements) {\n collectReturns(stmt)\n }\n if (returnExprs.length === 0) continue\n\n // Union modified fields across all return paths.\n const allModified = new Set<string>()\n let bailOut = false\n for (const returnExpr of returnExprs) {\n const stateExpr = returnExpr.elements[0]!\n const fields = analyzeModifiedFields(stateExpr, stateName, topLevelBits, topLevelBitsHi)\n if (!fields) {\n bailOut = true\n break\n }\n for (const f of fields) allModified.add(f)\n }\n if (bailOut) continue // at least one return path was too complex\n\n const modifiedFields = Array.from(allModified)\n\n // Compute the dirty mask for this case across both words. Fields\n // tracked in `topLevelBitsHi` contribute to `caseDirtyHi`; fields\n // tracked nowhere (`undefined` lookup in both) fall back to\n // FULL_MASK in the low word — same conservative behavior as\n // before, just preserved per-word now.\n let caseDirty = 0\n let caseDirtyHi = 0\n for (const field of modifiedFields) {\n const lo = topLevelBits.get(field)\n const hi = topLevelBitsHi.get(field)\n if (lo === undefined && hi === undefined) {\n caseDirty |= 0xffffffff | 0\n } else {\n if (lo !== undefined) caseDirty |= lo\n if (hi !== undefined) caseDirtyHi |= hi\n }\n }\n\n // Detect array operation pattern for structural block optimization\n const arrayOp = detectArrayOp(clause, modifiedFields, structuralMask, caseDirty)\n\n const handler = buildCaseHandler(f, caseDirty, caseDirtyHi, arrayOp)\n handlers.push(f.createPropertyAssignment(f.createStringLiteral(msgType), handler))\n }\n\n if (handlers.length === 0) return null\n\n return f.createPropertyAssignment('__handlers', f.createObjectLiteralExpression(handlers, true))\n}\n\ntype ArrayOp =\n | 'none'\n | 'clear'\n | 'mutate'\n | 'remove'\n | 'general'\n | { type: 'strided'; stride: number } // for (i = 0; i < len; i += stride) pattern\n\n/**\n * Detect the array operation pattern in a case body.\n * - 'none': no array field modified (e.g., only `selected` changes)\n * - 'clear': array set to empty literal `[]`\n * - 'mutate': array created via `.slice()` then mutated in place (same keys)\n * - 'general': unknown pattern, use generic reconcile\n */\nfunction detectArrayOp(\n clause: ts.CaseClause,\n modifiedFields: string[],\n _structuralMask?: number,\n _caseDirty?: number,\n): ArrayOp {\n // No fields modified → no Phase 1 needed (no bindings can care if no\n // state field changed). Safe to return 'none' here because it's a\n // tautology: every binding mask ANDed with zero is zero.\n if (modifiedFields.length === 0) return 'none'\n\n // The specialized methods (`reconcileClear`, `reconcileItems`,\n // `reconcileRemove`, `reconcileChanged`) only exist on `each` blocks.\n // Non-each blocks (`show`, `branch`, `scope`) leave them undefined,\n // so a method other than 0 (general reconcile) silently no-ops on\n // those blocks at runtime. If the case modifies fields BEYOND the\n // array op (e.g. `{ ...state, open: true, name: '', tags: [] }`),\n // any show/branch block whose mask intersects the case's dirty bits\n // would be selected for reconcile but then skipped by the no-op\n // method invocation — its `when`/`on` accessor never re-evaluates,\n // and the component appears structurally inert after mount.\n //\n // Conservative correctness: only emit a non-general method when the\n // array op is the SOLE field modification. With one modified field,\n // the only blocks selected by mask gating are ones that read that\n // single field — and the optimization is well-defined for that\n // narrow case (each blocks operating on the array). Multi-field\n // cases fall through to `'general'` (method=0), so every selected\n // block runs the standard `reconcile` path. We trade a niche\n // optimization (small benefit even when applicable) for guaranteed\n // structural reconciliation across the framework's primitive set.\n //\n // Sister of show-helper-reconcile.test.ts, which fixed the same\n // class of bug on the method=-1 path. Same architectural principle:\n // the compiler can't see every block in the view, so optimizations\n // that route around `reconcile` must be ironclad. When in doubt,\n // emit method=0 and let `_handleMsg`'s per-block mask gate filter.\n //\n // Previously: if `(structuralMask & caseDirty) === 0`, return 'none'\n // on the theory that no structural block's mask could intersect this\n // case's dirty bits. That optimization was UNSAFE: `computeStructuralMask`\n // only walks the view function's lexical AST and does not descend into\n // helper function calls. A view like\n //\n // view: () => [\n // ...show({ when: s => s.mode === 'signin', render: () => [signinFormBody()] }),\n // ]\n //\n // where `signinFormBody()` is a helper that internally does\n // ...show({ when: s => s.errors.email !== undefined, ... })\n //\n // produces a `structuralMask` that covers `mode` but MISSES\n // `errors.email`. At runtime the inner show block is still registered\n // in `inst.structuralBlocks`, and it legitimately needs to reconcile\n // when `errors` changes — but the compiler was emitting `method = -1`\n // (skip blocks entirely) for cases that only touch `errors`, and the\n // error paragraphs would never mount.\n if (modifiedFields.length !== 1) return 'general'\n const onlyField = modifiedFields[0]!\n\n // Look at the return expression's array field values\n for (const stmt of clause.statements) {\n const returnExpr = findReturnArray(stmt)\n if (!returnExpr) continue\n\n const stateExpr = returnExpr.elements[0]\n if (!stateExpr || !ts.isObjectLiteralExpression(stateExpr)) continue\n\n for (const prop of stateExpr.properties) {\n const name =\n ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)\n ? prop.name.text\n : ts.isShorthandPropertyAssignment(prop)\n ? prop.name.text\n : null\n if (!name) continue\n // The optimization only applies when the array op is on the\n // single tracked field. A `field: []` on a different field\n // (one not in modifiedFields, e.g. an untracked field) would\n // still no-op safely on each blocks via the mask gate, but to\n // keep the analysis tight we require an exact match.\n if (name !== onlyField) continue\n\n // Check for empty array literal: `field: []`\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isArrayLiteralExpression(prop.initializer) &&\n prop.initializer.elements.length === 0\n ) {\n return 'clear'\n }\n\n // Check for shorthand `field` where field was assigned via `.slice()` earlier\n // This catches: `const rows = state.rows.slice(); rows[i] = ...; return { ...state, rows }`\n if (ts.isShorthandPropertyAssignment(prop)) {\n const varName = prop.name.text\n if (hasSliceAssignment(clause, varName)) {\n // Check for strided for-loop: for (let i = 0; i < arr.length; i += STRIDE)\n const stride = detectStrideLoop(clause, varName)\n if (stride > 1) return { type: 'strided', stride }\n return 'mutate'\n }\n }\n\n // Check for property assignment with filter: `field: state.field.filter(...)`\n if (ts.isPropertyAssignment(prop) && ts.isCallExpression(prop.initializer)) {\n const call = prop.initializer\n if (\n ts.isPropertyAccessExpression(call.expression) &&\n call.expression.name.text === 'filter'\n ) {\n return 'remove'\n }\n }\n }\n }\n\n return 'general'\n}\n\nfunction findReturnArray(stmt: ts.Statement): ts.ArrayLiteralExpression | null {\n if (ts.isReturnStatement(stmt) && stmt.expression && ts.isArrayLiteralExpression(stmt.expression))\n return stmt.expression\n if (ts.isBlock(stmt)) {\n for (const inner of stmt.statements) {\n const result = findReturnArray(inner)\n if (result) return result\n }\n }\n return null\n}\n\n/**\n * Detect a strided for-loop: `for (let i = 0; i < arr.length; i += STRIDE)`\n * where `arr` is the named variable. Returns the stride or 0 if not found.\n */\nfunction detectStrideLoop(clause: ts.CaseClause, _arrName: string): number {\n function walk(node: ts.Node): number {\n if (ts.isForStatement(node) && node.incrementor) {\n // Check incrementor: i += STRIDE\n const inc = node.incrementor\n if (\n ts.isBinaryExpression(inc) &&\n inc.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken &&\n ts.isNumericLiteral(inc.right)\n ) {\n const stride = parseInt(inc.right.text, 10)\n if (stride > 1) return stride\n }\n }\n return ts.forEachChild(node, walk) ?? 0\n }\n for (const stmt of clause.statements) {\n const result = walk(stmt)\n if (result > 0) return result\n }\n return 0\n}\n\nfunction hasSliceAssignment(clause: ts.CaseClause, varName: string): boolean {\n function walk(node: ts.Node): boolean {\n // Look for: const varName = stateName.field.slice()\n if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === varName &&\n node.initializer\n ) {\n const init = node.initializer\n if (\n ts.isCallExpression(init) &&\n ts.isPropertyAccessExpression(init.expression) &&\n init.expression.name.text === 'slice'\n ) {\n return true\n }\n }\n return ts.forEachChild(node, walk) ?? false\n }\n for (const stmt of clause.statements) {\n if (walk(stmt)) return true\n }\n return false\n}\n\n/**\n * Analyze which top-level state fields are modified in a return expression.\n * Returns the set of field names, or null if too complex to determine.\n */\nfunction analyzeModifiedFields(\n stateExpr: ts.Expression,\n stateName: string,\n topLevelBits: Map<string, number>,\n topLevelBitsHi: Map<string, number> = new Map(),\n): string[] | null {\n // Recognize fields tracked in EITHER the low-word or high-word map.\n // 32..61-prefix components have their overflow paths in\n // `topLevelBitsHi`; the case handler's `caseDirty` / `caseDirtyHi`\n // logic depends on us recognizing those fields here.\n const isTracked = (name: string): boolean => topLevelBits.has(name) || topLevelBitsHi.has(name)\n // Pattern: { ...state, field1: ..., field2: ... } or { field1: ..., field2: ... }\n if (ts.isObjectLiteralExpression(stateExpr)) {\n const modified: string[] = []\n for (const prop of stateExpr.properties) {\n if (ts.isSpreadAssignment(prop)) {\n // Only `...state` is safe to ignore — re-spreading state back into\n // state doesn't change any field's identity. ANY other spread\n // (e.g. `...msg.props`, `...someObj`) can overwrite arbitrary\n // top-level fields with new references, and we cannot know which\n // ones statically. Bail out so the generic Phase 2 path runs\n // `__dirty` at runtime and produces a correct mask.\n if (ts.isIdentifier(prop.expression) && prop.expression.text === stateName) {\n continue\n }\n return null\n }\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {\n const fieldName = prop.name.text\n if (isTracked(fieldName)) {\n modified.push(fieldName)\n }\n }\n // Handle shorthand: { ...state, rows } where rows is a local variable\n if (ts.isShorthandPropertyAssignment(prop)) {\n const fieldName = prop.name.text\n if (isTracked(fieldName)) {\n modified.push(fieldName)\n }\n }\n }\n return modified.length > 0 ? modified : null\n }\n\n // Pattern: state (no change — early return)\n if (ts.isIdentifier(stateExpr) && stateExpr.text === stateName) {\n return [] // no fields modified\n }\n\n return null // too complex\n}\n\n/**\n * Build a handler function for a specific message type case.\n *\n * Generated: (inst, msg) => {\n * const [s, e] = inst.def.update(inst.state, msg)\n * inst.state = s\n * const bl = inst.structuralBlocks, b = inst.allBindings, p = b.length\n * // Phase 1: gated by caseDirty\n * for (let i = 0; i < bl.length; i++) {\n * if (bl[i].mask & caseDirty) bl[i].reconcile(s, caseDirty)\n * }\n * // Phase 2\n * __runPhase2(s, caseDirty, b, p)\n * return [s, e]\n * }\n */\n/**\n * Build a handler that delegates to __handleMsg(inst, msg, dirty, method).\n * method: 0=reconcile, 1=reconcileItems, 2=reconcileClear, 3=reconcileRemove, -1=skip blocks\n */\nfunction buildCaseHandler(\n f: ts.NodeFactory,\n caseDirty: number,\n caseDirtyHi: number,\n arrayOp: ArrayOp,\n): ts.ArrowFunction {\n const method =\n typeof arrayOp === 'object' && arrayOp.type === 'strided'\n ? 10 + arrayOp.stride // reconcileChanged with stride\n : arrayOp === 'none'\n ? -1\n : arrayOp === 'mutate'\n ? 1\n : arrayOp === 'clear'\n ? 2\n : arrayOp === 'remove'\n ? 3\n : 0 // general\n\n // (inst, msg) => __handleMsg(inst, msg, dirty, method, [dirtyHi])\n const args: ts.Expression[] = [\n f.createIdentifier('inst'),\n f.createIdentifier('msg'),\n createMaskLiteral(f, caseDirty),\n method >= 0\n ? f.createNumericLiteral(method)\n : f.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, f.createNumericLiteral(1)),\n ]\n // Emit the 5th positional arg only when the case touches a high-word\n // field. Stale runtime bundles' _handleMsg signatures ignored that\n // slot anyway; new ones (defaulted to 0) make it explicit when needed.\n if (caseDirtyHi !== 0) args.push(createMaskLiteral(f, caseDirtyHi))\n return f.createArrowFunction(\n undefined,\n undefined,\n [\n f.createParameterDeclaration(undefined, undefined, 'inst'),\n f.createParameterDeclaration(undefined, undefined, 'msg'),\n ],\n undefined,\n f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),\n f.createCallExpression(f.createIdentifier('__handleMsg'), undefined, args),\n )\n}\n\n/**\n * Compute the OR of all structural block masks found in the view function.\n * Returns FULL_MASK if any structural block uses FULL_MASK or if no blocks found.\n */\nfunction computeStructuralMask(\n configArg: ts.ObjectLiteralExpression,\n fieldBits: Map<string, number>,\n): number {\n const viewProp = configArg.properties.find(\n (p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'view',\n )\n if (!viewProp || !ts.isPropertyAssignment(viewProp)) return 0xffffffff | 0\n\n let mask = 0\n let foundStructural = false\n\n function walk(node: ts.Node): void {\n if (ts.isCallExpression(node)) {\n const name = ts.isIdentifier(node.expression) ? node.expression.text : ''\n if (['each', 'branch', 'scope', 'show'].includes(name) && node.arguments[0]) {\n foundStructural = true\n const opts = node.arguments[0]\n if (ts.isObjectLiteralExpression(opts)) {\n // Check for __mask property (already injected by tryInjectStructuralMask)\n for (const prop of opts.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === '__mask'\n ) {\n if (ts.isNumericLiteral(prop.initializer)) {\n mask |= parseInt(prop.initializer.text, 10)\n return\n }\n if (ts.isPrefixUnaryExpression(prop.initializer)) {\n // Handle negative literals like -1\n mask = 0xffffffff | 0\n return\n }\n }\n }\n // No __mask found — use driving accessor mask\n const driverProp = name === 'each' ? 'items' : name === 'branch' ? 'on' : 'when'\n for (const prop of opts.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n prop.name.text === driverProp\n ) {\n if (\n ts.isArrowFunction(prop.initializer) ||\n ts.isFunctionExpression(prop.initializer)\n ) {\n const { mask: m } = computeAccessorMask(prop.initializer, fieldBits)\n mask |= m || 0xffffffff | 0\n }\n break\n }\n }\n }\n }\n }\n ts.forEachChild(node, walk)\n }\n\n walk(viewProp.initializer)\n return foundStructural ? mask || 0xffffffff | 0 : 0\n}\n\n/**\n * Build the `__prefixes` property assignment from path → bit maps.\n *\n * Emits one arrow `(s) => s.<path>` per distinct path. Array index =\n * the path's bit position: positions 0..30 come from `fieldBits` (low\n * word), positions 31..61 from `fieldBitsHi` (high word). The runtime\n * walks this array and reference-compares `prefix(prev)` vs\n * `prefix(next)` per entry, fanning bits into a `(lo, hi)` pair when\n * the array length exceeds 31.\n *\n * Returns null if no paths are present.\n */\nfunction buildPrefixesProp(\n fieldBits: Map<string, number>,\n fieldBitsHi: Map<string, number>,\n f: ts.NodeFactory,\n hasOpaqueAccessor: boolean = false,\n): ts.PropertyAssignment | null {\n if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor) return null\n // Sort paths by bit value within each word. Bits are powers of two\n // inside their word (1, 2, 4, …, 1<<30), so sorting numerically gives\n // ascending bit position. FULL_MASK (-1) entries from past-61\n // overflow shouldn't drive a prefix entry — defensively skip them.\n const orderedLo = [...fieldBits.entries()]\n .filter(([, bit]) => bit > 0)\n .sort(([, a], [, b]) => a - b)\n const orderedHi = [...fieldBitsHi.entries()].sort(([, a], [, b]) => a - b)\n const buildArrow = (parts: string[]): ts.ArrowFunction => {\n // Empty parts → `(s) => s` (whole-state sentinel). Any other path\n // builds the optional-chain access expression.\n const body = parts.length === 0 ? f.createIdentifier('s') : buildAccess(f, 's', parts)\n return f.createArrowFunction(\n undefined,\n undefined,\n [f.createParameterDeclaration(undefined, undefined, 's')],\n undefined,\n f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),\n body,\n )\n }\n const arrows: ts.ArrowFunction[] = [\n ...orderedLo.map(([path]) => buildArrow(path.split('.'))),\n ...orderedHi.map(([path]) => buildArrow(path.split('.'))),\n ]\n // Append the whole-state sentinel `(s) => s` when any accessor in\n // the file flows state opaquely. Its prefix bit dirties on every\n // update (immutable reducers always return a new object identity),\n // so FULL_MASK bindings — whose mask covers every bit — fire even\n // when the changed field has no traceable prefix entry. Without\n // this, a field read ONLY through an opaque expression would\n // disappear from `__prefixes`; computeDirtyFromPrefixes would\n // return 0 for changes to it; (-1) & 0 = 0; the binding would\n // silently never re-evaluate.\n if (hasOpaqueAccessor) arrows.push(buildArrow([]))\n return f.createPropertyAssignment('__prefixes', f.createArrayLiteralExpression(arrows, false))\n}\n\nfunction buildAccess(f: ts.NodeFactory, root: string, parts: string[]): ts.Expression {\n let expr: ts.Expression = f.createIdentifier(root)\n for (const part of parts) {\n // Use optional chaining for nested paths\n if (parts.length > 1) {\n expr = f.createPropertyAccessChain(expr, f.createToken(ts.SyntaxKind.QuestionDotToken), part)\n } else {\n expr = f.createPropertyAccessExpression(expr, part)\n }\n }\n return expr\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opaque-state-flow.d.ts","sourceRoot":"","sources":["../../src/modules/opaque-state-flow.ts"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAwJlD,wBAAgB,qBAAqB,IAAI,cAAc,CAoDtD"}
|