dsh-ptc-plus 0.3.2 → 0.4.2

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.
Files changed (206) hide show
  1. package/README.en.md +63 -80
  2. package/README.md +63 -80
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30827 -742
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +556 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +7 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +77 -21
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +95 -19
  51. package/docs/durability-design.md +28 -10
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/publishing.md +5 -3
  55. package/docs/runtime-reference.md +76 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +759 -0
  58. package/docs/user-bindings.en.md +66 -0
  59. package/docs/user-bindings.md +66 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification-optimization-work.md +41 -0
  62. package/docs/verification.md +71 -0
  63. package/index.js +369 -92
  64. package/internal/ast-traversal.js +5 -2
  65. package/internal/async-local-storage-intrinsics.js +38 -0
  66. package/internal/binding-declaration-contract.js +8 -0
  67. package/internal/binding-descriptors.js +1 -0
  68. package/internal/binding-pattern-traversal.js +25 -0
  69. package/internal/binding-pattern.js +26 -29
  70. package/internal/binding-source-analysis.js +708 -0
  71. package/internal/binding-update-policy.js +72 -0
  72. package/internal/bounded-worker-round.js +56 -0
  73. package/internal/callable-definition-environment.js +42 -0
  74. package/internal/callable-source-catalog.js +129 -0
  75. package/internal/callable-source-encoding.js +47 -0
  76. package/internal/callable-source-facts.js +459 -0
  77. package/internal/callable-source-format.js +2 -0
  78. package/internal/callable-source-lowering.js +123 -0
  79. package/internal/cell-analysis-contract.js +25 -0
  80. package/internal/cell-analysis.js +253 -290
  81. package/internal/cell-completion.js +15 -0
  82. package/internal/cell-error.js +7 -0
  83. package/internal/cell-parser.js +66 -0
  84. package/internal/cell-rewriter.js +3 -677
  85. package/internal/commonjs-export-evidence.js +63 -0
  86. package/internal/commonjs-source-evidence.js +72 -0
  87. package/internal/compiler-amaro.cjs +2 -0
  88. package/internal/compiler-compression.js +12 -0
  89. package/internal/compiler-data.js +58 -0
  90. package/internal/compiler-descriptors.js +54 -0
  91. package/internal/compiler-dynamic-cache.js +48 -0
  92. package/internal/compiler-entry.js +35 -0
  93. package/internal/compiler-generated-names.js +17 -0
  94. package/internal/compiler-intrinsics.js +50 -0
  95. package/internal/compiler-module-links.js +37 -0
  96. package/internal/compiler-operations.js +61 -0
  97. package/internal/compiler-platform-factory.js +84 -0
  98. package/internal/compiler-platform.js +136 -0
  99. package/internal/compiler-record-roles.js +53 -0
  100. package/internal/compiler-region-output.js +259 -0
  101. package/internal/compiler-resource-lowering.js +103 -0
  102. package/internal/compiler-scope-facts.js +115 -0
  103. package/internal/compiler-service.js +109 -0
  104. package/internal/compiler-source-cache.js +32 -0
  105. package/internal/compiler-source-pieces.js +93 -0
  106. package/internal/compiler-source-regions.js +132 -0
  107. package/internal/compiler-storage-source.js +54 -0
  108. package/internal/compiler-text.js +15 -0
  109. package/internal/compiler-typescript.cjs +2 -0
  110. package/internal/config-spec.js +83 -27
  111. package/internal/cordis-tools-owner.js +130 -21
  112. package/internal/diagnostic.js +27 -1
  113. package/internal/direct-surface-owner.js +76 -23
  114. package/internal/dynamic-binding-evidence.js +16 -0
  115. package/internal/dynamic-environment-compiler.js +779 -0
  116. package/internal/dynamic-environment-integration.js +91 -0
  117. package/internal/dynamic-environment-runtime.js +383 -0
  118. package/internal/dynamic-native-calls.js +153 -0
  119. package/internal/dynamic-native-runtime.js +262 -0
  120. package/internal/dynamic-scope-analysis.js +90 -0
  121. package/internal/edit-transport-owner.js +27 -2
  122. package/internal/execution-seam-compat.js +193 -0
  123. package/internal/failure-reporting.js +136 -28
  124. package/internal/host-rpc.js +66 -0
  125. package/internal/isolated-worker.js +555 -0
  126. package/internal/kernel-child.js +139 -0
  127. package/internal/kernel-worker.js +1179 -233
  128. package/internal/language-semantics.js +14 -0
  129. package/internal/legacy-binding-catalog.js +48 -0
  130. package/internal/legacy-cell-analysis.js +600 -0
  131. package/internal/legacy-cell-parser.js +50 -0
  132. package/internal/legacy-cell-rewriter.js +631 -0
  133. package/internal/legacy-repl-convenience.js +291 -0
  134. package/internal/managed-module-operations.js +170 -0
  135. package/internal/module-compilation.js +322 -0
  136. package/internal/module-runtime-platform.js +19 -0
  137. package/internal/module-transform-contract.js +42 -0
  138. package/internal/native-await-declarations.js +68 -0
  139. package/internal/native-root-compilation.js +54 -0
  140. package/internal/native-root-dynamic.js +67 -0
  141. package/internal/record-utils.js +24 -15
  142. package/internal/recovery-tips.js +27 -15
  143. package/internal/rejected-cell-editor.js +13 -8
  144. package/internal/repl-convenience.js +2 -289
  145. package/internal/repl-memory-projection.js +81 -12
  146. package/internal/repl-observation-interest.js +70 -0
  147. package/internal/repl-rewrite-contract.js +6 -0
  148. package/internal/repl-scope-normalizer.js +2091 -0
  149. package/internal/repl-value-observer.js +117 -0
  150. package/internal/rpc-contract.js +52 -0
  151. package/internal/runtime-bridge-owner.js +172 -28
  152. package/internal/runtime-config.js +48 -52
  153. package/internal/runtime-contexts.js +82 -10
  154. package/internal/runtime-intrinsics.js +101 -0
  155. package/internal/runtime-messages.js +111 -0
  156. package/internal/session-cell-executor.js +402 -87
  157. package/internal/session-journal-recovery.js +684 -0
  158. package/internal/session-journal-schema.js +123 -0
  159. package/internal/session-journal.js +199 -654
  160. package/internal/session-log-view.js +42 -9
  161. package/internal/session-runtime.js +257 -95
  162. package/internal/session-state.js +247 -71
  163. package/internal/source-position-map.js +230 -71
  164. package/internal/stateful-module-compiler.js +154 -0
  165. package/internal/stateful-module-runtime.js +303 -0
  166. package/internal/stateful-root-compiler.js +600 -0
  167. package/internal/stateful-root-runtime.js +340 -0
  168. package/internal/typert-codec-compat.js +28 -0
  169. package/internal/typescript-transform.js +31 -0
  170. package/internal/user-binding-authoring.js +70 -0
  171. package/internal/user-binding-console-worker.js +244 -0
  172. package/internal/user-binding-console.js +148 -0
  173. package/internal/user-binding-draft-projection.js +335 -0
  174. package/internal/user-binding-model-context.js +31 -0
  175. package/internal/user-binding-runner.js +56 -0
  176. package/internal/user-bindings-owner.js +1065 -0
  177. package/internal/user-bindings-store.js +293 -0
  178. package/internal/user-bindings.js +361 -0
  179. package/internal/value-wire-schema.js +28 -0
  180. package/internal/value-wire.js +130 -91
  181. package/internal/worker-client.js +57 -67
  182. package/internal/worker-cwd-virtualization.js +80 -53
  183. package/internal/worker-environment.js +65 -0
  184. package/internal/worker-output-relay.js +29 -0
  185. package/internal/worker-repl-realm.js +134 -0
  186. package/internal/worker-shutdown.js +14 -0
  187. package/package.json +76 -7
  188. package/src/client-activity.js +95 -53
  189. package/src/client-authoring-view.js +580 -0
  190. package/src/client-binding-review.js +230 -0
  191. package/src/client-bindings-data.js +29 -0
  192. package/src/client-catalog.js +127 -0
  193. package/src/client-code-editor.js +84 -0
  194. package/src/client-console.js +112 -0
  195. package/src/client-copy.js +370 -0
  196. package/src/client-feature-gates.js +62 -0
  197. package/src/client-host-compat.js +150 -0
  198. package/src/client-indicator-view.js +267 -0
  199. package/src/client-repl-view.js +292 -0
  200. package/src/client-rpc.js +20 -0
  201. package/src/client-settings-view.js +221 -0
  202. package/src/client-styles.js +106 -0
  203. package/src/client-tool-view.js +108 -0
  204. package/src/client-transport.js +159 -0
  205. package/src/client-workbench.js +521 -0
  206. package/src/client.js +233 -615
