dsh-ptc-plus 0.3.2 → 0.4.1

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 (199) hide show
  1. package/README.en.md +65 -78
  2. package/README.md +65 -78
  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 +30596 -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 +554 -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 +6 -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 +73 -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 +25 -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 +72 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +755 -0
  58. package/docs/user-bindings.en.md +64 -0
  59. package/docs/user-bindings.md +64 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification.md +57 -0
  62. package/index.js +369 -92
  63. package/internal/ast-traversal.js +5 -2
  64. package/internal/binding-descriptors.js +1 -0
  65. package/internal/binding-pattern-traversal.js +25 -0
  66. package/internal/binding-pattern.js +26 -29
  67. package/internal/binding-source-analysis.js +391 -0
  68. package/internal/binding-update-policy.js +66 -0
  69. package/internal/bounded-worker-round.js +56 -0
  70. package/internal/callable-definition-environment.js +42 -0
  71. package/internal/callable-source-catalog.js +129 -0
  72. package/internal/callable-source-encoding.js +47 -0
  73. package/internal/callable-source-facts.js +459 -0
  74. package/internal/callable-source-format.js +2 -0
  75. package/internal/callable-source-lowering.js +123 -0
  76. package/internal/cell-analysis-contract.js +25 -0
  77. package/internal/cell-analysis.js +240 -290
  78. package/internal/cell-completion.js +15 -0
  79. package/internal/cell-error.js +7 -0
  80. package/internal/cell-parser.js +66 -0
  81. package/internal/cell-rewriter.js +3 -677
  82. package/internal/commonjs-export-evidence.js +63 -0
  83. package/internal/commonjs-source-evidence.js +72 -0
  84. package/internal/compiler-amaro.cjs +2 -0
  85. package/internal/compiler-compression.js +12 -0
  86. package/internal/compiler-data.js +58 -0
  87. package/internal/compiler-descriptors.js +54 -0
  88. package/internal/compiler-dynamic-cache.js +48 -0
  89. package/internal/compiler-entry.js +35 -0
  90. package/internal/compiler-generated-names.js +17 -0
  91. package/internal/compiler-intrinsics.js +84 -0
  92. package/internal/compiler-module-links.js +34 -0
  93. package/internal/compiler-operations.js +61 -0
  94. package/internal/compiler-platform-factory.js +84 -0
  95. package/internal/compiler-platform.js +136 -0
  96. package/internal/compiler-record-roles.js +53 -0
  97. package/internal/compiler-region-output.js +259 -0
  98. package/internal/compiler-resource-lowering.js +103 -0
  99. package/internal/compiler-scope-facts.js +115 -0
  100. package/internal/compiler-service.js +109 -0
  101. package/internal/compiler-source-cache.js +32 -0
  102. package/internal/compiler-source-pieces.js +93 -0
  103. package/internal/compiler-source-regions.js +132 -0
  104. package/internal/compiler-storage-source.js +54 -0
  105. package/internal/compiler-text.js +15 -0
  106. package/internal/compiler-typescript.cjs +2 -0
  107. package/internal/config-spec.js +83 -27
  108. package/internal/cordis-tools-owner.js +130 -21
  109. package/internal/diagnostic.js +27 -1
  110. package/internal/direct-surface-owner.js +76 -23
  111. package/internal/dynamic-binding-evidence.js +16 -0
  112. package/internal/dynamic-environment-compiler.js +779 -0
  113. package/internal/dynamic-environment-integration.js +87 -0
  114. package/internal/dynamic-environment-runtime.js +362 -0
  115. package/internal/dynamic-native-calls.js +150 -0
  116. package/internal/dynamic-native-runtime.js +248 -0
  117. package/internal/dynamic-scope-analysis.js +90 -0
  118. package/internal/edit-transport-owner.js +27 -2
  119. package/internal/execution-seam-compat.js +193 -0
  120. package/internal/failure-reporting.js +118 -18
  121. package/internal/host-rpc.js +66 -0
  122. package/internal/isolated-worker.js +548 -0
  123. package/internal/kernel-child.js +139 -0
  124. package/internal/kernel-worker.js +904 -120
  125. package/internal/language-semantics.js +14 -0
  126. package/internal/legacy-binding-catalog.js +48 -0
  127. package/internal/legacy-cell-analysis.js +600 -0
  128. package/internal/legacy-cell-parser.js +50 -0
  129. package/internal/legacy-cell-rewriter.js +631 -0
  130. package/internal/legacy-repl-convenience.js +291 -0
  131. package/internal/managed-module-operations.js +170 -0
  132. package/internal/module-compilation.js +321 -0
  133. package/internal/module-runtime-platform.js +19 -0
  134. package/internal/module-transform-contract.js +12 -0
  135. package/internal/native-await-declarations.js +68 -0
  136. package/internal/native-root-compilation.js +54 -0
  137. package/internal/native-root-dynamic.js +67 -0
  138. package/internal/recovery-tips.js +27 -15
  139. package/internal/rejected-cell-editor.js +13 -8
  140. package/internal/repl-convenience.js +2 -289
  141. package/internal/repl-memory-projection.js +81 -12
  142. package/internal/repl-observation-interest.js +70 -0
  143. package/internal/repl-rewrite-contract.js +6 -0
  144. package/internal/repl-scope-normalizer.js +2091 -0
  145. package/internal/repl-value-observer.js +114 -0
  146. package/internal/rpc-contract.js +52 -0
  147. package/internal/runtime-bridge-owner.js +172 -28
  148. package/internal/runtime-config.js +48 -52
  149. package/internal/runtime-contexts.js +82 -10
  150. package/internal/runtime-messages.js +111 -0
  151. package/internal/session-cell-executor.js +401 -87
  152. package/internal/session-journal-recovery.js +684 -0
  153. package/internal/session-journal-schema.js +106 -0
  154. package/internal/session-journal.js +184 -654
  155. package/internal/session-log-view.js +42 -9
  156. package/internal/session-runtime.js +256 -95
  157. package/internal/session-state.js +247 -71
  158. package/internal/source-position-map.js +211 -71
  159. package/internal/stateful-module-compiler.js +154 -0
  160. package/internal/stateful-module-runtime.js +303 -0
  161. package/internal/stateful-root-compiler.js +598 -0
  162. package/internal/stateful-root-runtime.js +340 -0
  163. package/internal/typert-codec-compat.js +28 -0
  164. package/internal/typescript-transform.js +29 -0
  165. package/internal/user-binding-authoring.js +70 -0
  166. package/internal/user-binding-console-worker.js +184 -0
  167. package/internal/user-binding-console.js +148 -0
  168. package/internal/user-binding-draft-projection.js +335 -0
  169. package/internal/user-binding-model-context.js +31 -0
  170. package/internal/user-binding-runner.js +56 -0
  171. package/internal/user-bindings-owner.js +1065 -0
  172. package/internal/user-bindings-store.js +293 -0
  173. package/internal/user-bindings.js +353 -0
  174. package/internal/value-wire-schema.js +28 -0
  175. package/internal/value-wire.js +29 -20
  176. package/internal/worker-client.js +57 -67
  177. package/internal/worker-environment.js +45 -0
  178. package/internal/worker-output-relay.js +29 -0
  179. package/internal/worker-shutdown.js +14 -0
  180. package/package.json +75 -7
  181. package/src/client-activity.js +88 -53
  182. package/src/client-authoring-view.js +580 -0
  183. package/src/client-binding-review.js +230 -0
  184. package/src/client-bindings-data.js +29 -0
  185. package/src/client-catalog.js +127 -0
  186. package/src/client-code-editor.js +84 -0
  187. package/src/client-console.js +112 -0
  188. package/src/client-copy.js +370 -0
  189. package/src/client-feature-gates.js +62 -0
  190. package/src/client-host-compat.js +150 -0
  191. package/src/client-indicator-view.js +267 -0
  192. package/src/client-repl-view.js +292 -0
  193. package/src/client-rpc.js +20 -0
  194. package/src/client-settings-view.js +221 -0
  195. package/src/client-styles.js +106 -0
  196. package/src/client-tool-view.js +108 -0
  197. package/src/client-transport.js +159 -0
  198. package/src/client-workbench.js +521 -0
  199. package/src/client.js +233 -615
