dsh-ptc-plus 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.en.md +65 -78
  2. package/README.md +65 -78
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30596 -742
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +554 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +6 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +73 -21
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +95 -19
  51. package/docs/durability-design.md +25 -10
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/publishing.md +5 -3
  55. package/docs/runtime-reference.md +72 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +755 -0
  58. package/docs/user-bindings.en.md +64 -0
  59. package/docs/user-bindings.md +64 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification.md +57 -0
  62. package/index.js +369 -92
  63. package/internal/ast-traversal.js +5 -2
  64. package/internal/binding-descriptors.js +1 -0
  65. package/internal/binding-pattern-traversal.js +25 -0
  66. package/internal/binding-pattern.js +26 -29
  67. package/internal/binding-source-analysis.js +391 -0
  68. package/internal/binding-update-policy.js +66 -0
  69. package/internal/bounded-worker-round.js +56 -0
  70. package/internal/callable-definition-environment.js +42 -0
  71. package/internal/callable-source-catalog.js +129 -0
  72. package/internal/callable-source-encoding.js +47 -0
  73. package/internal/callable-source-facts.js +459 -0
  74. package/internal/callable-source-format.js +2 -0
  75. package/internal/callable-source-lowering.js +123 -0
  76. package/internal/cell-analysis-contract.js +25 -0
  77. package/internal/cell-analysis.js +240 -290
  78. package/internal/cell-completion.js +15 -0
  79. package/internal/cell-error.js +7 -0
  80. package/internal/cell-parser.js +66 -0
  81. package/internal/cell-rewriter.js +3 -677
  82. package/internal/commonjs-export-evidence.js +63 -0
  83. package/internal/commonjs-source-evidence.js +72 -0
  84. package/internal/compiler-amaro.cjs +2 -0
  85. package/internal/compiler-compression.js +12 -0
  86. package/internal/compiler-data.js +58 -0
  87. package/internal/compiler-descriptors.js +54 -0
  88. package/internal/compiler-dynamic-cache.js +48 -0
  89. package/internal/compiler-entry.js +35 -0
  90. package/internal/compiler-generated-names.js +17 -0
  91. package/internal/compiler-intrinsics.js +84 -0
  92. package/internal/compiler-module-links.js +34 -0
  93. package/internal/compiler-operations.js +61 -0
  94. package/internal/compiler-platform-factory.js +84 -0
  95. package/internal/compiler-platform.js +136 -0
  96. package/internal/compiler-record-roles.js +53 -0
  97. package/internal/compiler-region-output.js +259 -0
  98. package/internal/compiler-resource-lowering.js +103 -0
  99. package/internal/compiler-scope-facts.js +115 -0
  100. package/internal/compiler-service.js +109 -0
  101. package/internal/compiler-source-cache.js +32 -0
  102. package/internal/compiler-source-pieces.js +93 -0
  103. package/internal/compiler-source-regions.js +132 -0
  104. package/internal/compiler-storage-source.js +54 -0
  105. package/internal/compiler-text.js +15 -0
  106. package/internal/compiler-typescript.cjs +2 -0
  107. package/internal/config-spec.js +83 -27
  108. package/internal/cordis-tools-owner.js +130 -21
  109. package/internal/diagnostic.js +27 -1
  110. package/internal/direct-surface-owner.js +76 -23
  111. package/internal/dynamic-binding-evidence.js +16 -0
  112. package/internal/dynamic-environment-compiler.js +779 -0
  113. package/internal/dynamic-environment-integration.js +87 -0
  114. package/internal/dynamic-environment-runtime.js +362 -0
  115. package/internal/dynamic-native-calls.js +150 -0
  116. package/internal/dynamic-native-runtime.js +248 -0
  117. package/internal/dynamic-scope-analysis.js +90 -0
  118. package/internal/edit-transport-owner.js +27 -2
  119. package/internal/execution-seam-compat.js +193 -0
  120. package/internal/failure-reporting.js +118 -18
  121. package/internal/host-rpc.js +66 -0
  122. package/internal/isolated-worker.js +548 -0
  123. package/internal/kernel-child.js +139 -0
  124. package/internal/kernel-worker.js +904 -120
  125. package/internal/language-semantics.js +14 -0
  126. package/internal/legacy-binding-catalog.js +48 -0
  127. package/internal/legacy-cell-analysis.js +600 -0
  128. package/internal/legacy-cell-parser.js +50 -0
  129. package/internal/legacy-cell-rewriter.js +631 -0
  130. package/internal/legacy-repl-convenience.js +291 -0
  131. package/internal/managed-module-operations.js +170 -0
  132. package/internal/module-compilation.js +321 -0
  133. package/internal/module-runtime-platform.js +19 -0
  134. package/internal/module-transform-contract.js +12 -0
  135. package/internal/native-await-declarations.js +68 -0
  136. package/internal/native-root-compilation.js +54 -0
  137. package/internal/native-root-dynamic.js +67 -0
  138. package/internal/recovery-tips.js +27 -15
  139. package/internal/rejected-cell-editor.js +13 -8
  140. package/internal/repl-convenience.js +2 -289
  141. package/internal/repl-memory-projection.js +81 -12
  142. package/internal/repl-observation-interest.js +70 -0
  143. package/internal/repl-rewrite-contract.js +6 -0
  144. package/internal/repl-scope-normalizer.js +2091 -0
  145. package/internal/repl-value-observer.js +114 -0
  146. package/internal/rpc-contract.js +52 -0
  147. package/internal/runtime-bridge-owner.js +172 -28
  148. package/internal/runtime-config.js +48 -52
  149. package/internal/runtime-contexts.js +82 -10
  150. package/internal/runtime-messages.js +111 -0
  151. package/internal/session-cell-executor.js +401 -87
  152. package/internal/session-journal-recovery.js +684 -0
  153. package/internal/session-journal-schema.js +106 -0
  154. package/internal/session-journal.js +184 -654
  155. package/internal/session-log-view.js +42 -9
  156. package/internal/session-runtime.js +256 -95
  157. package/internal/session-state.js +247 -71
  158. package/internal/source-position-map.js +211 -71
  159. package/internal/stateful-module-compiler.js +154 -0
  160. package/internal/stateful-module-runtime.js +303 -0
  161. package/internal/stateful-root-compiler.js +598 -0
  162. package/internal/stateful-root-runtime.js +340 -0
  163. package/internal/typert-codec-compat.js +28 -0
  164. package/internal/typescript-transform.js +29 -0
  165. package/internal/user-binding-authoring.js +70 -0
  166. package/internal/user-binding-console-worker.js +184 -0
  167. package/internal/user-binding-console.js +148 -0
  168. package/internal/user-binding-draft-projection.js +335 -0
  169. package/internal/user-binding-model-context.js +31 -0
  170. package/internal/user-binding-runner.js +56 -0
  171. package/internal/user-bindings-owner.js +1065 -0
  172. package/internal/user-bindings-store.js +293 -0
  173. package/internal/user-bindings.js +353 -0
  174. package/internal/value-wire-schema.js +28 -0
  175. package/internal/value-wire.js +29 -20
  176. package/internal/worker-client.js +57 -67
  177. package/internal/worker-environment.js +45 -0
  178. package/internal/worker-output-relay.js +29 -0
  179. package/internal/worker-shutdown.js +14 -0
  180. package/package.json +75 -7
  181. package/src/client-activity.js +88 -53
  182. package/src/client-authoring-view.js +580 -0
  183. package/src/client-binding-review.js +230 -0
  184. package/src/client-bindings-data.js +29 -0
  185. package/src/client-catalog.js +127 -0
  186. package/src/client-code-editor.js +84 -0
  187. package/src/client-console.js +112 -0
  188. package/src/client-copy.js +370 -0
  189. package/src/client-feature-gates.js +62 -0
  190. package/src/client-host-compat.js +150 -0
  191. package/src/client-indicator-view.js +267 -0
  192. package/src/client-repl-view.js +292 -0
  193. package/src/client-rpc.js +20 -0
  194. package/src/client-settings-view.js +221 -0
  195. package/src/client-styles.js +106 -0
  196. package/src/client-tool-view.js +108 -0
  197. package/src/client-transport.js +159 -0
  198. package/src/client-workbench.js +521 -0
  199. package/src/client.js +233 -615