@@ -0,0 +1,600 @@
1
+ /** Compile each cell into a private native frame backed by session identities. */
2
+ import { adaptRootModuleImports } from './managed-module-operations.js'
3
+ import { parse } from '@babel/parser'
4
+ import { createHash } from 'node:crypto'
5
+ import traverseModule from '@babel/traverse'
6
+ import { bindingNodes, createGeneratedNameAllocator, isWriteIdentifier } from './binding-pattern.js'
7
+ import { applySourceEdits, createMappedTextBuilder, identitySourceMap, mapSourceSpan } from './source-position-map.js'
8
+ import { CELL_PARSER_PLUGINS, RECOVERABLE_CELL_PARSE_ERRORS } from './repl-scope-normalizer.js'
9
+ import { adaptDynamicCell } from './dynamic-environment-integration.js'
10
+ import { sourceBinding, varInitializerTarget } from './dynamic-scope-analysis.js'
11
+
12
+ const traverse = traverseModule.default ?? traverseModule
13
+ const PARSER_OPTIONS = {
14
+ sourceType: 'script', allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true,
15
+ allowImportExportEverywhere: true, allowUndeclaredExports: true, plugins: CELL_PARSER_PLUGINS,
16
+ }
17
+ const TYPE_ONLY = new Set(['TSInterfaceDeclaration', 'TSTypeAliasDeclaration', 'TSDeclareFunction'])
18
+
19
+ function span(node) {
20
+ return { line: node.loc.start.line, column: node.loc.start.column + 1,
21
+ end: { line: node.loc.end.line, column: node.loc.end.column + 1 } }
22
+ }
23
+
24
+ function rootDeclarations(tree) {
25
+ const declarations = []
26
+ traverse(tree, { noScope: true,
27
+ VariableDeclaration(path) {
28
+ if (path.node.declare === true) return
29
+ const direct = path.parent.type === 'Program' || path.parent.type === 'ExportNamedDeclaration'
30
+ if (direct || path.node.kind === 'var' && path.getFunctionParent() === null
31
+ && path.findParent(parent => parent.isClass() || parent.isStaticBlock()) === null) declarations.push(path)
32
+ },
33
+ FunctionDeclaration(path) {
34
+ let owner = path.parentPath
35
+ while (owner.isLabeledStatement()) owner = owner.parentPath
36
+ if (owner.isProgram() || owner.isExportNamedDeclaration()
37
+ || owner.isExportDefaultDeclaration()) declarations.push(path)
38
+ },
39
+ ClassDeclaration(path) {
40
+ if (path.parent.type === 'Program' || path.parent.type === 'ExportNamedDeclaration'
41
+ || path.parent.type === 'ExportDefaultDeclaration') declarations.push(path)
42
+ },
43
+ })
44
+ return declarations
45
+ }
46
+
47
+ function patternText(pattern, code, reference) {
48
+ const ids = new Set(bindingNodes(pattern))
49
+ const edits = []
50
+ const visit = (node, parent, grandparent) => {
51
+ if (node === null || typeof node !== 'object') return
52
+ if (ids.has(node)) {
53
+ const shorthand = parent?.type === 'ObjectProperty' && parent.shorthand && parent.value === node
54
+ || parent?.type === 'AssignmentPattern' && grandparent?.type === 'ObjectProperty' && grandparent.shorthand
55
+ edits.push({ start: node.start, end: node.end,
56
+ text: `${shorthand ? `[${JSON.stringify(node.name)}]: ` : ''}${reference(node)}` })
57
+ return
58
+ }
59
+ for (const [key, value] of Object.entries(node)) {
60
+ if (['loc', 'start', 'end', 'extra'].includes(key)) continue
61
+ if (Array.isArray(value)) value.forEach(child => visit(child, node, parent))
62
+ else if (value?.type !== undefined) visit(value, node, parent)
63
+ }
64
+ }
65
+ visit(pattern)
66
+ const selected = edits.sort((a, b) => a.start - b.start)
67
+ const builder = createMappedTextBuilder(code)
68
+ let offset = pattern.start
69
+ for (const edit of selected) {
70
+ builder.appendSource(offset, edit.start)
71
+ builder.appendMapped(edit.text, edit.start, edit.end)
72
+ offset = edit.end
73
+ }
74
+ builder.appendSource(offset, pattern.end)
75
+ return builder.result()
76
+ }
77
+
78
+ function ownsImplicitArguments(path) {
79
+ return path.node.name === 'arguments'
80
+ && path.findParent(parent => parent.isFunction() && !parent.isArrowFunctionExpression()) !== null
81
+ }
82
+
83
+ function rewriteRootReferences(code, sourceMap, runtime, candidateNames, candidateReferences, originalSource) {
84
+ const tree = parse(code, PARSER_OPTIONS)
85
+ const edits = []
86
+ const classificationEdits = []
87
+ const handled = new Set()
88
+ const implicitDeclarations = new Map()
89
+ const readNames = new Set()
90
+ const dynamicFunctions = new WeakSet()
91
+ traverse(tree, { CallExpression(path) {
92
+ if (path.node.callee.type === 'Identifier' && path.node.callee.name === 'eval') {
93
+ const fn = path.getFunctionParent()
94
+ if (fn !== null) dynamicFunctions.add(fn.node)
95
+ }
96
+ } })
97
+ const sourceIdentity = createHash('sha256').update(originalSource).digest('hex')
98
+ traverse(tree, { Identifier(path) {
99
+ if (!isWriteIdentifier(path) || sourceBinding(path, path.node.name) !== undefined || ownsImplicitArguments(path)) return
100
+ const assignment = path.findParent(parent => parent.isAssignmentExpression() || parent.isUpdateExpression()
101
+ || parent.isForOfStatement() || parent.isForInStatement())
102
+ const position = mapSourceSpan(span(path.node), code, originalSource, sourceMap)
103
+ implicitDeclarations.set(path.node.start, { name: path.node.name, kind: 'variable', writable: true,
104
+ target: `write:${sourceIdentity}:${position.line}:${position.column}:${path.node.name}`,
105
+ definitionSpan: mapSourceSpan(span(assignment.node), code, originalSource, sourceMap) })
106
+ } })
107
+ const candidateFor = path => {
108
+ const assignment = path.findParent(parent => parent.isAssignmentExpression()
109
+ && (parent.node.left.type === 'ArrayPattern' || parent.node.left.type === 'ObjectPattern'))
110
+ if (assignment === null || path.node.start > assignment.node.left.end) return undefined
111
+ for (const [candidate, names] of candidateNames) {
112
+ if (!names.has(path.node.name)) continue
113
+ const mentions = node => {
114
+ if (node === null || typeof node !== 'object') return false
115
+ if (node.type === 'Identifier' && node.name === candidate) return true
116
+ return Object.values(node).some(value => Array.isArray(value)
117
+ ? value.some(mentions) : value?.type !== undefined && mentions(value))
118
+ }
119
+ if (mentions(assignment.node.left)) return candidate
120
+ }
121
+ return undefined
122
+ }
123
+ traverse(tree, { Decorator(path) {
124
+ const expression = path.node.expression
125
+ if (expression.extra?.parenthesized) return
126
+ // A computed root reference has a wider grammar than a bare decorator name.
127
+ const boundaries = [{ start: expression.start, end: expression.start, text: '(' },
128
+ { start: expression.end, end: expression.end, text: ')' }]
129
+ edits.push(...boundaries)
130
+ classificationEdits.push(...boundaries)
131
+ }, TSTypeAssertion(path) {
132
+ const edit = { start: path.node.start, end: path.node.expression.start,
133
+ text: ' '.repeat(path.node.expression.start - path.node.start) }
134
+ edits.push(edit)
135
+ classificationEdits.push(edit)
136
+ }, Identifier(path) {
137
+ if (handled.has(path.node.start) || sourceBinding(path, path.node.name) !== undefined || ownsImplicitArguments(path)) return
138
+ if (!path.isReferencedIdentifier() && !isWriteIdentifier(path)) return
139
+ if (path.findParent(parent => parent.isVariableDeclarator() && parent.node.id.name === runtime
140
+ || parent.isCallExpression() && parent.node.callee.type === 'MemberExpression'
141
+ && parent.node.callee.object.name === runtime && parent.node.callee.property.name === 'import'
142
+ && path.node.start >= parent.node.arguments[1].start && path.node.end <= parent.node.arguments[1].end) !== null) return
143
+ const parent = path.parent
144
+ // The direct-eval environment adapter owns this syntax and its callable
145
+ // identity check. A property read here would turn it into indirect eval.
146
+ if (path.node.name === 'eval' && parent.type === 'CallExpression' && parent.callee === path.node) return
147
+ const selectedCandidate = candidateFor(path)
148
+ if (selectedCandidate === undefined && path.findParent(parent => parent.isWithStatement() && parent.get('body').isAncestor(path)) !== null) return
149
+ if (path.findParent(parent => parent.isFunction() && dynamicFunctions.has(parent.node)) !== null) return
150
+ if (parent.type.startsWith('TS') && parent.expression !== path.node) return
151
+ // A static reference to an outer identity is a reuse event candidate.
152
+ // `for (x of ...)` and `for (x in ...)` bind the left target without
153
+ // reading its previous value, and `delete x` removes the reference without
154
+ // reading it, so both stay out; compound assignment, updates and `typeof`
155
+ // do read it.
156
+ const write = isWriteIdentifier(path)
157
+ const forHeadWrite = (parent.type === 'ForOfStatement' || parent.type === 'ForInStatement') && path.key === 'left'
158
+ const deleted = parent.type === 'UnaryExpression' && parent.operator === 'delete'
159
+ if ((path.isReferencedIdentifier() && !forHeadWrite && !deleted)
160
+ || write && parent.type === 'AssignmentExpression' && parent.operator !== '=') readNames.add(path.node.name)
161
+ const owner = selectedCandidate ?? runtime
162
+ const selectedReference = candidateReferences.has(owner)
163
+ let text = selectedReference ? `${owner}().value` : `${owner}.values[${JSON.stringify(path.node.name)}]`
164
+ if (!selectedReference && isWriteIdentifier(path)) {
165
+ text = `${owner}.reference(${JSON.stringify(path.node.name)}, ${path.isInStrictMode()}, ${JSON.stringify(implicitDeclarations.get(path.node.start).target)}).value`
166
+ }
167
+ if (parent.type === 'UnaryExpression' && (parent.operator === 'typeof' && owner === runtime
168
+ || selectedReference && ['typeof', 'delete'].includes(parent.operator))) {
169
+ edits.push({ start: parent.start, end: parent.end,
170
+ text: selectedReference ? `${owner}().${parent.operator}()` : `${runtime}.typeof(${JSON.stringify(path.node.name)})` })
171
+ handled.add(path.node.start)
172
+ return
173
+ }
174
+ const callable = (parent.type === 'CallExpression' || parent.type === 'OptionalCallExpression') && parent.callee === path.node
175
+ || parent.type === 'TaggedTemplateExpression' && parent.tag === path.node
176
+ if (callable) text = selectedReference ? `${owner}().callee` : `(0, ${text})`
177
+ if (parent.type === 'ObjectProperty' && parent.shorthand && parent.value === path.node) text = `[${JSON.stringify(path.node.name)}]: ${text}`
178
+ edits.push({ start: path.node.start, end: path.node.end, text,
179
+ ...(callable ? { mappings: [{ generatedStart: 0, generatedEnd: text.length,
180
+ originalStart: path.node.start, originalEnd: path.node.start + 1 }] } : {}) })
181
+ if (callable) {
182
+ // V8 reports an indirect call at its opening argument delimiter. Keep
183
+ // that generated call frame anchored to the source callee; arguments
184
+ // retain their own independent mappings.
185
+ const end = parent.type === 'TaggedTemplateExpression' ? parent.quasi.start + 1
186
+ : parent.arguments[0]?.start ?? parent.end
187
+ const punctuation = code.slice(path.node.end, end)
188
+ edits.push({ start: path.node.end, end, text: punctuation,
189
+ mappings: [{ generatedStart: 0, generatedEnd: punctuation.length,
190
+ originalStart: path.node.start, originalEnd: path.node.start + 1 }] })
191
+ }
192
+ handled.add(path.node.start)
193
+ } })
194
+ const classificationSource = applySourceEdits(code, sourceMap, classificationEdits)
195
+ return { ...applySourceEdits(code, sourceMap, edits),
196
+ classificationCode: classificationSource.code,
197
+ classificationSourceMap: classificationSource.sourceMap,
198
+ implicitDeclarations: [...implicitDeclarations.values()],
199
+ readNames: [...readNames] }
200
+ }
201
+
202
+ export function compileStatefulRoot(program, {
203
+ sourceMap = identitySourceMap(program.length), knownBindings = new Set(), reservedBindings = new Set(),
204
+ originalSource = program,
205
+ unavailableNames = [], languageSemantics = 'stateful-v1',
206
+ importBindings = new Map(), writableBindings = new Set(),
207
+ nativeBindings = new Set(),
208
+ nativeLexicalBindings = new Set(),
209
+ internalBindings = new Set(),
210
+ dynamicBindings = [],
211
+ privateBindings = [],
212
+ dynamicOrigins = [],
213
+ rootCandidates = new Map(),
214
+ establishedRoots = new Map(),
215
+ runtimeExpression, moduleExpression = global => `this[${JSON.stringify(global)}]`,
216
+ } = {}) {
217
+ let file = parse(program, { ...PARSER_OPTIONS, errorRecovery: true })
218
+ // Identifier name inference must precede root and pattern reference lowering.
219
+ const inferredNames = []
220
+ traverse(file, { noScope: true, 'AssignmentExpression|AssignmentPattern|VariableDeclarator'(path) {
221
+ if (path.node.type === 'AssignmentExpression' && !['=', '&&=', '||=', '??='].includes(path.node.operator)) return
222
+ const initializer = path.node.type === 'VariableDeclarator' ? path.node.init : path.node.right
223
+ if (initializer === null) return
224
+ let name = path.node.type === 'VariableDeclarator' ? path.node.id : path.node.left
225
+ let value = initializer
226
+ while ((name.type.startsWith('TS') || name.type === 'ParenthesizedExpression') && name.expression) name = name.expression
227
+ while ((value.type.startsWith('TS') || value.type === 'ParenthesizedExpression') && value.expression) value = value.expression
228
+ if (name.type !== 'Identifier' || !(value.type === 'ArrowFunctionExpression'
229
+ || ['FunctionExpression', 'ClassExpression'].includes(value.type) && value.id === null)) return
230
+ inferredNames.push({ start: initializer.start, end: initializer.start, text: `({[${JSON.stringify(name.name)}]:(` },
231
+ { start: initializer.end, end: initializer.end, text: `)})[${JSON.stringify(name.name)}]` })
232
+ } })
233
+ if (inferredNames.length !== 0) {
234
+ const named = applySourceEdits(program, sourceMap, inferredNames)
235
+ program = named.code
236
+ sourceMap = named.sourceMap
237
+ file = parse(program, { ...PARSER_OPTIONS, errorRecovery: true })
238
+ }
239
+ const protectedError = file.errors.find(error => error.reasonCode !== 'UnexpectedUsingDeclaration')
240
+ if (languageSemantics === 'protected-v1' && protectedError !== undefined) throw protectedError
241
+ const syntaxError = file.errors.find(error => !RECOVERABLE_CELL_PARSE_ERRORS.has(error.reasonCode))
242
+ if (syntaxError !== undefined) throw syntaxError
243
+ const root = rootDeclarations(file).filter(path => path.node.type === 'VariableDeclaration'
244
+ ? !path.node.declarations.every(declarator => {
245
+ const bindings = bindingNodes(declarator.id)
246
+ return bindings.length > 0 && bindings.every(binding => internalBindings.has(binding.name))
247
+ })
248
+ : !internalBindings.has(path.node.id?.name))
249
+ const paths = new Map()
250
+ traverse(file, { noScope: true, enter(path) { paths.set(path.node, path) } })
251
+ const logicalNames = new Map(dynamicBindings.map(binding => [binding.physicalName, binding.name]))
252
+ const allocate = createGeneratedNameAllocator(file, [...knownBindings, ...reservedBindings, ...unavailableNames])
253
+ const runtime = allocate('root')
254
+ const rootRuntimeName = allocate('root_runtime')
255
+ const commitSignal = allocate('root_commit')
256
+ const declarations = []
257
+ const declarationKinds = new Map()
258
+ const commitTargets = new Set()
259
+ const candidateNames = new Map()
260
+ const candidateReferences = new Set()
261
+ const moduleLoads = []
262
+ const imports = new Map()
263
+ const rewrites = []
264
+ const edits = []
265
+ const prologue = []
266
+ let varReferenceMarker
267
+ const varReference = () => {
268
+ if (!varReferenceMarker) {
269
+ varReferenceMarker = allocate('var_reference')
270
+ internalBindings.add(varReferenceMarker)
271
+ dynamicBindings.push({ physicalName: varReferenceMarker, role: 'var-reference' })
272
+ prologue.push(`const ${varReferenceMarker}=void 0;`)
273
+ }
274
+ return varReferenceMarker
275
+ }
276
+ const hoisted = []
277
+ const readOnly = new Set()
278
+ const rootKinds = new Map()
279
+ const sourceCopies = new Map()
280
+ const remember = (text, mappings) => { sourceCopies.set(text, mappings); return text }
281
+ const mapParts = parts => {
282
+ let offset = 0
283
+ return parts.flatMap(text => {
284
+ const mappings = (sourceCopies.get(text) ?? []).map(mapping => ({ ...mapping,
285
+ generatedStart: mapping.generatedStart + offset, generatedEnd: mapping.generatedEnd + offset }))
286
+ offset += text.length
287
+ return mappings
288
+ })
289
+ }
290
+ const emptyCompletion = expression => `const ${allocate('declaration_completion')} = (${expression});`
291
+ for (const path of root) {
292
+ const node = path.node
293
+ for (const binding of node.type === 'VariableDeclaration'
294
+ ? node.declarations.flatMap(declarator => bindingNodes(declarator.id)) : node.id === null ? [] : [node.id]) {
295
+ const kinds = rootKinds.get(binding.name) ?? new Set()
296
+ kinds.add(node.type === 'VariableDeclaration' ? node.kind : node.type)
297
+ rootKinds.set(binding.name, kinds)
298
+ }
299
+ }
300
+ const canInstantiate = name => !knownBindings.has(name) && !imports.has(name)
301
+ && rootKinds.has(name)
302
+ && [...rootKinds.get(name)].every(kind => kind === 'var' || kind === 'FunctionDeclaration')
303
+ const record = (name, kind, node, binding = node, suffix = '') => {
304
+ const target = `root:${node.start}:${name}${suffix}`
305
+ declarationKinds.set(target, kind === 'import' ? 'const' : kind === 'function' ? 'hoisted'
306
+ : kind === 'class' ? 'let' : node.kind ?? 'const')
307
+ declarations.push({ name, kind, writable: languageSemantics === 'stateful-v1'
308
+ || kind !== 'import' && (kind !== 'variable' || node.kind === 'let' || node.kind === 'var'),
309
+ original: true, span: mapSourceSpan(span(binding), program, originalSource, sourceMap),
310
+ definitionSpan: mapSourceSpan(span(node), program, originalSource, sourceMap), commitDependency: target })
311
+ commitTargets.add(target)
312
+ return target
313
+ }
314
+ const variable = (node, declarator, supplied = undefined) => {
315
+ const bindings = bindingNodes(declarator.id)
316
+ const names = [...new Set(bindings.map(binding => binding.name))]
317
+ if (names.length === 0) {
318
+ const original = supplied === undefined ? declarator : declarator.id
319
+ const source = program.slice(original.start, original.end)
320
+ const text = `const ${source}${supplied === undefined ? '' : ` = (${supplied})`};`
321
+ return remember(text, [{ generatedStart: 6, generatedEnd: 6 + source.length,
322
+ originalStart: original.start, originalEnd: original.end }])
323
+ }
324
+ const target = record(names[0], 'variable', node, bindings[0], `:${declarator.start}`)
325
+ for (const binding of bindings.slice(1)) {
326
+ record(binding.name, 'variable', node, binding, `:${declarator.start}`)
327
+ declarations.at(-1).commitDependency = target
328
+ }
329
+ if (declarator.init === null && supplied === undefined) {
330
+ return emptyCompletion(`${runtime}.declare(${JSON.stringify(names[0])}, ${JSON.stringify(target)})`)
331
+ }
332
+ let value = supplied ?? program.slice(declarator.init.start, declarator.init.end)
333
+ const redirected = new Map()
334
+ const initializerTargets = new Map()
335
+ if (node.kind === 'var') for (const binding of bindings) {
336
+ const selected = varInitializerTarget(paths.get(binding), file.program, binding.name,
337
+ node => logicalNames.get(node.name) ?? node.name)
338
+ initializerTargets.set(binding.name, selected)
339
+ if (selected.catchNode) {
340
+ redirected.set(binding.name, selected.catchNode.param.name)
341
+ }
342
+ }
343
+ if (declarator.id.type === 'Identifier') {
344
+ const selected = redirected.get(names[0])
345
+ const withDepth = initializerTargets.get(names[0])?.withNodes.length
346
+ const fallbackRead = selected ?? `${runtime}.values[${JSON.stringify(names[0])}]`
347
+ const fallbackWrite = selected === undefined
348
+ ? `${runtime}.assign(${JSON.stringify(names[0])}, next, ${JSON.stringify(target)})` : `${selected}=next`
349
+ const text = withDepth
350
+ ? emptyCompletion(`${varReference()}(${JSON.stringify(names[0])},${withDepth},{get:()=>${fallbackRead},set:next=>${fallbackWrite}}).value = (${value})`)
351
+ : selected === undefined
352
+ ? emptyCompletion(`${runtime}.assign(${JSON.stringify(names[0])}, (${value}), ${JSON.stringify(target)})`)
353
+ : emptyCompletion(`(${selected} = (${value}), ${runtime}.declare(${JSON.stringify(names[0])}, ${JSON.stringify(target)}))`)
354
+ if (supplied === undefined) {
355
+ const original = program.slice(declarator.init.start, declarator.init.end)
356
+ const start = text.indexOf(withDepth ? `= (${value})` : selected === undefined ? `, (${value}),` : `= (${value}),`) + 3 + value.indexOf(original)
357
+ remember(text, [{ generatedStart: start, generatedEnd: start + original.length,
358
+ originalStart: declarator.init.start, originalEnd: declarator.init.end }])
359
+ }
360
+ return text
361
+ }
362
+ const candidate = allocate('candidate')
363
+ const rhs = allocate('candidate_rhs')
364
+ const stored = names.filter(name => !redirected.has(name))
365
+ candidateNames.set(candidate, new Set(stored))
366
+ const captured = stored.filter(name => !initializerTargets.get(name)?.withNodes.length)
367
+ if (captured.length > 0) dynamicBindings.push({ physicalName: candidate, names: captured,
368
+ kind: node.kind, role: 'candidate', property: 'values', referenceMethod: 'reference' })
369
+ const references = new Map()
370
+ const referenceDeclarations = []
371
+ for (const name of names) {
372
+ const withDepth = initializerTargets.get(name)?.withNodes.length
373
+ if (!withDepth) continue
374
+ const reference = allocate('candidate_reference')
375
+ const caught = redirected.get(name)
376
+ const pending = allocate('candidate_written')
377
+ const fallback = caught ?? `${candidate}.values[${JSON.stringify(name)}]`
378
+ const get = caught ?? `${pending}?${fallback}:${runtime}.values[${JSON.stringify(name)}]`
379
+ const set = caught === undefined ? `(${pending}=true,${fallback}=next)` : `${caught}=next`
380
+ referenceDeclarations.push(`${caught === undefined ? `let ${pending}=false;` : ''}const ${reference}=()=>${varReference()}(${JSON.stringify(name)},${withDepth},{get:()=>${get},set:next=>${set}});`)
381
+ internalBindings.add(pending)
382
+ candidateReferences.add(reference)
383
+ candidateNames.set(reference, new Set([name]))
384
+ references.set(name, `${reference}().value`)
385
+ dynamicBindings.push({ physicalName: reference, name, kind: 'let', role: 'candidate', reference: true, accessor: true })
386
+ }
387
+ const pattern = patternText(declarator.id, program, binding => references.get(binding.name) ?? redirected.get(binding.name)
388
+ ?? `${candidate}.values[${JSON.stringify(binding.name)}]`)
389
+ const text = `{ const ${rhs} = (${value}); const ${candidate} = ${runtime}.candidate(${JSON.stringify(stored)}); ${referenceDeclarations.join('')} ${emptyCompletion(`((${pattern.text} = ${rhs}), ${candidate}.commit(${JSON.stringify(target)}))`)} }`
390
+ const valueStart = text.indexOf(`= (${value})`) + 3
391
+ const patternStart = text.indexOf(pattern.text)
392
+ return remember(text, [...(supplied === undefined ? [{ generatedStart: valueStart, generatedEnd: valueStart + value.length,
393
+ originalStart: declarator.init.start, originalEnd: declarator.init.end }] : []),
394
+ ...pattern.mappings.map(mapping => ({ ...mapping, generatedStart: patternStart + mapping.generatedStart,
395
+ generatedEnd: patternStart + mapping.generatedEnd }))])
396
+ }
397
+ const addLoad = node => {
398
+ const global = allocate('root_module')
399
+ const requiredExports = node.type === 'ImportDeclaration' ? node.specifiers
400
+ .filter(specifier => specifier.importKind !== 'type' && specifier.type !== 'ImportNamespaceSpecifier')
401
+ .map(specifier => specifier.type === 'ImportDefaultSpecifier' ? 'default' : specifier.imported.name ?? specifier.imported.value) : []
402
+ const attributes = node.attributes?.length > 0 ? { with: Object.fromEntries(node.attributes
403
+ .map(attribute => [attribute.key.name ?? attribute.key.value, attribute.value.value])) } : undefined
404
+ moduleLoads.push({ source: node.source.value, global, position: mapSourceSpan(span(node.source), program, originalSource, sourceMap),
405
+ ...(requiredExports.length === 0 ? {} : { requiredExports: [...new Set(requiredExports)] }),
406
+ ...(attributes === undefined ? {} : { options: attributes }) })
407
+ return global
408
+ }
409
+ for (const node of file.program.body) {
410
+ if (node.type === 'ImportDeclaration') {
411
+ if (node.importKind !== 'type' && (node.specifiers.length === 0
412
+ || node.specifiers.some(specifier => specifier.importKind !== 'type'))) {
413
+ const global = addLoad(node)
414
+ for (const specifier of node.specifiers.filter(specifier => specifier.importKind !== 'type')) {
415
+ const name = specifier.local.name
416
+ readOnly.add(name)
417
+ const imported = specifier.type === 'ImportNamespaceSpecifier' ? null
418
+ : specifier.type === 'ImportDefaultSpecifier' ? 'default' : specifier.imported.name ?? specifier.imported.value
419
+ const target = record(name, 'import', node, specifier.local)
420
+ imports.set(name, { namespace: global, ...(imported === null ? {} : { imported }), commitDependency: target })
421
+ prologue.push(emptyCompletion(`${runtime}.import(${JSON.stringify(name)}, ${moduleExpression(global)}, ${JSON.stringify(imported)}, ${JSON.stringify(target)})`))
422
+ }
423
+ rewrites.push({ kind: 'import', description: `adapted the static import of ${JSON.stringify(node.source.value)}`, source: node.source.value })
424
+ } else {
425
+ rewrites.push({ kind: 'import', description: `removed the type-only import of ${JSON.stringify(node.source.value)}`, source: node.source.value })
426
+ }
427
+ edits.push({ start: node.start, end: node.end, text: '' })
428
+ } else if (node.type === 'ExportAllDeclaration' || node.type === 'ExportNamedDeclaration' && node.declaration === null) {
429
+ if (node.source !== null && node.exportKind !== 'type') addLoad(node)
430
+ rewrites.push({ kind: 'export', description: node.exportKind === 'type'
431
+ ? 'removed a type-only export declaration'
432
+ : node.source == null ? 'removed a local re-export declaration'
433
+ : `converted the re-export of ${JSON.stringify(node.source.value)} into a side-effect import` })
434
+ edits.push({ start: node.start, end: node.end, text: '' })
435
+ } else if (node.type === 'ExportNamedDeclaration') {
436
+ rewrites.push({ kind: 'export', description: 'stripped the export modifier from a top-level declaration' })
437
+ edits.push({ start: node.start, end: node.declaration.start, text: '' })
438
+ } else if (node.type === 'ExportDefaultDeclaration') {
439
+ rewrites.push({ kind: 'export', description: TYPE_ONLY.has(node.declaration.type)
440
+ ? 'removed a type-only export declaration'
441
+ : 'converted the default export into a local __default binding' })
442
+ if (TYPE_ONLY.has(node.declaration.type)) {
443
+ edits.push({ start: node.start, end: node.end, text: '' })
444
+ } else if (!['FunctionDeclaration', 'ClassDeclaration'].includes(node.declaration.type)) {
445
+ const target = record('__default', 'variable', node)
446
+ edits.push({ start: node.start, end: node.end,
447
+ text: emptyCompletion(`${runtime}.assign("__default", (${program.slice(node.declaration.start, node.declaration.end)}), ${JSON.stringify(target)})`) })
448
+ }
449
+ }
450
+ }
451
+ for (const path of root) {
452
+ const node = path.node
453
+ if (node.type === 'VariableDeclaration') {
454
+ if (node.kind === 'const' || node.kind === 'using' || node.kind === 'await using') {
455
+ for (const binding of node.declarations.flatMap(declarator => bindingNodes(declarator.id))) readOnly.add(binding.name)
456
+ }
457
+ if (node.kind === 'using' || node.kind === 'await using') {
458
+ // Resource lifetime owns the acquired value even when the public
459
+ // logical binding is replaced before the scope ends.
460
+ const parts = node.declarations.flatMap(declarator => {
461
+ const resource = allocate('root_resource')
462
+ const value = program.slice(declarator.init.start, declarator.init.end)
463
+ const resourceText = `${node.kind} ${resource} = (${value});`
464
+ const valueStart = resourceText.indexOf(`= (${value})`) + 3
465
+ remember(resourceText, [{ generatedStart: valueStart, generatedEnd: valueStart + value.length,
466
+ originalStart: declarator.init.start, originalEnd: declarator.init.end }])
467
+ return [resourceText, variable(node, declarator, resource)]
468
+ })
469
+ edits.push({ start: node.start, end: node.end, text: parts.join(''), mappings: mapParts(parts) })
470
+ continue
471
+ }
472
+ for (const declarator of node.declarations) {
473
+ if (node.kind !== 'var') continue
474
+ for (const binding of bindingNodes(declarator.id)) {
475
+ if (!canInstantiate(binding.name) || hoisted.includes(binding.name)) continue
476
+ hoisted.push(binding.name)
477
+ const target = record(binding.name, 'variable', node, binding, ':hoist')
478
+ prologue.push(emptyCompletion(`${runtime}.declare(${JSON.stringify(binding.name)}, ${JSON.stringify(target)})`))
479
+ }
480
+ }
481
+ if (path.parent.type === 'ForOfStatement' || path.parent.type === 'ForInStatement') {
482
+ if (node.declarations[0].init !== null) {
483
+ let owner = path.parentPath
484
+ while (owner.parentPath?.isLabeledStatement()) owner = owner.parentPath
485
+ const prefix = ['{ ', variable(node, node.declarations[0]), '\n']
486
+ edits.push({ start: owner.node.start, end: owner.node.start, text: prefix.join(''), mappings: mapParts(prefix) })
487
+ edits.push({ start: owner.node.end, end: owner.node.end, text: ' }' })
488
+ }
489
+ const temporary = allocate('iteration')
490
+ edits.push({ start: node.start, end: node.end, text: `const ${temporary}` })
491
+ const body = path.parent.body
492
+ const assignments = variable(node, node.declarations[0], temporary)
493
+ if (body.type === 'BlockStatement') edits.push({ start: body.start + 1, end: body.start + 1, text: assignments,
494
+ mappings: sourceCopies.get(assignments) })
495
+ else {
496
+ edits.push({ start: body.start, end: body.start, text: `{ ${assignments}`, mappings: mapParts(['{ ', assignments]) })
497
+ edits.push({ start: body.end, end: body.end, text: '}' })
498
+ }
499
+ } else {
500
+ const variables = node.declarations.flatMap(declarator => [variable(node, declarator), '\n'])
501
+ const parts = ['{ ', ...variables, ' }']
502
+ if (path.parent.type === 'ForStatement') {
503
+ let owner = path.parentPath
504
+ while (owner.parentPath?.isLabeledStatement()) owner = owner.parentPath
505
+ const prefix = ['{ ', ...parts]
506
+ edits.push({ start: owner.node.start, end: owner.node.start, text: prefix.join(''), mappings: mapParts(prefix) })
507
+ edits.push({ start: node.start, end: node.end, text: '' })
508
+ edits.push({ start: owner.node.end, end: owner.node.end, text: ' }' })
509
+ } else edits.push({ start: node.start, end: node.end, text: parts.join(''), mappings: mapParts(parts) })
510
+ }
511
+ continue
512
+ }
513
+ const name = node.id?.name ?? '__default'
514
+ const kind = node.type === 'FunctionDeclaration' ? 'function' : 'class'
515
+ const target = record(name, kind, node, node.id ?? node)
516
+ let expression = program.slice(node.start, node.end)
517
+ if (kind === 'function' && node.id !== null) {
518
+ expression = `({ [${JSON.stringify(name)}]: ${program.slice(node.start, node.id.start)}${program.slice(node.id.end, node.end)} })[${JSON.stringify(name)}]`
519
+ }
520
+ if (node.id === null && path.parent.type === 'ExportDefaultDeclaration') {
521
+ expression = `({ ["default"]: (${expression}) })["default"]`
522
+ }
523
+ const text = emptyCompletion(`${runtime}.assign(${JSON.stringify(name)}, (${expression}), ${JSON.stringify(target)})`)
524
+ const expressionStart = text.indexOf(`, (${expression}),`) + 3
525
+ const sourceStart = kind === 'function' && node.id !== null ? node.id.end : node.start
526
+ const copied = program.slice(sourceStart, node.end)
527
+ const copiedStart = expressionStart + expression.indexOf(copied)
528
+ remember(text, [{ generatedStart: copiedStart, generatedEnd: copiedStart + copied.length,
529
+ originalStart: sourceStart, originalEnd: node.end }])
530
+ const canHoist = kind === 'function' && canInstantiate(name)
531
+ if (canHoist) prologue.push(text)
532
+ const defaultExport = path.parent.type === 'ExportDefaultDeclaration'
533
+ const suffix = defaultExport
534
+ ? emptyCompletion(`${runtime}.link("__default", ${JSON.stringify(name)}, ${JSON.stringify(record('__default', kind, path.parent))})`) : ''
535
+ const replacement = [canHoist ? '' : text, suffix]
536
+ if (path.parentPath.isLabeledStatement()) {
537
+ replacement.unshift('{')
538
+ replacement.push('}')
539
+ }
540
+ edits.push({ start: defaultExport ? path.parent.start : node.start,
541
+ end: defaultExport ? path.parent.end : node.end, text: replacement.join(''),
542
+ mappings: mapParts(replacement) })
543
+ }
544
+ const declared = new Set(declarations.map(declaration => declaration.name))
545
+ const rootBindings = { declared: [...declared], known: [...knownBindings], candidates: [...rootCandidates],
546
+ declarationKinds: [...declarationKinds],
547
+ declaredKinds: [...new Map(declarations.map(declaration => [declaration.name, declarationKinds.get(declaration.commitDependency)]))],
548
+ established: [...establishedRoots], readOnly: [...readOnly], languageSemantics,
549
+ legacyImports: [...importBindings], legacyLexicals: [...knownBindings].filter(name => !importBindings.has(name)),
550
+ legacyWritable: [...writableBindings].filter(name => !importBindings.has(name)),
551
+ legacyNative: [...nativeBindings], legacyNativeLexicals: [...nativeLexicalBindings] }
552
+ const accessRuntime = runtimeExpression === undefined ? `this[${JSON.stringify(rootRuntimeName)}]`
553
+ : runtimeExpression(rootBindings)
554
+ const prefixParts = [`;{\nconst ${runtime} = ${accessRuntime};\n`, ...prologue.flatMap(text => [text, '\n'])]
555
+ const directiveEnd = file.program.directives.at(-1)?.end ?? 0
556
+ if (directiveEnd === program.length) prefixParts.push('\n}')
557
+ edits.unshift({ start: directiveEnd, end: directiveEnd, text: prefixParts.join(''), mappings: mapParts(prefixParts) })
558
+ if (directiveEnd !== program.length) edits.push({ start: program.length, end: program.length, text: '\n}' })
559
+ const merged = []
560
+ for (const edit of edits.sort((left, right) => left.start - right.start || left.end - right.end)) {
561
+ const previous = merged.at(-1)
562
+ if (edit.start === edit.end && previous?.start === edit.start && previous.end === edit.end) {
563
+ previous.mappings = [...(previous.mappings ?? []), ...(edit.mappings ?? []).map(mapping => ({ ...mapping,
564
+ generatedStart: mapping.generatedStart + previous.text.length, generatedEnd: mapping.generatedEnd + previous.text.length }))]
565
+ previous.text += edit.text
566
+ } else merged.push({ ...edit })
567
+ }
568
+ const framed = applySourceEdits(program, sourceMap, merged)
569
+ let rewritten = rewriteRootReferences(framed.code, framed.sourceMap, runtime, candidateNames, candidateReferences,
570
+ originalSource)
571
+ rewritten = adaptRootModuleImports(rewritten, runtime)
572
+ rewritten = { ...rewritten, ...adaptDynamicCell(rewritten.code, rewritten.sourceMap, {
573
+ rootRuntime: runtime, bindings: dynamicBindings, privateBindings, internalBindings, parserPlugins: CELL_PARSER_PLUGINS, originalSource,
574
+ }) }
575
+ rootBindings.dynamicOrigins = [...dynamicOrigins, ...rewritten.dynamicOrigins.map(origin => origin.target)]
576
+ rootBindings.candidates = [...new Map([...rootCandidates, ...rewritten.implicitDeclarations.map(declaration => [declaration.target, declaration.name])])]
577
+ // Each record carries the reason this owner determined, so the diagnostic surface does not
578
+ // re-derive reserved-ness or protected policy from the request descriptors.
579
+ const collisions = declarations.filter(declaration => reservedBindings.has(declaration.name)
580
+ || languageSemantics === 'protected-v1' && knownBindings.has(declaration.name))
581
+ .map(declaration => ({ name: declaration.name, kind: declaration.kind,
582
+ reason: reservedBindings.has(declaration.name)
583
+ ? 'reserved-program-binding-not-shadowable' : 'protected-root-redeclaration',
584
+ start: { line: declaration.span.line, column: declaration.span.column }, end: declaration.span.end }))
585
+ // A binding is reused only when this cell's rewritten source statically
586
+ // references an identity that already existed and does not (re)declare that
587
+ // same name. The count is a source fact, not a runtime trace: an unreached or
588
+ // never-invoked reference still counts, and a redeclaration neither counts as
589
+ // a reuse here nor resets the accumulated count it carries.
590
+ const reusedNames = [...(rewritten.readNames ?? [])]
591
+ .filter(name => knownBindings.has(name) && !declared.has(name))
592
+ return {
593
+ ...rewritten, languageSemantics, rootRuntimeName, rootFrameBinding: runtime, commitSignal, commitTargets, declarations, declared,
594
+ rootPlan: rootBindings,
595
+ rootBindings,
596
+ rootBindingFacts: true, moduleLoads, imports, importNamespaces: new Set(), collisions,
597
+ redeclared: declarations.filter(declaration => knownBindings.has(declaration.name)), rewrites,
598
+ establishedRootLexicals: new Set(), reusedNames,
599
+ }
600
+ }