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,708 @@
1
+ import { parse } from '@babel/parser'
2
+ import { AMBIENT_GLOBALS, renderDurabilityReasons } from './module-policy.js'
3
+ import { CELL_PARSER_PLUGINS, normalizeTypeScriptValues } from './repl-scope-normalizer.js'
4
+ import { identitySourceMap } from './source-position-map.js'
5
+ import { LEGACY_USER_BINDING_TRANSFORM, USER_BINDING_TRANSFORM, transformTypeScriptSource } from './typescript-transform.js'
6
+ import { compileStatefulModule } from './module-compilation.js'
7
+ import { prepareProgram, classifyDurability } from './cell-analysis.js'
8
+ import { createCompilerSourceCache } from './compiler-source-cache.js'
9
+ import { bindingTypeNamespaceToken } from './binding-declaration-contract.js'
10
+
11
+ const MAX_NAME_LENGTH = 128
12
+ const LEGACY_GLOBAL_TYPE_NAMES = new Set([
13
+ 'Array', 'ArrayBuffer', 'ArrayBufferView', 'AsyncIterable', 'AsyncIterableIterator',
14
+ 'AsyncIterator', 'Awaited', 'BigInt', 'BigInt64Array', 'BigUint64Array', 'Boolean',
15
+ 'Buffer', 'ConstructorParameters', 'DataView', 'Date', 'Error', 'EvalError', 'Exclude',
16
+ 'Extract', 'Float32Array', 'Float64Array', 'Function', 'Generator', 'GeneratorFunction',
17
+ 'InstanceType', 'Int8Array', 'Int16Array', 'Int32Array', 'Iterable', 'IterableIterator',
18
+ 'Iterator', 'Map', 'NonNullable', 'Number', 'Object', 'Omit', 'OmitThisParameter',
19
+ 'Parameters', 'Partial', 'Pick', 'Promise', 'PromiseLike', 'RangeError', 'Readonly',
20
+ 'ReadonlyArray', 'ReadonlyMap', 'ReadonlySet', 'Record', 'ReferenceError', 'RegExp',
21
+ 'Required', 'ReturnType', 'Set', 'SharedArrayBuffer', 'String', 'Symbol', 'SyntaxError',
22
+ 'ThisParameterType', 'ThisType', 'TypeError', 'URIError', 'Uint8Array', 'Uint8ClampedArray',
23
+ 'Uint16Array', 'Uint32Array', 'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize',
24
+ 'WeakMap', 'WeakSet',
25
+ ])
26
+ const RESERVED_BINDINGS = new Set([
27
+ ...AMBIENT_GLOBALS,
28
+ 'capabilities',
29
+ 'code',
30
+ 'repl',
31
+ 'tools',
32
+ 'CapabilityExplorationError',
33
+ 'CodeExecutionError',
34
+ 'ToolCallError',
35
+ 'Buffer',
36
+ 'console',
37
+ 'global',
38
+ 'globalThis',
39
+ 'module',
40
+ 'process',
41
+ ])
42
+
43
+ export function identifier(value, subject, reserved = false) {
44
+ if (typeof value !== 'string' || value.length === 0 || value.length > MAX_NAME_LENGTH) {
45
+ throw new TypeError(`${subject} must be a non-empty identifier of at most ${MAX_NAME_LENGTH} characters`)
46
+ }
47
+ try {
48
+ const { program } = parse(`const ${value} = 0`, { sourceType: 'module' })
49
+ const declaration = program.body[0]
50
+ const binding = declaration.declarations[0].id
51
+ if (program.body.length !== 1 || declaration.declarations.length !== 1
52
+ || binding.type !== 'Identifier' || binding.name !== value) {
53
+ throw new TypeError('identifier spelling must match the complete binding name')
54
+ }
55
+ } catch {
56
+ throw new TypeError(`${subject} must be a valid JavaScript identifier`)
57
+ }
58
+ if (reserved && RESERVED_BINDINGS.has(value)) {
59
+ throw new TypeError(`${subject} conflicts with reserved REPL binding ${JSON.stringify(value)}`)
60
+ }
61
+ return value
62
+ }
63
+
64
+ function sourceSlice(source, node) {
65
+ return Number.isSafeInteger(node?.start) && Number.isSafeInteger(node?.end)
66
+ ? source.slice(node.start, node.end)
67
+ : ''
68
+ }
69
+
70
+ function bindingNames(pattern, names = []) {
71
+ if (pattern?.type === 'Identifier') names.push(pattern.name)
72
+ else if (pattern?.type === 'RestElement') bindingNames(pattern.argument, names)
73
+ else if (pattern?.type === 'AssignmentPattern') bindingNames(pattern.left, names)
74
+ else if (pattern?.type === 'ArrayPattern') {
75
+ for (const element of pattern.elements) bindingNames(element, names)
76
+ } else if (pattern?.type === 'ObjectPattern') {
77
+ for (const property of pattern.properties) {
78
+ bindingNames(property.type === 'RestElement' ? property.argument : property.value, names)
79
+ }
80
+ }
81
+ return names
82
+ }
83
+
84
+ function typeParameterNames(node) {
85
+ return (node?.params ?? [])
86
+ .map(parameter => parameter?.name)
87
+ .filter(name => typeof name === 'string')
88
+ }
89
+
90
+ function typeReferenceRoot(node) {
91
+ let current = node
92
+ while (current?.type === 'TSQualifiedName') current = current.left
93
+ return current?.type === 'Identifier' ? current.name : undefined
94
+ }
95
+
96
+ function typeReferenceRootNode(node) {
97
+ let current = node
98
+ while (current?.type === 'TSQualifiedName') current = current.left
99
+ return current?.type === 'Identifier' ? current : undefined
100
+ }
101
+
102
+ function projectedType(source, node, outerTypeNames, typeContext, usedTypeNames) {
103
+ const replacements = []
104
+ const commentRanges = new Set()
105
+ const visit = (current, inheritedNames) => {
106
+ if (current === null || typeof current !== 'object') return
107
+ if (current.type === 'CommentBlock' || current.type === 'CommentLine') {
108
+ if (Number.isSafeInteger(current.start) && Number.isSafeInteger(current.end)
109
+ && current.start >= node.start && current.end <= node.end) {
110
+ const key = `${current.start}:${current.end}`
111
+ if (!commentRanges.has(key)) {
112
+ commentRanges.add(key)
113
+ replacements.push({ start: current.start, end: current.end, text: ' ' })
114
+ }
115
+ }
116
+ return
117
+ }
118
+ let typeNames = inheritedNames
119
+ if (current.typeParameters?.type === 'TSTypeParameterDeclaration') {
120
+ typeNames = new Set([...inheritedNames, ...typeParameterNames(current.typeParameters)])
121
+ }
122
+ if (current.type === 'TSMappedType' && typeof current.typeParameter?.name === 'string') {
123
+ typeNames = new Set([...typeNames, current.typeParameter.name])
124
+ }
125
+ if (!typeContext.modern && (current.type === 'TSImportType' || current.type === 'TSTypeQuery')) {
126
+ replacements.push({ start: current.start, end: current.end, text: 'unknown' })
127
+ return
128
+ }
129
+ if (current.type === 'TSTypeQuery') {
130
+ const reference = current.exprName
131
+ const name = typeReferenceRoot(reference)
132
+ if (typeContext.modern && name !== undefined && !typeNames.has(name)) {
133
+ if (typeContext.importedNames.has(name)) {
134
+ throw new TypeError(`imported value ${JSON.stringify(name)} cannot be represented in the binding interface; use an explicit import(...) type query`)
135
+ }
136
+ if (typeContext.localValues.has(name)) {
137
+ const declaration = typeContext.localDeclarations.get(name)
138
+ if (declaration === undefined
139
+ || !['ClassDeclaration', 'TSEnumDeclaration'].includes(declaration.type)
140
+ || (reference.type !== 'Identifier' && declaration.type !== 'TSEnumDeclaration')) {
141
+ throw new TypeError(`local value query ${JSON.stringify(name)} cannot be represented in the binding interface; use an explicit structural type`)
142
+ }
143
+ usedTypeNames.add(name)
144
+ const root = typeReferenceRootNode(reference)
145
+ replacements.push({ start: root.start, end: root.end,
146
+ text: `${typeContext.typeNamespaceToken}.${name}` })
147
+ }
148
+ }
149
+ } else if (current.type === 'TSTypeReference' || current.type === 'TSExpressionWithTypeArguments') {
150
+ const reference = current.typeName ?? current.expression
151
+ const name = typeReferenceRoot(reference)
152
+ if (!typeContext.modern && (name === undefined || !typeNames.has(name)
153
+ && (typeContext.sourceTypeNames.has(name) || !LEGACY_GLOBAL_TYPE_NAMES.has(name)))) {
154
+ replacements.push({ start: current.start, end: current.end, text: 'unknown' })
155
+ return
156
+ }
157
+ if (typeContext.modern && name !== undefined && !typeNames.has(name)) {
158
+ if (typeContext.importedNames.has(name)) {
159
+ throw new TypeError(`imported type ${JSON.stringify(name)} cannot be represented in the binding interface; use an explicit import(...) type or a local structural type`)
160
+ }
161
+ if (typeContext.localDeclarations.has(name)) {
162
+ usedTypeNames.add(name)
163
+ const root = typeReferenceRootNode(reference)
164
+ replacements.push({ start: root.start, end: root.end,
165
+ text: `${typeContext.typeNamespaceToken}.${name}` })
166
+ }
167
+ }
168
+ }
169
+ for (const [key, value] of Object.entries(current)) {
170
+ if (key === 'loc' || key === 'start' || key === 'end'
171
+ || key === 'typeParameters' || key === 'typeName' || key === 'expression' || key === 'exprName') continue
172
+ if (Array.isArray(value)) value.forEach(item => visit(item, typeNames))
173
+ else visit(value, typeNames)
174
+ }
175
+ if (current.typeParameters !== undefined) visit(current.typeParameters, typeNames)
176
+ }
177
+ visit(node, outerTypeNames)
178
+ let text = sourceSlice(source, node) || 'unknown'
179
+ const start = node.start ?? 0
180
+ for (const replacement of replacements.sort((left, right) => right.start - left.start)) {
181
+ text = text.slice(0, replacement.start - start)
182
+ + replacement.text
183
+ + text.slice(replacement.end - start)
184
+ }
185
+ return text
186
+ }
187
+
188
+ function typeParameters(source, node, outerTypeNames, typeContext, usedTypeNames) {
189
+ const declaration = node?.typeParameters
190
+ if (declaration?.type !== 'TSTypeParameterDeclaration') {
191
+ return { text: '', names: outerTypeNames }
192
+ }
193
+ const names = new Set([...outerTypeNames, ...typeParameterNames(declaration)])
194
+ return { text: projectedType(source, declaration, names, typeContext, usedTypeNames), names }
195
+ }
196
+
197
+ function annotation(source, node, typeNames, typeContext, usedTypeNames) {
198
+ const type = node?.typeAnnotation?.typeAnnotation
199
+ return type === undefined ? 'unknown' : projectedType(source, type, typeNames, typeContext, usedTypeNames)
200
+ }
201
+
202
+ function parameter(source, node, index, typeNames, typeContext, usedTypeNames) {
203
+ if (node?.type === 'TSParameterProperty') {
204
+ return parameter(source, node.parameter, index, typeNames, typeContext, usedTypeNames)
205
+ }
206
+ if (node?.type === 'RestElement') {
207
+ const argument = node.argument
208
+ return argument?.type === 'Identifier'
209
+ ? `...${argument.name}: ${node.typeAnnotation === undefined ? 'unknown[]' : annotation(source, node, typeNames, typeContext, usedTypeNames)}`
210
+ : `...args${index}: unknown[]`
211
+ }
212
+ const optional = node?.type === 'AssignmentPattern'
213
+ const target = optional ? node.left : node
214
+ if (target?.type !== 'Identifier') return `arg${index}: unknown`
215
+ return `${target.name}${optional || target.optional === true ? '?' : ''}: ${annotation(source, target, typeNames, typeContext, usedTypeNames)}`
216
+ }
217
+
218
+ function returnType(source, node, typeNames, typeContext, usedTypeNames) {
219
+ const explicit = node?.returnType?.typeAnnotation
220
+ if (explicit !== undefined) return projectedType(source, explicit, typeNames, typeContext, usedTypeNames)
221
+ return node?.async === true ? 'Promise<unknown>' : 'unknown'
222
+ }
223
+
224
+ function functionType(source, node, outerTypeNames, typeContext, usedTypeNames) {
225
+ const generics = typeParameters(source, node, outerTypeNames, typeContext, usedTypeNames)
226
+ const parameters = (node.params ?? [])
227
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
228
+ return `${generics.text}(${parameters}) => ${returnType(source, node, generics.names, typeContext, usedTypeNames)}`
229
+ }
230
+
231
+ function inferredType(source, node, depth, typeContext, usedTypeNames) {
232
+ if (depth > 2 || node === null || node === undefined) return 'unknown'
233
+ if (node.type === 'StringLiteral' || node.type === 'TemplateLiteral') return 'string'
234
+ if (node.type === 'NumericLiteral') return 'number'
235
+ if (node.type === 'BooleanLiteral') return 'boolean'
236
+ if (node.type === 'BigIntLiteral') return 'bigint'
237
+ if (node.type === 'NullLiteral') return 'null'
238
+ if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {
239
+ return functionType(source, node, new Set(), typeContext, usedTypeNames)
240
+ }
241
+ if (node.type === 'ArrayExpression') return 'unknown[]'
242
+ if (node.type === 'ObjectExpression') {
243
+ const members = []
244
+ for (const property of node.properties) {
245
+ if (property.type !== 'ObjectProperty' || property.computed || property.method) return 'Record<string, unknown>'
246
+ const name = property.key.type === 'Identifier'
247
+ ? property.key.name
248
+ : property.key.type === 'StringLiteral' ? JSON.stringify(property.key.value) : undefined
249
+ if (name === undefined) return 'Record<string, unknown>'
250
+ members.push(`${name}: ${inferredType(source, property.value, depth + 1, typeContext, usedTypeNames)}`)
251
+ }
252
+ return `{ ${members.join('; ')} }`
253
+ }
254
+ return 'unknown'
255
+ }
256
+
257
+ function classMemberName(member) {
258
+ return member.key?.type === 'Identifier'
259
+ ? member.key.name
260
+ : member.key?.type === 'StringLiteral' ? JSON.stringify(member.key.value) : undefined
261
+ }
262
+
263
+ function modernClassMemberName(member) {
264
+ const key = classMemberKey(member)
265
+ return classMemberName(member) ?? (key === undefined ? undefined : JSON.stringify(key))
266
+ }
267
+
268
+ function classMemberKey(member) {
269
+ if (member.computed && !['StringLiteral', 'NumericLiteral', 'BigIntLiteral'].includes(member.key?.type)) {
270
+ throw new TypeError('computed class member key cannot be represented in the binding interface; use a literal property key')
271
+ }
272
+ return member.key?.type === 'Identifier'
273
+ ? member.key.name
274
+ : member.key?.type === 'StringLiteral' ? member.key.value
275
+ : member.key?.type === 'NumericLiteral' ? String(member.key.value)
276
+ : member.key?.type === 'BigIntLiteral' ? String(BigInt(member.key.value)) : undefined
277
+ }
278
+
279
+ function isPublicClassMember(member) {
280
+ return !member.static
281
+ && member.accessibility !== 'private' && member.accessibility !== 'protected'
282
+ && member.key?.type !== 'PrivateName'
283
+ }
284
+
285
+ function parameterPropertyMember(source, node, classTypeNames, typeContext, usedTypeNames) {
286
+ if (node?.type !== 'TSParameterProperty' || node.accessibility === 'private' || node.accessibility === 'protected') return undefined
287
+ const parameterNode = node.parameter
288
+ const optional = parameterNode?.type === 'AssignmentPattern'
289
+ const target = optional ? parameterNode.left : parameterNode
290
+ if (target?.type !== 'Identifier') return undefined
291
+ return `${node.readonly === true ? 'readonly ' : ''}${target.name}${optional || target.optional === true ? '?' : ''}: ${annotation(source, target, classTypeNames, typeContext, usedTypeNames)}`
292
+ }
293
+
294
+ function parameterPropertyName(node) {
295
+ if (node?.type !== 'TSParameterProperty' || node.accessibility === 'private' || node.accessibility === 'protected') return undefined
296
+ const parameter = node.parameter?.type === 'AssignmentPattern' ? node.parameter.left : node.parameter
297
+ return parameter?.type === 'Identifier' ? parameter.name : undefined
298
+ }
299
+
300
+ function legacyClassMembers(source, node, classTypeNames, typeContext, usedTypeNames) {
301
+ const members = []
302
+ const memberNames = new Set()
303
+ let constructorParameters = '...args: unknown[]'
304
+ for (const member of node.body?.body ?? []) {
305
+ if (!['ClassMethod', 'TSDeclareMethod'].includes(member.type)
306
+ || member.static || member.computed || member.accessibility === 'private' || member.key?.type === 'PrivateName') continue
307
+ const name = classMemberName(member)
308
+ if (name === undefined) continue
309
+ const generics = typeParameters(source, member, classTypeNames, typeContext, usedTypeNames)
310
+ const parameters = (member.params ?? [])
311
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
312
+ if (member.kind === 'constructor') {
313
+ constructorParameters = parameters
314
+ }
315
+ else if (member.kind === 'get' || member.kind === 'set') {
316
+ const signature = `${member.kind}:${name}`
317
+ if (memberNames.has(signature)) continue
318
+ members.push(member.kind === 'get'
319
+ ? `get ${name}(): ${returnType(source, member, generics.names, typeContext, usedTypeNames)}`
320
+ : `set ${name}(${parameters})`)
321
+ memberNames.add(signature)
322
+ }
323
+ else if (member.kind === 'method') {
324
+ members.push(`${name}${member.optional === true ? '?' : ''}${generics.text}(${parameters}): ${returnType(source, member, generics.names, typeContext, usedTypeNames)}`)
325
+ memberNames.add(name)
326
+ }
327
+ }
328
+ return { constructorParameters, members, instance: `{ ${members.join('; ')} }` }
329
+ }
330
+
331
+ function classMembers(source, node, classTypeNames, typeContext, usedTypeNames) {
332
+ if (!typeContext.modern) return legacyClassMembers(source, node, classTypeNames, typeContext, usedTypeNames)
333
+ const body = node.body?.body ?? []
334
+ const fields = new Map()
335
+ const parameterProperties = new Map()
336
+ const prototypeMembers = new Map()
337
+ let constructorNode
338
+ for (const member of body) {
339
+ if (['ClassProperty', 'TSAbstractPropertyDefinition'].includes(member.type)) {
340
+ if (!isPublicClassMember(member)) continue
341
+ const key = classMemberKey(member)
342
+ if (key !== undefined) fields.set(key, member)
343
+ continue
344
+ }
345
+ if (member.type === 'ClassAccessorProperty') {
346
+ if (!isPublicClassMember(member)) continue
347
+ const key = classMemberKey(member)
348
+ if (key !== undefined) prototypeMembers.set(key, { kind: 'accessor', get: member, set: member })
349
+ continue
350
+ }
351
+ if (!['ClassMethod', 'TSDeclareMethod'].includes(member.type) || !isPublicClassMember(member)) continue
352
+ const key = classMemberKey(member)
353
+ if (key === undefined) continue
354
+ if (member.kind === 'constructor') {
355
+ constructorNode = member
356
+ } else if (member.kind === 'get' || member.kind === 'set') {
357
+ const current = prototypeMembers.get(key)
358
+ const descriptor = current?.kind === 'accessor' ? { ...current } : { kind: 'accessor' }
359
+ descriptor[member.kind] = member
360
+ prototypeMembers.set(key, descriptor)
361
+ } else if (member.kind === 'method') {
362
+ prototypeMembers.set(key, { kind: 'method', node: member })
363
+ }
364
+ }
365
+ for (const parameter of constructorNode?.params ?? []) {
366
+ const name = parameterPropertyName(parameter)
367
+ if (name !== undefined) parameterProperties.set(name, parameter)
368
+ }
369
+ const ownMember = name => parameterProperties.get(name) ?? fields.get(name)
370
+ const members = []
371
+ let constructorParameters = '...args: unknown[]'
372
+ for (const member of body) {
373
+ if (['ClassProperty', 'TSAbstractPropertyDefinition'].includes(member.type)) {
374
+ if (!isPublicClassMember(member)) continue
375
+ const key = classMemberKey(member)
376
+ if (key === undefined || ownMember(key) !== member) continue
377
+ const name = modernClassMemberName(member)
378
+ members.push(`${member.readonly === true ? 'readonly ' : ''}${name}${member.optional === true ? '?' : ''}: ${annotation(source, member, classTypeNames, typeContext, usedTypeNames)}`)
379
+ continue
380
+ }
381
+ if (member.type === 'ClassAccessorProperty') {
382
+ if (!isPublicClassMember(member)) continue
383
+ const key = classMemberKey(member)
384
+ const name = modernClassMemberName(member)
385
+ const selected = key === undefined || ownMember(key) !== undefined ? undefined : prototypeMembers.get(key)
386
+ if (selected?.kind !== 'accessor') continue
387
+ if (selected.get === member && selected.set === member) {
388
+ members.push(`${name}${member.optional === true ? '?' : ''}: ${annotation(source, member, classTypeNames, typeContext, usedTypeNames)}`)
389
+ } else {
390
+ const type = annotation(source, member, classTypeNames, typeContext, usedTypeNames)
391
+ if (selected.get === member) members.push(`get ${name}(): ${type}`)
392
+ if (selected.set === member) members.push(`set ${name}(value: ${type})`)
393
+ }
394
+ continue
395
+ }
396
+ if (!['ClassMethod', 'TSDeclareMethod'].includes(member.type) || !isPublicClassMember(member)) continue
397
+ const key = classMemberKey(member)
398
+ if (key === undefined) continue
399
+ const name = modernClassMemberName(member)
400
+ if (member.kind === 'constructor') {
401
+ if (member !== constructorNode) continue
402
+ const generics = typeParameters(source, member, classTypeNames, typeContext, usedTypeNames)
403
+ const parameters = (member.params ?? [])
404
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
405
+ constructorParameters = parameters
406
+ for (const item of member.params ?? []) {
407
+ const fieldName = parameterPropertyName(item)
408
+ if (fieldName === undefined || ownMember(fieldName) !== item) continue
409
+ members.push(parameterPropertyMember(source, item, classTypeNames, typeContext, usedTypeNames))
410
+ }
411
+ continue
412
+ }
413
+ if (ownMember(key) !== undefined) continue
414
+ const selected = prototypeMembers.get(key)
415
+ if (member.kind === 'get' || member.kind === 'set') {
416
+ if (selected?.kind !== 'accessor' || selected[member.kind] !== member) continue
417
+ const generics = typeParameters(source, member, classTypeNames, typeContext, usedTypeNames)
418
+ const parameters = (member.params ?? [])
419
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
420
+ members.push(member.kind === 'get'
421
+ ? `get ${name}(): ${returnType(source, member, generics.names, typeContext, usedTypeNames)}`
422
+ : `set ${name}(${parameters})`)
423
+ } else if (member.kind === 'method' && selected?.kind === 'method' && selected.node === member) {
424
+ const generics = typeParameters(source, member, classTypeNames, typeContext, usedTypeNames)
425
+ const parameters = (member.params ?? [])
426
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
427
+ members.push(`${name}${member.optional === true ? '?' : ''}${generics.text}(${parameters}): ${returnType(source, member, generics.names, typeContext, usedTypeNames)}`)
428
+ }
429
+ }
430
+ return { constructorParameters, members, instance: `{ ${members.join('; ')} }` }
431
+ }
432
+
433
+ function valueReferenceRootNode(node) {
434
+ let current = node
435
+ while (current?.type === 'MemberExpression' && !current.computed) current = current.object
436
+ return current?.type === 'Identifier' ? current : undefined
437
+ }
438
+
439
+ function classHeritage(source, node, classTypeNames, typeContext, usedTypeNames) {
440
+ const base = node.superClass
441
+ if (base === null || base === undefined) return { clause: '', instance: '' }
442
+ const root = valueReferenceRootNode(base)
443
+ if (root === undefined || !['Identifier', 'MemberExpression'].includes(base.type)) {
444
+ throw new TypeError('class heritage cannot be represented in the binding interface; use a named class base')
445
+ }
446
+ if (typeContext.importedNames.has(root.name)) {
447
+ throw new TypeError(`imported class ${JSON.stringify(root.name)} cannot be represented in the binding interface; use an explicit structural type`)
448
+ }
449
+ let reference = sourceSlice(source, base)
450
+ if (base.type === 'Identifier' && typeContext.localDeclarations.has(root.name)) {
451
+ const declaration = typeContext.localDeclarations.get(root.name)
452
+ if (declaration.type !== 'ClassDeclaration') {
453
+ throw new TypeError(`local class base ${JSON.stringify(root.name)} cannot be represented in the binding interface; use a class declaration`)
454
+ }
455
+ usedTypeNames.add(root.name)
456
+ reference = `${typeContext.typeNamespaceToken}.${root.name}`
457
+ } else if (typeContext.localValues.has(root.name)) {
458
+ throw new TypeError(`local class base ${JSON.stringify(root.name)} cannot be represented in the binding interface; use a class declaration`)
459
+ }
460
+ const argumentsNode = node.superTypeParameters ?? node.superTypeArguments
461
+ const typeArguments = argumentsNode === undefined ? ''
462
+ : projectedType(source, argumentsNode, classTypeNames, typeContext, usedTypeNames)
463
+ const instance = `${reference}${typeArguments}`
464
+ return { clause: ` extends ${instance}`, instance }
465
+ }
466
+
467
+ function localTypeDeclaration(source, name, node, typeContext, usedTypeNames) {
468
+ if (node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration'
469
+ || node.type === 'TSEnumDeclaration') {
470
+ const ownTypeNames = new Set(typeParameterNames(node.typeParameters))
471
+ const text = projectedType(source, node, ownTypeNames, typeContext, usedTypeNames)
472
+ .replace(/^declare\s+/, '')
473
+ return `export ${text}`
474
+ }
475
+ if (node.type === 'ClassDeclaration') {
476
+ const generics = typeParameters(source, node, new Set(), typeContext, usedTypeNames)
477
+ const heritage = classHeritage(source, node, generics.names, typeContext, usedTypeNames)
478
+ const shape = classMembers(source, node, generics.names, typeContext, usedTypeNames)
479
+ return `export ${node.abstract === true ? 'abstract ' : ''}class ${name}${generics.text}${heritage.clause} { constructor(${shape.constructorParameters});${shape.members.length === 0 ? '' : ` ${shape.members.join('; ')};`} }`
480
+ }
481
+ throw new TypeError(`local type ${JSON.stringify(name)} cannot be represented in the binding interface; use a local interface, type alias, enum, or class`)
482
+ }
483
+
484
+ function typeDependencyDeclarations(source, roots, typeContext) {
485
+ if (!typeContext.modern) return []
486
+ const pending = [...roots]
487
+ const seen = new Set()
488
+ const declarations = []
489
+ while (pending.length > 0) {
490
+ const name = pending.shift()
491
+ if (seen.has(name)) continue
492
+ seen.add(name)
493
+ const node = typeContext.localDeclarations.get(name)
494
+ if (node === undefined) continue
495
+ const dependencies = new Set()
496
+ declarations.push(localTypeDeclaration(source, name, node, typeContext, dependencies))
497
+ for (const dependency of dependencies) if (!seen.has(dependency)) pending.push(dependency)
498
+ }
499
+ return declarations
500
+ }
501
+
502
+ function jsdocPurpose(...nodes) {
503
+ const comment = nodes.flatMap(node => node?.leadingComments ?? [])
504
+ .find(item => item.type === 'CommentBlock' && item.value.startsWith('*'))
505
+ if (comment === undefined) return ''
506
+ return comment.value.slice(1).split(/\r?\n/)
507
+ .map(line => line.replace(/^\s*\*?\s?/, '').trim())
508
+ .find(line => line !== '' && !line.startsWith('@')) ?? ''
509
+ }
510
+
511
+ function symbolDescriptor(source, name, node, exportNode, typeContext) {
512
+ const usedTypeNames = new Set()
513
+ const complete = descriptor => ({
514
+ ...descriptor,
515
+ typeNamespaceToken: typeContext.typeNamespaceToken,
516
+ typeDeclarations: typeDependencyDeclarations(source, usedTypeNames, typeContext),
517
+ })
518
+ if (node?.type === 'FunctionDeclaration') {
519
+ const generics = typeParameters(source, node, new Set(), typeContext, usedTypeNames)
520
+ const parameters = (node.params ?? [])
521
+ .map((item, index) => parameter(source, item, index, generics.names, typeContext, usedTypeNames)).join(', ')
522
+ return complete({
523
+ name,
524
+ kind: 'function',
525
+ purpose: jsdocPurpose(exportNode, node),
526
+ declaration: `function ${name}${generics.text}(${parameters}): ${returnType(source, node, generics.names, typeContext, usedTypeNames)}`,
527
+ member: `${name}${generics.text}(${parameters}): ${returnType(source, node, generics.names, typeContext, usedTypeNames)}`,
528
+ })
529
+ }
530
+ if (node?.type === 'ClassDeclaration') {
531
+ const generics = typeParameters(source, node, new Set(), typeContext, usedTypeNames)
532
+ const heritage = classHeritage(source, node, generics.names, typeContext, usedTypeNames)
533
+ const shape = classMembers(source, node, generics.names, typeContext, usedTypeNames)
534
+ const instance = heritage.instance === '' ? shape.instance : `${heritage.instance} & ${shape.instance}`
535
+ return complete({
536
+ name,
537
+ kind: 'class',
538
+ purpose: jsdocPurpose(exportNode, node),
539
+ declaration: `${node.abstract === true ? 'abstract ' : ''}class ${name}${generics.text}${heritage.clause} { constructor(${shape.constructorParameters});${shape.members.length === 0 ? '' : ` ${shape.members.join('; ')};`} }`,
540
+ member: node.abstract === true
541
+ ? `${name}: abstract new${generics.text}(${shape.constructorParameters}) => ${instance}`
542
+ : `${name}: { new${generics.text}(${shape.constructorParameters}): ${instance} }`,
543
+ })
544
+ }
545
+ const declarator = node?.type === 'VariableDeclarator' ? node : undefined
546
+ const type = declarator?.id?.type !== 'Identifier'
547
+ ? 'unknown'
548
+ : declarator.id.typeAnnotation !== undefined
549
+ ? annotation(source, declarator.id, new Set(), typeContext, usedTypeNames)
550
+ : inferredType(source, declarator.init, 0, typeContext, usedTypeNames)
551
+ return complete({
552
+ name,
553
+ kind: 'variable',
554
+ purpose: jsdocPurpose(exportNode, node),
555
+ declaration: `const ${name}: ${type}`,
556
+ member: `${name}: ${type}`,
557
+ })
558
+ }
559
+
560
+ export const exportedSymbols = createCompilerSourceCache(analyzeExportedSymbols)
561
+
562
+ function analyzeExportedSymbols(source, transform) {
563
+ const metadataSource = source
564
+ let metadataAst
565
+ try {
566
+ metadataAst = parse(metadataSource, {
567
+ sourceType: 'module',
568
+ plugins: transform === LEGACY_USER_BINDING_TRANSFORM
569
+ ? ['typescript', 'topLevelAwait', 'importAttributes'] : CELL_PARSER_PLUGINS,
570
+ errorRecovery: transform !== LEGACY_USER_BINDING_TRANSFORM,
571
+ })
572
+ } catch (error) {
573
+ throw new SyntaxError(`binding source could not be parsed: ${error.message}`)
574
+ }
575
+ const importedNames = new Set()
576
+ const localDeclarations = new Map()
577
+ const localValueNames = new Set()
578
+ const metadataLocals = new Map()
579
+ const metadataExportNodes = new Map()
580
+ for (const statement of metadataAst.program.body) {
581
+ const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement
582
+ if (statement.type === 'ImportDeclaration') {
583
+ for (const specifier of statement.specifiers) importedNames.add(specifier.local.name)
584
+ }
585
+ if (declaration?.type === 'TSTypeAliasDeclaration'
586
+ || declaration?.type === 'TSInterfaceDeclaration'
587
+ || declaration?.type === 'TSEnumDeclaration'
588
+ || declaration?.type === 'TSModuleDeclaration'
589
+ || declaration?.type === 'ClassDeclaration') {
590
+ if (declaration.id?.type === 'Identifier') localDeclarations.set(declaration.id.name, declaration)
591
+ }
592
+ if (declaration?.type === 'TSEnumDeclaration' || declaration?.type === 'TSModuleDeclaration') {
593
+ if (declaration.id?.type === 'Identifier') localValueNames.add(declaration.id.name)
594
+ }
595
+ if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
596
+ if (declaration.id !== null) {
597
+ localValueNames.add(declaration.id.name)
598
+ metadataLocals.set(declaration.id.name, declaration)
599
+ if (statement.type === 'ExportNamedDeclaration') metadataExportNodes.set(declaration.id.name, statement)
600
+ }
601
+ } else if (declaration?.type === 'VariableDeclaration') {
602
+ for (const item of declaration.declarations) {
603
+ for (const name of bindingNames(item.id)) {
604
+ localValueNames.add(name)
605
+ metadataLocals.set(name, item)
606
+ if (statement.type === 'ExportNamedDeclaration') metadataExportNodes.set(name, statement)
607
+ }
608
+ }
609
+ }
610
+ if (statement.type === 'ExportNamedDeclaration') {
611
+ for (const specifier of statement.specifiers) {
612
+ if (specifier.type === 'ExportSpecifier' && specifier.local.type === 'Identifier') {
613
+ metadataExportNodes.set(specifier.local.name, statement)
614
+ }
615
+ }
616
+ }
617
+ }
618
+ const typeContext = {
619
+ modern: transform === USER_BINDING_TRANSFORM,
620
+ importedNames,
621
+ localDeclarations,
622
+ localValues: localValueNames,
623
+ sourceTypeNames: new Set([...importedNames, ...localDeclarations.keys()]),
624
+ typeNamespaceToken: bindingTypeNamespaceToken(metadataSource),
625
+ }
626
+ let ast = metadataAst
627
+ if (transform !== LEGACY_USER_BINDING_TRANSFORM) {
628
+ source = normalizeTypeScriptValues(source, identitySourceMap(source.length), 'module').code
629
+ ast = parse(source, { sourceType: 'module', plugins: CELL_PARSER_PLUGINS, errorRecovery: true })
630
+ }
631
+ const locals = new Map()
632
+ for (const statement of ast.program.body) {
633
+ const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement
634
+ if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
635
+ if (declaration.id !== null) locals.set(declaration.id.name, declaration)
636
+ } else if (declaration?.type === 'VariableDeclaration') {
637
+ for (const item of declaration.declarations) {
638
+ for (const name of bindingNames(item.id)) locals.set(name, item)
639
+ }
640
+ }
641
+ }
642
+ const exports = new Map()
643
+ const descriptor = (name, runtimeNode, exportNode, localName = name) => {
644
+ const metadataNode = metadataLocals.get(localName)
645
+ return metadataNode === undefined
646
+ ? symbolDescriptor(source, name, runtimeNode, exportNode, typeContext)
647
+ : symbolDescriptor(metadataSource, name, metadataNode,
648
+ metadataExportNodes.get(localName) ?? metadataNode, typeContext)
649
+ }
650
+ for (const statement of ast.program.body) {
651
+ if (statement.type === 'ExportDefaultDeclaration' || statement.type === 'ExportAllDeclaration') {
652
+ throw new TypeError('binding source supports named exports only')
653
+ }
654
+ if (statement.type !== 'ExportNamedDeclaration' || statement.exportKind === 'type') continue
655
+ if (statement.source !== null && statement.source !== undefined) {
656
+ throw new TypeError('binding source cannot re-export from another module')
657
+ }
658
+ const declaration = statement.declaration
659
+ if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
660
+ if (declaration.id === null) throw new TypeError('binding source exports must be named')
661
+ exports.set(declaration.id.name, descriptor(declaration.id.name, declaration, statement))
662
+ continue
663
+ }
664
+ if (declaration?.type === 'VariableDeclaration') {
665
+ for (const item of declaration.declarations) {
666
+ for (const name of bindingNames(item.id)) {
667
+ exports.set(name, descriptor(name, item, statement))
668
+ }
669
+ }
670
+ continue
671
+ }
672
+ for (const specifier of statement.specifiers) {
673
+ if (specifier.exportKind === 'type' || specifier.type !== 'ExportSpecifier') continue
674
+ const exported = specifier.exported.type === 'Identifier' ? specifier.exported.name : specifier.exported.value
675
+ const local = specifier.local.type === 'Identifier' ? specifier.local.name : specifier.local.value
676
+ identifier(exported, 'exported binding name')
677
+ const target = locals.get(local)
678
+ if (target === undefined) throw new TypeError(`export ${JSON.stringify(exported)} has no local value declaration`)
679
+ exports.set(exported, descriptor(exported, target, target, local))
680
+ }
681
+ }
682
+ if (exports.size === 0) throw new TypeError('binding source must contain at least one named value export')
683
+ return exports
684
+ }
685
+
686
+ export const sourceDurability = createCompilerSourceCache(analyzeSourceDurability)
687
+
688
+ function analyzeSourceDurability(source, transform) {
689
+ const compiled = compileStatefulModule(source, { transform })
690
+ // Keep source imports visible to durability analysis after runtime adaptation.
691
+ const javascript = transformTypeScriptSource(compiled.classificationCode,
692
+ transform === LEGACY_USER_BINDING_TRANSFORM ? {} : { module: true, transform: { tsEnumIsMutable: true } }).code
693
+ const prepared = transform !== LEGACY_USER_BINDING_TRANSFORM
694
+ ? classifyDurability(javascript, new Set(), { sourceType: 'module',
695
+ internalModules: new Set([new URL('./stateful-module-runtime.js', import.meta.url).href]) })
696
+ : prepareProgram(javascript, {
697
+ languageSemantics: 'legacy-v1',
698
+ knownBindings: new Set(),
699
+ bindingPolicy: { variableRedeclarations: true, functionClassRedeclarations: true },
700
+ reservedBindings: new Set(),
701
+ rewritesEnabled: { autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true },
702
+ })
703
+ const reason = prepared.reason ?? renderDurabilityReasons(prepared.reasons)
704
+ return {
705
+ durability: prepared.durability,
706
+ ...(reason === '' ? {} : { volatileReason: reason }),
707
+ }
708
+ }