@@ -0,0 +1,87 @@
1
+ import { commonJsCompilerImport } from './compiler-module-links.js'
2
+ import { createHash } from 'node:crypto'
3
+ import { createGeneratedNameAllocator } from './binding-pattern.js'
4
+ import { compileDynamicEnvironmentSource } from './dynamic-environment-compiler.js'
5
+ import { applySourceEdits, mappedSourceTransform, mapSourceSpan, sourceLineStarts, sourceTextAtSpan, sourceOffsetAt } from './source-position-map.js'
6
+ import { visitRegionSource, applyRegionEdits } from './compiler-region-output.js'
7
+ import { visitSource } from './compiler-source-regions.js'
8
+
9
+ /** Keep dynamic name resolution behind the lexical facts of the cell compiler. */
10
+ export function adaptDynamicCell(code, sourceMap, options) {
11
+ const parserOptions = { sourceType: options.sourceType ?? 'script',
12
+ ...(options.sourceType === 'commonjs' ? {} : { allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true }),
13
+ plugins: options.parserPlugins }
14
+ let rootEnd, directiveEnd, strict, allocate
15
+ let lexicalDynamic = options.sourceRegions?.lexicalDynamic ?? false
16
+ const discoverDynamics = options.sourceRegions?.lexicalDynamic === undefined
17
+ const inspectRegion = region => region.kind === 'program' || discoverDynamics || options.rootRuntime !== undefined
18
+ visitRegionSource({ code, sourceMap, sourceRegions: options.sourceRegions }, parserOptions, input => {
19
+ allocate ??= options.sourceRegions?.allocate ?? createGeneratedNameAllocator(input.tree, options.reservedBindings ?? [])
20
+ if (input.region.kind === 'program') {
21
+ directiveEnd = input.tree.program.directives.at(-1)?.end ?? input.tree.program.interpreter?.end ?? 0
22
+ strict = input.tree.program.directives.some(directive => directive.value.value === 'use strict')
23
+ }
24
+ if (discoverDynamics || options.rootRuntime !== undefined) visitSource(input.tree, {
25
+ VariableDeclarator(path) {
26
+ if (path.node.id.name === options.rootRuntime) rootEnd = sourceOffsetAt(input.sourceMap, path.parent.end - 1) + 1
27
+ },
28
+ CallExpression(path) { if (path.node.callee.type === 'Identifier' && path.node.callee.name === 'eval') lexicalDynamic = true },
29
+ WithStatement() { lexicalDynamic = true },
30
+ })
31
+ }, inspectRegion)
32
+ const environmentName = allocate('dynamic_environment')
33
+ let expression
34
+ let setup
35
+ if (options.module === true) {
36
+ const runtimeUrl = new URL('./dynamic-environment-runtime.js', import.meta.url)
37
+ if (options.sourceType === 'module') {
38
+ const factory = allocate('dynamic_factory')
39
+ setup = `\nimport {createDynamicEnvironmentRuntime as ${factory}} from ${JSON.stringify(runtimeUrl.href)};\n`
40
+ expression = `${factory}(${options.importOperation === undefined ? '' : `{importModule:${options.importOperation}}`}).installIntrinsics().environment({strict:true,getThis:()=>void 0})`
41
+ options = { ...options, internalBindings: new Set([...options.internalBindings ?? [], factory]) }
42
+ } else {
43
+ const names = ['exports', 'module', 'require', '__filename', '__dirname', 'arguments']
44
+ const bindings = names.map(name => `[${JSON.stringify(name)},{kind:"param",get:()=>${name}${name === 'arguments' && strict ? '' : `,set:v=>${name}=v`}}]`).join(',')
45
+ setup = `\nconst ${environmentName}=${commonJsCompilerImport(runtimeUrl)}.createDynamicEnvironmentRuntime(${options.importOperation === undefined ? '' : `{importModule:${options.importOperation}}`}).installIntrinsics().environment({strict:${strict},getThis:()=>this,getNewTarget:()=>new.target,allowNewTarget:true,nativeBindings:[${bindings}]});\n`
46
+ }
47
+ } else setup = options.nativeRoot === true ? `\nconst ${environmentName}=${options.environmentGlobal};\n`
48
+ : `\nconst ${environmentName}=${options.rootRuntime}.dynamic();\n`
49
+ const insertion = options.module === true || options.nativeRoot === true
50
+ ? directiveEnd : rootEnd
51
+ const framed = applyRegionEdits({ code, sourceMap, sourceRegions: options.sourceRegions }, [{ start: insertion, end: insertion, text: setup }])
52
+ const callableRanges = options.callableRanges?.map(range => ({ ...range,
53
+ start: range.start >= insertion ? range.start + setup.length : range.start,
54
+ end: range.end > insertion ? range.end + setup.length : range.end }))
55
+ const dynamicOrigins = []
56
+ const sourceIdentity = createHash('sha256').update(options.originalSource).digest('hex')
57
+ const originalLineStarts = sourceLineStarts(options.originalSource)
58
+ const coordinates = { generatedStarts: sourceLineStarts(framed.code), originalStarts: originalLineStarts }
59
+ const evalOrigin = node => {
60
+ const definitionSpan = mapSourceSpan({ line: node.loc.start.line, column: node.loc.start.column + 1,
61
+ end: { line: node.loc.end.line, column: node.loc.end.column + 1 } }, framed.code, options.originalSource, framed.sourceMap, coordinates)
62
+ const target = `eval:${sourceIdentity}:${definitionSpan.line}:${definitionSpan.column}`
63
+ dynamicOrigins.push({ target, definitionSpan })
64
+ return target
65
+ }
66
+ const writeTarget = node => {
67
+ const position = mapSourceSpan({ line: node.loc.start.line, column: node.loc.start.column + 1 },
68
+ framed.code, options.originalSource, framed.sourceMap, coordinates)
69
+ return `write:${sourceIdentity}:${position.line}:${position.column}:${node.name}`
70
+ }
71
+ const calleeSource = node => sourceTextAtSpan(options.originalSource, mapSourceSpan({
72
+ line: node.loc.start.line, column: node.loc.start.column + 1,
73
+ end: { line: node.loc.end.line, column: node.loc.end.column + 1 },
74
+ }, framed.code, options.originalSource, framed.sourceMap, coordinates), originalLineStarts)
75
+ const result = compileDynamicEnvironmentSource(framed.code, { cell: { ...options, environmentName,
76
+ sourceRegions: framed.sourceRegions,
77
+ callableRanges,
78
+ staticOnly: !lexicalDynamic && options.logicalRoots !== true,
79
+ calleeSource,
80
+ environmentExpression: expression, evalOrigin: options.module === true ? undefined : evalOrigin,
81
+ writeTarget: options.module === true ? undefined : writeTarget } })
82
+ const emission = result.sourceOffsets === undefined
83
+ ? mappedSourceTransform(framed.code, framed.sourceMap, { code: result.code, map: result.sourceMap })
84
+ : applySourceEdits(framed.code, framed.sourceMap, [{ start: 0, end: framed.code.length, text: result.code, mappings: result.sourceOffsets }])
85
+ return { ...emission, sourceRegions: result.sourceRegions, callableRanges: result.callableRanges,
86
+ dynamicOrigins, dynamicEnvironmentName: environmentName }
87
+ }
@@ -0,0 +1,362 @@
1
+ import { compileDynamicSource, isCompilerSyntaxError } from './compiler-service.js'
2
+ import { createNativeCallAdapter } from './dynamic-native-runtime.js'
3
+ import { captureCompilerIntrinsics, moduleRuntimeIntrinsics as internal } from './compiler-intrinsics.js'
4
+ import { types } from 'node:util'
5
+
6
+ const reflectionIntrinsics = new internal.WeakMap()
7
+ function captureReflection(reflect) {
8
+ let captured = internal.weakMapGet(reflectionIntrinsics, reflect)
9
+ if (captured === undefined) {
10
+ captured = { apply: reflect.apply, construct: reflect.construct, get: reflect.get,
11
+ has: reflect.has, set: reflect.set, deleteProperty: reflect.deleteProperty,
12
+ defineProperty: reflect.defineProperty, ownKeys: reflect.ownKeys }
13
+ internal.weakMapSet(reflectionIntrinsics, reflect, captured)
14
+ internal.weakMapSet(reflectionIntrinsics, captured, captured)
15
+ }
16
+ return captured
17
+ }
18
+ const defaultIntrinsics = { intrinsicEval: eval, realmFunction: Function, globalObject: globalThis, reflect: captureReflection(Reflect) }
19
+
20
+ const isObject = value => value !== null && (typeof value === 'object' || typeof value === 'function')
21
+ const isMap = types.isMap
22
+ const bindingStores = new internal.WeakMap()
23
+ const asBindings = value => {
24
+ if (internal.isArray(value)) {
25
+ const result = new internal.Map()
26
+ for (let index = 0; index < value.length; index++) {
27
+ const entry = value[index]
28
+ internal.mapSet(result, entry[0], entry[1])
29
+ }
30
+ value = result
31
+ }
32
+ // Logical roots implement this same live lookup/update contract. Native Map
33
+ // storage adapts once; callers never select its mutable prototype methods.
34
+ if (!isMap(value)) return value
35
+ let result = internal.weakMapGet(bindingStores, value)
36
+ if (result !== undefined) return result
37
+ result = { has: name => internal.mapHas(value, name), get: name => internal.mapGet(value, name),
38
+ set: (name, binding) => internal.mapSet(value, name, binding), delete: name => internal.mapDelete(value, name),
39
+ forEach: visit => internal.mapForEach(value, visit) }
40
+ internal.weakMapSet(bindingStores, value, result)
41
+ return result
42
+ }
43
+
44
+ /** Native reference operations over compiler-proved lexical and object frames. */
45
+ export function createDynamicEnvironmentRuntime({
46
+ importModule = (source, options) => import(source, options),
47
+ intrinsicEval = defaultIntrinsics.intrinsicEval, realmFunction = defaultIntrinsics.realmFunction, globalObject = defaultIntrinsics.globalObject,
48
+ errors, reflect = defaultIntrinsics.reflect, object, interfaceOwner,
49
+ } = {}) {
50
+ const intrinsics = captureCompilerIntrinsics(realmFunction)
51
+ const { unscopables, Object: intrinsicObject, array: internalArray } = intrinsics
52
+ object ??= intrinsicObject
53
+ errors ??= intrinsics
54
+ // Reference mechanics use the realm's captured operations. Explicit source
55
+ // Reflect calls still observe the mutable user-visible Reflect object.
56
+ reflect = captureReflection(reflect)
57
+ const parameterEnvironments = new internal.WeakMap()
58
+ let rootEnvironment
59
+ let defaultRootEnvironment
60
+ const evaluate = (callee, receiver, args, environment, compilerOptions = {}) => {
61
+ if (!nativeCalls.isEval(callee)) return reflect.apply(callee, receiver, args)
62
+ const source = args[0]
63
+ if (typeof source !== 'string') return source
64
+ let compiled
65
+ try {
66
+ compiled = compileDynamicSource(source, { strict: environment.strict, allowNewTarget: environment.allowNewTarget,
67
+ privateNames: environment.privateNames, allowSuper: environment.allowSuper, allowSuperCall: environment.allowSuperCall,
68
+ forbidArguments: environment.forbidArguments, resolveOriginalSource: nativeCalls.originalSource, ...compilerOptions })
69
+ } catch (error) {
70
+ if (!isCompilerSyntaxError(error)) throw error
71
+ throw new errors.SyntaxError(error.message)
72
+ }
73
+ nativeCalls.registerSources(compiled.callableSources)
74
+ environment.declareEvalVars(compiled.varNames)
75
+ return nativeCalls.evaluate(compiled, environment)
76
+ }
77
+ const nativeCalls = createNativeCallAdapter({ realmFunction, intrinsicEval, reflect, errors, evaluate, interfaceOwner,
78
+ rootEnvironment(origin) {
79
+ if (rootEnvironment === undefined && defaultRootEnvironment === undefined) {
80
+ const varFrame = new internal.Map()
81
+ defaultRootEnvironment = environment({ varFrame, frames: [{ kind: 'lexical', bindings: varFrame }],
82
+ declareVars: declareGlobals,
83
+ createVar(name) {
84
+ const target = ambientReference(name, false)
85
+ return { kind: 'var', get: () => target.value, set: value => { target.value = value },
86
+ typeof: () => target.typeof(), delete: () => target.delete() }
87
+ },
88
+ })
89
+ }
90
+ return (rootEnvironment?.() ?? defaultRootEnvironment).context({ strict: false,
91
+ getThis: () => globalObject, allowNewTarget: false }).at(origin)
92
+ },
93
+ })
94
+ function declareGlobals(names, functionNames = []) {
95
+ for (let index = 0; index < functionNames.length; index++) {
96
+ const name = functionNames[index]
97
+ if (!internal.includes(names, name)) continue
98
+ const descriptor = intrinsicObject.getOwnPropertyDescriptor(globalObject, name)
99
+ const allowed = descriptor === undefined ? intrinsicObject.isExtensible(globalObject)
100
+ : descriptor.configurable || intrinsicObject.hasOwn(descriptor, 'value') && descriptor.writable && descriptor.enumerable
101
+ if (!allowed) throw new errors.TypeError(`Cannot declare global function '${name}'`)
102
+ }
103
+ nativeCalls.declareGlobals(names)
104
+ }
105
+ const reference = (name, descriptor, receiver, strict, origin, writeTarget) => descriptor.reference === undefined ? ({
106
+ get value() { return descriptor.get() },
107
+ set value(value) {
108
+ if (descriptor.kind === 'self' && descriptor.set === undefined) {
109
+ if (strict) throw new errors.TypeError('Assignment to constant variable.')
110
+ return
111
+ }
112
+ descriptor.set(value, strict, origin, writeTarget)
113
+ },
114
+ get callee() {
115
+ const value = descriptor.get()
116
+ return nativeCalls.referenceCall(value, receiver)
117
+ },
118
+ get evalInvocation() {
119
+ const value = descriptor.get()
120
+ return (environment, args, callOrigin) => nativeCalls.isEval(value)
121
+ ? () => evaluate(value, receiver, args, environment)
122
+ : nativeCalls.beginInvocation(nativeCalls.prepareInvocation(value, receiver, callOrigin), args)
123
+ },
124
+ typeof() { return descriptor.typeof === undefined ? typeof descriptor.get() : descriptor.typeof() },
125
+ delete() { return descriptor.delete === undefined ? false : descriptor.delete(strict) },
126
+ }) : descriptor.reference()
127
+ const forwardReference = resolve => ({
128
+ get value() { return resolve().value },
129
+ set value(value) { resolve().value = value },
130
+ get callee() { return resolve().callee },
131
+ get evalInvocation() { return resolve().evalInvocation },
132
+ typeof() { return resolve().typeof() },
133
+ delete() { return resolve().delete() },
134
+ })
135
+ const objectReference = (object, name, strict) => reference(name, {
136
+ get: () => reflect.get(object, name, object),
137
+ set(value) {
138
+ if (!reflect.set(object, name, value, object) && strict) throw new errors.TypeError(`Cannot assign to property '${name}'`)
139
+ },
140
+ delete() {
141
+ const deleted = reflect.deleteProperty(object, name)
142
+ if (!deleted && strict) throw new errors.TypeError(`Cannot delete property '${name}'`)
143
+ return deleted
144
+ },
145
+ }, object, strict)
146
+ const ambientReference = (name, strict) => reference(name, {
147
+ get() {
148
+ if (!reflect.has(globalObject, name)) throw new errors.ReferenceError(`${name} is not defined`)
149
+ return reflect.get(globalObject, name, globalObject)
150
+ },
151
+ set(value) {
152
+ if (strict && !reflect.has(globalObject, name)) throw new errors.ReferenceError(`${name} is not defined`)
153
+ if (!reflect.set(globalObject, name, value, globalObject) && strict) throw new errors.TypeError(`Cannot assign to '${name}'`)
154
+ },
155
+ typeof: () => reflect.has(globalObject, name) ? typeof reflect.get(globalObject, name, globalObject) : 'undefined',
156
+ delete: () => reflect.deleteProperty(globalObject, name),
157
+ }, undefined, strict)
158
+
159
+ function environment({ frames = [], varFrame = new internal.Map(), strict = false, origin, lexicalContext = {},
160
+ getThis = () => globalObject, getNewTarget = () => undefined, allowNewTarget = false,
161
+ ambient = ambientReference, createVar, declareVars, nativeAwait = false } = {}) {
162
+ varFrame = asBindings(varFrame)
163
+ const capturedFrames = []
164
+ for (let index = 0; index < frames.length; index++) {
165
+ const frame = frames[index]
166
+ internal.appendArray(capturedFrames, frame.kind === 'object' ? frame : { ...frame, bindings: asBindings(frame.bindings) })
167
+ }
168
+ frames = capturedFrames
169
+ const result = {
170
+ importModule,
171
+ internalArray,
172
+ expose: nativeCalls.exposedValue,
173
+ prepareCall: nativeCalls.prepareCall,
174
+ prepareInvocation: nativeCalls.prepareInvocation,
175
+ releaseMemberReceiver: nativeCalls.releaseMemberReceiver,
176
+ prepareMemberInvocation: nativeCalls.prepareMemberInvocation,
177
+ beginInvocation: nativeCalls.beginInvocation,
178
+ prepareTagInvocation: nativeCalls.prepareTagInvocation,
179
+ templateArguments: nativeCalls.templateArguments,
180
+ propagate: nativeCalls.propagate,
181
+ strict,
182
+ allowNewTarget,
183
+ privateNames: internal.Object.keys(lexicalContext.privateReferences ?? {}),
184
+ allowSuper: lexicalContext.getSuper !== undefined,
185
+ allowSuperCall: lexicalContext.callSuper !== undefined,
186
+ forbidArguments: lexicalContext.forbidArguments === true,
187
+ thisValue: () => getThis(),
188
+ newTarget: () => getNewTarget(),
189
+ get superReference() {
190
+ const receiver = getThis()
191
+ return key => reference(key, lexicalContext.getSuper(key), receiver, strict)
192
+ },
193
+ get superCall() { return lexicalContext.callSuper },
194
+ privateReference(name, receiver, optional = false) {
195
+ return optional && receiver == null ? undefined : reference(name, lexicalContext.privateReferences[name](receiver), receiver, strict)
196
+ },
197
+ privateHas(name, receiver) { return lexicalContext.privateReferences[name](receiver).has() },
198
+ reference(name, writeTarget) {
199
+ for (let index = 0; index < frames.length; index++) {
200
+ const frame = frames[index]
201
+ if (frame.kind === 'lexical' || frame.kind === 'self') {
202
+ if (frame.bindings.has(name)) return reference(name, frame.bindings.get(name), undefined, strict, origin, writeTarget)
203
+ } else if (reflect.has(frame.object, name)) {
204
+ const excluded = reflect.get(frame.object, unscopables, frame.object)
205
+ if (!isObject(excluded) || !reflect.get(excluded, name, excluded)) return objectReference(frame.object, name, strict)
206
+ }
207
+ }
208
+ return ambient(name, strict, origin, writeTarget)
209
+ },
210
+ deferredReference(name, writeTarget) {
211
+ return forwardReference(() => result.reference(name, writeTarget))
212
+ },
213
+ withReference(name, withDepth, fallback) {
214
+ const select = () => {
215
+ let remaining = withDepth
216
+ for (let index = 0; index < frames.length; index++) {
217
+ const frame = frames[index]
218
+ if (remaining === 0) break
219
+ if (frame.kind !== 'object') continue
220
+ remaining--
221
+ if (!reflect.has(frame.object, name)) continue
222
+ const excluded = reflect.get(frame.object, unscopables, frame.object)
223
+ if (!isObject(excluded) || !reflect.get(excluded, name, excluded)) return objectReference(frame.object, name, strict)
224
+ }
225
+ return reference(name, fallback, undefined, strict, origin)
226
+ }
227
+ return forwardReference(select)
228
+ },
229
+ initialize(name, value) {
230
+ result.reference(name).value = value
231
+ return value
232
+ },
233
+ capture(scopes, nextStrict = strict, rootIndex = -1) {
234
+ const captured = []
235
+ for (let index = 0; index < scopes.length; index++) internal.appendArray(captured, { kind: 'lexical', bindings: asBindings(scopes[index]) })
236
+ let combined = internal.copyArray(frames, 0, frames.length, internal.copyArray(captured))
237
+ if (nativeAwait && rootIndex >= 0) {
238
+ let boundary = 0
239
+ for (let index = 0; index < frames.length; index++) {
240
+ if (frames[index].kind === 'lexical' && frames[index].bindings === varFrame) { boundary = index + 1; break }
241
+ }
242
+ for (let index = rootIndex; index < captured.length; index++) captured[index].bindings.forEach((binding, name) => {
243
+ if (binding.kind === 'hoisted' && !varFrame.has(name)) varFrame.set(name, binding)
244
+ })
245
+ combined = internal.copyArray(captured, 0, rootIndex)
246
+ internal.copyArray(frames, 0, boundary, combined)
247
+ internal.copyArray(captured, rootIndex, captured.length, combined)
248
+ internal.copyArray(frames, boundary, frames.length, combined)
249
+ }
250
+ return environment({ frames: combined,
251
+ varFrame, strict: nextStrict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
252
+ },
253
+ awaitActivation() {
254
+ const local = new internal.Map()
255
+ return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'lexical', bindings: local }]), varFrame: local,
256
+ strict, getThis, getNewTarget, allowNewTarget, ambient, nativeAwait: true, origin, lexicalContext })
257
+ },
258
+ activation(bindings, nextGetThis = getThis, nextGetNewTarget = getNewTarget, nextStrict = strict, ownFunction = true, selfBindings) {
259
+ bindings = asBindings(bindings)
260
+ const activationFrames = [{ kind: 'lexical', bindings }]
261
+ if (selfBindings !== undefined) internal.appendArray(activationFrames, { kind: 'self', bindings: asBindings(selfBindings) })
262
+ return environment({ frames: internal.copyArray(frames, 0, frames.length, activationFrames), varFrame: bindings,
263
+ strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin,
264
+ lexicalContext: ownFunction ? { privateReferences: lexicalContext.privateReferences } : lexicalContext })
265
+ },
266
+ parameters(key, bindings, nextGetThis = getThis, nextGetNewTarget = getNewTarget, nextStrict = strict, ownFunction = true, selfBindings) {
267
+ let selected = internal.weakMapGet(parameterEnvironments, key)
268
+ if (selected === undefined) {
269
+ bindings = asBindings(bindings)
270
+ if (ownFunction && !bindings.has('arguments')) {
271
+ let value = key
272
+ bindings.set('arguments', { kind: 'param', get: () => value, set: next => { value = next } })
273
+ }
274
+ const parameterFrames = [{ kind: 'lexical', bindings }]
275
+ if (selfBindings !== undefined) internal.appendArray(parameterFrames, { kind: 'self', bindings: asBindings(selfBindings) })
276
+ selected = environment({ frames: internal.copyArray(frames, 0, frames.length, parameterFrames), varFrame: bindings,
277
+ strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin, lexicalContext })
278
+ internal.weakMapSet(parameterEnvironments, key, selected)
279
+ }
280
+ return selected
281
+ },
282
+ propertyKey(value) { return reflect.ownKeys({ [value]: undefined })[0] },
283
+ parameterArrow(fn, name) {
284
+ intrinsics.Reflect.defineProperty(fn, 'length', { value: internal.max(0, fn.length - 1) })
285
+ if (name !== undefined && fn.name === '') intrinsics.Reflect.defineProperty(fn, 'name', { value: name })
286
+ const adapter = new internal.Proxy(fn, { apply(target, receiver, args) {
287
+ return reflect.apply(target, receiver, internal.copyArray(args, 0, args.length, [{}]))
288
+ } })
289
+ return nativeCalls.registerCallableSourceTarget(adapter, fn)
290
+ },
291
+ context(options) { return environment({ frames, varFrame, strict: options.strict ?? strict,
292
+ getThis: options.getThis ?? getThis, getNewTarget: options.getNewTarget ?? getNewTarget,
293
+ allowNewTarget: options.allowNewTarget ?? allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin,
294
+ lexicalContext: { ...lexicalContext, ...options } }) },
295
+ at(nextOrigin) { return environment({ frames, varFrame, strict, getThis, getNewTarget,
296
+ allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin: nextOrigin, lexicalContext }) },
297
+ withObject(value) {
298
+ if (value === null || value === undefined) throw new errors.TypeError('Cannot convert undefined or null to object')
299
+ return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'object', object: object(value) }]),
300
+ varFrame, strict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
301
+ },
302
+ declareEvalVars(names) {
303
+ // EvalDeclarationInstantiation checks every name before any initializer
304
+ // runs. Object environments do not create lexical conflicts.
305
+ for (let index = 0; index < names.length; index++) {
306
+ const name = names[index]
307
+ for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
308
+ const frame = frames[frameIndex]
309
+ if (frame.kind !== 'lexical') continue
310
+ const binding = frame.bindings.get(name)
311
+ if (binding !== undefined && binding.kind !== 'var' && binding.kind !== 'param' && binding.kind !== 'hoisted') {
312
+ throw new errors.SyntaxError(`Identifier '${name}' has already been declared`)
313
+ }
314
+ if (frame.bindings === varFrame) break
315
+ }
316
+ }
317
+ if (declareVars === undefined) {
318
+ const declarations = []
319
+ for (let index = 0; index < names.length; index++) internal.appendArray(declarations, [names[index]])
320
+ result.initializeEvalDeclarations(declarations)
321
+ }
322
+ },
323
+ initializeEvalDeclarations(declarations) {
324
+ for (let index = 0; index < declarations.length; index++) {
325
+ const declaration = declarations[index]
326
+ const name = declaration[0], value = declaration[1], isFunction = declaration[2] === true
327
+ declareVars?.([name], isFunction ? [name] : [])
328
+ if (!varFrame.has(name)) {
329
+ if (createVar !== undefined) varFrame.set(name, createVar(name, origin))
330
+ else {
331
+ let current
332
+ const binding = { kind: 'var', get: () => current, set: next => {
333
+ current = next
334
+ varFrame.set(name, binding)
335
+ }, delete: () => varFrame.delete(name) }
336
+ varFrame.set(name, binding)
337
+ }
338
+ }
339
+ if (isFunction) result.initializeEvalFunction(name, value)
340
+ }
341
+ },
342
+ initializeEvalFunction(name, value) { varFrame.get(name).set(value, strict, origin) },
343
+ }
344
+ return result
345
+ }
346
+ return {
347
+ installIntrinsics() { nativeCalls.install(); return this },
348
+ exposedIntrinsic: nativeCalls.exposedValue,
349
+ registerSources: nativeCalls.registerSources,
350
+ declareGlobals,
351
+ setRootEnvironment(getEnvironment) { rootEnvironment = getEnvironment },
352
+ reference,
353
+ environment(options = {}) {
354
+ const varFrame = options.varFrame ?? new internal.Map()
355
+ const frames = internal.copyArray(options.frames ?? [])
356
+ if (options.nativeBindings !== undefined) internal.appendArray(frames, { kind: 'lexical', bindings: asBindings(options.nativeBindings) })
357
+ internal.appendArray(frames, { kind: 'lexical', bindings: varFrame })
358
+ return environment({ ...options, varFrame, frames })
359
+ },
360
+ evaluate,
361
+ }
362
+ }
@@ -0,0 +1,150 @@
1
+ import traverseModule from '@babel/traverse'
2
+ import { types as t } from '@babel/core'
3
+ import { transform as transformOptional, transformOptionalChain } from '@babel/plugin-transform-optional-chaining'
4
+ import { isWriteIdentifier as isWriteTarget } from './binding-pattern.js'
5
+ import { withGeneratedNameAllocator } from './compiler-generated-names.js'
6
+
7
+ const traverse = traverseModule.default ?? traverseModule
8
+
9
+ /** Select intrinsic interfaces at owned source value and invocation boundaries. */
10
+ export function rewriteNativeCalls(tree, environment, { origin, skip, operations, originalCallees, allocate }) {
11
+ const { internal } = operations
12
+ let memberReceiver
13
+ let programScope
14
+ const helper = (name, args) => {
15
+ return operations.operation(t.callExpression(t.memberExpression(t.cloneNode(environment), t.identifier(name)), args))
16
+ }
17
+ const skipOwned = path => path.isTSType() || skip(path)
18
+ || operations.callee(path.node)
19
+ const undefinedValue = () => t.unaryExpression('void', t.numericLiteral(0))
20
+ if (originalCallees === undefined) {
21
+ originalCallees = new WeakSet()
22
+ traverse(tree, {
23
+ enter(path) { if (path.isTSType() || skip(path)) path.skip() },
24
+ 'CallExpression|OptionalCallExpression'(path) { originalCallees.add(path.node.callee) },
25
+ })
26
+ }
27
+ traverse(tree, { Program(path) { programScope = path.scope; path.stop() } })
28
+ const expose = path => {
29
+ // Only GetValue results select an interface. References must retain their
30
+ // write/delete semantics, receivers and optional-chain short circuiting.
31
+ const parent = path.parentPath
32
+ if (operations.owns(path.node) && !operations.isValue(path.node)
33
+ || !path.isReferenced() || isWriteTarget(path) || parent.isUnaryExpression({ operator: 'delete' })
34
+ || parent.isUnaryExpression({ operator: 'typeof' }) && path.isIdentifier()
35
+ || (parent.isCallExpression() || parent.isOptionalCallExpression()) && path.key === 'callee'
36
+ || parent.isTaggedTemplateExpression() && path.key === 'tag'
37
+ || parent.isDecorator()
38
+ || parent.isOptionalMemberExpression() && path.key === 'object'
39
+ || path.isIdentifier() && internal.has(path.node.name)) return
40
+ if (parent.isObjectProperty() && parent.node.shorthand) {
41
+ parent.node.shorthand = false
42
+ parent.node.computed = true
43
+ parent.node.key = t.stringLiteral(path.node.name)
44
+ }
45
+ path.replaceWith(t.inherits(helper('expose', [path.node]), path.node))
46
+ path.skip()
47
+ }
48
+ const prepare = (callee, target, optional = false) => {
49
+ const stamp = target === undefined ? undefinedValue() : t.valueToNode(target)
50
+ const options = [stamp, t.booleanLiteral(optional)]
51
+ const prepared = (name, args) => t.inherits(helper(name, args), callee)
52
+ if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
53
+ if (t.isSuper(callee.object)) return prepared('prepareInvocation', [callee, t.thisExpression(), ...options])
54
+ if (memberReceiver === undefined) {
55
+ memberReceiver = t.identifier(allocate('member_receiver'))
56
+ programScope.push({ id: memberReceiver })
57
+ internal.add(memberReceiver.name)
58
+ }
59
+ // Argument evaluation saves the receiver before key/getter reentrancy can
60
+ // change the temporary; the member read itself stays in its source frame.
61
+ const receiver = helper('releaseMemberReceiver', [t.cloneNode(memberReceiver),
62
+ t.assignmentExpression('=', t.cloneNode(memberReceiver), undefinedValue())])
63
+ return prepared('prepareMemberInvocation', [t.assignmentExpression('=', t.cloneNode(memberReceiver), callee.object),
64
+ t.inherits(t.memberExpression(receiver, callee.property, callee.computed), callee), ...options])
65
+ }
66
+ return prepared('prepareInvocation', [callee, undefinedValue(), ...options])
67
+ }
68
+ const invoke = (prepared, args) => operations.operation(t.callExpression(helper('beginInvocation', [prepared, args]), []))
69
+ // Receiver extraction must run after complete chains acquire their native
70
+ // short-circuit boundary, including grouped calls and computed-key effects.
71
+ traverse(tree, {
72
+ enter(path) { if (skipOwned(path)) path.skip() },
73
+ 'OptionalCallExpression|OptionalMemberExpression'(path) {
74
+ const assumptions = { pureGetters: false, noDocumentAll: false }
75
+ withGeneratedNameAllocator(path.scope, allocate, () => {
76
+ if (path.isOptionalMemberExpression() && path.parentPath.isTaggedTemplateExpression()) {
77
+ const target = origin(path.parent)
78
+ transformOptionalChain(path, assumptions, path, undefinedValue(), callee => helper('prepareTagInvocation', [prepare(callee, target)]))
79
+ } else transformOptional(path, assumptions)
80
+ })
81
+ },
82
+ })
83
+ traverse(tree, {
84
+ enter(path) { if (skipOwned(path)) path.skip() },
85
+ 'TSAsExpression|TSSatisfiesExpression|TSNonNullExpression|TSTypeAssertion': { enter(path) {
86
+ path.replaceWith(path.node.expression)
87
+ } },
88
+ ExportSpecifier(path) {
89
+ // Babel's printer compares identifier names when eliding an alias. Both
90
+ // string ModuleExportNames otherwise appear equal as undefined names.
91
+ const { local, exported } = path.node
92
+ if (t.isStringLiteral(local) && t.isStringLiteral(exported)) exported.name = exported.value
93
+ path.skip()
94
+ },
95
+ ReferencedIdentifier: { exit: expose },
96
+ 'MemberExpression|OptionalMemberExpression|AwaitExpression|YieldExpression': { exit: expose },
97
+ ThrowStatement: { exit(path) {
98
+ if (operations.owns(path.node)) return
99
+ const argument = path.node.argument
100
+ path.node.argument = t.inherits(helper('propagate', [argument, t.valueToNode(origin(argument))]), argument)
101
+ path.skip()
102
+ } },
103
+ 'CallExpression|OptionalCallExpression': { exit(path) {
104
+ if (operations.owns(path.node)) {
105
+ if (operations.isValue(path.node)) expose(path)
106
+ return
107
+ }
108
+ if (t.isSuper(path.node.callee) || t.isImport(path.node.callee)
109
+ || t.isIdentifier(path.node.callee, { name: 'eval' })) return
110
+ const node = path.node
111
+ // Babel expresses saved receivers through generated call/bind members.
112
+ // The intrinsic interface already owns invocation, so use the saved
113
+ // receiver directly without observing user-replaced call/bind properties.
114
+ if (t.isMemberExpression(node.callee) && !originalCallees.has(node.callee)
115
+ && t.isIdentifier(node.callee.property) && ['call', 'bind'].includes(node.callee.property.name)) {
116
+ const prepared = helper('prepareInvocation', [node.callee.object, node.arguments[0],
117
+ t.valueToNode(origin(node)), t.booleanLiteral(false)])
118
+ path.replaceWith(t.inherits(node.callee.property.name === 'bind'
119
+ ? helper('prepareTagInvocation', [prepared]) : invoke(prepared, t.arrayExpression(node.arguments.slice(1))), node))
120
+ path.skip()
121
+ return
122
+ }
123
+ const callee = prepare(node.callee, origin(node), node.optional === true)
124
+ path.replaceWith(t.inherits(invoke(callee, t.arrayExpression(node.arguments)), node))
125
+ path.skip()
126
+ } },
127
+ NewExpression: { exit(path) {
128
+ if (operations.owns(path.node)) return
129
+ const target = origin(path.node)
130
+ const invocation = t.inherits(invoke(helper('prepareInvocation', [path.node.callee, undefinedValue(),
131
+ target === undefined ? undefinedValue() : t.valueToNode(target), t.booleanLiteral(false), t.booleanLiteral(true)]), t.arrayExpression(path.node.arguments)), path.node)
132
+ // Native Error construction records the continuation call site. Anchor
133
+ // that private call to the original new expression, after its arguments.
134
+ if (invocation.loc !== undefined) invocation.callee.loc = { ...invocation.loc, end: invocation.loc.start }
135
+ path.replaceWith(invocation)
136
+ path.skip()
137
+ } },
138
+ TaggedTemplateExpression: { exit(path) {
139
+ if (operations.owns(path.node)) return
140
+ const args = t.taggedTemplateExpression(t.memberExpression(t.cloneNode(environment), t.identifier('templateArguments')), path.node.quasi)
141
+ path.replaceWith(t.inherits(invoke(prepare(path.node.tag, origin(path.node)), args), path.node))
142
+ path.skip()
143
+ } },
144
+ Decorator: { exit(path) {
145
+ if (operations.owns(path.node)) return
146
+ path.node.expression = helper('prepareTagInvocation', [prepare(path.node.expression, origin(path.node))])
147
+ path.skip()
148
+ } },
149
+ })
150
+ }