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.
- package/README.en.md +65 -78
- package/README.md +65 -78
- 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 +30596 -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 +554 -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 +6 -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 +73 -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 +25 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +72 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +755 -0
- package/docs/user-bindings.en.md +64 -0
- package/docs/user-bindings.md +64 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification.md +57 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- 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 +391 -0
- package/internal/binding-update-policy.js +66 -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 +240 -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 +84 -0
- package/internal/compiler-module-links.js +34 -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 +87 -0
- package/internal/dynamic-environment-runtime.js +362 -0
- package/internal/dynamic-native-calls.js +150 -0
- package/internal/dynamic-native-runtime.js +248 -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 +118 -18
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +548 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +904 -120
- 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 +321 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +12 -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/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 +114 -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-messages.js +111 -0
- package/internal/session-cell-executor.js +401 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +106 -0
- package/internal/session-journal.js +184 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +256 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +211 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +598 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +29 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +184 -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 +353 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +29 -20
- package/internal/worker-client.js +57 -67
- package/internal/worker-environment.js +45 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +75 -7
- package/src/client-activity.js +88 -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
|
@@ -8,10 +8,13 @@ export function walkAst(node, enter, leave = undefined, context = undefined, par
|
|
|
8
8
|
const entered = enter(node, parent, parentKey, context)
|
|
9
9
|
if (entered === SKIP_AST_CHILDREN) return
|
|
10
10
|
const childContext = entered === undefined ? context : entered
|
|
11
|
-
|
|
11
|
+
const keys = Object.keys(node)
|
|
12
|
+
for (let index = 0; index < keys.length; index++) {
|
|
13
|
+
const key = keys[index]
|
|
12
14
|
if (AST_METADATA_KEYS.has(key)) continue
|
|
15
|
+
const value = node[key]
|
|
13
16
|
if (Array.isArray(value)) {
|
|
14
|
-
for (
|
|
17
|
+
for (let child = 0; child < value.length; child++) walkAst(value[child], enter, leave, childContext, node, key)
|
|
15
18
|
} else {
|
|
16
19
|
walkAst(value, enter, leave, childContext, node, key)
|
|
17
20
|
}
|
|
@@ -86,6 +86,7 @@ export function normalizeBindingDescriptors(bindings) {
|
|
|
86
86
|
workerDescriptors: Object.freeze(namespaces.map(namespace => Object.freeze({
|
|
87
87
|
global: namespace.global,
|
|
88
88
|
members: namespace.members,
|
|
89
|
+
...(reservedNames.has(namespace.global) ? {} : { shadowable: true }),
|
|
89
90
|
...(namespace.emptyObjectMembers === undefined
|
|
90
91
|
? {}
|
|
91
92
|
: { emptyObjectMembers: namespace.emptyObjectMembers }),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Read binding names from Acorn or Babel patterns without compiler dependencies. */
|
|
2
|
+
export function walkBindingPattern(pattern, visit) {
|
|
3
|
+
if (pattern === null || typeof pattern !== 'object') return
|
|
4
|
+
if (pattern.type === 'Identifier') {
|
|
5
|
+
visit(pattern)
|
|
6
|
+
return
|
|
7
|
+
}
|
|
8
|
+
if (pattern.type === 'RestElement') return walkBindingPattern(pattern.argument, visit)
|
|
9
|
+
if (pattern.type === 'AssignmentPattern') return walkBindingPattern(pattern.left, visit)
|
|
10
|
+
if (pattern.type === 'ArrayPattern') {
|
|
11
|
+
for (const element of pattern.elements) walkBindingPattern(element, visit)
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
if (pattern.type === 'ObjectPattern') {
|
|
15
|
+
for (const property of pattern.properties) {
|
|
16
|
+
walkBindingPattern(property.type === 'RestElement' ? property.argument : property.value, visit)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function bindingNodes(pattern) {
|
|
22
|
+
const nodes = []
|
|
23
|
+
walkBindingPattern(pattern, node => nodes.push(node))
|
|
24
|
+
return nodes
|
|
25
|
+
}
|
|
@@ -1,51 +1,48 @@
|
|
|
1
1
|
/** Shared binding-pattern traversal used by cell analysis and REPL policy code. */
|
|
2
|
+
import { types as t } from '@babel/core'
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
-
if (pattern === null || typeof pattern !== 'object') return
|
|
5
|
-
if (pattern.type === 'Identifier') {
|
|
6
|
-
visit(pattern)
|
|
7
|
-
return
|
|
8
|
-
}
|
|
9
|
-
if (pattern.type === 'RestElement') return walkBindingPattern(pattern.argument, visit)
|
|
10
|
-
if (pattern.type === 'AssignmentPattern') return walkBindingPattern(pattern.left, visit)
|
|
11
|
-
if (pattern.type === 'ArrayPattern') {
|
|
12
|
-
for (const element of pattern.elements) walkBindingPattern(element, visit)
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
if (pattern.type === 'ObjectPattern') {
|
|
16
|
-
for (const property of pattern.properties) {
|
|
17
|
-
walkBindingPattern(property.type === 'RestElement' ? property.argument : property.value, visit)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
4
|
+
export { walkBindingPattern, bindingNodes } from './binding-pattern-traversal.js'
|
|
21
5
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
/** Recognize an actual assignment target through erased expression syntax. */
|
|
7
|
+
export function isWriteIdentifier(path) {
|
|
8
|
+
let selected = path
|
|
9
|
+
while (selected.parentPath?.isObjectProperty() && selected.key === 'value'
|
|
10
|
+
|| selected.parentPath?.isObjectPattern() || selected.parentPath?.isArrayPattern()
|
|
11
|
+
|| selected.parentPath?.isRestElement() && selected.key === 'argument'
|
|
12
|
+
|| selected.parentPath?.isAssignmentPattern() && selected.key === 'left'
|
|
13
|
+
|| selected.parent?.type.startsWith('TS') && selected.key === 'expression'
|
|
14
|
+
|| selected.parentPath?.isParenthesizedExpression() && selected.key === 'expression') selected = selected.parentPath
|
|
15
|
+
const parent = selected.parentPath
|
|
16
|
+
return parent?.isAssignmentExpression() && selected.key === 'left'
|
|
17
|
+
|| parent?.isUpdateExpression() && selected.key === 'argument'
|
|
18
|
+
|| (parent?.isForOfStatement() || parent?.isForInStatement()) && selected.key === 'left'
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
/** Allocate private identifiers outside both source and caller-owned name sets. */
|
|
29
|
-
export function createGeneratedNameAllocator(root, unavailableNames = []) {
|
|
22
|
+
export function createGeneratedNameAllocator(root, unavailableNames = [], { compact = false } = {}) {
|
|
30
23
|
const used = new Set(unavailableNames)
|
|
31
|
-
const seen = new Set()
|
|
32
24
|
const pending = [root]
|
|
33
25
|
while (pending.length > 0) {
|
|
34
26
|
const value = pending.pop()
|
|
35
|
-
if (value === null || typeof value !== 'object'
|
|
36
|
-
|
|
27
|
+
if (value === null || typeof value !== 'object') continue
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
for (const item of value) pending.push(item)
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
37
32
|
if (value.type === 'Identifier') used.add(value.name)
|
|
38
|
-
for (const
|
|
39
|
-
|
|
33
|
+
for (const key of t.VISITOR_KEYS[value.type] ?? Object.keys(value)) {
|
|
34
|
+
const child = value[key]
|
|
35
|
+
if (Array.isArray(child)) for (const item of child) pending.push(item)
|
|
40
36
|
else if (child !== null && typeof child === 'object') pending.push(child)
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
39
|
const sequences = new Map()
|
|
40
|
+
let nextCompact = 0
|
|
44
41
|
return (purpose) => {
|
|
45
42
|
let sequence = sequences.get(purpose) ?? 0
|
|
46
43
|
let name
|
|
47
44
|
do {
|
|
48
|
-
name = `__dsh_ptc_${purpose}_${sequence++}__`
|
|
45
|
+
name = compact ? `__ptc$${(nextCompact++).toString(36)}` : `__dsh_ptc_${purpose}_${sequence++}__`
|
|
49
46
|
} while (used.has(name))
|
|
50
47
|
sequences.set(purpose, sequence)
|
|
51
48
|
used.add(name)
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { parse } from '@babel/parser'
|
|
2
|
+
import { AMBIENT_GLOBALS, renderDurabilityReasons } from './module-policy.js'
|
|
3
|
+
import { CELL_PARSER_PLUGINS, normalizeTypeScriptValues } from './repl-scope-normalizer.js'
|
|
4
|
+
import { identitySourceMap } from './source-position-map.js'
|
|
5
|
+
import { LEGACY_USER_BINDING_TRANSFORM, transformTypeScriptSource } from './typescript-transform.js'
|
|
6
|
+
import { compileStatefulModule } from './module-compilation.js'
|
|
7
|
+
import { prepareProgram, classifyDurability } from './cell-analysis.js'
|
|
8
|
+
import { createCompilerSourceCache } from './compiler-source-cache.js'
|
|
9
|
+
|
|
10
|
+
const MAX_NAME_LENGTH = 128
|
|
11
|
+
const GLOBAL_TYPE_NAMES = new Set([
|
|
12
|
+
'Array', 'ArrayBuffer', 'ArrayBufferView', 'AsyncIterable', 'AsyncIterableIterator',
|
|
13
|
+
'AsyncIterator', 'Awaited', 'BigInt', 'BigInt64Array', 'BigUint64Array', 'Boolean',
|
|
14
|
+
'Buffer', 'ConstructorParameters', 'DataView', 'Date', 'Error', 'EvalError', 'Exclude',
|
|
15
|
+
'Extract', 'Float32Array', 'Float64Array', 'Function', 'Generator', 'GeneratorFunction',
|
|
16
|
+
'InstanceType', 'Int8Array', 'Int16Array', 'Int32Array', 'Iterable', 'IterableIterator',
|
|
17
|
+
'Iterator', 'Map', 'NonNullable', 'Number', 'Object', 'Omit', 'OmitThisParameter',
|
|
18
|
+
'Parameters', 'Partial', 'Pick', 'Promise', 'PromiseLike', 'RangeError', 'Readonly',
|
|
19
|
+
'ReadonlyArray', 'ReadonlyMap', 'ReadonlySet', 'Record', 'ReferenceError', 'RegExp',
|
|
20
|
+
'Required', 'ReturnType', 'Set', 'SharedArrayBuffer', 'String', 'Symbol', 'SyntaxError',
|
|
21
|
+
'ThisParameterType', 'ThisType', 'TypeError', 'URIError', 'Uint8Array', 'Uint8ClampedArray',
|
|
22
|
+
'Uint16Array', 'Uint32Array', 'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize',
|
|
23
|
+
'WeakMap', 'WeakSet',
|
|
24
|
+
])
|
|
25
|
+
const RESERVED_BINDINGS = new Set([
|
|
26
|
+
...AMBIENT_GLOBALS,
|
|
27
|
+
'capabilities',
|
|
28
|
+
'code',
|
|
29
|
+
'repl',
|
|
30
|
+
'tools',
|
|
31
|
+
'CapabilityExplorationError',
|
|
32
|
+
'CodeExecutionError',
|
|
33
|
+
'ToolCallError',
|
|
34
|
+
'Buffer',
|
|
35
|
+
'console',
|
|
36
|
+
'global',
|
|
37
|
+
'globalThis',
|
|
38
|
+
'module',
|
|
39
|
+
'process',
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
export function identifier(value, subject, reserved = false) {
|
|
43
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > MAX_NAME_LENGTH) {
|
|
44
|
+
throw new TypeError(`${subject} must be a non-empty identifier of at most ${MAX_NAME_LENGTH} characters`)
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const { program } = parse(`const ${value} = 0`, { sourceType: 'module' })
|
|
48
|
+
const declaration = program.body[0]
|
|
49
|
+
const binding = declaration.declarations[0].id
|
|
50
|
+
if (program.body.length !== 1 || declaration.declarations.length !== 1
|
|
51
|
+
|| binding.type !== 'Identifier' || binding.name !== value) {
|
|
52
|
+
throw new TypeError('identifier spelling must match the complete binding name')
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
throw new TypeError(`${subject} must be a valid JavaScript identifier`)
|
|
56
|
+
}
|
|
57
|
+
if (reserved && RESERVED_BINDINGS.has(value)) {
|
|
58
|
+
throw new TypeError(`${subject} conflicts with reserved REPL binding ${JSON.stringify(value)}`)
|
|
59
|
+
}
|
|
60
|
+
return value
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function sourceSlice(source, node) {
|
|
64
|
+
return Number.isSafeInteger(node?.start) && Number.isSafeInteger(node?.end)
|
|
65
|
+
? source.slice(node.start, node.end)
|
|
66
|
+
: ''
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function bindingNames(pattern, names = []) {
|
|
70
|
+
if (pattern?.type === 'Identifier') names.push(pattern.name)
|
|
71
|
+
else if (pattern?.type === 'RestElement') bindingNames(pattern.argument, names)
|
|
72
|
+
else if (pattern?.type === 'AssignmentPattern') bindingNames(pattern.left, names)
|
|
73
|
+
else if (pattern?.type === 'ArrayPattern') {
|
|
74
|
+
for (const element of pattern.elements) bindingNames(element, names)
|
|
75
|
+
} else if (pattern?.type === 'ObjectPattern') {
|
|
76
|
+
for (const property of pattern.properties) {
|
|
77
|
+
bindingNames(property.type === 'RestElement' ? property.argument : property.value, names)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return names
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function typeParameterNames(node) {
|
|
84
|
+
return (node?.params ?? [])
|
|
85
|
+
.map(parameter => parameter?.name)
|
|
86
|
+
.filter(name => typeof name === 'string')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function typeReferenceRoot(node) {
|
|
90
|
+
let current = node
|
|
91
|
+
while (current?.type === 'TSQualifiedName') current = current.left
|
|
92
|
+
return current?.type === 'Identifier' ? current.name : undefined
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function projectedType(source, node, outerTypeNames = new Set(), sourceTypeNames = new Set()) {
|
|
96
|
+
const replacements = []
|
|
97
|
+
const commentRanges = new Set()
|
|
98
|
+
const visit = (current, inheritedNames) => {
|
|
99
|
+
if (current === null || typeof current !== 'object') return
|
|
100
|
+
if (current.type === 'CommentBlock' || current.type === 'CommentLine') {
|
|
101
|
+
if (Number.isSafeInteger(current.start) && Number.isSafeInteger(current.end)
|
|
102
|
+
&& current.start >= node.start && current.end <= node.end) {
|
|
103
|
+
const key = `${current.start}:${current.end}`
|
|
104
|
+
if (!commentRanges.has(key)) {
|
|
105
|
+
commentRanges.add(key)
|
|
106
|
+
replacements.push({ start: current.start, end: current.end, text: ' ' })
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
let typeNames = inheritedNames
|
|
112
|
+
if (current.typeParameters?.type === 'TSTypeParameterDeclaration') {
|
|
113
|
+
typeNames = new Set([...inheritedNames, ...typeParameterNames(current.typeParameters)])
|
|
114
|
+
}
|
|
115
|
+
if (current.type === 'TSMappedType' && typeof current.typeParameter?.name === 'string') {
|
|
116
|
+
typeNames = new Set([...typeNames, current.typeParameter.name])
|
|
117
|
+
}
|
|
118
|
+
if (current.type === 'TSImportType' || current.type === 'TSTypeQuery') {
|
|
119
|
+
replacements.push({ start: current.start, end: current.end, text: 'unknown' })
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
if (current.type === 'TSTypeReference' || current.type === 'TSExpressionWithTypeArguments') {
|
|
123
|
+
const name = typeReferenceRoot(current.typeName ?? current.expression)
|
|
124
|
+
if (name === undefined || (!typeNames.has(name)
|
|
125
|
+
&& (sourceTypeNames.has(name) || !GLOBAL_TYPE_NAMES.has(name)))) {
|
|
126
|
+
replacements.push({ start: current.start, end: current.end, text: 'unknown' })
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
for (const [key, value] of Object.entries(current)) {
|
|
131
|
+
if (key === 'loc' || key === 'start' || key === 'end'
|
|
132
|
+
|| key === 'typeParameters' || key === 'typeName' || key === 'expression') continue
|
|
133
|
+
if (Array.isArray(value)) value.forEach(item => visit(item, typeNames))
|
|
134
|
+
else visit(value, typeNames)
|
|
135
|
+
}
|
|
136
|
+
if (current.typeParameters !== undefined) visit(current.typeParameters, typeNames)
|
|
137
|
+
}
|
|
138
|
+
visit(node, outerTypeNames)
|
|
139
|
+
let text = sourceSlice(source, node) || 'unknown'
|
|
140
|
+
const start = node.start ?? 0
|
|
141
|
+
for (const replacement of replacements.sort((left, right) => right.start - left.start)) {
|
|
142
|
+
text = text.slice(0, replacement.start - start)
|
|
143
|
+
+ replacement.text
|
|
144
|
+
+ text.slice(replacement.end - start)
|
|
145
|
+
}
|
|
146
|
+
return text
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function typeParameters(source, node, outerTypeNames = new Set(), sourceTypeNames = new Set()) {
|
|
150
|
+
const declaration = node?.typeParameters
|
|
151
|
+
if (declaration?.type !== 'TSTypeParameterDeclaration') {
|
|
152
|
+
return { text: '', names: outerTypeNames }
|
|
153
|
+
}
|
|
154
|
+
const names = new Set([...outerTypeNames, ...typeParameterNames(declaration)])
|
|
155
|
+
return { text: projectedType(source, declaration, names, sourceTypeNames), names }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function annotation(source, node, typeNames = new Set(), sourceTypeNames = new Set()) {
|
|
159
|
+
const type = node?.typeAnnotation?.typeAnnotation
|
|
160
|
+
return type === undefined ? 'unknown' : projectedType(source, type, typeNames, sourceTypeNames)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function parameter(source, node, index, typeNames = new Set(), sourceTypeNames = new Set()) {
|
|
164
|
+
if (node?.type === 'TSParameterProperty') {
|
|
165
|
+
return parameter(source, node.parameter, index, typeNames, sourceTypeNames)
|
|
166
|
+
}
|
|
167
|
+
if (node?.type === 'RestElement') {
|
|
168
|
+
const argument = node.argument
|
|
169
|
+
return argument?.type === 'Identifier'
|
|
170
|
+
? `...${argument.name}: ${node.typeAnnotation === undefined ? 'unknown[]' : annotation(source, node, typeNames, sourceTypeNames)}`
|
|
171
|
+
: `...args${index}: unknown[]`
|
|
172
|
+
}
|
|
173
|
+
const optional = node?.type === 'AssignmentPattern'
|
|
174
|
+
const target = optional ? node.left : node
|
|
175
|
+
if (target?.type !== 'Identifier') return `arg${index}: unknown`
|
|
176
|
+
return `${target.name}${optional || target.optional === true ? '?' : ''}: ${annotation(source, target, typeNames, sourceTypeNames)}`
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function returnType(source, node, typeNames = new Set(), sourceTypeNames = new Set()) {
|
|
180
|
+
const explicit = node?.returnType?.typeAnnotation
|
|
181
|
+
if (explicit !== undefined) return projectedType(source, explicit, typeNames, sourceTypeNames)
|
|
182
|
+
return node?.async === true ? 'Promise<unknown>' : 'unknown'
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function functionType(source, node, outerTypeNames = new Set(), sourceTypeNames = new Set()) {
|
|
186
|
+
const generics = typeParameters(source, node, outerTypeNames, sourceTypeNames)
|
|
187
|
+
const parameters = (node.params ?? [])
|
|
188
|
+
.map((item, index) => parameter(source, item, index, generics.names, sourceTypeNames)).join(', ')
|
|
189
|
+
return `${generics.text}(${parameters}) => ${returnType(source, node, generics.names, sourceTypeNames)}`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function inferredType(source, node, depth = 0, sourceTypeNames = new Set()) {
|
|
193
|
+
if (depth > 2 || node === null || node === undefined) return 'unknown'
|
|
194
|
+
if (node.type === 'StringLiteral' || node.type === 'TemplateLiteral') return 'string'
|
|
195
|
+
if (node.type === 'NumericLiteral') return 'number'
|
|
196
|
+
if (node.type === 'BooleanLiteral') return 'boolean'
|
|
197
|
+
if (node.type === 'BigIntLiteral') return 'bigint'
|
|
198
|
+
if (node.type === 'NullLiteral') return 'null'
|
|
199
|
+
if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {
|
|
200
|
+
return functionType(source, node, new Set(), sourceTypeNames)
|
|
201
|
+
}
|
|
202
|
+
if (node.type === 'ArrayExpression') return 'unknown[]'
|
|
203
|
+
if (node.type === 'ObjectExpression') {
|
|
204
|
+
const members = []
|
|
205
|
+
for (const property of node.properties) {
|
|
206
|
+
if (property.type !== 'ObjectProperty' || property.computed || property.method) return 'Record<string, unknown>'
|
|
207
|
+
const name = property.key.type === 'Identifier'
|
|
208
|
+
? property.key.name
|
|
209
|
+
: property.key.type === 'StringLiteral' ? JSON.stringify(property.key.value) : undefined
|
|
210
|
+
if (name === undefined) return 'Record<string, unknown>'
|
|
211
|
+
members.push(`${name}: ${inferredType(source, property.value, depth + 1, sourceTypeNames)}`)
|
|
212
|
+
}
|
|
213
|
+
return `{ ${members.join('; ')} }`
|
|
214
|
+
}
|
|
215
|
+
return 'unknown'
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function classMembers(source, node, classTypeNames, sourceTypeNames) {
|
|
219
|
+
const members = []
|
|
220
|
+
let constructorParameters = '...args: unknown[]'
|
|
221
|
+
for (const member of node.body?.body ?? []) {
|
|
222
|
+
if (member.type !== 'ClassMethod' || member.static || member.computed
|
|
223
|
+
|| member.accessibility === 'private' || member.key?.type === 'PrivateName') continue
|
|
224
|
+
const name = member.key?.type === 'Identifier'
|
|
225
|
+
? member.key.name
|
|
226
|
+
: member.key?.type === 'StringLiteral' ? JSON.stringify(member.key.value) : undefined
|
|
227
|
+
if (name === undefined) continue
|
|
228
|
+
const generics = typeParameters(source, member, classTypeNames, sourceTypeNames)
|
|
229
|
+
const parameters = (member.params ?? [])
|
|
230
|
+
.map((item, index) => parameter(source, item, index, generics.names, sourceTypeNames)).join(', ')
|
|
231
|
+
if (member.kind === 'constructor') constructorParameters = parameters
|
|
232
|
+
else if (member.kind === 'method') {
|
|
233
|
+
members.push(`${name}${generics.text}(${parameters}): ${returnType(source, member, generics.names, sourceTypeNames)}`)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { constructorParameters, members, instance: `{ ${members.join('; ')} }` }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function jsdocPurpose(...nodes) {
|
|
240
|
+
const comment = nodes.flatMap(node => node?.leadingComments ?? [])
|
|
241
|
+
.find(item => item.type === 'CommentBlock' && item.value.startsWith('*'))
|
|
242
|
+
if (comment === undefined) return ''
|
|
243
|
+
return comment.value.slice(1).split(/\r?\n/)
|
|
244
|
+
.map(line => line.replace(/^\s*\*?\s?/, '').trim())
|
|
245
|
+
.find(line => line !== '' && !line.startsWith('@')) ?? ''
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function symbolDescriptor(source, name, node, exportNode = node, sourceTypeNames = new Set()) {
|
|
249
|
+
if (node?.type === 'FunctionDeclaration') {
|
|
250
|
+
const generics = typeParameters(source, node, new Set(), sourceTypeNames)
|
|
251
|
+
const parameters = (node.params ?? [])
|
|
252
|
+
.map((item, index) => parameter(source, item, index, generics.names, sourceTypeNames)).join(', ')
|
|
253
|
+
return {
|
|
254
|
+
name,
|
|
255
|
+
kind: 'function',
|
|
256
|
+
purpose: jsdocPurpose(exportNode, node),
|
|
257
|
+
declaration: `function ${name}${generics.text}(${parameters}): ${returnType(source, node, generics.names, sourceTypeNames)}`,
|
|
258
|
+
member: `${name}${generics.text}(${parameters}): ${returnType(source, node, generics.names, sourceTypeNames)}`,
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (node?.type === 'ClassDeclaration') {
|
|
262
|
+
const generics = typeParameters(source, node, new Set(), sourceTypeNames)
|
|
263
|
+
const shape = classMembers(source, node, generics.names, sourceTypeNames)
|
|
264
|
+
return {
|
|
265
|
+
name,
|
|
266
|
+
kind: 'class',
|
|
267
|
+
purpose: jsdocPurpose(exportNode, node),
|
|
268
|
+
declaration: `class ${name}${generics.text} { constructor(${shape.constructorParameters});${shape.members.length === 0 ? '' : ` ${shape.members.join('; ')};`} }`,
|
|
269
|
+
member: `${name}: { new${generics.text}(${shape.constructorParameters}): ${shape.instance} }`,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const declarator = node?.type === 'VariableDeclarator' ? node : undefined
|
|
273
|
+
const type = declarator?.id?.type !== 'Identifier'
|
|
274
|
+
? 'unknown'
|
|
275
|
+
: declarator.id.typeAnnotation !== undefined
|
|
276
|
+
? annotation(source, declarator.id, new Set(), sourceTypeNames)
|
|
277
|
+
: inferredType(source, declarator.init, 0, sourceTypeNames)
|
|
278
|
+
return {
|
|
279
|
+
name,
|
|
280
|
+
kind: 'variable',
|
|
281
|
+
purpose: jsdocPurpose(exportNode, node),
|
|
282
|
+
declaration: `const ${name}: ${type}`,
|
|
283
|
+
member: `${name}: ${type}`,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export const exportedSymbols = createCompilerSourceCache(analyzeExportedSymbols)
|
|
288
|
+
|
|
289
|
+
function analyzeExportedSymbols(source, transform) {
|
|
290
|
+
let ast
|
|
291
|
+
try {
|
|
292
|
+
ast = parse(source, {
|
|
293
|
+
sourceType: 'module',
|
|
294
|
+
plugins: transform === LEGACY_USER_BINDING_TRANSFORM
|
|
295
|
+
? ['typescript', 'topLevelAwait', 'importAttributes'] : CELL_PARSER_PLUGINS,
|
|
296
|
+
errorRecovery: transform !== LEGACY_USER_BINDING_TRANSFORM,
|
|
297
|
+
})
|
|
298
|
+
} catch (error) {
|
|
299
|
+
throw new SyntaxError(`binding source could not be parsed: ${error.message}`)
|
|
300
|
+
}
|
|
301
|
+
const sourceTypeNames = new Set()
|
|
302
|
+
for (const statement of ast.program.body) {
|
|
303
|
+
const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement
|
|
304
|
+
if (statement.type === 'ImportDeclaration') {
|
|
305
|
+
for (const specifier of statement.specifiers) sourceTypeNames.add(specifier.local.name)
|
|
306
|
+
}
|
|
307
|
+
if (declaration?.type === 'TSTypeAliasDeclaration'
|
|
308
|
+
|| declaration?.type === 'TSInterfaceDeclaration'
|
|
309
|
+
|| declaration?.type === 'TSEnumDeclaration'
|
|
310
|
+
|| declaration?.type === 'TSModuleDeclaration'
|
|
311
|
+
|| declaration?.type === 'ClassDeclaration') {
|
|
312
|
+
if (declaration.id?.type === 'Identifier') sourceTypeNames.add(declaration.id.name)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (transform !== LEGACY_USER_BINDING_TRANSFORM) {
|
|
316
|
+
source = normalizeTypeScriptValues(source, identitySourceMap(source.length), 'module').code
|
|
317
|
+
ast = parse(source, { sourceType: 'module', plugins: CELL_PARSER_PLUGINS, errorRecovery: true })
|
|
318
|
+
}
|
|
319
|
+
const locals = new Map()
|
|
320
|
+
for (const statement of ast.program.body) {
|
|
321
|
+
const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement
|
|
322
|
+
if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
|
|
323
|
+
if (declaration.id !== null) locals.set(declaration.id.name, declaration)
|
|
324
|
+
} else if (declaration?.type === 'VariableDeclaration') {
|
|
325
|
+
for (const item of declaration.declarations) {
|
|
326
|
+
for (const name of bindingNames(item.id)) locals.set(name, item)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const exports = new Map()
|
|
331
|
+
for (const statement of ast.program.body) {
|
|
332
|
+
if (statement.type === 'ExportDefaultDeclaration' || statement.type === 'ExportAllDeclaration') {
|
|
333
|
+
throw new TypeError('binding source supports named exports only')
|
|
334
|
+
}
|
|
335
|
+
if (statement.type !== 'ExportNamedDeclaration' || statement.exportKind === 'type') continue
|
|
336
|
+
if (statement.source !== null && statement.source !== undefined) {
|
|
337
|
+
throw new TypeError('binding source cannot re-export from another module')
|
|
338
|
+
}
|
|
339
|
+
const declaration = statement.declaration
|
|
340
|
+
if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') {
|
|
341
|
+
if (declaration.id === null) throw new TypeError('binding source exports must be named')
|
|
342
|
+
exports.set(declaration.id.name, symbolDescriptor(
|
|
343
|
+
source, declaration.id.name, declaration, statement, sourceTypeNames,
|
|
344
|
+
))
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
347
|
+
if (declaration?.type === 'VariableDeclaration') {
|
|
348
|
+
for (const item of declaration.declarations) {
|
|
349
|
+
for (const name of bindingNames(item.id)) {
|
|
350
|
+
exports.set(name, symbolDescriptor(source, name, item, statement, sourceTypeNames))
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
continue
|
|
354
|
+
}
|
|
355
|
+
for (const specifier of statement.specifiers) {
|
|
356
|
+
if (specifier.exportKind === 'type' || specifier.type !== 'ExportSpecifier') continue
|
|
357
|
+
const exported = specifier.exported.type === 'Identifier' ? specifier.exported.name : specifier.exported.value
|
|
358
|
+
const local = specifier.local.type === 'Identifier' ? specifier.local.name : specifier.local.value
|
|
359
|
+
identifier(exported, 'exported binding name')
|
|
360
|
+
const target = locals.get(local)
|
|
361
|
+
if (target === undefined) throw new TypeError(`export ${JSON.stringify(exported)} has no local value declaration`)
|
|
362
|
+
exports.set(exported, symbolDescriptor(source, exported, target, target, sourceTypeNames))
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (exports.size === 0) throw new TypeError('binding source must contain at least one named value export')
|
|
366
|
+
return exports
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export const sourceDurability = createCompilerSourceCache(analyzeSourceDurability)
|
|
370
|
+
|
|
371
|
+
function analyzeSourceDurability(source, transform) {
|
|
372
|
+
const compiled = compileStatefulModule(source, { transform })
|
|
373
|
+
// Keep source imports visible to durability analysis after runtime adaptation.
|
|
374
|
+
const javascript = transformTypeScriptSource(compiled.classificationCode,
|
|
375
|
+
transform === LEGACY_USER_BINDING_TRANSFORM ? {} : { module: true, transform: { tsEnumIsMutable: true } }).code
|
|
376
|
+
const prepared = transform !== LEGACY_USER_BINDING_TRANSFORM
|
|
377
|
+
? classifyDurability(javascript, new Set(), { sourceType: 'module',
|
|
378
|
+
internalModules: new Set([new URL('./stateful-module-runtime.js', import.meta.url).href]) })
|
|
379
|
+
: prepareProgram(javascript, {
|
|
380
|
+
languageSemantics: 'legacy-v1',
|
|
381
|
+
knownBindings: new Set(),
|
|
382
|
+
bindingPolicy: { variableRedeclarations: true, functionClassRedeclarations: true },
|
|
383
|
+
reservedBindings: new Set(),
|
|
384
|
+
rewritesEnabled: { autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true },
|
|
385
|
+
})
|
|
386
|
+
const reason = prepared.reason ?? renderDurabilityReasons(prepared.reasons)
|
|
387
|
+
return {
|
|
388
|
+
durability: prepared.durability,
|
|
389
|
+
...(reason === '' ? {} : { volatileReason: reason }),
|
|
390
|
+
}
|
|
391
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LIVE_MODULE_SEMANTICS } from './repl-rewrite-contract.js'
|
|
2
|
+
import { LEGACY_LANGUAGE_SEMANTICS, STATEFUL_LANGUAGE_SEMANTICS,
|
|
3
|
+
PROTECTED_LANGUAGE_SEMANTICS, normalizeLanguageSemantics } from './language-semantics.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Translate the public compatibility settings into the execution policy used
|
|
7
|
+
* by the compiler and journal. Keeping this mapping in one owner prevents
|
|
8
|
+
* individual lowering paths from combining legacy switches differently.
|
|
9
|
+
*/
|
|
10
|
+
export function executionPolicies(config, replayRecord = undefined) {
|
|
11
|
+
if (config.bindingUpdates !== undefined && !['stateful', 'protected'].includes(config.bindingUpdates)) {
|
|
12
|
+
throw new TypeError('ptc-plus: bindingUpdates must be stateful or protected')
|
|
13
|
+
}
|
|
14
|
+
if (replayRecord !== undefined) {
|
|
15
|
+
const bindingPolicy = Object.freeze({ ...replayRecord.bindingPolicy })
|
|
16
|
+
const rewritesEnabled = Object.freeze({ ...replayRecord.rewritePolicy })
|
|
17
|
+
const moduleSemantics = Object.freeze({ ...replayRecord.moduleSemantics })
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
languageSemantics: normalizeLanguageSemantics(replayRecord.languageSemantics ?? LEGACY_LANGUAGE_SEMANTICS),
|
|
20
|
+
bindingPolicy,
|
|
21
|
+
rewritesEnabled,
|
|
22
|
+
moduleSemantics,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
if (config.bindingUpdates === 'stateful' && config.legacyBindingSettings !== true) {
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
languageSemantics: STATEFUL_LANGUAGE_SEMANTICS,
|
|
28
|
+
bindingPolicy: Object.freeze({ variableRedeclarations: true, functionClassRedeclarations: true }),
|
|
29
|
+
rewritesEnabled: Object.freeze({ autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true }),
|
|
30
|
+
moduleSemantics: LIVE_MODULE_SEMANTICS,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
if (config.bindingUpdates === 'protected' && config.legacyBindingSettings !== true) {
|
|
34
|
+
return Object.freeze({
|
|
35
|
+
languageSemantics: PROTECTED_LANGUAGE_SEMANTICS,
|
|
36
|
+
bindingPolicy: Object.freeze({ variableRedeclarations: false, functionClassRedeclarations: false }),
|
|
37
|
+
// Module syntax is part of the language in protected mode too. The
|
|
38
|
+
// policy protects existing names; it does not remove valid syntax.
|
|
39
|
+
rewritesEnabled: Object.freeze({ autoRewriteImports: true, autoStripExports: true, autoSplitRedeclarations: true }),
|
|
40
|
+
moduleSemantics: LIVE_MODULE_SEMANTICS,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
languageSemantics: LEGACY_LANGUAGE_SEMANTICS,
|
|
45
|
+
bindingPolicy: Object.freeze({
|
|
46
|
+
variableRedeclarations: config.looseTopLevelRedeclarations === true,
|
|
47
|
+
functionClassRedeclarations: config.looseTopLevelFunctionClassRedeclarations === true,
|
|
48
|
+
}),
|
|
49
|
+
rewritesEnabled: Object.freeze({
|
|
50
|
+
autoRewriteImports: config.autoRewriteImports === true,
|
|
51
|
+
autoStripExports: config.autoStripExports === true,
|
|
52
|
+
autoSplitRedeclarations: config.autoSplitRedeclarations === true,
|
|
53
|
+
}),
|
|
54
|
+
moduleSemantics: LIVE_MODULE_SEMANTICS,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Stable prose inputs for the model-visible REPL guidance. */
|
|
59
|
+
export function guidancePolicies(config) {
|
|
60
|
+
const policies = executionPolicies(config)
|
|
61
|
+
return Object.freeze({
|
|
62
|
+
...policies,
|
|
63
|
+
durableReplay: config.durableReplay === true,
|
|
64
|
+
cordisToolsEnabled: config.cordisToolsEnabled === true,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** How a bounded worker round ended without a result. */
|
|
2
|
+
export const ROUND_TIMEOUT = 'timeout'
|
|
3
|
+
export const ROUND_CANCELLED = 'cancelled'
|
|
4
|
+
export const ROUND_OUTPUT_LIMIT = 'output-limit'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Own one bounded worker round: captured output bytes, the wall-clock deadline,
|
|
8
|
+
* cancellation and a single settlement. Worker creation, retention and
|
|
9
|
+
* termination stay with the caller, which is told exactly once how the round
|
|
10
|
+
* ended through `settle({ ok: true, result })` or `settle({ ok: false, reason })`.
|
|
11
|
+
*/
|
|
12
|
+
export function createBoundedWorkerRound({ maxOutputBytes, maxWallMs, signal, settle }) {
|
|
13
|
+
const logs = []
|
|
14
|
+
let capturedBytes = 0
|
|
15
|
+
let ended = false
|
|
16
|
+
const end = (outcome) => {
|
|
17
|
+
if (ended) return false
|
|
18
|
+
ended = true
|
|
19
|
+
clearTimeout(timer)
|
|
20
|
+
signal?.removeEventListener('abort', abort)
|
|
21
|
+
settle(outcome)
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
const fail = reason => end({ ok: false, reason })
|
|
25
|
+
const abort = () => { fail(ROUND_CANCELLED) }
|
|
26
|
+
const timer = setTimeout(() => fail(ROUND_TIMEOUT), maxWallMs)
|
|
27
|
+
signal?.addEventListener('abort', abort, { once: true })
|
|
28
|
+
if (signal?.aborted === true) fail(ROUND_CANCELLED)
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
logs,
|
|
31
|
+
/** Record one stream chunk; ends the round when the byte budget is exceeded. */
|
|
32
|
+
capture(channel, text) {
|
|
33
|
+
if (ended) return
|
|
34
|
+
capturedBytes += Buffer.byteLength(text, 'utf8')
|
|
35
|
+
if (capturedBytes > maxOutputBytes) { fail(ROUND_OUTPUT_LIMIT); return }
|
|
36
|
+
logs.push({ channel, text })
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* True when the byte budget is spent.
|
|
40
|
+
*
|
|
41
|
+
* `envelope` measures the object the caller returns with the captured `logs`
|
|
42
|
+
* included as a member, so log wrappers and JSON escaping count against the
|
|
43
|
+
* same budget; that is the candidate run's returned-envelope budget. Without
|
|
44
|
+
* it the raw captured bytes plus the serialized payload are measured, which is
|
|
45
|
+
* the workbench console's output budget.
|
|
46
|
+
*/
|
|
47
|
+
exceeds(payload, { envelope = false } = {}) {
|
|
48
|
+
if (envelope) {
|
|
49
|
+
return Buffer.byteLength(JSON.stringify({ ...payload, logs }), 'utf8') > maxOutputBytes
|
|
50
|
+
}
|
|
51
|
+
return capturedBytes + Buffer.byteLength(JSON.stringify(payload), 'utf8') > maxOutputBytes
|
|
52
|
+
},
|
|
53
|
+
succeed(result) { return end({ ok: true, result }) },
|
|
54
|
+
fail,
|
|
55
|
+
})
|
|
56
|
+
}
|