dsh-ptc-plus 0.2.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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/README.zh.md +137 -0
  4. package/assets/dsh-ptc-plus-banner.webp +0 -0
  5. package/assets/ptc-plus-repair.png +0 -0
  6. package/assets/ptc-plus-settings.png +0 -0
  7. package/client.js +366 -0
  8. package/cordis.patch.yml +5 -0
  9. package/docs/README.md +21 -0
  10. package/docs/adr/0001-delegate-governance-to-dsh.md +3 -0
  11. package/docs/adr/0002-limit-work-map-scope.md +3 -0
  12. package/docs/adr/0003-prefer-native-program-surfaces.md +3 -0
  13. package/docs/adr/0004-declare-program-bindings-at-the-host.md +5 -0
  14. package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +129 -0
  15. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +45 -0
  16. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +39 -0
  17. package/docs/adr/0008-define-agent-operating-contract.md +25 -0
  18. package/docs/adr/0009-bound-expensive-acceptance-default.md +39 -0
  19. package/docs/adr/0010-session-log-derived-recovery-tips.md +26 -0
  20. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +20 -0
  21. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +23 -0
  22. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +21 -0
  23. package/docs/adr/0014-persist-cell-rewrite-policy.md +25 -0
  24. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +25 -0
  25. package/docs/adr/0016-archive-resolved-review-findings.md +43 -0
  26. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +23 -0
  27. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +25 -0
  28. package/docs/adr/0019-plugin-settings-and-kill-switch.md +32 -0
  29. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +36 -0
  30. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +68 -0
  31. package/docs/adr/README.md +18 -0
  32. package/docs/architecture.md +134 -0
  33. package/docs/capability-projection.md +48 -0
  34. package/docs/client-ui.md +47 -0
  35. package/docs/durability-design.md +265 -0
  36. package/docs/evaluation.md +62 -0
  37. package/docs/installation.md +82 -0
  38. package/docs/program-data-plane.md +61 -0
  39. package/docs/publishing.md +37 -0
  40. package/docs/runtime-reference.md +119 -0
  41. package/docs/value-wire.md +61 -0
  42. package/index.js +532 -0
  43. package/internal/ast-traversal.js +20 -0
  44. package/internal/binding-descriptors.js +95 -0
  45. package/internal/binding-pattern.js +54 -0
  46. package/internal/builtin-esm-sync.js +9 -0
  47. package/internal/cell-analysis.js +467 -0
  48. package/internal/cell-rewriter.js +520 -0
  49. package/internal/config-spec.js +179 -0
  50. package/internal/cordis-tools-owner.js +363 -0
  51. package/internal/diagnostic.js +133 -0
  52. package/internal/direct-surface-owner.js +326 -0
  53. package/internal/edit-transport-owner.js +287 -0
  54. package/internal/failure-reporting.js +139 -0
  55. package/internal/kernel-worker.js +484 -0
  56. package/internal/module-policy.js +46 -0
  57. package/internal/program-bindings.js +187 -0
  58. package/internal/record-utils.js +53 -0
  59. package/internal/recovery-tips.js +81 -0
  60. package/internal/rejected-cell-editor.js +328 -0
  61. package/internal/repl-convenience.js +201 -0
  62. package/internal/runtime-bridge-owner.js +417 -0
  63. package/internal/runtime-config.js +77 -0
  64. package/internal/runtime-contexts.js +31 -0
  65. package/internal/sdk-projection.js +88 -0
  66. package/internal/session-cell-executor.js +612 -0
  67. package/internal/session-journal.js +889 -0
  68. package/internal/session-log-view.js +80 -0
  69. package/internal/session-runtime.js +536 -0
  70. package/internal/session-state.js +45 -0
  71. package/internal/source-position-map.js +224 -0
  72. package/internal/tool-call-canonicalizer.js +339 -0
  73. package/internal/value-wire.js +421 -0
  74. package/internal/worker-client.js +218 -0
  75. package/internal/worker-cwd-virtualization.js +155 -0
  76. package/package.json +100 -0
  77. package/src/client.js +165 -0