@@ -0,0 +1,291 @@
1
+ /** Historical legacy-v1 lowering, retained from c51616c8d6c8:repl-convenience.js. */
2
+ import { bindingNodes, createGeneratedNameAllocator } from './binding-pattern.js'
3
+ import {
4
+ CLASS_REDECLARATION_REWRITE,
5
+ FUNCTION_REDECLARATION_REWRITE,
6
+ MIXED_REDECLARATION_REWRITE,
7
+ redeclarationCommitTarget,
8
+ } from './repl-rewrite-contract.js'
9
+ import { applySourceEdits, createMappedTextBuilder, identitySourceMap } from './source-position-map.js'
10
+ import { SKIP_AST_CHILDREN, walkAst } from './ast-traversal.js'
11
+
12
+ /**
13
+ * Optional compatibility policy for a persistent REPL. The cell language does
14
+ * not own this policy: callers may replace it when persistence uses separate
15
+ * lexical frames instead of one shared REPL environment.
16
+ */
17
+
18
+ function containsTopLevelAwait(node) {
19
+ let found = false
20
+ walkAst(node, current => {
21
+ if (current.type === 'AwaitExpression') found = true
22
+ if (current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression'
23
+ || current.type === 'ArrowFunctionExpression') return SKIP_AST_CHILDREN
24
+ })
25
+ return found
26
+ }
27
+
28
+ function mixedDeclaratorText(statement, declarator, bindings, code, allocateName) {
29
+ const fresh = bindings.filter(binding => !binding.existing)
30
+ const existing = bindings.filter(binding => binding.existing)
31
+ const valueName = allocateName('mixed_value')
32
+ const commitName = allocateName('mixed_commit')
33
+ const valuesName = allocateName('mixed_values')
34
+ const positions = new Map(bindings.map((binding, index) => [binding.name, index]))
35
+ const asynchronous = containsTopLevelAwait(declarator.id)
36
+ const builder = createMappedTextBuilder(code)
37
+ const appendBindingName = binding => builder.appendMapped(binding.name, binding.start, binding.end)
38
+ builder.append(statement.kind === 'var' ? 'var [' : 'let [')
39
+ fresh.forEach((binding, index) => {
40
+ if (index > 0) builder.append(', ')
41
+ appendBindingName(binding)
42
+ })
43
+ builder.append(`] = ${asynchronous ? 'await ' : ''}(`)
44
+ builder.append(`(${asynchronous ? 'async ' : ''}(${valueName}, ${commitName}) => { ${statement.kind} `)
45
+ builder.appendSource(declarator.id.start, declarator.id.end)
46
+ builder.append(` = ${valueName}; return ${commitName}([`)
47
+ bindings.forEach((binding, index) => {
48
+ if (index > 0) builder.append(', ')
49
+ appendBindingName(binding)
50
+ })
51
+ builder.append(`]); })((`)
52
+ if (declarator.init === null) builder.append('undefined')
53
+ else builder.appendSource(declarator.init.start, declarator.init.end)
54
+ builder.append(`), (${valuesName}) => { `)
55
+ existing.forEach((binding, index) => {
56
+ if (index > 0) builder.append(' ')
57
+ appendBindingName(binding)
58
+ builder.append(` = ${valuesName}[${positions.get(binding.name)}];`)
59
+ })
60
+ builder.append(' return [')
61
+ fresh.forEach((binding, index) => {
62
+ if (index > 0) builder.append(', ')
63
+ builder.append(valuesName)
64
+ builder.append(`[${positions.get(binding.name)}]`)
65
+ })
66
+ builder.append(']; }) );')
67
+ return builder.result()
68
+ }
69
+
70
+ function existingDeclaratorText(declarator, code) {
71
+ const builder = createMappedTextBuilder(code)
72
+ builder.append(';(')
73
+ builder.appendSource(declarator.id.start, declarator.id.end)
74
+ builder.append(' = ')
75
+ if (declarator.init === null) builder.append('undefined')
76
+ else builder.appendSource(declarator.init.start, declarator.init.end)
77
+ builder.append(');')
78
+ return builder.result()
79
+ }
80
+
81
+ function freshDeclaratorText(statement, declarator, code) {
82
+ const builder = createMappedTextBuilder(code)
83
+ builder.append(statement.kind === 'var' ? 'var ' : 'let ')
84
+ builder.appendSource(declarator.start, declarator.end)
85
+ builder.append(';')
86
+ return builder.result()
87
+ }
88
+
89
+ function bindingEntries(pattern, declarationSpan) {
90
+ return bindingNodes(pattern).map(node => ({
91
+ name: node.name,
92
+ start: node.start,
93
+ end: node.end,
94
+ span: declarationSpan(node),
95
+ }))
96
+ }
97
+
98
+ function existingFunctionText(statement, code) {
99
+ const builder = createMappedTextBuilder(code)
100
+ builder.append(';(')
101
+ builder.appendMapped(statement.id.name, statement.id.start, statement.id.end)
102
+ builder.append(' = ')
103
+ builder.appendSource(statement.start, statement.id.start)
104
+ builder.appendSource(statement.id.end, statement.end)
105
+ builder.append(');')
106
+ return builder.result()
107
+ }
108
+
109
+ function existingClassText(statement, code) {
110
+ const builder = createMappedTextBuilder(code)
111
+ builder.append(';(')
112
+ builder.appendMapped(statement.id.name, statement.id.start, statement.id.end)
113
+ builder.append(' = ')
114
+ builder.appendSource(statement.start, statement.end)
115
+ builder.append(');')
116
+ return builder.result()
117
+ }
118
+
119
+ export function rewriteReplRedeclarations({
120
+ code,
121
+ sourceMap = identitySourceMap(code.length),
122
+ body,
123
+ knownBindings,
124
+ variableRedeclarationBindings = knownBindings,
125
+ writableBindings,
126
+ declarations,
127
+ declarationSpan,
128
+ collisionFor,
129
+ bindingPolicy,
130
+ autoSplitRedeclarations,
131
+ commitSignal,
132
+ }) {
133
+ const redeclared = []
134
+ const rewrites = []
135
+ if (body === undefined) {
136
+ return {
137
+ executableCode: code,
138
+ executableSourceMap: sourceMap,
139
+ collisions: declarations.filter(declaration => knownBindings.has(declaration.name)).map(collisionFor),
140
+ redeclared,
141
+ rewrites,
142
+ }
143
+ }
144
+ const replacements = []
145
+ const rejected = []
146
+ const allocateName = createGeneratedNameAllocator(body)
147
+ for (const statement of body) {
148
+ if (statement.type !== 'VariableDeclaration') {
149
+ if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration')
150
+ && statement.id !== null && knownBindings.has(statement.id.name)) {
151
+ const kind = statement.type === 'ClassDeclaration' ? 'class' : 'function'
152
+ if (!writableBindings.has(statement.id.name)) {
153
+ rejected.push({
154
+ name: statement.id.name,
155
+ kind,
156
+ reason: 'binding-not-writable',
157
+ span: declarationSpan(statement.id),
158
+ })
159
+ } else if (!bindingPolicy.functionClassRedeclarations) {
160
+ rejected.push({
161
+ name: statement.id.name,
162
+ kind,
163
+ reason: 'function-class-redeclarations-disabled',
164
+ span: declarationSpan(statement.id),
165
+ })
166
+ } else {
167
+ const commitDependency = redeclarationCommitTarget(statement.id.name, statement.start)
168
+ const replacement = kind === 'class'
169
+ ? existingClassText(statement, code)
170
+ : existingFunctionText(statement, code)
171
+ replacement.text += ` void 0; this[${JSON.stringify(commitSignal)}](${JSON.stringify(commitDependency)});`
172
+ replacements.push({
173
+ start: statement.start,
174
+ end: statement.end,
175
+ text: replacement.text,
176
+ mappings: replacement.mappings,
177
+ })
178
+ redeclared.push(collisionFor({
179
+ name: statement.id.name,
180
+ kind,
181
+ commitDependency,
182
+ span: declarationSpan(statement.id),
183
+ }))
184
+ rewrites.push({
185
+ kind: 'redeclaration',
186
+ description: kind === 'class'
187
+ ? CLASS_REDECLARATION_REWRITE
188
+ : FUNCTION_REDECLARATION_REWRITE,
189
+ source: statement.id.name,
190
+ })
191
+ }
192
+ }
193
+ continue
194
+ }
195
+ const entries = []
196
+ let statementRejected = false
197
+ for (const declarator of statement.declarations) {
198
+ const bindings = bindingEntries(declarator.id, declarationSpan)
199
+ const existing = bindings.filter(binding => variableRedeclarationBindings.has(binding.name))
200
+ const immutable = existing.filter(binding => !writableBindings.has(binding.name))
201
+ if (immutable.length > 0) {
202
+ rejected.push(...immutable.map(binding => ({
203
+ ...binding,
204
+ kind: 'variable',
205
+ reason: 'binding-not-writable',
206
+ })))
207
+ statementRejected = true
208
+ continue
209
+ }
210
+ if (existing.length > 0 && !bindingPolicy.variableRedeclarations) {
211
+ rejected.push(...existing.map(binding => ({
212
+ ...binding,
213
+ kind: 'variable',
214
+ reason: 'variable-redeclarations-disabled',
215
+ })))
216
+ statementRejected = true
217
+ continue
218
+ }
219
+ if (existing.length > 0 && existing.length < bindings.length) {
220
+ if (autoSplitRedeclarations) entries.push({ declarator, bindings, existing })
221
+ else {
222
+ rejected.push(...existing.map(binding => ({ ...binding, kind: 'variable',
223
+ reason: 'redeclaration-splitting-disabled' })))
224
+ statementRejected = true
225
+ }
226
+ continue
227
+ }
228
+ entries.push({ declarator, bindings, existing })
229
+ }
230
+ if (statementRejected) continue
231
+ if (!entries.some(entry => entry.existing.length > 0)) {
232
+ if (statement.kind === 'const' && bindingPolicy.variableRedeclarations) {
233
+ replacements.push({
234
+ start: statement.start,
235
+ end: statement.start + statement.kind.length,
236
+ text: 'let',
237
+ })
238
+ }
239
+ continue
240
+ }
241
+ let replacementText = ''
242
+ const replacementMappings = []
243
+ const appendPart = (part) => {
244
+ if (replacementText.length > 0) replacementText += '\n'
245
+ const partOffset = replacementText.length
246
+ replacementText += part.text
247
+ part.mappings.forEach(mapping => replacementMappings.push({
248
+ ...mapping,
249
+ generatedStart: mapping.generatedStart + partOffset,
250
+ generatedEnd: mapping.generatedEnd + partOffset,
251
+ }))
252
+ }
253
+ for (const { declarator, bindings, existing } of entries) {
254
+ if (existing.length > 0 && existing.length < bindings.length) {
255
+ appendPart(mixedDeclaratorText(
256
+ statement,
257
+ declarator,
258
+ bindings.map(binding => ({ ...binding, existing: existing.includes(binding) })),
259
+ code,
260
+ allocateName,
261
+ ))
262
+ redeclared.push(...existing.map(collisionFor))
263
+ rewrites.push({
264
+ kind: 'redeclaration',
265
+ description: MIXED_REDECLARATION_REWRITE,
266
+ source: existing.map(binding => binding.name).join(', '),
267
+ })
268
+ } else if (existing.length === bindings.length && bindings.length > 0) {
269
+ redeclared.push(...existing.map(collisionFor))
270
+ appendPart(existingDeclaratorText(declarator, code))
271
+ } else {
272
+ appendPart(freshDeclaratorText(statement, declarator, code))
273
+ }
274
+ }
275
+ replacements.push({
276
+ start: statement.start,
277
+ end: statement.end,
278
+ text: replacementText,
279
+ mappings: replacementMappings,
280
+ })
281
+ }
282
+ const collisions = rejected.map(collisionFor)
283
+ let executableCode = code
284
+ let executableSourceMap = sourceMap
285
+ if (collisions.length === 0) {
286
+ const applied = applySourceEdits(code, sourceMap, replacements)
287
+ executableCode = applied.code
288
+ executableSourceMap = applied.sourceMap
289
+ }
290
+ return { executableCode, executableSourceMap, collisions, redeclared, rewrites }
291
+ }
@@ -0,0 +1,170 @@
1
+ import { commonJsCompilerImport } from './compiler-module-links.js'
2
+ import { parse } from '@babel/parser'
3
+ import traverseModule from '@babel/traverse'
4
+ import { bindingNodes, createGeneratedNameAllocator } from './binding-pattern.js'
5
+ import { applySourceEdits, sourceOffsetAt } from './source-position-map.js'
6
+ import { visitRegionSource, applyRegionEdits } from './compiler-region-output.js'
7
+ import { visitSource } from './compiler-source-regions.js'
8
+ import { CELL_PARSER_PLUGINS, analyzeLogicalScopes } from './repl-scope-normalizer.js'
9
+ import { resolveSourceBinding } from './compiler-scope-facts.js'
10
+
11
+ const traverse = traverseModule.default ?? traverseModule
12
+
13
+ /** Every module environment owns imports, including runtime-created source. */
14
+ export function adaptModuleOperations(normalized, { target, url }) {
15
+ let allocate, insertion, strictCommonJs = false, sourceRequire = false
16
+ const calls = []
17
+ visitRegionSource(normalized, { sourceType: target === 'module' ? 'module' : 'commonjs', plugins: CELL_PARSER_PLUGINS }, input => {
18
+ allocate ??= normalized.sourceRegions?.allocate ?? createGeneratedNameAllocator(input.tree)
19
+ if (input.region.kind === 'program') {
20
+ insertion = input.tree.program.directives.at(-1)?.end ?? 0
21
+ strictCommonJs = target === 'commonjs' && input.tree.program.directives.some(item => item.value.value === 'use strict')
22
+ sourceRequire = target === 'commonjs' && input.tree.program.body.some(item =>
23
+ item.type === 'FunctionDeclaration' && item.id.name === 'require')
24
+ }
25
+ visitSource(input.tree, { CallExpression(path) {
26
+ if (path.node.callee.type === 'Import') calls.push({ start: sourceOffsetAt(input.sourceMap, path.node.callee.start),
27
+ end: sourceOffsetAt(input.sourceMap, path.node.callee.end - 1) + 1 })
28
+ } })
29
+ })
30
+ const runtime = allocate('module_operations')
31
+ const importer = allocate('module_import')
32
+ const runtimeUrl = new URL('./stateful-module-runtime.js', import.meta.url)
33
+ const bootstrap = target === 'commonjs' ? allocate('module_bootstrap') : undefined
34
+ const originalRequire = strictCommonJs && !sourceRequire ? allocate('wrapper_require') : undefined
35
+ const parent = target === 'module' ? 'import.meta.url' : url === undefined
36
+ ? `(typeof __filename === 'string' ? ${runtime}.pathToFileURL(__filename).href : ${JSON.stringify(import.meta.url)})` : JSON.stringify(url)
37
+ const edits = calls.map(node => ({ start: node.start, end: node.end, text: importer }))
38
+ const nativeRequire = `typeof __filename === 'string' ? process.getBuiltinModule('module').createRequire(__filename) : ${sourceRequire ? 'arguments[1]' : 'require'}`
39
+ const loaderSetup = sourceRequire
40
+ ? strictCommonJs ? `arguments[1]=${runtime}.managedRequire(${parent},${nativeRequire});` : ''
41
+ : `${originalRequire ? `const ${originalRequire}=require;` : ''}require=${runtime}.managedRequire(${parent},${nativeRequire});`
42
+ // Sloppy wrappers have mapped arguments. Strict wrappers need their
43
+ // original host argument adapted once before source observes either path.
44
+ + (originalRequire ? `if(arguments[1]===${originalRequire})arguments[1]=require;` : '')
45
+ const setup = target === 'module'
46
+ ? `import * as ${runtime} from ${JSON.stringify(runtimeUrl.href)};`
47
+ : `const ${runtime}=${commonJsCompilerImport(runtimeUrl)};const ${bootstrap}=(()=>{${loaderSetup}})();`
48
+ // Function declarations remain usable during cyclic module instantiation.
49
+ const operation = `function ${importer}(source,options){return ${runtime}.managedModuleImport(${parent},source,options)}`
50
+ edits.push({ start: insertion, end: insertion, text: `\n${setup}\n${operation}\n` })
51
+ return { ...applyRegionEdits(normalized, edits), importOperation: importer,
52
+ internalBindings: new Set([...normalized.internalBindings ?? [], runtime, importer,
53
+ ...bootstrap ? [bootstrap] : [], ...originalRequire ? [originalRequire] : []]) }
54
+ }
55
+
56
+ /** Root compilation supplies the execution-owned operation without globals. */
57
+ export function adaptRootModuleImports(normalized, runtime) {
58
+ const tree = parse(normalized.code, { sourceType: 'script', allowAwaitOutsideFunction: true,
59
+ allowReturnOutsideFunction: true, plugins: CELL_PARSER_PLUGINS })
60
+ const edits = []
61
+ traverse(tree, { noScope: true, CallExpression(path) {
62
+ if (path.node.callee.type === 'Import') edits.push({ start: path.node.callee.start,
63
+ end: path.node.callee.end, text: `${runtime}.importModule` })
64
+ } })
65
+ return { ...normalized, ...applySourceEdits(normalized.code, normalized.sourceMap, edits) }
66
+ }
67
+
68
+ /** Retain the frozen legacy lowering; adapt only its module operation entry. */
69
+ export function adaptLegacyModuleImports(prepared, options) {
70
+ if (prepared.collisions.length !== 0) return prepared
71
+ const tree = parse(prepared.code, { sourceType: 'script', allowAwaitOutsideFunction: true,
72
+ allowReturnOutsideFunction: true, plugins: CELL_PARSER_PLUGINS })
73
+ const calls = []
74
+ traverse(tree, { noScope: true, CallExpression(path) {
75
+ if (path.node.callee.type === 'Import') calls.push(path.node.callee)
76
+ } })
77
+ if (calls.length === 0) return prepared
78
+ const allocate = createGeneratedNameAllocator(tree, [...prepared.importNamespaces,
79
+ ...options.knownBindings ?? [], ...options.reservedBindings ?? []])
80
+ const importer = allocate('module_import')
81
+ const global = allocate('module_import_global')
82
+ const edits = calls.map(node => ({ start: node.start, end: node.end, text: importer }))
83
+ const insertion = tree.program.directives.at(-1)?.end ?? tree.program.interpreter?.end ?? 0
84
+ edits.push({ start: insertion, end: insertion, text: `;\nconst ${importer}=${global};\n` })
85
+ return { ...prepared, ...applySourceEdits(prepared.code, prepared.sourceMap, edits),
86
+ importNamespaces: new Set([...prepared.importNamespaces, importer]),
87
+ moduleLoads: [...prepared.moduleLoads, { operation: 'import', global }] }
88
+ }
89
+
90
+ /** Legacy module bindings stay native; only reads cross the managed interface. */
91
+ export function adaptLegacyModuleReferences(normalized) {
92
+ const facts = analyzeLogicalScopes(normalized.code, { target: 'module', compact: true })
93
+ const { tree, allocate } = facts
94
+ for (const [node, name] of facts.names) node.name = name
95
+ const reader = allocate('module_import_read')
96
+ const imported = new Map()
97
+ const dynamicBindings = []
98
+ const accessors = []
99
+ const exports = []
100
+ const stars = []
101
+ const name = node => node.name ?? node.value
102
+ const relation = node => ({ source: node.source.value, attributes: Object.fromEntries(
103
+ (node.attributes ?? []).map(item => [name(item.key), item.value.value])) })
104
+ for (const node of tree.program.body) {
105
+ if (node.type !== 'ImportDeclaration') continue
106
+ for (const item of node.specifiers) imported.set(item.local.name, { ...relation(node),
107
+ imported: item.type === 'ImportNamespaceSpecifier' ? null
108
+ : item.type === 'ImportDefaultSpecifier' ? 'default' : name(item.imported), local: item.local })
109
+ }
110
+ for (const node of tree.program.body) {
111
+ if (node.type === 'ExportDefaultDeclaration') exports.push({ name: 'default', kind: 'native' })
112
+ if (node.type === 'ExportAllDeclaration') stars.push(relation(node))
113
+ if (node.type !== 'ExportNamedDeclaration') continue
114
+ if (node.declaration != null) {
115
+ const declaration = node.declaration
116
+ const names = declaration.type === 'VariableDeclaration'
117
+ ? declaration.declarations.flatMap(item => bindingNodes(item.id)).map(item => item.name) : [declaration.id.name]
118
+ exports.push(...names.map(name => ({ name, kind: 'native' })))
119
+ }
120
+ for (const item of node.specifiers) {
121
+ const exported = name(item.exported)
122
+ const source = node.source == null ? imported.get(name(item.local)) : { ...relation(node),
123
+ imported: item.type === 'ExportNamespaceSpecifier' ? null : name(item.local) }
124
+ exports.push(source === undefined ? { name: exported, kind: 'native' }
125
+ : { name: exported, kind: source.imported === null ? 'namespace' : 'forward',
126
+ source: source.source, imported: source.imported, attributes: source.attributes })
127
+ }
128
+ }
129
+ const edits = []
130
+ const sourceFor = path => {
131
+ const source = imported.get(path.node.name)
132
+ return source !== undefined && resolveSourceBinding(facts, facts.paths.get(path.node), path.node.name)
133
+ ?.occurrences.some(item => item.node === source.local) ? source : undefined
134
+ }
135
+ const read = (path, source) => `${reader}(import.meta.url,${JSON.stringify(source.source)},${JSON.stringify(source.imported)},()=>${path.node.name},${JSON.stringify(source.attributes)})`
136
+ const write = path => {
137
+ const source = sourceFor(path)
138
+ if (source === undefined) return
139
+ const value = allocate('module_import_value')
140
+ // Read-modify-write observes the logical value and its coercion effects,
141
+ // then delegates the forbidden import write to its native binding.
142
+ edits.push({ start: path.node.start, end: path.node.end,
143
+ text: `({get v(){return ${read(path, source)}},set v(${value}){${path.node.name}=${value}}}).v` })
144
+ }
145
+ visitSource(tree, {
146
+ AssignmentExpression(path) { if (path.node.operator !== '=' && path.node.left.type === 'Identifier') write(path.get('left')) },
147
+ UpdateExpression(path) { if (path.node.argument.type === 'Identifier') write(path.get('argument')) },
148
+ ReferencedIdentifier(path) {
149
+ const source = sourceFor(path)
150
+ if (source === undefined || path.parentPath.isExportSpecifier() || path.parentPath.isUpdateExpression()
151
+ || (path.parentPath.isForInStatement() || path.parentPath.isForOfStatement()) && path.key === 'left') return
152
+ const value = `(${read(path, source)})`
153
+ edits.push({ start: path.node.start, end: path.node.end,
154
+ text: path.parentPath.isObjectProperty({ shorthand: true }) ? `[${JSON.stringify(path.node.name)}]:${value}` : value })
155
+ },
156
+ })
157
+ const runtime = new URL('./stateful-module-runtime.js', import.meta.url).href
158
+ for (const [name, source] of imported) {
159
+ const physicalName = allocate('module_import_cell')
160
+ const value = allocate('module_import_value')
161
+ const get = `${reader}(import.meta.url,${JSON.stringify(source.source)},${JSON.stringify(source.imported)},()=>${name},${JSON.stringify(source.attributes)})`
162
+ accessors.push(`function ${physicalName}(){return {get v(){return ${get}},set v(${value}){${name}=${value}}}}`)
163
+ dynamicBindings.push({ name, physicalName, kind: 'module', accessor: true, property: 'v' })
164
+ }
165
+ edits.push({ start: 0, end: 0,
166
+ text: `import {readModuleImport as ${reader}} from ${JSON.stringify(runtime)};\n${accessors.join('\n')}\n` })
167
+ return { ...applyRegionEdits(normalized, edits),
168
+ moduleInterface: { exports, stars }, dynamicBindings: [...normalized.dynamicBindings ?? [], ...dynamicBindings],
169
+ internalBindings: new Set([...normalized.internalBindings ?? [], reader, ...imported.keys()]) }
170
+ }