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.
- package/README.en.md +63 -80
- package/README.md +63 -80
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +30827 -742
- package/compiler-amaro.cjs +5 -0
- package/compiler-amaro.cjs.map +6 -0
- package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
- package/compiler-assets.json +3 -0
- package/compiler-core.cjs +556 -0
- package/compiler-core.cjs.map +6 -0
- package/compiler-platform.cjs +2 -0
- package/compiler-platform.cjs.map +6 -0
- package/compiler-typescript.cjs +388 -0
- package/compiler-typescript.cjs.map +6 -0
- package/docs/README.md +7 -0
- package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
- package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
- package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
- package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
- package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
- package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
- package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
- package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
- package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
- package/docs/adr/0023-global-user-bindings.md +104 -0
- package/docs/adr/0024-repl-console-observation.md +33 -0
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
- package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
- package/docs/architecture.md +77 -21
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +95 -19
- package/docs/durability-design.md +28 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +76 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +759 -0
- package/docs/user-bindings.en.md +66 -0
- package/docs/user-bindings.md +66 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +71 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/async-local-storage-intrinsics.js +38 -0
- package/internal/binding-declaration-contract.js +8 -0
- package/internal/binding-descriptors.js +1 -0
- package/internal/binding-pattern-traversal.js +25 -0
- package/internal/binding-pattern.js +26 -29
- package/internal/binding-source-analysis.js +708 -0
- package/internal/binding-update-policy.js +72 -0
- package/internal/bounded-worker-round.js +56 -0
- package/internal/callable-definition-environment.js +42 -0
- package/internal/callable-source-catalog.js +129 -0
- package/internal/callable-source-encoding.js +47 -0
- package/internal/callable-source-facts.js +459 -0
- package/internal/callable-source-format.js +2 -0
- package/internal/callable-source-lowering.js +123 -0
- package/internal/cell-analysis-contract.js +25 -0
- package/internal/cell-analysis.js +253 -290
- package/internal/cell-completion.js +15 -0
- package/internal/cell-error.js +7 -0
- package/internal/cell-parser.js +66 -0
- package/internal/cell-rewriter.js +3 -677
- package/internal/commonjs-export-evidence.js +63 -0
- package/internal/commonjs-source-evidence.js +72 -0
- package/internal/compiler-amaro.cjs +2 -0
- package/internal/compiler-compression.js +12 -0
- package/internal/compiler-data.js +58 -0
- package/internal/compiler-descriptors.js +54 -0
- package/internal/compiler-dynamic-cache.js +48 -0
- package/internal/compiler-entry.js +35 -0
- package/internal/compiler-generated-names.js +17 -0
- package/internal/compiler-intrinsics.js +50 -0
- package/internal/compiler-module-links.js +37 -0
- package/internal/compiler-operations.js +61 -0
- package/internal/compiler-platform-factory.js +84 -0
- package/internal/compiler-platform.js +136 -0
- package/internal/compiler-record-roles.js +53 -0
- package/internal/compiler-region-output.js +259 -0
- package/internal/compiler-resource-lowering.js +103 -0
- package/internal/compiler-scope-facts.js +115 -0
- package/internal/compiler-service.js +109 -0
- package/internal/compiler-source-cache.js +32 -0
- package/internal/compiler-source-pieces.js +93 -0
- package/internal/compiler-source-regions.js +132 -0
- package/internal/compiler-storage-source.js +54 -0
- package/internal/compiler-text.js +15 -0
- package/internal/compiler-typescript.cjs +2 -0
- package/internal/config-spec.js +83 -27
- package/internal/cordis-tools-owner.js +130 -21
- package/internal/diagnostic.js +27 -1
- package/internal/direct-surface-owner.js +76 -23
- package/internal/dynamic-binding-evidence.js +16 -0
- package/internal/dynamic-environment-compiler.js +779 -0
- package/internal/dynamic-environment-integration.js +91 -0
- package/internal/dynamic-environment-runtime.js +383 -0
- package/internal/dynamic-native-calls.js +153 -0
- package/internal/dynamic-native-runtime.js +262 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +27 -2
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +136 -28
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +555 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +1179 -233
- package/internal/language-semantics.js +14 -0
- package/internal/legacy-binding-catalog.js +48 -0
- package/internal/legacy-cell-analysis.js +600 -0
- package/internal/legacy-cell-parser.js +50 -0
- package/internal/legacy-cell-rewriter.js +631 -0
- package/internal/legacy-repl-convenience.js +291 -0
- package/internal/managed-module-operations.js +170 -0
- package/internal/module-compilation.js +322 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +42 -0
- package/internal/native-await-declarations.js +68 -0
- package/internal/native-root-compilation.js +54 -0
- package/internal/native-root-dynamic.js +67 -0
- package/internal/record-utils.js +24 -15
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -289
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +6 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +117 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -52
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +402 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +123 -0
- package/internal/session-journal.js +199 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +257 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +230 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +600 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +31 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +244 -0
- package/internal/user-binding-console.js +148 -0
- package/internal/user-binding-draft-projection.js +335 -0
- package/internal/user-binding-model-context.js +31 -0
- package/internal/user-binding-runner.js +56 -0
- package/internal/user-bindings-owner.js +1065 -0
- package/internal/user-bindings-store.js +293 -0
- package/internal/user-bindings.js +361 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +130 -91
- package/internal/worker-client.js +57 -67
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +65 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-repl-realm.js +134 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +76 -7
- package/src/client-activity.js +95 -53
- package/src/client-authoring-view.js +580 -0
- package/src/client-binding-review.js +230 -0
- package/src/client-bindings-data.js +29 -0
- package/src/client-catalog.js +127 -0
- package/src/client-code-editor.js +84 -0
- package/src/client-console.js +112 -0
- package/src/client-copy.js +370 -0
- package/src/client-feature-gates.js +62 -0
- package/src/client-host-compat.js +150 -0
- package/src/client-indicator-view.js +267 -0
- package/src/client-repl-view.js +292 -0
- package/src/client-rpc.js +20 -0
- package/src/client-settings-view.js +221 -0
- package/src/client-styles.js +106 -0
- package/src/client-tool-view.js +108 -0
- package/src/client-transport.js +159 -0
- package/src/client-workbench.js +521 -0
- package/src/client.js +233 -615
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { staticModuleLinkReference } from './compiler-module-links.js'
|
|
2
|
+
import { parse } from '@babel/parser'
|
|
3
|
+
import { types as t } from '@babel/core'
|
|
4
|
+
import { CELL_PARSER_PLUGINS, normalizeStatefulScopes, normalizeTypeScriptValues, lowerNativeLanguageSource,
|
|
5
|
+
hasModuleResources } from './repl-scope-normalizer.js'
|
|
6
|
+
import { bindingNodes, createGeneratedNameAllocator } from './binding-pattern.js'
|
|
7
|
+
import { applySourceEdits, identitySourceMap, sourceOffsetAt } from './source-position-map.js'
|
|
8
|
+
import { applyRegionEdits, indexSourceRegions, visitRegionSource, transformRegionSource, validateRegionSource, sourceRegionData } from './compiler-region-output.js'
|
|
9
|
+
import { adaptDynamicCell } from './dynamic-environment-integration.js'
|
|
10
|
+
import { adaptLegacyModuleReferences, adaptModuleOperations } from './managed-module-operations.js'
|
|
11
|
+
import { markCallableSources, collectRegionCallableRanges, createRegionCallableCollector, emitRegionCallableSources, callableSourceCatalog } from './callable-source-facts.js'
|
|
12
|
+
import { commonJsExportEvidence } from './commonjs-source-evidence.js'
|
|
13
|
+
export { commonJsExportEvidence, linkCommonJsEvidenceSource } from './commonjs-source-evidence.js'
|
|
14
|
+
import { COMMONJS_PARAMETERS } from './compiler-scope-facts.js'
|
|
15
|
+
import {
|
|
16
|
+
LEGACY_USER_BINDING_TRANSFORM, USER_BINDING_TRANSFORM, PROTECTED_MODULE_TRANSFORM,
|
|
17
|
+
isStatefulUserBindingTransform, supportedUserBindingTransform, transformTypeScriptSource,
|
|
18
|
+
} from './typescript-transform.js'
|
|
19
|
+
|
|
20
|
+
const topLevelRegion = region => region.kind === 'program' || region.top === true
|
|
21
|
+
|
|
22
|
+
/** Keep one native export mapping while executing every source occurrence. */
|
|
23
|
+
function normalizeModuleExports(source, sourceMap) {
|
|
24
|
+
const tree = parse(source, { sourceType: 'module', errorRecovery: true,
|
|
25
|
+
plugins: CELL_PARSER_PLUGINS })
|
|
26
|
+
for (const error of tree.errors) if (error.reasonCode === 'ModuleExportUndefined') throw error
|
|
27
|
+
const allocate = createGeneratedNameAllocator(tree)
|
|
28
|
+
const exports = new Map()
|
|
29
|
+
const edits = []
|
|
30
|
+
const anonymousFunctions = []
|
|
31
|
+
const dependencyEdits = []
|
|
32
|
+
const exportName = node => node.type === 'Identifier' ? node.name : node.value
|
|
33
|
+
for (const statement of tree.program.body) {
|
|
34
|
+
if (statement.type === 'ExportDefaultDeclaration') {
|
|
35
|
+
const declaration = statement.declaration
|
|
36
|
+
const named = ['FunctionDeclaration', 'ClassDeclaration'].includes(declaration.type)
|
|
37
|
+
if (declaration.type === 'FunctionDeclaration' && declaration.id === null) {
|
|
38
|
+
// Its synthetic native binding is inaccessible to source writes. Keep
|
|
39
|
+
// instantiation-time identity and the native inferred name "default".
|
|
40
|
+
exports.set('default', { nativeFunction: statement })
|
|
41
|
+
anonymousFunctions.push(statement)
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
const local = named && declaration.id !== null ? declaration.id.name : allocate('module_default')
|
|
45
|
+
exports.set('default', local)
|
|
46
|
+
if (named && declaration.id !== null) {
|
|
47
|
+
edits.push({ start: statement.start, end: declaration.start, text: '' })
|
|
48
|
+
} else {
|
|
49
|
+
const value = source.slice(declaration.start, declaration.end)
|
|
50
|
+
const anonymous = declaration.type === 'ClassDeclaration'
|
|
51
|
+
|| ['FunctionExpression', 'ClassExpression', 'ArrowFunctionExpression'].includes(declaration.type) && declaration.id == null
|
|
52
|
+
edits.push({ start: statement.start, end: statement.end,
|
|
53
|
+
text: `let ${local} = (${anonymous ? `({default: (${value})}).default` : value});` })
|
|
54
|
+
}
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
if (statement.type !== 'ExportNamedDeclaration') continue
|
|
58
|
+
const declaration = statement.declaration
|
|
59
|
+
if (declaration !== null && declaration !== undefined) {
|
|
60
|
+
const names = declaration.type === 'VariableDeclaration'
|
|
61
|
+
? declaration.declarations.flatMap(item => bindingNodes(item.id)).map(item => item.name)
|
|
62
|
+
: declaration.id?.type === 'Identifier' ? [declaration.id.name] : []
|
|
63
|
+
for (const name of names) exports.set(name, name)
|
|
64
|
+
edits.push({ start: statement.start, end: declaration.start, text: '' })
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
const dependencies = []
|
|
68
|
+
for (const specifier of statement.specifiers) {
|
|
69
|
+
if (specifier.exportKind === 'type') continue
|
|
70
|
+
const name = exportName(specifier.exported)
|
|
71
|
+
if (statement.source === null || statement.source === undefined) {
|
|
72
|
+
exports.set(name, exportName(specifier.local))
|
|
73
|
+
} else {
|
|
74
|
+
const local = allocate('module_export')
|
|
75
|
+
const binding = specifier.type === 'ExportNamespaceSpecifier'
|
|
76
|
+
? `* as ${local}` : `{ ${JSON.stringify(exportName(specifier.local))} as ${local} }`
|
|
77
|
+
const dependency = `import ${binding} from ${source.slice(statement.source.start, statement.end)}`
|
|
78
|
+
const mapping = specifier.type === 'ExportNamespaceSpecifier' ? `* as ${JSON.stringify(name)}`
|
|
79
|
+
: `{ ${JSON.stringify(exportName(specifier.local))} as ${JSON.stringify(name)} }`
|
|
80
|
+
const selected = { native: `export ${mapping} from ${source.slice(statement.source.start, statement.end)}` }
|
|
81
|
+
exports.set(name, selected)
|
|
82
|
+
dependencies.push({ name, selected, dependency })
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (statement.source != null && statement.specifiers.length === 0) {
|
|
86
|
+
dependencies.push(`import ${source.slice(statement.source.start, statement.end)}`)
|
|
87
|
+
}
|
|
88
|
+
dependencyEdits.push({ start: statement.start, end: statement.end, dependencies })
|
|
89
|
+
}
|
|
90
|
+
for (const statement of anonymousFunctions) {
|
|
91
|
+
if (exports.get('default')?.nativeFunction !== statement) {
|
|
92
|
+
// An anonymous function declaration has no initializer effects or local
|
|
93
|
+
// source name once a later export mapping replaces its only exposure.
|
|
94
|
+
edits.push({ start: statement.start, end: statement.end, text: '' })
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const { start, end, dependencies } of dependencyEdits) {
|
|
98
|
+
// A retained native re-export already owns linking. An extra named import
|
|
99
|
+
// can make Node reject an otherwise valid cyclic forwarding graph. Only
|
|
100
|
+
// replaced mappings need a separate import to retain their source effects
|
|
101
|
+
// and missing-export validation.
|
|
102
|
+
edits.push({ start, end, text: dependencies.filter(item => typeof item === 'string' || exports.get(item.name) !== item.selected)
|
|
103
|
+
.map(item => typeof item === 'string' ? item : item.dependency).join('\n') })
|
|
104
|
+
}
|
|
105
|
+
const locals = [...exports].filter(([, binding]) => typeof binding === 'string')
|
|
106
|
+
const native = [...exports.values()].filter(binding => binding.native !== undefined).map(binding => binding.native)
|
|
107
|
+
if (exports.size > 0) edits.push({ start: source.length, end: source.length,
|
|
108
|
+
text: `\n${locals.length > 0 ? `export { ${locals.map(([name, local]) => `${local} as ${JSON.stringify(name)}`).join(', ')} };\n` : ''}${native.join('\n')}\n` })
|
|
109
|
+
return applySourceEdits(source, sourceMap, edits)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function moduleLinkPlan(source) {
|
|
113
|
+
const tree = parse(source, { sourceType: 'module', errorRecovery: true,
|
|
114
|
+
allowUndeclaredExports: true, plugins: CELL_PARSER_PLUGINS })
|
|
115
|
+
const allocate = createGeneratedNameAllocator(tree)
|
|
116
|
+
const reader = allocate('module_import_read')
|
|
117
|
+
const nativeReader = allocate('module_native_read')
|
|
118
|
+
const internalBindings = [reader, nativeReader]
|
|
119
|
+
const exports = []
|
|
120
|
+
const stars = []
|
|
121
|
+
const exportName = node => node.name ?? node.value
|
|
122
|
+
for (const statement of tree.program.body) {
|
|
123
|
+
if (statement.type === 'ExportDefaultDeclaration') exports.push({ name: 'default', kind: 'native' })
|
|
124
|
+
if (!['ExportNamedDeclaration', 'ExportAllDeclaration'].includes(statement.type)) continue
|
|
125
|
+
const relation = statement.source ? { source: statement.source.value,
|
|
126
|
+
attributes: Object.fromEntries((statement.attributes ?? [])
|
|
127
|
+
.map(attribute => [exportName(attribute.key), attribute.value.value])) } : undefined
|
|
128
|
+
if (statement.type === 'ExportAllDeclaration') stars.push(relation)
|
|
129
|
+
else for (const item of statement.specifiers) {
|
|
130
|
+
const name = exportName(item.exported)
|
|
131
|
+
exports.push(relation === undefined ? { name, kind: 'accessor' }
|
|
132
|
+
: item.type === 'ExportNamespaceSpecifier' ? { name, kind: 'namespace', ...relation }
|
|
133
|
+
: { name, kind: 'forward', imported: exportName(item.local), ...relation })
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const runtime = new URL('./stateful-module-runtime.js', import.meta.url).href
|
|
137
|
+
return { reader, internalBindings, moduleInterface: { exports, stars },
|
|
138
|
+
prefix: `import {readModuleImport as ${nativeReader}} from ${JSON.stringify(runtime)};\nfunction ${reader}(source,name,get,attributes){return ${nativeReader}(import.meta.url,source,name,get,attributes)}\n` }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function adaptStaticModuleLinks(normalized, staticLinks) {
|
|
142
|
+
const edits = []
|
|
143
|
+
visitRegionSource(normalized, { sourceType: 'module', plugins: CELL_PARSER_PLUGINS }, input => {
|
|
144
|
+
for (const node of input.selected.body) {
|
|
145
|
+
if (node.source == null || !['ImportDeclaration', 'ExportNamedDeclaration', 'ExportAllDeclaration'].includes(node.type)) continue
|
|
146
|
+
const source = node.source.value
|
|
147
|
+
const attributes = Object.fromEntries((node.attributes ?? []).map(item => [item.key.name ?? item.key.value, item.value.value]))
|
|
148
|
+
const reference = staticModuleLinkReference(source, attributes)
|
|
149
|
+
staticLinks.push({ source, reference })
|
|
150
|
+
edits.push({ start: sourceOffsetAt(input.sourceMap, node.source.start),
|
|
151
|
+
end: sourceOffsetAt(input.sourceMap, node.source.end - 1) + 1,
|
|
152
|
+
text: JSON.stringify(reference) })
|
|
153
|
+
}
|
|
154
|
+
}, topLevelRegion)
|
|
155
|
+
return applyRegionEdits(normalized, edits)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function commonJsBodyRange(source) {
|
|
159
|
+
const body = parse(source).program.body[0].body
|
|
160
|
+
return { start: body.start + 1, end: body.end - 1 }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Module activations share lexical updates while retaining the native linker. */
|
|
164
|
+
export function compileStatefulModule(source, {
|
|
165
|
+
transform = USER_BINDING_TRANSFORM, target = 'module', url, nativeUsing, programBindings = false,
|
|
166
|
+
} = {}) {
|
|
167
|
+
if (transform !== PROTECTED_MODULE_TRANSFORM && !supportedUserBindingTransform(transform)) {
|
|
168
|
+
throw new TypeError('user binding snapshot cannot prove its historical TypeScript transform')
|
|
169
|
+
}
|
|
170
|
+
const staticLinks = []
|
|
171
|
+
const sourceType = target === 'commonjs' ? 'commonjs' : 'module'
|
|
172
|
+
const callableParserOptions = { sourceType, plugins: CELL_PARSER_PLUGINS,
|
|
173
|
+
...(target === 'commonjs' ? { allowAwaitOutsideFunction: undefined, allowReturnOutsideFunction: undefined } : {}) }
|
|
174
|
+
let mapped = { code: source, sourceMap: identitySourceMap(source.length) }
|
|
175
|
+
let callableSources = []
|
|
176
|
+
let nativeJavaScript = false
|
|
177
|
+
if (source.startsWith('#!')) {
|
|
178
|
+
// Interpreter directives belong to the source's first line, never to the
|
|
179
|
+
// prefixed module or CommonJS wrapper. Retain its original line boundary.
|
|
180
|
+
const directive = source.match(/^#![^\n\r\u2028\u2029]*/u)
|
|
181
|
+
mapped = applySourceEdits(source, mapped.sourceMap, [{ start: 0,
|
|
182
|
+
end: directive[0].length, text: '' }])
|
|
183
|
+
}
|
|
184
|
+
if (transform !== LEGACY_USER_BINDING_TRANSFORM) {
|
|
185
|
+
const marked = markCallableSources(mapped.code, mapped.sourceMap, callableParserOptions,
|
|
186
|
+
{ lowerNativeSource: lowerNativeLanguageSource, nativeUsing })
|
|
187
|
+
callableSources = marked.callableSources
|
|
188
|
+
nativeJavaScript = marked.nativeJavaScript
|
|
189
|
+
mapped = marked
|
|
190
|
+
if (!nativeJavaScript) mapped = normalizeTypeScriptValues(mapped.code, mapped.sourceMap, target)
|
|
191
|
+
if (target !== 'commonjs' && (isStatefulUserBindingTransform(transform)
|
|
192
|
+
|| transform === PROTECTED_MODULE_TRANSFORM && hasModuleResources(mapped.code))) {
|
|
193
|
+
mapped = normalizeModuleExports(mapped.code, mapped.sourceMap)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const commonJsSource = target === 'commonjs'
|
|
197
|
+
? commonJsExportEvidence(mapped.code, { legacy: transform === LEGACY_USER_BINDING_TRANSFORM }) : undefined
|
|
198
|
+
const links = isStatefulUserBindingTransform(transform) && target === 'module'
|
|
199
|
+
? moduleLinkPlan(mapped.code) : undefined
|
|
200
|
+
let normalized = transform === LEGACY_USER_BINDING_TRANSFORM ? mapped
|
|
201
|
+
: normalizeStatefulScopes(mapped.code, mapped.sourceMap, { target, moduleImport: links?.reader, nativeJavaScript, nativeUsing,
|
|
202
|
+
mode: transform === PROTECTED_MODULE_TRANSFORM ? 'protected-v1' : 'stateful-v1' })
|
|
203
|
+
// Protected entries retain native declaration policy; adapters still need
|
|
204
|
+
// bounded source regions after TypeScript and decorator lowering.
|
|
205
|
+
if (transform === PROTECTED_MODULE_TRANSFORM && normalized.sourceRegions === undefined) normalized = { ...normalized,
|
|
206
|
+
sourceRegions: indexSourceRegions(normalized.code, callableParserOptions) }
|
|
207
|
+
let protectedInterface
|
|
208
|
+
if (transform === PROTECTED_MODULE_TRANSFORM && target === 'module') {
|
|
209
|
+
const lexicalExports = normalized.moduleLexicalExports
|
|
210
|
+
normalized = adaptLegacyModuleReferences(normalized)
|
|
211
|
+
protectedInterface = normalized.moduleInterface
|
|
212
|
+
if (lexicalExports !== undefined) protectedInterface = { ...protectedInterface,
|
|
213
|
+
exports: protectedInterface.exports.map(entry => lexicalExports.has(entry.name) ? { ...entry, kind: 'accessor' } : entry) }
|
|
214
|
+
}
|
|
215
|
+
if (links !== undefined) normalized = { ...applyRegionEdits(normalized,
|
|
216
|
+
[{ start: 0, end: 0, text: links.prefix }]),
|
|
217
|
+
internalBindings: new Set([...normalized.internalBindings ?? [], ...links.internalBindings]) }
|
|
218
|
+
const classificationCode = normalized.code
|
|
219
|
+
if (links !== undefined || protectedInterface !== undefined) normalized = adaptStaticModuleLinks(normalized, staticLinks)
|
|
220
|
+
if (transform !== LEGACY_USER_BINDING_TRANSFORM) normalized = adaptModuleOperations(normalized, { target, url })
|
|
221
|
+
if (transform !== LEGACY_USER_BINDING_TRANSFORM) normalized = { ...normalized, ...adaptDynamicCell(normalized.code, normalized.sourceMap, {
|
|
222
|
+
sourceRegions: normalized.sourceRegions,
|
|
223
|
+
callableCollector: createRegionCallableCollector(callableSources),
|
|
224
|
+
module: true, compactOutput: true, importOperation: normalized.importOperation, sourceType, originalSource: source,
|
|
225
|
+
logicalRoots: programBindings,
|
|
226
|
+
bindings: normalized.dynamicBindings, privateBindings: normalized.privateBindings,
|
|
227
|
+
internalBindings: normalized.internalBindings, parserPlugins: CELL_PARSER_PLUGINS,
|
|
228
|
+
}) }
|
|
229
|
+
// The published legacy map ends at its maintained transform input.
|
|
230
|
+
const wrapper = target === 'commonjs' ? 'function __ptc_commonjs__(){\n' : ''
|
|
231
|
+
let input = normalized
|
|
232
|
+
if (transform === LEGACY_USER_BINDING_TRANSFORM && wrapper) {
|
|
233
|
+
input = applySourceEdits(input.code, input.sourceMap, [{ start: 0, end: 0, text: wrapper }])
|
|
234
|
+
input = applySourceEdits(input.code, input.sourceMap, [{ start: input.code.length, end: input.code.length, text: '\n}' }])
|
|
235
|
+
}
|
|
236
|
+
let transformed, nativeExtraction, emission, sources
|
|
237
|
+
let moduleInterface = links?.moduleInterface ?? protectedInterface
|
|
238
|
+
if (transform === LEGACY_USER_BINDING_TRANSFORM) {
|
|
239
|
+
// Preserve the historical TypeScript lowering before adapting native
|
|
240
|
+
// bindings. Its unexpanded output is the source indexed by shared regions.
|
|
241
|
+
transformed = transformTypeScriptSource(input.code)
|
|
242
|
+
let code = transformed.code
|
|
243
|
+
if (wrapper) {
|
|
244
|
+
nativeExtraction = commonJsBodyRange(code)
|
|
245
|
+
code = code.slice(nativeExtraction.start, nativeExtraction.end)
|
|
246
|
+
}
|
|
247
|
+
let entry = { code, sourceMap: identitySourceMap(code.length),
|
|
248
|
+
sourceRegions: indexSourceRegions(code, callableParserOptions) }
|
|
249
|
+
if (target === 'commonjs') entry = normalizeStatefulScopes(code, entry.sourceMap,
|
|
250
|
+
{ mode: 'protected-v1', target, nativeJavaScript: true, deferDecorators: true, deferResources: true })
|
|
251
|
+
if (target === 'module') {
|
|
252
|
+
entry = adaptLegacyModuleReferences(entry)
|
|
253
|
+
moduleInterface = entry.moduleInterface
|
|
254
|
+
entry = adaptStaticModuleLinks(entry, staticLinks)
|
|
255
|
+
}
|
|
256
|
+
entry = adaptModuleOperations(entry, { target, url })
|
|
257
|
+
emission = adaptDynamicCell(entry.code, entry.sourceMap, { module: true,
|
|
258
|
+
sourceRegions: entry.sourceRegions,
|
|
259
|
+
importOperation: entry.importOperation, sourceType, originalSource: source,
|
|
260
|
+
bindings: entry.dynamicBindings, internalBindings: entry.internalBindings, parserPlugins: CELL_PARSER_PLUGINS,
|
|
261
|
+
})
|
|
262
|
+
} else {
|
|
263
|
+
const owners = normalized.callableRanges === undefined ? collectRegionCallableRanges(normalized, callableSources, callableParserOptions)
|
|
264
|
+
: new Map(normalized.callableRanges.map(range => [range.start, range]))
|
|
265
|
+
// Native JavaScript has no remaining TypeScript emission work. Retain the
|
|
266
|
+
// generator's exact source and owner facts instead of expanding it again.
|
|
267
|
+
const output = nativeJavaScript ? { ...normalized, callableRanges: [...owners.values()] }
|
|
268
|
+
: transformRegionSource(normalized, { ...callableParserOptions, wrapCommonJs: true }, region => {
|
|
269
|
+
const generated = transformTypeScriptSource(region.code, {
|
|
270
|
+
module: target === 'module' && !region.prefix, sourceMap: true,
|
|
271
|
+
// Type-only declarations and the complete module interface were
|
|
272
|
+
// resolved before partitioning; omitted bodies cannot erase imports.
|
|
273
|
+
transform: { tsEnumIsMutable: true, verbatimModuleSyntax: true,
|
|
274
|
+
noEmptyExport: target === 'commonjs' || !!region.prefix },
|
|
275
|
+
})
|
|
276
|
+
return emitRegionCallableSources(region, generated, owners, callableParserOptions)
|
|
277
|
+
})
|
|
278
|
+
emission = nativeJavaScript ? output : { ...output, ...applySourceEdits(normalized.code, normalized.sourceMap,
|
|
279
|
+
[{ start: 0, end: normalized.code.length, text: output.code, mappings: output.sourceMap }]) }
|
|
280
|
+
sources = callableSourceCatalog(emission.code, callableSources, output.callableRanges)
|
|
281
|
+
}
|
|
282
|
+
// Callable ownership collection validates native output's exact grammar
|
|
283
|
+
// regions. Only the later TypeScript/legacy emitter changes that code.
|
|
284
|
+
if (!nativeJavaScript) validateRegionSource(emission, { sourceType, plugins: ['importAttributes'] })
|
|
285
|
+
return { code: emission.code, classificationCode, transform, target, moduleInterface, commonJsSource,
|
|
286
|
+
staticLinks, callableSources: sources,
|
|
287
|
+
sourceRegions: sourceRegionData(emission.sourceRegions),
|
|
288
|
+
sourceMap: { normalization: input.sourceMap, typescript: transformed?.map, nativeExtraction,
|
|
289
|
+
...(transform === LEGACY_USER_BINDING_TRANSFORM ? {} : { emission: emission.sourceMap }) },
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function detectModuleSourceFormat(source, { extension } = {}) {
|
|
294
|
+
// Synchronous CommonJS hooks may leave format undefined. For an untyped
|
|
295
|
+
// package Node detects module syntax, including lexical wrapper-name clashes.
|
|
296
|
+
// Parse without executing source, allowing the repetitions PTC owns.
|
|
297
|
+
if (extension === '.ts') source = normalizeTypeScriptValues(source, identitySourceMap(source.length)).code
|
|
298
|
+
const tree = parse(source, { sourceType: 'unambiguous', errorRecovery: true,
|
|
299
|
+
allowReturnOutsideFunction: true, allowNewTargetOutsideFunction: true, plugins: CELL_PARSER_PLUGINS })
|
|
300
|
+
const wrapperNames = new Set(COMMONJS_PARAMETERS)
|
|
301
|
+
const lexicalWrapperName = tree.program.body.some(node => node.type === 'VariableDeclaration' && node.kind !== 'var'
|
|
302
|
+
? node.declarations.some(item => bindingNodes(item.id).some(binding => wrapperNames.has(binding.name)))
|
|
303
|
+
: node.type === 'ClassDeclaration' && wrapperNames.has(node.id.name))
|
|
304
|
+
return tree.program.sourceType === 'module' || lexicalWrapperName ? 'module' : 'commonjs'
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function attachModuleNamespace(source, attributes, reference, sourceRegions) {
|
|
308
|
+
const text = source
|
|
309
|
+
const names = new Set()
|
|
310
|
+
visitRegionSource({ code: text, sourceMap: identitySourceMap(text.length), sourceRegions }, { sourceType: 'module' }, input => {
|
|
311
|
+
t.traverseFast(input.tree, node => { if (t.isIdentifier(node)) names.add(node.name) })
|
|
312
|
+
})
|
|
313
|
+
const allocate = createGeneratedNameAllocator(undefined, names)
|
|
314
|
+
const namespace = allocate('module_native_namespace')
|
|
315
|
+
const register = allocate('module_register_namespace')
|
|
316
|
+
const runtime = new URL('./stateful-module-runtime.js', import.meta.url).href
|
|
317
|
+
// A namespace import adds no named-import validation and reads no exports.
|
|
318
|
+
// Register after successful evaluation, before native require can return.
|
|
319
|
+
const entries = Object.entries(attributes ?? {})
|
|
320
|
+
const suffix = entries.length === 0 ? '' : ` with {${entries.map(([key, value]) => `${JSON.stringify(key)}:${JSON.stringify(value)}`).join(',')}}`
|
|
321
|
+
return `${text}\nimport * as ${namespace} from ${JSON.stringify(reference)}${suffix};\nimport {recordStatefulModuleNamespace as ${register}} from ${JSON.stringify(runtime)};\n${register}(import.meta.url,${namespace});\n`
|
|
322
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { registerHooks } from 'node:module'
|
|
2
|
+
import { compilerPlatformBridge } from './compiler-platform.js'
|
|
3
|
+
|
|
4
|
+
const nativeRegisterHooks = registerHooks
|
|
5
|
+
const apply = Reflect.apply
|
|
6
|
+
// Acquire the public hook lifecycle before any owned source can replace Node
|
|
7
|
+
// exports or the hook prototype. The empty bootstrap hook changes no edge.
|
|
8
|
+
const bootstrapHook = nativeRegisterHooks({})
|
|
9
|
+
const deregister = bootstrapHook.deregister
|
|
10
|
+
apply(deregister, bootstrapHook, [])
|
|
11
|
+
|
|
12
|
+
/** Each native resolution scope has one captured registration and disposer. */
|
|
13
|
+
export function registerModuleResolutionHook(resolve) {
|
|
14
|
+
const hook = nativeRegisterHooks({ resolve })
|
|
15
|
+
return () => apply(deregister, hook, [])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const fileURLToPath = compilerPlatformBridge.fileURLToPath
|
|
19
|
+
export const pathToFileURL = compilerPlatformBridge.pathToFileURL
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const LEGACY_USER_BINDING_TRANSFORM = 'amaro@1.1.11'
|
|
2
|
+
export const PREVIOUS_USER_BINDING_TRANSFORM = 'stateful-module-v1+amaro@1.1.11'
|
|
3
|
+
export const USER_BINDING_TRANSFORM = 'stateful-module-v2+amaro@1.1.11'
|
|
4
|
+
export const PROTECTED_MODULE_TRANSFORM = 'protected-module-v1+amaro@1.1.11'
|
|
5
|
+
export const MODULE_TRANSFORMS = new Set([
|
|
6
|
+
LEGACY_USER_BINDING_TRANSFORM,
|
|
7
|
+
PREVIOUS_USER_BINDING_TRANSFORM,
|
|
8
|
+
USER_BINDING_TRANSFORM,
|
|
9
|
+
PROTECTED_MODULE_TRANSFORM,
|
|
10
|
+
])
|
|
11
|
+
|
|
12
|
+
export function isStatefulUserBindingTransform(transform) {
|
|
13
|
+
return transform === USER_BINDING_TRANSFORM || transform === PREVIOUS_USER_BINDING_TRANSFORM
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function moduleTransformForLanguage(languageSemantics) {
|
|
17
|
+
return languageSemantics === 'stateful-v1' ? USER_BINDING_TRANSFORM
|
|
18
|
+
: languageSemantics === 'protected-v1' ? PROTECTED_MODULE_TRANSFORM : LEGACY_USER_BINDING_TRANSFORM
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function historicalModuleTransformForLanguage(languageSemantics) {
|
|
22
|
+
return languageSemantics === 'stateful-v1' ? PREVIOUS_USER_BINDING_TRANSFORM
|
|
23
|
+
: languageSemantics === 'protected-v1' ? PROTECTED_MODULE_TRANSFORM : LEGACY_USER_BINDING_TRANSFORM
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function moduleTransformMatchesLanguage(transform, languageSemantics) {
|
|
27
|
+
return languageSemantics === 'stateful-v1' ? isStatefulUserBindingTransform(transform)
|
|
28
|
+
: languageSemantics === 'protected-v1' ? transform === PROTECTED_MODULE_TRANSFORM
|
|
29
|
+
: languageSemantics === 'legacy-v1' ? transform === LEGACY_USER_BINDING_TRANSFORM : false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function normalizeModuleTransform(transform, languageSemantics) {
|
|
33
|
+
if (!MODULE_TRANSFORMS.has(transform)) throw new TypeError('invalid dsh-ptc-plus journal module transform')
|
|
34
|
+
if (!moduleTransformMatchesLanguage(transform, languageSemantics)) {
|
|
35
|
+
throw new TypeError('dsh-ptc-plus journal module transform does not match its language semantics')
|
|
36
|
+
}
|
|
37
|
+
return transform
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function supportedUserBindingTransform(transform) {
|
|
41
|
+
return isStatefulUserBindingTransform(transform) || transform === LEGACY_USER_BINDING_TRANSFORM
|
|
42
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import traverseModule from '@babel/traverse'
|
|
2
|
+
import { types as t } from '@babel/core'
|
|
3
|
+
|
|
4
|
+
const traverse = traverseModule.default ?? traverseModule
|
|
5
|
+
|
|
6
|
+
/** Native await owns persistent declaration instantiation; references own writes. */
|
|
7
|
+
export function rewriteNativeAwaitDeclarations(tree, { hiddenBindings, nativePlaceholders, reference, initialize, namedValue, replaceIterationDeclaration }) {
|
|
8
|
+
const placeholders = []
|
|
9
|
+
const preserve = node => { nativePlaceholders.add(node); placeholders.push(node) }
|
|
10
|
+
const rootIdentifiers = node => {
|
|
11
|
+
if (t.isIdentifier(node)) return [node]
|
|
12
|
+
if (t.isObjectPattern(node)) return node.properties.flatMap(property => rootIdentifiers(property.value ?? property.argument))
|
|
13
|
+
if (t.isArrayPattern(node)) return node.elements.flatMap(element => rootIdentifiers(element))
|
|
14
|
+
// Native REPL await registers direct pattern identifiers. Default targets
|
|
15
|
+
// and array rest targets remain assignment references in that generation.
|
|
16
|
+
return []
|
|
17
|
+
}
|
|
18
|
+
const lexicalPlaceholder = name => preserve(t.variableDeclaration('let', [
|
|
19
|
+
t.variableDeclarator(t.identifier(name), t.identifier(name)),
|
|
20
|
+
]))
|
|
21
|
+
const assignmentPattern = (node, path) => {
|
|
22
|
+
if (t.isIdentifier(node)) return reference(path, node.name)
|
|
23
|
+
if (t.isArrayPattern(node)) return t.arrayPattern(node.elements.map(element => element === null ? null : assignmentPattern(element, path)))
|
|
24
|
+
if (t.isObjectPattern(node)) return t.objectPattern(node.properties.map(property => t.isRestElement(property)
|
|
25
|
+
? t.restElement(assignmentPattern(property.argument, path))
|
|
26
|
+
: t.objectProperty(property.key, assignmentPattern(property.value, path), property.computed, false)))
|
|
27
|
+
if (t.isAssignmentPattern(node)) return t.assignmentPattern(assignmentPattern(node.left, path),
|
|
28
|
+
t.isIdentifier(node.left) ? namedValue(node.left.name, node.right) : node.right)
|
|
29
|
+
return t.restElement(assignmentPattern(node.argument, path))
|
|
30
|
+
}
|
|
31
|
+
traverse(tree, {
|
|
32
|
+
VariableDeclaration(path) {
|
|
33
|
+
if (path.node.declarations.some(declaration => t.isIdentifier(declaration.id) && hiddenBindings.has(declaration.id.name))
|
|
34
|
+
|| path.getFunctionParent() !== null || path.node.kind !== 'var' && !path.parentPath.isProgram()) return
|
|
35
|
+
const original = path.node
|
|
36
|
+
if (original.kind === 'var') {
|
|
37
|
+
const declaration = t.cloneNode(original, true)
|
|
38
|
+
for (const item of declaration.declarations) item.init = t.unaryExpression('void', t.numericLiteral(0))
|
|
39
|
+
preserve(t.ifStatement(t.booleanLiteral(false), t.blockStatement([declaration])))
|
|
40
|
+
} else for (const item of original.declarations) for (const name of rootIdentifiers(item.id)) lexicalPlaceholder(name.name)
|
|
41
|
+
const assignment = item => {
|
|
42
|
+
const value = item.init ?? t.unaryExpression('void', t.numericLiteral(0))
|
|
43
|
+
return t.isIdentifier(item.id) ? initialize(path, item.id.name, namedValue(item.id.name, value))
|
|
44
|
+
: t.assignmentExpression('=', assignmentPattern(item.id, path), value)
|
|
45
|
+
}
|
|
46
|
+
if (path.parentPath.isForOfStatement() || path.parentPath.isForInStatement()) {
|
|
47
|
+
replaceIterationDeclaration(path, assignmentPattern(original.declarations[0].id, path),
|
|
48
|
+
original.declarations.filter(item => item.init !== null).map(assignment))
|
|
49
|
+
} else {
|
|
50
|
+
const assignments = original.declarations.map(assignment)
|
|
51
|
+
const expression = t.inherits(assignments.length === 1 ? assignments[0] : t.sequenceExpression(assignments), original)
|
|
52
|
+
path.replaceWith(path.parentPath.isForStatement() ? expression : t.expressionStatement(t.unaryExpression('void', expression)))
|
|
53
|
+
}
|
|
54
|
+
path.skip()
|
|
55
|
+
},
|
|
56
|
+
ClassDeclaration(path) {
|
|
57
|
+
if (!path.parentPath.isProgram()) return
|
|
58
|
+
const name = path.node.id.name
|
|
59
|
+
lexicalPlaceholder(name)
|
|
60
|
+
const target = reference(path.parentPath, name)
|
|
61
|
+
path.node.type = 'ClassExpression'
|
|
62
|
+
const assignment = t.inherits(t.assignmentExpression('=', target, path.node), path.node)
|
|
63
|
+
path.replaceWith(t.expressionStatement(t.unaryExpression('void', assignment)))
|
|
64
|
+
path.skip()
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
tree.program.body.unshift(...placeholders)
|
|
68
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { parse } from '@babel/parser'
|
|
2
|
+
import { bindingNodes, createGeneratedNameAllocator } from './binding-pattern.js'
|
|
3
|
+
import { markCallableSources, collectCallableSources } from './callable-source-facts.js'
|
|
4
|
+
import { adaptDynamicCell } from './dynamic-environment-integration.js'
|
|
5
|
+
import { CELL_PARSER_PLUGINS } from './repl-scope-normalizer.js'
|
|
6
|
+
|
|
7
|
+
/** Native declarations remain frozen; dynamic entries retain their native root. */
|
|
8
|
+
export function adaptNativeRootDynamic(prepared, options, originalSource) {
|
|
9
|
+
if (prepared.collisions.length !== 0) return { ...prepared, nativeLexicals: new Set() }
|
|
10
|
+
const parser = { sourceType: 'script', allowAwaitOutsideFunction: true,
|
|
11
|
+
allowReturnOutsideFunction: true, plugins: CELL_PARSER_PLUGINS }
|
|
12
|
+
const marked = markCallableSources(prepared.code, prepared.sourceMap, parser)
|
|
13
|
+
const tree = parse(marked.code, parser)
|
|
14
|
+
const nativeLexicals = new Set(tree.program.body.flatMap(statement =>
|
|
15
|
+
statement.type === 'VariableDeclaration' && statement.kind !== 'var'
|
|
16
|
+
? statement.declarations.flatMap(declaration => bindingNodes(declaration.id).map(binding => binding.name))
|
|
17
|
+
: statement.type === 'ClassDeclaration' ? [statement.id.name] : []))
|
|
18
|
+
const nativeAwait = hasRootAwait(tree.program)
|
|
19
|
+
const reservedBindings = new Set([...prepared.importNamespaces,
|
|
20
|
+
...options.knownBindings ?? [], ...options.reservedBindings ?? []])
|
|
21
|
+
const allocate = createGeneratedNameAllocator(parse(marked.code, parser), reservedBindings)
|
|
22
|
+
const global = allocate('native_environment_global')
|
|
23
|
+
const established = [...options.establishedRoots ?? []]
|
|
24
|
+
const logicalRoots = established.filter(([, source]) => source !== 'absent').map(([name]) => name)
|
|
25
|
+
const nativePublications = prepared.declarations.filter(declaration => options.establishedRoots?.has(declaration.name)
|
|
26
|
+
&& !prepared.redeclared.some(redeclaration => redeclaration.name === declaration.name))
|
|
27
|
+
.map(declaration => ({ name: declaration.name, writable: declaration.writable,
|
|
28
|
+
nativeLexical: nativeLexicals.has(declaration.name),
|
|
29
|
+
import: prepared.imports.get(declaration.name) }))
|
|
30
|
+
const dynamic = adaptDynamicCell(marked.code, marked.sourceMap, { nativeRoot: true,
|
|
31
|
+
environmentGlobal: global, reservedBindings, internalBindings: prepared.importNamespaces,
|
|
32
|
+
originalSource, parserPlugins: CELL_PARSER_PLUGINS, nativeAwait, logicalRoots: logicalRoots.length > 0 })
|
|
33
|
+
const callableSources = collectCallableSources(dynamic.code, marked.callableSources, parser)
|
|
34
|
+
return { ...prepared, code: dynamic.code, sourceMap: dynamic.sourceMap, nativeLexicals,
|
|
35
|
+
...(established.length === 0 ? {} : { rootBindingFacts: true, rootBindings: {
|
|
36
|
+
known: [...options.knownBindings ?? []], established, candidates: [...options.rootCandidates ?? []],
|
|
37
|
+
dynamicOrigins: options.dynamicOrigins ?? [], legacyImports: [...options.importBindings ?? []],
|
|
38
|
+
} }),
|
|
39
|
+
importNamespaces: new Set([...prepared.importNamespaces, dynamic.dynamicEnvironmentName]),
|
|
40
|
+
moduleLoads: [...prepared.moduleLoads, { operation: 'native-dynamic', global, callableSources, awaitRoot: nativeAwait,
|
|
41
|
+
nativeLexicals: [...options.nativeLexicalBindings ?? []],
|
|
42
|
+
logicalRoots, writableRoots: logicalRoots.filter(name => options.writableBindings?.has(name)), nativePublications }] }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function hasRootAwait(node) {
|
|
46
|
+
if (node === null || typeof node !== 'object') return false
|
|
47
|
+
if (node.type === 'AwaitExpression' || node.type === 'ForOfStatement' && node.await) return true
|
|
48
|
+
if (['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'].includes(node.type)) return false
|
|
49
|
+
if (['ObjectMethod', 'ClassMethod', 'ClassPrivateMethod'].includes(node.type)) {
|
|
50
|
+
return node.computed && hasRootAwait(node.key)
|
|
51
|
+
}
|
|
52
|
+
return Object.entries(node).some(([key, value]) => !['loc', 'extra', 'start', 'end'].includes(key)
|
|
53
|
+
&& (Array.isArray(value) ? value.some(hasRootAwait) : value?.type !== undefined && hasRootAwait(value)))
|
|
54
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createDynamicEnvironmentRuntime } from './dynamic-environment-runtime.js'
|
|
2
|
+
import { moduleRuntimeIntrinsics as internal } from './compiler-intrinsics.js'
|
|
3
|
+
|
|
4
|
+
const { Map, Set, mapGet, mapSet, mapHas, mapDelete, setHas, setAdd, appendArray } = internal
|
|
5
|
+
|
|
6
|
+
/** Native storage and catalog-proved logical roots share a captured legacy view. */
|
|
7
|
+
export function createNativeRootDynamic({ intrinsics, importModule, read, write, typeOf, remove, logicalReference }) {
|
|
8
|
+
const interfaceOwner = {}
|
|
9
|
+
const runtime = createDynamicEnvironmentRuntime({ ...intrinsics, importModule, interfaceOwner }).installIntrinsics()
|
|
10
|
+
const descriptor = name => ({ kind: 'var', get: () => read(name),
|
|
11
|
+
set: (value, strict) => write(name, value, strict), delete: () => remove(name), typeof: () => typeOf(name) })
|
|
12
|
+
const environment = runtime.environment({
|
|
13
|
+
ambient(name, strict) {
|
|
14
|
+
return runtime.reference(name, descriptor(name), undefined, strict)
|
|
15
|
+
},
|
|
16
|
+
declareVars: runtime.declareGlobals,
|
|
17
|
+
createVar: descriptor,
|
|
18
|
+
})
|
|
19
|
+
runtime.setRootEnvironment(() => environment)
|
|
20
|
+
return {
|
|
21
|
+
environment(callableSources, awaitRoot = false, logicalRoots = [], writableRoots = []) {
|
|
22
|
+
if (logicalRoots.length === 0) {
|
|
23
|
+
runtime.registerSources(callableSources)
|
|
24
|
+
return awaitRoot ? environment.awaitActivation() : environment
|
|
25
|
+
}
|
|
26
|
+
// Each captured legacy environment keeps its own root view. Installing a
|
|
27
|
+
// later bridge must not change escaped eval/Function calls from old cells.
|
|
28
|
+
const bridgedRuntime = createDynamicEnvironmentRuntime({ ...intrinsics, importModule, interfaceOwner }).installIntrinsics()
|
|
29
|
+
const writable = new Set()
|
|
30
|
+
for (let index = 0; index < writableRoots.length; index++) setAdd(writable, writableRoots[index])
|
|
31
|
+
const bindings = new Map(), varFrame = new Map(), roots = new Map()
|
|
32
|
+
for (let index = 0; index < logicalRoots.length; index++) {
|
|
33
|
+
const name = logicalRoots[index], binding = logicalReference(name, setHas(writable, name))
|
|
34
|
+
mapSet(bindings, name, binding)
|
|
35
|
+
mapSet(roots, name, binding)
|
|
36
|
+
if (binding.kind === 'var') mapSet(varFrame, name, binding)
|
|
37
|
+
const remove = binding.delete
|
|
38
|
+
binding.delete = () => {
|
|
39
|
+
if (!remove()) return false
|
|
40
|
+
mapDelete(bindings, name)
|
|
41
|
+
mapDelete(varFrame, name)
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const bridged = bridgedRuntime.environment({ frames: [{ kind: 'lexical', bindings }], varFrame,
|
|
46
|
+
ambient: (name, strict) => bridgedRuntime.reference(name, descriptor(name), undefined, strict),
|
|
47
|
+
declareVars(names, functionNames) {
|
|
48
|
+
const globals = []
|
|
49
|
+
for (let index = 0; index < names.length; index++) {
|
|
50
|
+
if (!mapHas(roots, names[index])) appendArray(globals, names[index])
|
|
51
|
+
}
|
|
52
|
+
bridgedRuntime.declareGlobals(globals, functionNames)
|
|
53
|
+
},
|
|
54
|
+
createVar(name) {
|
|
55
|
+
const root = mapGet(roots, name)
|
|
56
|
+
if (root === undefined) return descriptor(name)
|
|
57
|
+
root.declare()
|
|
58
|
+
mapSet(bindings, name, root)
|
|
59
|
+
return root
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
bridgedRuntime.setRootEnvironment(() => bridged)
|
|
63
|
+
bridgedRuntime.registerSources(callableSources)
|
|
64
|
+
return awaitRoot ? bridged.awaitActivation() : bridged
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
}
|
package/internal/record-utils.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
/** Shared structural guards for closed PTC metadata boundaries. */
|
|
2
2
|
|
|
3
|
+
import { runtimeIntrinsics as internal } from './runtime-intrinsics.js'
|
|
4
|
+
|
|
5
|
+
const { TypeError, isArray, reflectOwnKeys, objectGetOwnPropertyDescriptor,
|
|
6
|
+
objectHasOwn, objectPropertyIsEnumerable, objectFreeze, trimString, toString,
|
|
7
|
+
Set, setHas, setAdd, setSize, appendArray, popArray } = internal
|
|
8
|
+
|
|
3
9
|
export function isRecord(value) {
|
|
4
|
-
return value !== null && typeof value === 'object' && !
|
|
10
|
+
return value !== null && typeof value === 'object' && !isArray(value)
|
|
5
11
|
}
|
|
6
12
|
|
|
7
13
|
export function assertOwnFields(value, allowed, label) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
const keys = reflectOwnKeys(value)
|
|
15
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
16
|
+
const key = keys[index]
|
|
17
|
+
if (typeof key !== 'string' || !setHas(allowed, key)
|
|
18
|
+
|| !objectPropertyIsEnumerable(value, key)) {
|
|
19
|
+
throw new TypeError(`invalid ${label} field ${toString(key)}`)
|
|
12
20
|
}
|
|
13
21
|
}
|
|
14
22
|
}
|
|
@@ -16,7 +24,7 @@ export function assertOwnFields(value, allowed, label) {
|
|
|
16
24
|
export function assertFields(value, allowed, label) {
|
|
17
25
|
if (!isRecord(value)) throw new TypeError(`invalid ${label}`)
|
|
18
26
|
assertOwnFields(value, allowed, label)
|
|
19
|
-
if (
|
|
27
|
+
if (reflectOwnKeys(value).length !== setSize(allowed)) throw new TypeError(`invalid ${label} fields`)
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
export function record(value, label) {
|
|
@@ -25,7 +33,7 @@ export function record(value, label) {
|
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
export function text(value, label) {
|
|
28
|
-
if (typeof value !== 'string' || value
|
|
36
|
+
if (typeof value !== 'string' || trimString(value).length === 0) {
|
|
29
37
|
throw new TypeError(`ptc-plus: ${label} must be a non-empty string`)
|
|
30
38
|
}
|
|
31
39
|
return value
|
|
@@ -37,17 +45,18 @@ export function deepFreeze(value) {
|
|
|
37
45
|
const pending = [value]
|
|
38
46
|
const seen = new Set()
|
|
39
47
|
while (pending.length > 0) {
|
|
40
|
-
const current = pending
|
|
41
|
-
if (seen
|
|
42
|
-
seen
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const current = popArray(pending)
|
|
49
|
+
if (setHas(seen, current)) continue
|
|
50
|
+
setAdd(seen, current)
|
|
51
|
+
const keys = reflectOwnKeys(current)
|
|
52
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
53
|
+
const descriptor = objectGetOwnPropertyDescriptor(current, keys[index])
|
|
54
|
+
if (descriptor !== undefined && objectHasOwn(descriptor, 'value')) {
|
|
46
55
|
const child = descriptor.value
|
|
47
|
-
if (child !== null && typeof child === 'object') pending
|
|
56
|
+
if (child !== null && typeof child === 'object') appendArray(pending, child)
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
|
-
|
|
59
|
+
objectFreeze(current)
|
|
51
60
|
}
|
|
52
61
|
return value
|
|
53
62
|
}
|