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,50 @@
1
+ /** Historical legacy-v1 cell grammar, retained from c51616c8d6c8:cell-parser.js. */
2
+ import { stripTypeScriptTypes } from 'node:module'
3
+ import { getLineInfo, parse } from 'acorn'
4
+ import { walkAst } from './ast-traversal.js'
5
+ import { ModuleRewriteError } from './cell-rewriter.js'
6
+
7
+ const CELL_PREFIX = 'async function __ptc_cell__(){\n'
8
+ const CELL_SUFFIX = '\n}'
9
+ const PARSER_OPTIONS = { ecmaVersion: 'latest', sourceType: 'script', locations: true }
10
+
11
+ /** Parse the async body once and expose only cell-relative source coordinates. */
12
+ export function parseExecutableCell(source, { eraseTypes = false } = {}) {
13
+ const wrapped = CELL_PREFIX + source + CELL_SUFFIX
14
+ let executable = wrapped
15
+ let tree
16
+ try {
17
+ tree = parse(executable, PARSER_OPTIONS)
18
+ } catch (javascriptError) {
19
+ if (eraseTypes) {
20
+ try {
21
+ executable = stripTypeScriptTypes(wrapped)
22
+ tree = parse(executable, PARSER_OPTIONS)
23
+ } catch {
24
+ tree = undefined
25
+ }
26
+ }
27
+ if (tree === undefined) {
28
+ const offset = Math.max(0, Math.min(source.length, javascriptError.pos - CELL_PREFIX.length))
29
+ const position = getLineInfo(source, offset)
30
+ throw new ModuleRewriteError(javascriptError.message.replace(/ \(\d+:\d+\)$/, ''),
31
+ { line: position.line, column: position.column + 1 })
32
+ }
33
+ }
34
+ const code = executable.slice(CELL_PREFIX.length, -CELL_SUFFIX.length)
35
+ const body = tree.body[0].body
36
+ walkAst(body, node => {
37
+ if (typeof node.start !== 'number') return
38
+ node.start -= CELL_PREFIX.length
39
+ node.end -= CELL_PREFIX.length
40
+ node.loc = {
41
+ start: { line: node.loc.start.line - 1, column: node.loc.start.column },
42
+ end: { line: node.loc.end.line - 1, column: node.loc.end.column },
43
+ }
44
+ })
45
+ body.start = 0
46
+ body.end = code.length
47
+ body.loc.start = getLineInfo(code, 0)
48
+ body.loc.end = getLineInfo(code, code.length)
49
+ return { code, body }
50
+ }
@@ -0,0 +1,631 @@
1
+ /** Historical legacy-v1 lowering, retained from c51616c8d6c8:cell-rewriter.js. */
2
+ /** Adapts TypeScript module declarations to the async function-body grammar used by PTC cells. */
3
+ import { parse } from '@babel/parser'
4
+ import traverseModule, { Hub, NodePath } from '@babel/traverse'
5
+ import { bindingNodes, createGeneratedNameAllocator } from './binding-pattern.js'
6
+ import { applySourceEdits, createMappedTextBuilder, identitySourceMap } from './source-position-map.js'
7
+ import {
8
+ LEGACY_DEFAULT_EXPORT_BINDING,
9
+ LEGACY_IMPORT_EXPRESSION_BOUNDARY,
10
+ LIVE_DEFAULT_EXPORT_BINDING,
11
+ LIVE_IMPORT_EXPRESSION_BOUNDARY,
12
+ LIVE_MODULE_SEMANTICS,
13
+ } from './repl-rewrite-contract.js'
14
+
15
+ import { ModuleRewriteError } from './cell-rewriter.js'
16
+ export { ModuleRewriteError }
17
+
18
+ const PARSER_PLUGINS = ['typescript', 'importAttributes']
19
+ const TYPE_DECLARATIONS = new Set([
20
+ 'TSDeclareFunction',
21
+ 'TSEnumDeclaration',
22
+ 'TSInterfaceDeclaration',
23
+ 'TSModuleDeclaration',
24
+ 'TSTypeAliasDeclaration',
25
+ ])
26
+ const traverse = traverseModule.default ?? traverseModule
27
+
28
+ function declaredTypeNames(program) {
29
+ const names = new Set()
30
+ for (const node of program.body) {
31
+ const declaration = node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration'
32
+ ? node.declaration
33
+ : node
34
+ if (TYPE_DECLARATIONS.has(declaration?.type) && declaration.id?.type === 'Identifier') {
35
+ names.add(declaration.id.name)
36
+ }
37
+ }
38
+ return names
39
+ }
40
+
41
+ function createProgramScope(file) {
42
+ const hub = new Hub()
43
+ hub.buildError = (node, message, ErrorType = TypeError) => {
44
+ const error = new ErrorType(message)
45
+ error.loc = node.loc?.start
46
+ return error
47
+ }
48
+ const path = NodePath.get({ hub, parent: file, container: file, key: 'program' })
49
+ path.setContext()
50
+ path.scope = path.getScope()
51
+ path.scope.init()
52
+ return path.scope
53
+ }
54
+
55
+ function validateLocalExports(file, programScope) {
56
+ const localExports = file.program.body.filter(node => node.type === 'ExportNamedDeclaration'
57
+ && node.source === null && node.declaration === null)
58
+ const valueSpecifiers = localExports.flatMap(node => node.specifiers
59
+ .filter(specifier => specifier.exportKind !== 'type'))
60
+ if (valueSpecifiers.length === 0) return
61
+ const typeNames = declaredTypeNames(file.program)
62
+ const missing = valueSpecifiers.find(specifier => (
63
+ programScope.getBinding(specifier.local.name) === undefined && !typeNames.has(specifier.local.name)
64
+ ))
65
+ if (missing === undefined) return
66
+ throw new ModuleRewriteError(`Export '${missing.local.name}' is not defined.`, {
67
+ line: missing.local.loc.start.line,
68
+ column: missing.local.loc.start.column + 1,
69
+ })
70
+ }
71
+
72
+ function parseCell(code) {
73
+ try {
74
+ const file = parse(code, {
75
+ sourceType: 'script',
76
+ allowAwaitOutsideFunction: true,
77
+ allowImportExportEverywhere: true,
78
+ allowReturnOutsideFunction: true,
79
+ allowUndeclaredExports: true,
80
+ plugins: PARSER_PLUGINS,
81
+ })
82
+ validateLocalExports(file, createProgramScope(file))
83
+ return file.program
84
+ } catch (error) {
85
+ if (error instanceof ModuleRewriteError) throw error
86
+ const loc = error?.loc
87
+ throw new ModuleRewriteError(error instanceof Error ? error.message : String(error),
88
+ Number.isSafeInteger(loc?.line) && Number.isSafeInteger(loc?.column)
89
+ ? { line: loc.line, column: loc.column + 1 }
90
+ : undefined)
91
+ }
92
+ }
93
+
94
+ function parseSource(node) { return node.source.value }
95
+ function importOptions(node) {
96
+ if (!node.attributes || node.attributes.length === 0) return undefined
97
+ const attributes = Object.fromEntries(node.attributes.map((attribute) => {
98
+ const key = attribute.key.type === 'Identifier' ? attribute.key.name : attribute.key.value
99
+ return [key, attribute.value.value]
100
+ }))
101
+ const keyword = node.attributes[0].type === 'ImportAttribute' ? 'with' : 'assert'
102
+ return { [keyword]: attributes }
103
+ }
104
+ function moduleLoad(node, source, global = undefined, requiredExports = []) {
105
+ return {
106
+ source,
107
+ ...(global === undefined ? {} : { global }),
108
+ ...(requiredExports.length === 0 ? {} : { requiredExports }),
109
+ ...(importOptions(node) === undefined ? {} : { options: importOptions(node) }),
110
+ position: {
111
+ line: node.source.loc.start.line,
112
+ column: node.source.loc.start.column + 1,
113
+ end: {
114
+ line: node.source.loc.end.line,
115
+ column: node.source.loc.end.column + 1,
116
+ },
117
+ },
118
+ }
119
+ }
120
+ function record(kind, description, node, source) {
121
+ return { kind, description, ...(source === undefined ? {} : { source }), at: node.start }
122
+ }
123
+ function preserveLines(original, replacement = '') {
124
+ const missing = (original.match(/\n/g)?.length ?? 0) - (replacement.match(/\n/g)?.length ?? 0)
125
+ return missing > 0 ? replacement + '\n'.repeat(missing) : replacement
126
+ }
127
+ function editNode(edits, node, code, replacement = '') {
128
+ const mapped = typeof replacement === 'string' ? { text: replacement } : replacement
129
+ const separated = node.end < code.length && code[node.end] !== '\n' && code[node.end] !== '\r'
130
+ ? `${mapped.text}\n`
131
+ : mapped.text
132
+ edits.push({
133
+ start: node.start,
134
+ end: node.end,
135
+ text: preserveLines(code.slice(node.start, node.end), separated),
136
+ ...(mapped.mappings === undefined ? {} : { mappings: mapped.mappings }),
137
+ })
138
+ }
139
+ function edit(edits, start, end, text) { edits.push({ start, end, text }) }
140
+ function localName(specifier) { return specifier.local.name }
141
+ function importedName(specifier) {
142
+ if (specifier.type === 'ImportDefaultSpecifier') return 'default'
143
+ if (specifier.type === 'ImportNamespaceSpecifier') return undefined
144
+ return specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value
145
+ }
146
+
147
+ function importEdits(
148
+ node,
149
+ code,
150
+ edits,
151
+ rewrites,
152
+ imports,
153
+ importDeclarations,
154
+ moduleLoads,
155
+ namespaceCaptures,
156
+ allocateNamespace,
157
+ allocateGlobal,
158
+ ) {
159
+ const source = parseSource(node)
160
+ const rewrite = record('import', `adapted the static import of ${JSON.stringify(source)} for REPL execution`, node, source)
161
+ if (node.importKind === 'type') {
162
+ editNode(edits, node, code)
163
+ rewrites.push(record('import', `removed the type-only import of ${JSON.stringify(source)}`, node, source))
164
+ return
165
+ }
166
+ if (node.specifiers.length > 0 && node.specifiers.every(specifier => specifier.importKind === 'type')) {
167
+ editNode(edits, node, code)
168
+ rewrites.push(record('import', `removed the type-only import of ${JSON.stringify(source)}`, node, source))
169
+ return
170
+ }
171
+ const specifiers = node.specifiers.filter(specifier => specifier.importKind !== 'type')
172
+ if (specifiers.length === 0) {
173
+ moduleLoads.push(moduleLoad(node, source))
174
+ editNode(edits, node, code)
175
+ rewrites.push(rewrite)
176
+ return
177
+ }
178
+ const namespace = allocateNamespace('import_namespace')
179
+ const global = allocateGlobal('import_global')
180
+ const requiredExports = []
181
+ for (const specifier of specifiers) {
182
+ const imported = importedName(specifier)
183
+ imports.set(localName(specifier), { namespace, imported })
184
+ if (imported !== undefined && !requiredExports.includes(imported)) requiredExports.push(imported)
185
+ importDeclarations.push({
186
+ name: localName(specifier),
187
+ kind: 'import',
188
+ span: {
189
+ line: specifier.local.loc.start.line,
190
+ column: specifier.local.loc.start.column + 1,
191
+ end: {
192
+ line: specifier.local.loc.end.line,
193
+ column: specifier.local.loc.end.column + 1,
194
+ },
195
+ },
196
+ definitionSpan: {
197
+ line: node.loc.start.line,
198
+ column: node.loc.start.column + 1,
199
+ end: {
200
+ line: node.loc.end.line,
201
+ column: node.loc.end.column + 1,
202
+ },
203
+ },
204
+ original: true,
205
+ })
206
+ }
207
+ moduleLoads.push(moduleLoad(node, source, global, requiredExports))
208
+ namespaceCaptures.push({ namespace, global, source: node.source })
209
+ editNode(edits, node, code)
210
+ rewrites.push(rewrite)
211
+ }
212
+
213
+ function importPrologueEdit(program, tree, namespaceCaptures) {
214
+ if (namespaceCaptures.length === 0) return undefined
215
+ const directive = tree.directives.at(-1)
216
+ let insertion = directive?.end ?? tree.interpreter?.end ?? 0
217
+ if (directive === undefined && tree.interpreter !== null && tree.interpreter !== undefined) {
218
+ if (program[insertion] === '\r' && program[insertion + 1] === '\n') insertion += 2
219
+ else if (program[insertion] === '\r' || program[insertion] === '\n') insertion += 1
220
+ }
221
+ const builder = createMappedTextBuilder(program)
222
+ if (directive !== undefined && program[insertion - 1] !== ';') builder.append(';')
223
+ for (const capture of namespaceCaptures) {
224
+ builder.append('const ')
225
+ builder.appendMapped(capture.namespace, capture.source.start, capture.source.end)
226
+ builder.append(' = ')
227
+ builder.appendMapped(capture.global, capture.source.start, capture.source.end)
228
+ builder.append(';')
229
+ }
230
+ return { start: insertion, end: insertion, ...builder.result() }
231
+ }
232
+
233
+ function importMember(namespace, imported) {
234
+ return imported === undefined ? namespace
235
+ : /^[A-Za-z_$][\w$]*$/.test(imported) ? `${namespace}.${imported}`
236
+ : `${namespace}[${JSON.stringify(imported)}]`
237
+ }
238
+
239
+ function appendReadonlyImportWrite(builder, appendValue) {
240
+ builder.append("((__dsh_ptc_import_value__) => { throw new TypeError('Assignment to constant variable.'); })(")
241
+ appendValue()
242
+ builder.append(')')
243
+ }
244
+
245
+ function importedBindingFor(path, identifier, imports) {
246
+ const binding = imports.get(identifier.name)
247
+ return binding !== undefined && path.scope.getBinding(identifier.name) === undefined ? binding : undefined
248
+ }
249
+
250
+ function importedWriteBinding(path, imports) {
251
+ if (path.isAssignmentExpression() && path.node.left.type === 'Identifier') {
252
+ return importedBindingFor(path, path.node.left, imports)
253
+ }
254
+ return undefined
255
+ }
256
+
257
+ function assertNoImportedWriteAncestor(path, imports) {
258
+ if (path.findParent(parent => importedWriteBinding(parent, imports) !== undefined) !== null) {
259
+ throw new ModuleRewriteError('nested assignment to an imported binding is not supported')
260
+ }
261
+ }
262
+
263
+ function preserveExpressionStatementBoundary(path, edits, boundary) {
264
+ const statement = path.findParent(parent => parent.isExpressionStatement())
265
+ if (statement?.node.expression.start === path.node.start
266
+ && (boundary !== LIVE_IMPORT_EXPRESSION_BOUNDARY || statement.inList)) {
267
+ edits.push({ start: path.node.start, end: path.node.start, text: ';' })
268
+ }
269
+ }
270
+
271
+ function assertNoDynamicImportResolution(tree, imports) {
272
+ if (imports.size === 0) return
273
+ traverse(tree, {
274
+ WithStatement() {
275
+ throw new ModuleRewriteError('with statement is not supported while imported bindings are active')
276
+ },
277
+ CallExpression(path) {
278
+ if (path.node.callee.type === 'Identifier' && path.node.callee.name === 'eval'
279
+ && !imports.has('eval') && path.scope.getBinding('eval') === undefined) {
280
+ throw new ModuleRewriteError('direct eval is not supported while imported bindings are active')
281
+ }
282
+ },
283
+ })
284
+ }
285
+
286
+ function rewriteImportReferences(code, sourceMap, imports, boundary) {
287
+ if (imports.size === 0) return { code, sourceMap }
288
+ const parseRewritten = source => parse(source, {
289
+ sourceType: 'script',
290
+ allowAwaitOutsideFunction: true,
291
+ allowReturnOutsideFunction: true,
292
+ plugins: PARSER_PLUGINS,
293
+ })
294
+ let file = parseRewritten(code)
295
+ const writeEdits = []
296
+ traverse(file, {
297
+ AssignmentExpression(path) {
298
+ if (path.node.left.type !== 'Identifier') {
299
+ const names = bindingNodes(path.node.left).map(node => node.name)
300
+ if (names.some(name => imports.has(name) && path.scope.getBinding(name) === undefined)) {
301
+ throw new ModuleRewriteError('destructuring assignment to an imported binding is not supported')
302
+ }
303
+ return
304
+ }
305
+ const binding = importedBindingFor(path, path.node.left, imports)
306
+ if (binding === undefined) return
307
+ assertNoImportedWriteAncestor(path, imports)
308
+ if (boundary === LIVE_IMPORT_EXPRESSION_BOUNDARY) preserveExpressionStatementBoundary(path, writeEdits, boundary)
309
+ const member = importMember(binding.namespace, binding.imported)
310
+ const builder = createMappedTextBuilder(code)
311
+ const appendMember = () => builder.appendMapped(member, path.node.left.start, path.node.left.end)
312
+ const appendRight = () => builder.appendSource(path.node.right.start, path.node.right.end)
313
+ if (path.node.operator === '=') appendReadonlyImportWrite(builder, appendRight)
314
+ else if (['&&=', '||=', '??='].includes(path.node.operator)) {
315
+ const operator = path.node.operator.slice(0, -1)
316
+ appendMember()
317
+ builder.append(` ${operator} `)
318
+ appendReadonlyImportWrite(builder, appendRight)
319
+ } else {
320
+ appendReadonlyImportWrite(builder, () => {
321
+ appendMember()
322
+ builder.append(` ${path.node.operator.slice(0, -1)} (`)
323
+ appendRight()
324
+ builder.append(')')
325
+ })
326
+ }
327
+ writeEdits.push({
328
+ start: path.node.start,
329
+ end: path.node.end,
330
+ ...builder.result(),
331
+ })
332
+ },
333
+ UpdateExpression(path) {
334
+ if (path.node.argument.type !== 'Identifier') return
335
+ const binding = importedBindingFor(path, path.node.argument, imports)
336
+ if (binding === undefined) return
337
+ assertNoImportedWriteAncestor(path, imports)
338
+ if (boundary === LIVE_IMPORT_EXPRESSION_BOUNDARY) preserveExpressionStatementBoundary(path, writeEdits, boundary)
339
+ const member = importMember(binding.namespace, binding.imported)
340
+ const builder = createMappedTextBuilder(code)
341
+ builder.append('((__dsh_ptc_import_value__) => { ')
342
+ builder.append(path.node.operator === '++' ? '__dsh_ptc_import_value__++' : '__dsh_ptc_import_value__--')
343
+ builder.append("; throw new TypeError('Assignment to constant variable.'); })(")
344
+ builder.appendMapped(member, path.node.argument.start, path.node.argument.end)
345
+ builder.append(')')
346
+ writeEdits.push({
347
+ start: path.node.start,
348
+ end: path.node.end,
349
+ ...builder.result(),
350
+ })
351
+ },
352
+ UnaryExpression(path) {
353
+ if (path.node.operator !== 'delete' || path.node.argument.type !== 'Identifier') return
354
+ if (importedBindingFor(path, path.node.argument, imports) !== undefined) {
355
+ throw new ModuleRewriteError('delete of an imported binding is not supported')
356
+ }
357
+ },
358
+ ForInStatement(path) {
359
+ if (path.node.left.type === 'VariableDeclaration') return
360
+ const names = bindingNodes(path.node.left)
361
+ if (names.some(node => importedBindingFor(path, node, imports) !== undefined)) {
362
+ throw new ModuleRewriteError('for-in assignment to an imported binding is not supported')
363
+ }
364
+ },
365
+ ForOfStatement(path) {
366
+ if (path.node.left.type === 'VariableDeclaration') return
367
+ const names = bindingNodes(path.node.left)
368
+ if (names.some(node => importedBindingFor(path, node, imports) !== undefined)) {
369
+ throw new ModuleRewriteError('for-of assignment to an imported binding is not supported')
370
+ }
371
+ },
372
+ })
373
+ const written = applySourceEdits(code, sourceMap, writeEdits)
374
+ file = parseRewritten(written.code)
375
+ const readEdits = []
376
+ traverse(file, {
377
+ ReferencedIdentifier(path) {
378
+ const binding = imports.get(path.node.name)
379
+ if (binding === undefined || path.scope.getBinding(path.node.name) !== undefined) return
380
+ const member = importMember(binding.namespace, binding.imported)
381
+ const parent = path.parent
382
+ if (((parent.type === 'CallExpression' || parent.type === 'OptionalCallExpression') && parent.callee === path.node)
383
+ || (parent.type === 'TaggedTemplateExpression' && parent.tag === path.node)) {
384
+ preserveExpressionStatementBoundary(path, readEdits, boundary)
385
+ readEdits.push({ start: path.node.start, end: path.node.end, text: `(0, ${member})` })
386
+ return
387
+ }
388
+ if (parent.type === 'ObjectProperty' && parent.shorthand && parent.value === path.node) {
389
+ readEdits.push({ start: parent.start, end: parent.end, text: `${path.node.name}: ${member}` })
390
+ return
391
+ }
392
+ readEdits.push({ start: path.node.start, end: path.node.end, text: member })
393
+ },
394
+ })
395
+ return applySourceEdits(written.code, written.sourceMap, readEdits)
396
+ }
397
+
398
+ function exportNamedEdits(node, code, edits, rewrites, moduleLoads) {
399
+ const onlyTypeSpecifiers = node.specifiers.length > 0
400
+ && node.specifiers.every(specifier => specifier.exportKind === 'type')
401
+ if (node.exportKind === 'type' || onlyTypeSpecifiers
402
+ || (node.declaration && ['TSInterfaceDeclaration', 'TSTypeAliasDeclaration', 'TSDeclareFunction'].includes(node.declaration.type))) {
403
+ editNode(edits, node, code)
404
+ const source = node.exportKind === 'type' || onlyTypeSpecifiers ? 'type' : node.declaration.type
405
+ rewrites.push(record('export', 'removed a type-only export declaration', node, source))
406
+ return
407
+ }
408
+ if (node.source !== null && node.source !== undefined) {
409
+ const source = parseSource(node)
410
+ moduleLoads.push(moduleLoad(node, source))
411
+ editNode(edits, node, code)
412
+ rewrites.push(record('export', `converted the re-export of ${JSON.stringify(source)} into a side-effect import`, node, source))
413
+ return
414
+ }
415
+ if (node.declaration !== null && node.declaration !== undefined) {
416
+ edit(edits, node.start, node.declaration.start, preserveLines(code.slice(node.start, node.declaration.start)))
417
+ rewrites.push(record('export', 'stripped the export modifier from a top-level declaration', node))
418
+ return
419
+ }
420
+ editNode(edits, node, code)
421
+ rewrites.push(record('export', 'removed a local re-export declaration', node))
422
+ }
423
+
424
+ function exportAllEdits(node, code, edits, rewrites, moduleLoads) {
425
+ if (node.exportKind === 'type') {
426
+ editNode(edits, node, code)
427
+ rewrites.push(record('export', 'removed a type-only export declaration', node, 'type'))
428
+ return
429
+ }
430
+ const source = parseSource(node)
431
+ moduleLoads.push(moduleLoad(node, source))
432
+ editNode(edits, node, code)
433
+ rewrites.push(record('export', `converted the re-export of ${JSON.stringify(source)} into a side-effect import`, node, source))
434
+ }
435
+
436
+ function prepareDefaultExport(node, code, edits, rewrites, defaultNameAvailable, exportDeclarations, semantics) {
437
+ const declaration = node.declaration
438
+ if (declaration.type === 'TSInterfaceDeclaration') {
439
+ editNode(edits, node, code)
440
+ rewrites.push(record('export', 'removed a type-only export declaration', node, 'interface'))
441
+ return false
442
+ }
443
+ if (semantics === LEGACY_DEFAULT_EXPORT_BINDING && declaration.id?.name === '__default') {
444
+ edit(edits, node.start, declaration.start, preserveLines(code.slice(node.start, declaration.start)))
445
+ rewrites.push(record('export', 'stripped the export modifier from the __default declaration', node))
446
+ return false
447
+ }
448
+ if (!defaultNameAvailable) {
449
+ throw new ModuleRewriteError(
450
+ 'export default cannot be exposed as __default because that name is already declared',
451
+ { line: node.loc.start.line, column: node.loc.start.column + 1 },
452
+ )
453
+ }
454
+ const span = {
455
+ line: node.loc.start.line,
456
+ column: node.loc.start.column + 1,
457
+ end: { line: node.loc.end.line, column: node.loc.end.column + 1 },
458
+ }
459
+ exportDeclarations.push({
460
+ name: '__default',
461
+ kind: declaration.type === 'FunctionDeclaration'
462
+ ? 'function'
463
+ : declaration.type === 'ClassDeclaration' ? 'class' : 'variable',
464
+ ...(semantics === LIVE_DEFAULT_EXPORT_BINDING ? { commitDependency: '__default' } : {}),
465
+ span,
466
+ definitionSpan: span,
467
+ original: true,
468
+ })
469
+ rewrites.push(record('export', 'converted the default export into a local __default binding', node))
470
+ return true
471
+ }
472
+
473
+ function exportDefaultEdits({
474
+ node,
475
+ code,
476
+ edits,
477
+ imports,
478
+ allocateNamespace,
479
+ commitSignal,
480
+ commitTargets,
481
+ }) {
482
+ const declaration = node.declaration
483
+ const namedDeclaration = (declaration.type === 'FunctionDeclaration'
484
+ || declaration.type === 'ClassDeclaration') && declaration.id !== null
485
+ const retainedNamedDeclaration = namedDeclaration && declaration.id.name !== '__default'
486
+ const existingAlias = imports.get('__default')
487
+ const reuseAlias = existingAlias?.syntheticDefault === true
488
+ const namespace = reuseAlias ? existingAlias.namespace : allocateNamespace('default_namespace')
489
+ const member = importMember(namespace, 'default')
490
+ imports.set('__default', {
491
+ namespace,
492
+ imported: 'default',
493
+ syntheticDefault: true,
494
+ commitDependency: '__default',
495
+ })
496
+ commitTargets.add('__default')
497
+ if (declaration.type === 'ClassDeclaration' && declaration.id !== null) {
498
+ commitTargets.add(declaration.id.name)
499
+ }
500
+ const commit = [...new Set([...(declaration.type === 'ClassDeclaration' && declaration.id !== null
501
+ ? [declaration.id.name]
502
+ : []), '__default'])]
503
+ .map(name => ` this[${JSON.stringify(commitSignal)}](${JSON.stringify(name)});`)
504
+ .join('')
505
+ const assignmentPrefix = reuseAlias ? `${member} = ` : `const ${namespace} = { default: `
506
+ const assignmentSuffix = reuseAlias ? '' : ' }'
507
+ if (retainedNamedDeclaration) {
508
+ edit(edits, node.start, declaration.start, preserveLines(code.slice(node.start, declaration.start)))
509
+ edit(edits, node.end, node.end,
510
+ `; ${assignmentPrefix}${declaration.id.name}${assignmentSuffix};${commit}`)
511
+ } else {
512
+ const prefix = code.slice(node.start, declaration.start)
513
+ edit(edits, node.start, declaration.start, preserveLines(prefix, assignmentPrefix))
514
+ edit(edits, node.end, node.end, `${assignmentSuffix};${commit}`)
515
+ }
516
+ }
517
+
518
+ function legacyExportDefaultEdits(node, code, edits) {
519
+ const declaration = node.declaration
520
+ if (declaration.type === 'FunctionDeclaration' && declaration.id !== null) {
521
+ const prefix = code.slice(node.start, declaration.start)
522
+ edit(edits, node.start, declaration.start, preserveLines(prefix, `const __default = ${declaration.id.name}; `))
523
+ } else if (declaration.type === 'ClassDeclaration' && declaration.id !== null) {
524
+ edit(edits, node.start, declaration.start, preserveLines(code.slice(node.start, declaration.start)))
525
+ edit(edits, node.end, node.end, `; const __default = ${declaration.id.name};`)
526
+ } else if (declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') {
527
+ const prefix = code.slice(node.start, declaration.start)
528
+ edit(edits, node.start, declaration.start, preserveLines(prefix, 'const __default = '))
529
+ edit(edits, node.end, node.end, ';')
530
+ } else {
531
+ const prefix = code.slice(node.start, declaration.start)
532
+ edit(edits, node.start, declaration.start, preserveLines(prefix, 'const __default = '))
533
+ }
534
+ }
535
+
536
+ function ascending(left, right) { return left.at - right.at }
537
+
538
+ export function rewriteModuleImportsExports(program, enabled, existingImports = new Map(), existingNamespaces = new Set(), unavailableNames = new Set(), moduleSemantics = LIVE_MODULE_SEMANTICS) {
539
+ if (![LEGACY_DEFAULT_EXPORT_BINDING, LIVE_DEFAULT_EXPORT_BINDING]
540
+ .includes(moduleSemantics?.defaultExportBinding)) {
541
+ throw new TypeError('ptc-plus: unsupported default export binding semantics')
542
+ }
543
+ if (![LEGACY_IMPORT_EXPRESSION_BOUNDARY, LIVE_IMPORT_EXPRESSION_BOUNDARY]
544
+ .includes(moduleSemantics.importExpressionBoundary)) {
545
+ throw new TypeError('ptc-plus: unsupported import expression boundary semantics')
546
+ }
547
+ const tree = parseCell(program)
548
+ const edits = []
549
+ const rewrites = []
550
+ const imports = new Map(existingImports)
551
+ const importDeclarations = []
552
+ const exportDeclarations = []
553
+ const moduleLoads = []
554
+ const importNamespaces = new Set(existingNamespaces)
555
+ const allocateName = createGeneratedNameAllocator(tree, [...unavailableNames, ...importNamespaces])
556
+ const commitSignal = allocateName('redeclaration_commit')
557
+ const generatedNamespaces = new Set()
558
+ const allocateImportName = purpose => {
559
+ const name = allocateName(purpose)
560
+ importNamespaces.add(name)
561
+ generatedNamespaces.add(name)
562
+ return name
563
+ }
564
+ const namespaceCaptures = []
565
+ const commitTargets = new Set()
566
+ const currentCellDefaultNameAvailable = !tree.body.some((node) => {
567
+ const declaration = node.type === 'ExportNamedDeclaration' ? node.declaration : node
568
+ if (declaration?.type === 'VariableDeclaration' && declaration.declare !== true) {
569
+ return declaration.declarations.some(entry => bindingNodes(entry.id).some(binding => binding.name === '__default'))
570
+ }
571
+ if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
572
+ return declaration.id?.name === '__default'
573
+ }
574
+ return node.type === 'ImportDeclaration' && node.importKind !== 'type' && node.specifiers.some(specifier => (
575
+ specifier.importKind !== 'type' && specifier.local.name === '__default'
576
+ ))
577
+ })
578
+ const existingDefault = existingImports.get('__default')
579
+ const persistentDefaultNameAvailable = !unavailableNames.has('__default')
580
+ || existingDefault?.syntheticDefault === true
581
+ const defaultNameAvailable = currentCellDefaultNameAvailable
582
+ && (moduleSemantics.defaultExportBinding === LEGACY_DEFAULT_EXPORT_BINDING
583
+ || persistentDefaultNameAvailable)
584
+ for (const node of tree.body) {
585
+ if (node.type === 'ImportDeclaration' && enabled.autoRewriteImports) {
586
+ importEdits(node, program, edits, rewrites, imports, importDeclarations,
587
+ moduleLoads, namespaceCaptures, allocateImportName, allocateName)
588
+ }
589
+ else if (node.type === 'ExportNamedDeclaration' && enabled.autoStripExports) {
590
+ exportNamedEdits(node, program, edits, rewrites, moduleLoads)
591
+ }
592
+ else if (node.type === 'ExportAllDeclaration' && enabled.autoStripExports) {
593
+ exportAllEdits(node, program, edits, rewrites, moduleLoads)
594
+ }
595
+ else if (node.type === 'ExportDefaultDeclaration' && enabled.autoStripExports) {
596
+ if (!prepareDefaultExport(node, program, edits, rewrites, defaultNameAvailable,
597
+ exportDeclarations, moduleSemantics.defaultExportBinding)) continue
598
+ if (moduleSemantics.defaultExportBinding === LEGACY_DEFAULT_EXPORT_BINDING) {
599
+ legacyExportDefaultEdits(node, program, edits)
600
+ } else {
601
+ exportDefaultEdits({
602
+ node,
603
+ code: program,
604
+ edits,
605
+ imports,
606
+ allocateNamespace: allocateImportName,
607
+ commitSignal,
608
+ commitTargets,
609
+ })
610
+ }
611
+ }
612
+ }
613
+ assertNoDynamicImportResolution(tree, imports)
614
+ const prologue = importPrologueEdit(program, tree, namespaceCaptures)
615
+ if (prologue !== undefined) edits.push(prologue)
616
+ const applied = applySourceEdits(program, identitySourceMap(program.length), edits)
617
+ const rewritten = rewriteImportReferences(applied.code, applied.sourceMap, imports, moduleSemantics.importExpressionBoundary)
618
+ rewrites.sort(ascending)
619
+ return {
620
+ ...rewritten,
621
+ imports,
622
+ importNamespaces,
623
+ generatedNamespaces,
624
+ importDeclarations,
625
+ exportDeclarations,
626
+ moduleLoads,
627
+ commitSignal,
628
+ commitTargets,
629
+ rewrites: rewrites.map(({ at: _at, ...rest }) => rest),
630
+ }
631
+ }