@@ -0,0 +1,54 @@
1
+ /** Shared binding-pattern traversal used by cell analysis and REPL policy code. */
2
+
3
+ export function walkBindingPattern(pattern, visit) {
4
+ if (pattern === null || typeof pattern !== 'object') return
5
+ if (pattern.type === 'Identifier') {
6
+ visit(pattern)
7
+ return
8
+ }
9
+ if (pattern.type === 'RestElement') return walkBindingPattern(pattern.argument, visit)
10
+ if (pattern.type === 'AssignmentPattern') return walkBindingPattern(pattern.left, visit)
11
+ if (pattern.type === 'ArrayPattern') {
12
+ for (const element of pattern.elements) walkBindingPattern(element, visit)
13
+ return
14
+ }
15
+ if (pattern.type === 'ObjectPattern') {
16
+ for (const property of pattern.properties) {
17
+ walkBindingPattern(property.type === 'RestElement' ? property.argument : property.value, visit)
18
+ }
19
+ }
20
+ }
21
+
22
+ export function bindingNodes(pattern) {
23
+ const nodes = []
24
+ walkBindingPattern(pattern, node => nodes.push(node))
25
+ return nodes
26
+ }
27
+
28
+ /** Allocate private identifiers outside both source and caller-owned name sets. */
29
+ export function createGeneratedNameAllocator(root, unavailableNames = []) {
30
+ const used = new Set(unavailableNames)
31
+ const seen = new Set()
32
+ const pending = [root]
33
+ while (pending.length > 0) {
34
+ const value = pending.pop()
35
+ if (value === null || typeof value !== 'object' || seen.has(value)) continue
36
+ seen.add(value)
37
+ if (value.type === 'Identifier') used.add(value.name)
38
+ for (const child of Object.values(value)) {
39
+ if (Array.isArray(child)) pending.push(...child)
40
+ else if (child !== null && typeof child === 'object') pending.push(child)
41
+ }
42
+ }
43
+ const sequences = new Map()
44
+ return (purpose) => {
45
+ let sequence = sequences.get(purpose) ?? 0
46
+ let name
47
+ do {
48
+ name = `__dsh_ptc_${purpose}_${sequence++}__`
49
+ } while (used.has(name))
50
+ sequences.set(purpose, sequence)
51
+ used.add(name)
52
+ return name
53
+ }
54
+ }
@@ -0,0 +1,9 @@
1
+ import { syncBuiltinESMExports } from 'node:module'
2
+
3
+ export function synchronizeBuiltinEsmExports(sync = syncBuiltinESMExports) {
4
+ try {
5
+ sync()
6
+ } catch (cause) {
7
+ throw new Error('ptc-plus: failed to synchronize patched Node filesystem exports', { cause })
8
+ }
9
+ }
@@ -0,0 +1,467 @@
1
+ import { stripTypeScriptTypes } from 'node:module'
2
+ import { parse } from 'acorn'
3
+ import {
4
+ STRIP_PREFIX,
5
+ STRIP_SUFFIX,
6
+ rewriteModuleImportsExports,
7
+ } from './cell-rewriter.js'
8
+ import {
9
+ bindingNodes,
10
+ createGeneratedNameAllocator,
11
+ walkBindingPattern as walkPattern,
12
+ } from './binding-pattern.js'
13
+ import {
14
+ AMBIENT_GLOBALS,
15
+ DYNAMIC_MODULE_REASON,
16
+ classifyModuleSource,
17
+ renderDurabilityReason,
18
+ renderDurabilityReasons,
19
+ } from './module-policy.js'
20
+ import { rewriteLooseRedeclarations } from './repl-convenience.js'
21
+ import { applySourceEdits, mapSourceSpan } from './source-position-map.js'
22
+ import { SKIP_AST_CHILDREN, walkAst } from './ast-traversal.js'
23
+
24
+ /**
25
+ * Pure AST analysis for PTC cells: binding inventory, durability classification,
26
+ * return rewriting, and program preparation. This module owns no worker, journal,
27
+ * or session state so its behavior is fully testable in isolation.
28
+ */
29
+
30
+ export function declarationSpan(node) {
31
+ const start = node.loc?.start
32
+ /* c8 ignore next */
33
+ const end = node.loc?.end ?? start
34
+ /* c8 ignore next */
35
+ if (start === undefined) return undefined
36
+ return {
37
+ line: Math.max(1, start.line - 1),
38
+ column: start.column + 1,
39
+ /* c8 ignore next */
40
+ ...(end === undefined ? {} : {
41
+ end: {
42
+ line: Math.max(1, end.line - 1),
43
+ column: end.column + 1,
44
+ },
45
+ }),
46
+ }
47
+ }
48
+
49
+ function addPatternBindings(pattern, names) {
50
+ walkPattern(pattern, node => names.add(node.name))
51
+ }
52
+
53
+ function addPatternDeclarations(pattern, declarations) {
54
+ bindingNodes(pattern).forEach(node => declarations.push({
55
+ name: node.name,
56
+ span: declarationSpan(node),
57
+ }))
58
+ }
59
+
60
+ function topLevelBindings(body) {
61
+ return new Set(topLevelDeclarations(body).map(declaration => declaration.name))
62
+ }
63
+
64
+ function topLevelDeclarations(body) {
65
+ const declarations = []
66
+ for (const statement of body) {
67
+ if (statement.type === 'VariableDeclaration') {
68
+ for (const declaration of statement.declarations) addPatternDeclarations(declaration.id, declarations)
69
+ } else if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration')
70
+ && statement.id !== null) {
71
+ declarations.push({
72
+ name: statement.id.name,
73
+ span: declarationSpan(statement.id),
74
+ })
75
+ }
76
+ }
77
+ return declarations
78
+ }
79
+
80
+ function directBlockBindings(body) {
81
+ const names = new Set()
82
+ for (const statement of body) {
83
+ if (statement.type === 'VariableDeclaration' && statement.kind !== 'var') {
84
+ for (const declaration of statement.declarations) addPatternBindings(declaration.id, names)
85
+ } else if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration')
86
+ && statement.id !== null) {
87
+ names.add(statement.id.name)
88
+ }
89
+ }
90
+ return names
91
+ }
92
+
93
+ function functionBindings(node) {
94
+ const names = new Set()
95
+ if (node.id !== null && node.id !== undefined) names.add(node.id.name)
96
+ /* c8 ignore next */
97
+ for (const param of node.params ?? []) addPatternBindings(param, names)
98
+ walkAst(node.body, (current) => {
99
+ if (current !== node && isFunction(current)) {
100
+ if (current.type === 'FunctionDeclaration' && current.id !== null) names.add(current.id.name)
101
+ return SKIP_AST_CHILDREN
102
+ }
103
+ if (current.type === 'VariableDeclaration' && current.kind === 'var') {
104
+ for (const declaration of current.declarations) addPatternBindings(declaration.id, names)
105
+ }
106
+ })
107
+ return names
108
+ }
109
+
110
+ function loopBindings(node) {
111
+ const declaration = node.type === 'ForStatement' ? node.init : node.left
112
+ if (declaration?.type !== 'VariableDeclaration' || declaration.kind === 'var') return new Set()
113
+ const names = new Set()
114
+ for (const entry of declaration.declarations) addPatternBindings(entry.id, names)
115
+ return names
116
+ }
117
+
118
+ function isReferenceIdentifier(node, parent, key) {
119
+ /* c8 ignore next */
120
+ if (parent === undefined) return false
121
+ if ((parent.type === 'MemberExpression' || parent.type === 'OptionalMemberExpression')
122
+ && key === 'property' && !parent.computed) return false
123
+ if ((parent.type === 'Property' || parent.type === 'MethodDefinition' || parent.type === 'PropertyDefinition')
124
+ && key === 'key' && !parent.computed && !parent.shorthand) return false
125
+ if (['VariableDeclarator', 'FunctionDeclaration', 'FunctionExpression', 'ClassDeclaration', 'ClassExpression']
126
+ .includes(parent.type) && key === 'id') return false
127
+ if ((parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ArrowFunctionExpression')
128
+ && key === 'params') return false
129
+ if (parent.type === 'CatchClause' && key === 'param') return false
130
+ if (['LabeledStatement', 'BreakStatement', 'ContinueStatement'].includes(parent.type) && key === 'label') return false
131
+ return true
132
+ }
133
+
134
+ function isStableProcessMember(node, parent) {
135
+ /* c8 ignore next */
136
+ if (node.name !== 'process' || parent?.type !== 'MemberExpression' || parent.object !== node) return false
137
+ const member = parent.computed
138
+ ? parent.property?.type === 'Literal' ? parent.property.value : undefined
139
+ /* c8 ignore next */
140
+ : parent.property?.type === 'Identifier' ? parent.property.name : undefined
141
+ return ['stdout', 'stderr', 'cwd'].includes(member)
142
+ }
143
+
144
+ function staticMemberName(node) {
145
+ if (node?.type !== 'MemberExpression') return undefined
146
+ if (!node.computed && node.property?.type === 'Identifier') return node.property.name
147
+ if (node.computed && node.property?.type === 'Literal' && typeof node.property.value === 'string') {
148
+ return node.property.value
149
+ }
150
+ return undefined
151
+ }
152
+
153
+ function globalThisMember(node) {
154
+ return node?.type === 'MemberExpression'
155
+ && node.object?.type === 'Identifier'
156
+ && node.object.name === 'globalThis'
157
+ ? staticMemberName(node)
158
+ : undefined
159
+ }
160
+
161
+ function isFunction(node) {
162
+ return node.type === 'FunctionDeclaration'
163
+ || node.type === 'FunctionExpression'
164
+ || node.type === 'ArrowFunctionExpression'
165
+ }
166
+
167
+ export class PreflightError extends Error {
168
+ constructor(message, node, span = undefined) {
169
+ super(message)
170
+ this.span = span ?? declarationSpan(node)
171
+ }
172
+ }
173
+
174
+ function staticModuleClassification(moduleLoads) {
175
+ const reasons = new Map()
176
+ for (const load of moduleLoads) {
177
+ const classification = classifyModuleSource(load.source)
178
+ if (classification.status === 'forbidden') {
179
+ throw new PreflightError(
180
+ `cell import of ${load.source} is forbidden because it exposes kernel control`,
181
+ undefined,
182
+ load.position,
183
+ )
184
+ }
185
+ if (classification.reason !== undefined) {
186
+ reasons.set(renderDurabilityReason(classification.reason), classification.reason)
187
+ }
188
+ }
189
+ return [...reasons.values()]
190
+ }
191
+
192
+ /** Conservatively classify a cell before giving it non-journalable capability. */
193
+ export function classifyDurability(code, knownBindings = new Set()) {
194
+ const tree = parse(`${STRIP_PREFIX}${code}${STRIP_SUFFIX}`, { ecmaVersion: 'latest', sourceType: 'script', locations: true })
195
+ const outer = tree.body[0]
196
+ /* c8 ignore next */
197
+ if (outer?.type !== 'FunctionDeclaration') throw new Error('ptc-plus: failed to parse cell wrapper')
198
+ const declared = topLevelBindings(outer.body.body)
199
+ const rootBindings = new Set([...knownBindings, ...declared])
200
+ const reasons = new Map()
201
+ const addReason = reason => reasons.set(renderDurabilityReason(reason), reason)
202
+ const classifyModule = (source) => {
203
+ if (source?.type !== 'Literal' || typeof source.value !== 'string') {
204
+ addReason(DYNAMIC_MODULE_REASON)
205
+ return
206
+ }
207
+ const classification = classifyModuleSource(source.value)
208
+ if (classification.status === 'forbidden') {
209
+ throw new PreflightError(`cell import of ${source.value} is forbidden because it exposes kernel control`, source)
210
+ }
211
+ if (classification.reason !== undefined) addReason(classification.reason)
212
+ }
213
+ const isBound = (name, scopes) => {
214
+ for (let index = scopes.length - 1; index >= 0; index -= 1) {
215
+ if (scopes[index].has(name)) return true
216
+ }
217
+ return false
218
+ }
219
+ walkAst(outer.body, (node, parent, parentKey, scopes) => {
220
+ let nestedScopes = scopes
221
+ if (isFunction(node)) {
222
+ nestedScopes = [...scopes, functionBindings(node)]
223
+ } else if (node.type === 'BlockStatement' && node !== outer.body) {
224
+ nestedScopes = [...scopes, directBlockBindings(node.body)]
225
+ } else if (node.type === 'CatchClause') {
226
+ const names = new Set()
227
+ addPatternBindings(node.param, names)
228
+ nestedScopes = [...scopes, names]
229
+ } else if (['ForStatement', 'ForInStatement', 'ForOfStatement'].includes(node.type)) {
230
+ nestedScopes = [...scopes, loopBindings(node)]
231
+ }
232
+ if (node.type === 'ImportExpression') {
233
+ classifyModule(node.source)
234
+ }
235
+ if (node.type === 'CallExpression' && node.callee?.type === 'Identifier' && node.callee.name === 'require'
236
+ && !isBound('require', nestedScopes)) {
237
+ classifyModule(node.arguments[0])
238
+ }
239
+ if (node.type === 'Identifier' && isReferenceIdentifier(node, parent, parentKey)
240
+ && !isBound(node.name, nestedScopes) && AMBIENT_GLOBALS.has(node.name)
241
+ && !(node.name === 'require' && parent?.type === 'CallExpression' && parent.callee === node)) {
242
+ addReason(Object.freeze({ kind: 'ambient', name: node.name }))
243
+ }
244
+ if (node.type === 'Identifier' && isReferenceIdentifier(node, parent, parentKey)
245
+ && !isBound('process', nestedScopes) && node.name === 'process' && !isStableProcessMember(node, parent)) {
246
+ addReason(Object.freeze({ kind: 'ambient', name: 'process' }))
247
+ }
248
+ if (node.type === 'MemberExpression'
249
+ && ((node.object?.type === 'Identifier' && node.object.name === 'Math' && !isBound('Math', nestedScopes))
250
+ || (globalThisMember(node.object) === 'Math' && !isBound('globalThis', nestedScopes)))
251
+ && staticMemberName(node) === 'random') {
252
+ addReason(Object.freeze({ kind: 'math-random' }))
253
+ }
254
+ if (node.type === 'MemberExpression' && node.object?.type === 'Identifier'
255
+ && node.object.name === 'globalThis' && !isBound('globalThis', nestedScopes)) {
256
+ const member = staticMemberName(node)
257
+ if (member === undefined) addReason(Object.freeze({ kind: 'computed-global-access' }))
258
+ else if (member === 'process') addReason(Object.freeze({ kind: 'ambient', name: 'process' }))
259
+ else if (AMBIENT_GLOBALS.has(member)) addReason(Object.freeze({ kind: 'ambient', name: member }))
260
+ }
261
+ return nestedScopes
262
+ }, undefined, [rootBindings], outer, 'body')
263
+ return {
264
+ durability: reasons.size === 0 ? 'durable' : 'volatile',
265
+ reasons: Object.freeze([...reasons.values()]),
266
+ declared,
267
+ }
268
+ }
269
+
270
+ function rewriteCellReturns(code, sourceMap, unavailableNames) {
271
+ const wrapped = STRIP_PREFIX + code + STRIP_SUFFIX
272
+ const tree = parse(wrapped, { ecmaVersion: 'latest', sourceType: 'script' })
273
+ const outer = tree.body[0]
274
+ /* c8 ignore next */
275
+ if (outer?.type !== 'FunctionDeclaration') throw new Error('ptc-plus: failed to parse cell wrapper')
276
+ const offset = STRIP_PREFIX.length
277
+ const edits = []
278
+ const allocateName = createGeneratedNameAllocator(tree, unavailableNames)
279
+ const returnSignal = allocateName('return_signal')
280
+ const signalReference = `this[${JSON.stringify(returnSignal)}]`
281
+
282
+ walkAst(outer.body, (node) => {
283
+ if (node !== outer.body && isFunction(node)) return SKIP_AST_CHILDREN
284
+ if (node.type === 'ReturnStatement') {
285
+ const start = node.start - offset
286
+ const end = node.end - offset
287
+ const argument = node.argument === null
288
+ ? ''
289
+ : code.slice(node.argument.start - offset, node.argument.end - offset)
290
+ // A ReturnStatement may be the last clause body in a switch case. The
291
+ // generated throw must terminate explicitly because the original return
292
+ // statement's semicolon is part of the replaced AST range.
293
+ edits.push({ start, end, text: `throw new ${signalReference}(${argument});` })
294
+ return SKIP_AST_CHILDREN
295
+ }
296
+ if (node.type === 'CatchClause') {
297
+ const bodyStart = node.body.start - offset + 1
298
+ const temporary = allocateName('caught')
299
+ if (node.param === null) {
300
+ edits.push({ start: node.start - offset + 5, end: node.start - offset + 5, text: ` (${temporary})` })
301
+ edits.push({ start: bodyStart, end: bodyStart, text: `\nif (${temporary} instanceof ${signalReference}) throw ${temporary};` })
302
+ } else if (node.param.type === 'Identifier') {
303
+ edits.push({
304
+ start: bodyStart,
305
+ end: bodyStart,
306
+ text: `\nif (${node.param.name} instanceof ${signalReference}) throw ${node.param.name};`,
307
+ })
308
+ } else {
309
+ const pattern = code.slice(node.param.start - offset, node.param.end - offset)
310
+ edits.push({ start: node.param.start - offset, end: node.param.end - offset, text: temporary })
311
+ edits.push({
312
+ start: bodyStart,
313
+ end: bodyStart,
314
+ text: `\nif (${temporary} instanceof ${signalReference}) throw ${temporary};\nconst ${pattern} = ${temporary};`,
315
+ })
316
+ }
317
+ }
318
+ })
319
+
320
+ /* c8 ignore next */
321
+ edits.sort((left, right) => right.start - left.start || right.end - left.end)
322
+ return { ...applySourceEdits(code, sourceMap, edits), returnSignal }
323
+ }
324
+
325
+ export function prepareProgram(program, knownBindings, looseTopLevelRedeclarations, reservedBindings = new Set(), rewritesEnabled, importBindings = new Map(), importNamespaces = new Set()) {
326
+ if (typeof program !== 'string') throw new TypeError('ptc-plus: program must be a string')
327
+ if (rewritesEnabled === null || typeof rewritesEnabled !== 'object' || Array.isArray(rewritesEnabled)
328
+ || typeof rewritesEnabled.autoRewriteImports !== 'boolean'
329
+ || typeof rewritesEnabled.autoStripExports !== 'boolean'
330
+ || typeof rewritesEnabled.autoSplitRedeclarations !== 'boolean') {
331
+ throw new TypeError('ptc-plus: rewrite policy must define autoRewriteImports, autoStripExports, and autoSplitRedeclarations booleans')
332
+ }
333
+ const unavailableGeneratedNames = new Set([
334
+ ...knownBindings,
335
+ ...reservedBindings,
336
+ ...importBindings.keys(),
337
+ ...importNamespaces,
338
+ ])
339
+ const moduleRewrite = rewriteModuleImportsExports(
340
+ program,
341
+ rewritesEnabled,
342
+ importBindings,
343
+ importNamespaces,
344
+ unavailableGeneratedNames,
345
+ )
346
+ const staticModuleReasons = staticModuleClassification(moduleRewrite.moduleLoads)
347
+ const wrapped = STRIP_PREFIX + moduleRewrite.code + STRIP_SUFFIX
348
+ let stripped = wrapped
349
+ let tree
350
+ try {
351
+ tree = parse(wrapped, { ecmaVersion: 'latest', sourceType: 'script', locations: true })
352
+ } catch (javascriptError) {
353
+ try {
354
+ stripped = stripTypeScriptTypes(wrapped)
355
+ tree = parse(stripped, { ecmaVersion: 'latest', sourceType: 'script', locations: true })
356
+ } catch {
357
+ throw javascriptError
358
+ }
359
+ }
360
+ const code = stripped.slice(STRIP_PREFIX.length, stripped.length - STRIP_SUFFIX.length)
361
+ const sourceMap = moduleRewrite.sourceMap
362
+ const outer = tree.body[0]
363
+ /* c8 ignore next */
364
+ const generatedDeclarations = outer?.type === 'FunctionDeclaration' ? topLevelDeclarations(outer.body.body) : []
365
+ const collisionFor = (declaration) => {
366
+ /* c8 ignore next */
367
+ const mapped = declaration.original === true ? declaration.span : declaration.span === undefined
368
+ ? { line: 1, column: 1 }
369
+ : mapSourceSpan(declaration.span, code, program, sourceMap)
370
+ return {
371
+ name: declaration.name,
372
+ start: { line: mapped.line, column: mapped.column },
373
+ /* c8 ignore next */
374
+ ...(mapped.end === undefined ? {} : { end: mapped.end }),
375
+ }
376
+ }
377
+ const classifyPrepared = (preparedCode, preparedSourceMap) => {
378
+ try {
379
+ const classification = classifyDurability(preparedCode, knownBindings)
380
+ const reasons = new Map()
381
+ for (const reason of [...staticModuleReasons, ...classification.reasons]) {
382
+ reasons.set(renderDurabilityReason(reason), reason)
383
+ }
384
+ return {
385
+ ...classification,
386
+ durability: reasons.size === 0 ? 'durable' : 'volatile',
387
+ reasons: Object.freeze([...reasons.values()]),
388
+ reason: renderDurabilityReasons([...reasons.values()]),
389
+ }
390
+ } catch (error) {
391
+ if (error instanceof PreflightError && error.span !== undefined) {
392
+ error.span = mapSourceSpan(error.span, preparedCode, program, preparedSourceMap)
393
+ }
394
+ throw error
395
+ }
396
+ }
397
+ const importedNames = new Set(moduleRewrite.imports.keys())
398
+ const declarations = [
399
+ ...moduleRewrite.importDeclarations,
400
+ ...generatedDeclarations.filter(declaration => !moduleRewrite.generatedNamespaces.has(declaration.name)),
401
+ ]
402
+ const normalizeClassification = classification => {
403
+ const imports = new Map(moduleRewrite.imports)
404
+ for (const name of classification.declared) {
405
+ if (!moduleRewrite.generatedNamespaces.has(name)) imports.delete(name)
406
+ }
407
+ return {
408
+ ...classification,
409
+ imports,
410
+ declared: new Set([...classification.declared, ...importedNames]),
411
+ }
412
+ }
413
+ const reserved = declarations.filter(declaration => (
414
+ reservedBindings.has(declaration.name) || moduleRewrite.importNamespaces.has(declaration.name)
415
+ ))
416
+ if (reserved.length > 0) {
417
+ const classification = normalizeClassification(classifyPrepared(code, sourceMap))
418
+ return {
419
+ code,
420
+ ...classification,
421
+ declarations,
422
+ imports: classification.imports,
423
+ importNamespaces: moduleRewrite.importNamespaces,
424
+ collisions: reserved.map(collisionFor),
425
+ redeclared: [],
426
+ rewrites: moduleRewrite.rewrites,
427
+ moduleLoads: moduleRewrite.moduleLoads,
428
+ }
429
+ }
430
+ const convenience = rewriteLooseRedeclarations({
431
+ code,
432
+ sourceMap,
433
+ body: looseTopLevelRedeclarations && outer?.type === 'FunctionDeclaration' ? outer.body.body : undefined,
434
+ offset: STRIP_PREFIX.length,
435
+ knownBindings: new Set([...knownBindings].filter(name => !importBindings.has(name))),
436
+ declarations,
437
+ declarationSpan,
438
+ collisionFor,
439
+ autoSplitRedeclarations: rewritesEnabled.autoSplitRedeclarations,
440
+ })
441
+ const { executableCode, executableSourceMap, collisions, redeclared, rewrites } = convenience
442
+ // Classification sees the rewritten program so declared bindings reflect the
443
+ // split form; it must never see the return rewrite, whose computed
444
+ // globalThis access would mark every returning cell volatile.
445
+ const classification = normalizeClassification(classifyPrepared(executableCode, executableSourceMap))
446
+ let lowered = { code, sourceMap }
447
+ if (collisions.length === 0) {
448
+ lowered = rewriteCellReturns(
449
+ executableCode,
450
+ executableSourceMap,
451
+ unavailableGeneratedNames,
452
+ )
453
+ }
454
+ return {
455
+ code: lowered.code,
456
+ sourceMap: lowered.sourceMap,
457
+ ...(lowered.returnSignal === undefined ? {} : { returnSignal: lowered.returnSignal }),
458
+ ...classification,
459
+ declarations,
460
+ imports: classification.imports,
461
+ importNamespaces: moduleRewrite.importNamespaces,
462
+ collisions,
463
+ redeclared,
464
+ rewrites: [...moduleRewrite.rewrites, ...rewrites],
465
+ moduleLoads: moduleRewrite.moduleLoads,
466
+ }
467
+ }