dsh-ptc-plus 0.4.1 → 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 +6 -10
- package/README.md +6 -10
- package/client.js +262 -31
- package/compiler-core.cjs +132 -130
- package/compiler-core.cjs.map +3 -3
- package/docs/README.md +1 -0
- package/docs/adr/0023-global-user-bindings.md +6 -6
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +3 -3
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +5 -5
- package/docs/architecture.md +9 -5
- package/docs/client-ui.md +1 -1
- package/docs/durability-design.md +6 -3
- package/docs/installation.md +4 -4
- package/docs/runtime-reference.md +5 -1
- package/docs/stateful-binding-updates-proposal.md +8 -4
- package/docs/user-bindings.en.md +5 -3
- package/docs/user-bindings.md +4 -2
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +15 -1
- package/internal/async-local-storage-intrinsics.js +38 -0
- package/internal/binding-declaration-contract.js +8 -0
- package/internal/binding-source-analysis.js +381 -64
- package/internal/binding-update-policy.js +7 -1
- package/internal/cell-analysis.js +21 -8
- package/internal/compiler-intrinsics.js +9 -43
- package/internal/compiler-module-links.js +7 -4
- package/internal/dynamic-environment-integration.js +8 -4
- package/internal/dynamic-environment-runtime.js +24 -3
- package/internal/dynamic-native-calls.js +4 -1
- package/internal/dynamic-native-runtime.js +15 -1
- package/internal/failure-reporting.js +38 -30
- package/internal/isolated-worker.js +17 -10
- package/internal/kernel-worker.js +493 -331
- package/internal/module-compilation.js +5 -4
- package/internal/module-transform-contract.js +32 -2
- package/internal/record-utils.js +24 -15
- package/internal/repl-value-observer.js +6 -3
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/session-cell-executor.js +2 -1
- package/internal/session-journal-schema.js +30 -13
- package/internal/session-journal.js +19 -4
- package/internal/session-runtime.js +1 -0
- package/internal/source-position-map.js +19 -0
- package/internal/stateful-root-compiler.js +3 -1
- package/internal/typescript-transform.js +4 -2
- package/internal/user-binding-console-worker.js +101 -41
- package/internal/user-bindings.js +10 -2
- package/internal/value-wire.js +101 -71
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +20 -0
- package/internal/worker-repl-realm.js +134 -0
- package/package.json +2 -1
- package/src/client-activity.js +8 -1
|
@@ -14,7 +14,7 @@ export { commonJsExportEvidence, linkCommonJsEvidenceSource } from './commonjs-s
|
|
|
14
14
|
import { COMMONJS_PARAMETERS } from './compiler-scope-facts.js'
|
|
15
15
|
import {
|
|
16
16
|
LEGACY_USER_BINDING_TRANSFORM, USER_BINDING_TRANSFORM, PROTECTED_MODULE_TRANSFORM,
|
|
17
|
-
supportedUserBindingTransform, transformTypeScriptSource,
|
|
17
|
+
isStatefulUserBindingTransform, supportedUserBindingTransform, transformTypeScriptSource,
|
|
18
18
|
} from './typescript-transform.js'
|
|
19
19
|
|
|
20
20
|
const topLevelRegion = region => region.kind === 'program' || region.top === true
|
|
@@ -162,7 +162,7 @@ function commonJsBodyRange(source) {
|
|
|
162
162
|
|
|
163
163
|
/** Module activations share lexical updates while retaining the native linker. */
|
|
164
164
|
export function compileStatefulModule(source, {
|
|
165
|
-
transform = USER_BINDING_TRANSFORM, target = 'module', url, nativeUsing,
|
|
165
|
+
transform = USER_BINDING_TRANSFORM, target = 'module', url, nativeUsing, programBindings = false,
|
|
166
166
|
} = {}) {
|
|
167
167
|
if (transform !== PROTECTED_MODULE_TRANSFORM && !supportedUserBindingTransform(transform)) {
|
|
168
168
|
throw new TypeError('user binding snapshot cannot prove its historical TypeScript transform')
|
|
@@ -188,14 +188,14 @@ export function compileStatefulModule(source, {
|
|
|
188
188
|
nativeJavaScript = marked.nativeJavaScript
|
|
189
189
|
mapped = marked
|
|
190
190
|
if (!nativeJavaScript) mapped = normalizeTypeScriptValues(mapped.code, mapped.sourceMap, target)
|
|
191
|
-
if (target !== 'commonjs' && (transform
|
|
191
|
+
if (target !== 'commonjs' && (isStatefulUserBindingTransform(transform)
|
|
192
192
|
|| transform === PROTECTED_MODULE_TRANSFORM && hasModuleResources(mapped.code))) {
|
|
193
193
|
mapped = normalizeModuleExports(mapped.code, mapped.sourceMap)
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
const commonJsSource = target === 'commonjs'
|
|
197
197
|
? commonJsExportEvidence(mapped.code, { legacy: transform === LEGACY_USER_BINDING_TRANSFORM }) : undefined
|
|
198
|
-
const links = transform
|
|
198
|
+
const links = isStatefulUserBindingTransform(transform) && target === 'module'
|
|
199
199
|
? moduleLinkPlan(mapped.code) : undefined
|
|
200
200
|
let normalized = transform === LEGACY_USER_BINDING_TRANSFORM ? mapped
|
|
201
201
|
: normalizeStatefulScopes(mapped.code, mapped.sourceMap, { target, moduleImport: links?.reader, nativeJavaScript, nativeUsing,
|
|
@@ -222,6 +222,7 @@ export function compileStatefulModule(source, {
|
|
|
222
222
|
sourceRegions: normalized.sourceRegions,
|
|
223
223
|
callableCollector: createRegionCallableCollector(callableSources),
|
|
224
224
|
module: true, compactOutput: true, importOperation: normalized.importOperation, sourceType, originalSource: source,
|
|
225
|
+
logicalRoots: programBindings,
|
|
225
226
|
bindings: normalized.dynamicBindings, privateBindings: normalized.privateBindings,
|
|
226
227
|
internalBindings: normalized.internalBindings, parserPlugins: CELL_PARSER_PLUGINS,
|
|
227
228
|
}) }
|
|
@@ -1,12 +1,42 @@
|
|
|
1
1
|
export const LEGACY_USER_BINDING_TRANSFORM = 'amaro@1.1.11'
|
|
2
|
-
export const
|
|
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'
|
|
3
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
|
+
}
|
|
4
15
|
|
|
5
16
|
export function moduleTransformForLanguage(languageSemantics) {
|
|
6
17
|
return languageSemantics === 'stateful-v1' ? USER_BINDING_TRANSFORM
|
|
7
18
|
: languageSemantics === 'protected-v1' ? PROTECTED_MODULE_TRANSFORM : LEGACY_USER_BINDING_TRANSFORM
|
|
8
19
|
}
|
|
9
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
|
+
|
|
10
40
|
export function supportedUserBindingTransform(transform) {
|
|
11
|
-
return transform
|
|
41
|
+
return isStatefulUserBindingTransform(transform) || transform === LEGACY_USER_BINDING_TRANSFORM
|
|
12
42
|
}
|
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
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { types } from 'node:util'
|
|
2
|
-
import { runInContext } from 'node:vm'
|
|
2
|
+
import { isContext, runInContext, runInThisContext } from 'node:vm'
|
|
3
3
|
import { parse } from 'acorn'
|
|
4
4
|
import { randomUUID } from 'node:crypto'
|
|
5
5
|
import { walkAst, SKIP_AST_CHILDREN } from './ast-traversal.js'
|
|
@@ -16,6 +16,9 @@ const now = Date.now
|
|
|
16
16
|
const bigintText = BigInt.prototype.toString
|
|
17
17
|
const BIGINT_LIMIT = 10n ** 128n
|
|
18
18
|
const unreadable = () => ({ status: 'unreadable', text: '', truncated: false })
|
|
19
|
+
const runInRealm = (source, context, options) => isContext(context)
|
|
20
|
+
? runInContext(source, context, options)
|
|
21
|
+
: runInThisContext(source, options)
|
|
19
22
|
|
|
20
23
|
function primitiveText(value) {
|
|
21
24
|
if (typeof value === 'string') return stringify(value.slice(0, MAX_TEXT))
|
|
@@ -56,7 +59,7 @@ export async function supportsAwaitLexicals(context, evaluate) {
|
|
|
56
59
|
try {
|
|
57
60
|
await evaluate(`let ${names[0]} = await Promise.resolve(41); const ${names[1]} = 42;`)
|
|
58
61
|
return names.every((name, index) => ownDescriptor(context, name) === undefined
|
|
59
|
-
&&
|
|
62
|
+
&& runInRealm(name, context, { timeout: 25 }) === index + 41)
|
|
60
63
|
} catch {
|
|
61
64
|
return false
|
|
62
65
|
} finally {
|
|
@@ -97,7 +100,7 @@ export function createReplValueObserver(context, { awaitLexicals = false } = {})
|
|
|
97
100
|
if (lexicals.has(name)) {
|
|
98
101
|
// Lexical storage shadows global properties, even while uninitialized.
|
|
99
102
|
if (/^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(name) && now() - at < 100) {
|
|
100
|
-
preview = previewBindingValue(
|
|
103
|
+
preview = previewBindingValue(runInRealm(name, context, { timeout: 25, displayErrors: false }))
|
|
101
104
|
}
|
|
102
105
|
} else if (globals.has(name)) {
|
|
103
106
|
const descriptor = ownDescriptor(context, name)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { compilerDescriptors } from './compiler-descriptors.js'
|
|
2
|
+
|
|
3
|
+
const uncurry = Function.prototype.bind.bind(Function.prototype.call)
|
|
4
|
+
const mapKeys = uncurry(Map.prototype.keys)
|
|
5
|
+
const mapIteratorNext = uncurry(Object.getPrototypeOf(new Map().keys()).next)
|
|
6
|
+
const weakMapGet = uncurry(WeakMap.prototype.get)
|
|
7
|
+
const weakMapSet = uncurry(WeakMap.prototype.set)
|
|
8
|
+
|
|
9
|
+
function appendArray(target, value) {
|
|
10
|
+
compilerDescriptors.defineProperty(target, target.length,
|
|
11
|
+
{ value, writable: true, enumerable: true, configurable: true })
|
|
12
|
+
return target
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function copyArray(source, start = 0, end = source.length, target = []) {
|
|
16
|
+
for (let index = start; index < end; index++) appendArray(target, source[index])
|
|
17
|
+
return target
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Host-private operations captured before any owned realm executes user code. */
|
|
21
|
+
export const runtimeIntrinsics = {
|
|
22
|
+
Object: compilerDescriptors.Object,
|
|
23
|
+
Reflect: {
|
|
24
|
+
apply: Reflect.apply,
|
|
25
|
+
construct: Reflect.construct,
|
|
26
|
+
deleteProperty: Reflect.deleteProperty,
|
|
27
|
+
defineProperty: compilerDescriptors.reflectDefineProperty,
|
|
28
|
+
has: Reflect.has,
|
|
29
|
+
ownKeys: Reflect.ownKeys,
|
|
30
|
+
},
|
|
31
|
+
Error, TypeError, Array, Map, Set, WeakMap, WeakSet, RegExp, Proxy,
|
|
32
|
+
objectCreate: Object.create,
|
|
33
|
+
objectDefineProperty: Object.defineProperty,
|
|
34
|
+
objectEntries: Object.entries,
|
|
35
|
+
objectFreeze: Object.freeze,
|
|
36
|
+
objectGetOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
|
|
37
|
+
objectGetPrototypeOf: Object.getPrototypeOf,
|
|
38
|
+
objectHasOwn: Object.hasOwn,
|
|
39
|
+
objectIs: Object.is,
|
|
40
|
+
objectKeys: Object.keys,
|
|
41
|
+
objectPropertyIsEnumerable: uncurry(Object.prototype.propertyIsEnumerable),
|
|
42
|
+
reflectOwnKeys: Reflect.ownKeys,
|
|
43
|
+
numberIsFinite: Number.isFinite,
|
|
44
|
+
numberIsNaN: Number.isNaN,
|
|
45
|
+
numberIsSafeInteger: Number.isSafeInteger,
|
|
46
|
+
toBigInt: BigInt,
|
|
47
|
+
toNumber: Number,
|
|
48
|
+
toString: String,
|
|
49
|
+
mapGet: uncurry(Map.prototype.get),
|
|
50
|
+
mapHas: uncurry(Map.prototype.has),
|
|
51
|
+
mapSet: uncurry(Map.prototype.set),
|
|
52
|
+
mapDelete: uncurry(Map.prototype.delete),
|
|
53
|
+
mapClear: uncurry(Map.prototype.clear),
|
|
54
|
+
mapSize: uncurry(Object.getOwnPropertyDescriptor(Map.prototype, 'size').get),
|
|
55
|
+
mapFirstKey: value => mapIteratorNext(mapKeys(value)).value,
|
|
56
|
+
mapForEach: uncurry(Map.prototype.forEach),
|
|
57
|
+
setHas: uncurry(Set.prototype.has),
|
|
58
|
+
setAdd: uncurry(Set.prototype.add),
|
|
59
|
+
setDelete: uncurry(Set.prototype.delete),
|
|
60
|
+
setClear: uncurry(Set.prototype.clear),
|
|
61
|
+
setSize: uncurry(Object.getOwnPropertyDescriptor(Set.prototype, 'size').get),
|
|
62
|
+
setForEach: uncurry(Set.prototype.forEach),
|
|
63
|
+
weakMapHas: uncurry(WeakMap.prototype.has),
|
|
64
|
+
weakMapGet,
|
|
65
|
+
weakMapSet,
|
|
66
|
+
weakSetHas: uncurry(WeakSet.prototype.has),
|
|
67
|
+
weakSetAdd: uncurry(WeakSet.prototype.add),
|
|
68
|
+
isArray: Array.isArray,
|
|
69
|
+
everyArray: uncurry(Array.prototype.every),
|
|
70
|
+
includes: uncurry(Array.prototype.includes),
|
|
71
|
+
join: uncurry(Array.prototype.join),
|
|
72
|
+
popArray: uncurry(Array.prototype.pop),
|
|
73
|
+
prependArray: uncurry(Array.prototype.unshift),
|
|
74
|
+
someArray: uncurry(Array.prototype.some),
|
|
75
|
+
sliceString: uncurry(String.prototype.slice),
|
|
76
|
+
splitString: uncurry(String.prototype.split),
|
|
77
|
+
searchString: uncurry(String.prototype.search),
|
|
78
|
+
replaceString: uncurry(String.prototype.replace),
|
|
79
|
+
trimString: uncurry(String.prototype.trim),
|
|
80
|
+
replaceAllString: uncurry(String.prototype.replaceAll),
|
|
81
|
+
includesString: uncurry(String.prototype.includes),
|
|
82
|
+
startsWith: uncurry(String.prototype.startsWith),
|
|
83
|
+
endsWith: uncurry(String.prototype.endsWith),
|
|
84
|
+
regexpExec: uncurry(RegExp.prototype.exec),
|
|
85
|
+
regexpTest: uncurry(RegExp.prototype.test),
|
|
86
|
+
floor: Math.floor,
|
|
87
|
+
min: Math.min,
|
|
88
|
+
max: Math.max,
|
|
89
|
+
appendArray,
|
|
90
|
+
copyArray,
|
|
91
|
+
sort: uncurry(Array.prototype.sort),
|
|
92
|
+
compare: uncurry(String.prototype.localeCompare),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof Buffer === 'function') {
|
|
96
|
+
runtimeIntrinsics.bufferByteLength = Buffer.byteLength
|
|
97
|
+
runtimeIntrinsics.bufferConcat = Buffer.concat
|
|
98
|
+
runtimeIntrinsics.bufferIsBuffer = Buffer.isBuffer
|
|
99
|
+
runtimeIntrinsics.bufferSubarray = uncurry(Buffer.prototype.subarray)
|
|
100
|
+
runtimeIntrinsics.bufferToString = uncurry(Buffer.prototype.toString)
|
|
101
|
+
}
|
|
@@ -414,7 +414,7 @@ export class SessionCellExecutor {
|
|
|
414
414
|
}
|
|
415
415
|
const priorBindingCatalog = userBindingPlan.catalog
|
|
416
416
|
const catalog = priorBindingCatalog.inputs()
|
|
417
|
-
const { bindingPolicy, rewritesEnabled, moduleSemantics, languageSemantics } = executionPolicies(config, replayRecord)
|
|
417
|
+
const { bindingPolicy, rewritesEnabled, moduleSemantics, languageSemantics, moduleTransform } = executionPolicies(config, replayRecord)
|
|
418
418
|
const prepareCell = program => prepareProgram(program, {
|
|
419
419
|
knownBindings: catalog.knownBindings,
|
|
420
420
|
bindingPolicy,
|
|
@@ -576,6 +576,7 @@ export class SessionCellExecutor {
|
|
|
576
576
|
type: 'run', id, program: prepared.code, namespaces: bindings.workerDescriptors,
|
|
577
577
|
moduleLoads: prepared.moduleLoads,
|
|
578
578
|
languageSemantics,
|
|
579
|
+
moduleTransform,
|
|
579
580
|
rootRuntimeName: prepared.rootRuntimeName,
|
|
580
581
|
rootBindings: prepared.rootBindings,
|
|
581
582
|
importBindingNamespaces: new Map([...catalog.importBindings].map(([name, binding]) => [name, binding.namespace])),
|
|
@@ -13,7 +13,8 @@ export const RECOVERY_BOUNDARY_KEY = 'dshPtcPlusRecoveryBoundaries'
|
|
|
13
13
|
export const IMPORT_BOUNDARY_JOURNAL_VERSION = 7
|
|
14
14
|
export const PER_NAME_USER_BINDINGS_JOURNAL_VERSION = 8
|
|
15
15
|
export const LANGUAGE_SEMANTICS_JOURNAL_VERSION = 9
|
|
16
|
-
export const
|
|
16
|
+
export const MODULE_TRANSFORM_JOURNAL_VERSION = 10
|
|
17
|
+
export const JOURNAL_VERSION = MODULE_TRANSFORM_JOURNAL_VERSION
|
|
17
18
|
export const LIVE_USER_BINDINGS_SHADOW_POLICY = 'per-name'
|
|
18
19
|
export const LEGACY_USER_BINDINGS_SHADOW_POLICY = 'whole-entry'
|
|
19
20
|
export const LIVE_USER_BINDINGS_REUSE_POLICY = 'implementation-v1'
|
|
@@ -30,7 +31,8 @@ export const STATUSES = new Set(['durable', 'volatile', 'discarded', 'noop'])
|
|
|
30
31
|
export const BINDING_MODES = new Set(['loose', 'strict'])
|
|
31
32
|
export const WHOLE_ENTRY_JOURNAL_FIELDS = new Set(['version', 'bindingPolicy', 'rewritePolicy', 'moduleSemantics', 'userBindingsFingerprint', 'userBindingsReusePolicy', 'status', 'calls', 'operations', 'confirms', 'diagnostics', 'completion', 'volatileReason'])
|
|
32
33
|
export const PER_NAME_JOURNAL_FIELDS = new Set([...WHOLE_ENTRY_JOURNAL_FIELDS, 'userBindingsShadowPolicy', 'userBindingNames'])
|
|
33
|
-
export const
|
|
34
|
+
export const LANGUAGE_SEMANTICS_JOURNAL_FIELDS = new Set([...PER_NAME_JOURNAL_FIELDS, 'languageSemantics'])
|
|
35
|
+
export const JOURNAL_FIELDS = new Set([...LANGUAGE_SEMANTICS_JOURNAL_FIELDS, 'moduleTransform'])
|
|
34
36
|
export const FINGERPRINT_REUSE_JOURNAL_FIELDS = new Set([...WHOLE_ENTRY_JOURNAL_FIELDS].filter(field => field !== 'userBindingsReusePolicy'))
|
|
35
37
|
export const RELATIONLESS_JOURNAL_FIELDS = new Set([...FINGERPRINT_REUSE_JOURNAL_FIELDS].filter(field => field !== 'userBindingsFingerprint'))
|
|
36
38
|
export const PREDECESSOR_JOURNAL_FIELDS = new Set(['version', 'bindingMode', 'rewritePolicy', 'status', 'calls', 'operations', 'confirms', 'diagnostics', 'completion', 'volatileReason'])
|
|
@@ -56,32 +58,47 @@ export const ERROR_FIELDS = new Set(['kind', 'message'])
|
|
|
56
58
|
export const EDIT_TARGET_FIELDS = new Set(['targetCallSeq'])
|
|
57
59
|
export const DERIVED_RUN_FIELDS = new Set(['code', 'description'])
|
|
58
60
|
|
|
59
|
-
export const JOURNAL_VERSIONS = new Set([LEGACY_JOURNAL_VERSION, INTERMEDIATE_JOURNAL_VERSION, PREVIOUS_JOURNAL_VERSION, USER_BINDING_RELATIONLESS_JOURNAL_VERSION, FINGERPRINT_REUSE_JOURNAL_VERSION, VERSIONED_BINDING_REUSE_JOURNAL_VERSION, IMPORT_BOUNDARY_JOURNAL_VERSION, PER_NAME_USER_BINDINGS_JOURNAL_VERSION, JOURNAL_VERSION])
|
|
61
|
+
export const JOURNAL_VERSIONS = new Set([LEGACY_JOURNAL_VERSION, INTERMEDIATE_JOURNAL_VERSION, PREVIOUS_JOURNAL_VERSION, USER_BINDING_RELATIONLESS_JOURNAL_VERSION, FINGERPRINT_REUSE_JOURNAL_VERSION, VERSIONED_BINDING_REUSE_JOURNAL_VERSION, IMPORT_BOUNDARY_JOURNAL_VERSION, PER_NAME_USER_BINDINGS_JOURNAL_VERSION, LANGUAGE_SEMANTICS_JOURNAL_VERSION, JOURNAL_VERSION])
|
|
60
62
|
export const USER_BINDINGS_REUSE_POLICIES = new Set([LEGACY_USER_BINDINGS_REUSE_POLICY, LIVE_USER_BINDINGS_REUSE_POLICY])
|
|
61
63
|
export const USER_BINDINGS_SHADOW_POLICIES = new Set([LEGACY_USER_BINDINGS_SHADOW_POLICY, LIVE_USER_BINDINGS_SHADOW_POLICY])
|
|
62
64
|
const USER_BINDING_NAME_STATES = new Set(['provider', 'local', 'absent', 'unknown'])
|
|
65
|
+
const isArray = Array.isArray
|
|
66
|
+
const freeze = Object.freeze
|
|
67
|
+
const ownKeys = Reflect.ownKeys
|
|
68
|
+
const defineProperty = Object.defineProperty
|
|
69
|
+
const uncurry = Function.prototype.bind.bind(Function.prototype.call)
|
|
70
|
+
const setHas = uncurry(Set.prototype.has)
|
|
71
|
+
const setAdd = uncurry(Set.prototype.add)
|
|
72
|
+
const sort = uncurry(Array.prototype.sort)
|
|
73
|
+
const enumerable = uncurry(Object.prototype.propertyIsEnumerable)
|
|
63
74
|
|
|
64
75
|
/** Closed, value-free evidence shared by worker settlement, persistence and Client. */
|
|
65
76
|
export function normalizeUserBindingNames(value) {
|
|
66
|
-
if (!
|
|
77
|
+
if (!isArray(value)) throw new TypeError('invalid user binding name evidence')
|
|
67
78
|
const names = new Set()
|
|
68
|
-
|
|
79
|
+
const normalized = []
|
|
80
|
+
for (let index = 0; index < value.length; index++) {
|
|
81
|
+
const fact = value[index]
|
|
69
82
|
if (fact === null || typeof fact !== 'object'
|
|
70
|
-
|| !USER_BINDING_NAME_STATES
|
|
83
|
+
|| !setHas(USER_BINDING_NAME_STATES, fact.state)
|
|
71
84
|
|| typeof fact.name !== 'string' || fact.name.length > 128
|
|
72
85
|
|| !/^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u.test(fact.name)
|
|
73
|
-
|| names
|
|
86
|
+
|| setHas(names, fact.name)) throw new TypeError('invalid user binding name evidence')
|
|
74
87
|
const fields = fact.state === 'provider' ? ['name', 'state', 'entryId'] : ['name', 'state']
|
|
75
|
-
|
|
76
|
-
|
|
88
|
+
let validFields = ownKeys(fact).length === fields.length
|
|
89
|
+
for (let field = 0; validFields && field < fields.length; field++) validFields = enumerable(fact, fields[field])
|
|
90
|
+
if (!validFields
|
|
77
91
|
|| (fact.state === 'provider' && (typeof fact.entryId !== 'string'
|
|
78
92
|
|| !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(fact.entryId)))) {
|
|
79
93
|
throw new TypeError('invalid user binding name evidence')
|
|
80
94
|
}
|
|
81
|
-
names
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
setAdd(names, fact.name)
|
|
96
|
+
defineProperty(normalized, normalized.length, { configurable: true, enumerable: true, writable: true,
|
|
97
|
+
value: freeze({ name: fact.name, state: fact.state,
|
|
98
|
+
...(fact.state === 'provider' ? { entryId: fact.entryId } : {}) }) })
|
|
99
|
+
}
|
|
100
|
+
sort(normalized, (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)
|
|
101
|
+
return freeze(normalized)
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
export function normalizeJournalUserBindingNames(journal) {
|
|
@@ -3,6 +3,8 @@ import { normalizeDiagnostic } from './diagnostic.js'
|
|
|
3
3
|
import { assertOwnFields, isRecord } from './record-utils.js'
|
|
4
4
|
import { sessionEvents } from './session-events.js'
|
|
5
5
|
import { LEGACY_LANGUAGE_SEMANTICS, normalizeLanguageSemantics } from './language-semantics.js'
|
|
6
|
+
import { LEGACY_USER_BINDING_TRANSFORM, historicalModuleTransformForLanguage,
|
|
7
|
+
moduleTransformForLanguage, normalizeModuleTransform } from './module-transform-contract.js'
|
|
6
8
|
import {
|
|
7
9
|
LEGACY_DEFAULT_EXPORT_BINDING,
|
|
8
10
|
LEGACY_IMPORT_EXPRESSION_BOUNDARY,
|
|
@@ -16,6 +18,8 @@ import {
|
|
|
16
18
|
REWRITES_KEY,
|
|
17
19
|
RECOVERY_BOUNDARY_KEY,
|
|
18
20
|
JOURNAL_VERSION,
|
|
21
|
+
LANGUAGE_SEMANTICS_JOURNAL_VERSION,
|
|
22
|
+
LANGUAGE_SEMANTICS_JOURNAL_FIELDS,
|
|
19
23
|
IMPORT_BOUNDARY_JOURNAL_VERSION,
|
|
20
24
|
PER_NAME_USER_BINDINGS_JOURNAL_VERSION,
|
|
21
25
|
PER_NAME_JOURNAL_FIELDS,
|
|
@@ -251,12 +255,18 @@ function normalizeUserBindingsFingerprint(value) {
|
|
|
251
255
|
|
|
252
256
|
function migrateJournal(value, resolveLegacyConfirm) {
|
|
253
257
|
if (value.version === JOURNAL_VERSION) return value
|
|
258
|
+
if (value.version === LANGUAGE_SEMANTICS_JOURNAL_VERSION) {
|
|
259
|
+
assertOwnFields(value, LANGUAGE_SEMANTICS_JOURNAL_FIELDS, 'dsh-ptc-plus journal')
|
|
260
|
+
const languageSemantics = normalizeLanguageSemantics(value.languageSemantics)
|
|
261
|
+
return { ...value, version: JOURNAL_VERSION, moduleTransform: historicalModuleTransformForLanguage(languageSemantics) }
|
|
262
|
+
}
|
|
254
263
|
if (value.version === PER_NAME_USER_BINDINGS_JOURNAL_VERSION) {
|
|
255
264
|
assertOwnFields(value, PER_NAME_JOURNAL_FIELDS, 'dsh-ptc-plus journal')
|
|
256
|
-
return { ...value, version: JOURNAL_VERSION, languageSemantics: LEGACY_LANGUAGE_SEMANTICS
|
|
265
|
+
return { ...value, version: JOURNAL_VERSION, languageSemantics: LEGACY_LANGUAGE_SEMANTICS,
|
|
266
|
+
moduleTransform: LEGACY_USER_BINDING_TRANSFORM }
|
|
257
267
|
}
|
|
258
268
|
const shadow = { userBindingsShadowPolicy: LEGACY_USER_BINDINGS_SHADOW_POLICY, userBindingNames: null,
|
|
259
|
-
languageSemantics: LEGACY_LANGUAGE_SEMANTICS }
|
|
269
|
+
languageSemantics: LEGACY_LANGUAGE_SEMANTICS, moduleTransform: LEGACY_USER_BINDING_TRANSFORM }
|
|
260
270
|
if (value.version === IMPORT_BOUNDARY_JOURNAL_VERSION) {
|
|
261
271
|
assertOwnFields(value, WHOLE_ENTRY_JOURNAL_FIELDS, 'dsh-ptc-plus journal')
|
|
262
272
|
return { ...value, version: JOURNAL_VERSION, ...shadow }
|
|
@@ -325,6 +335,7 @@ export function normalizeJournal(value, options = {}) {
|
|
|
325
335
|
const migrated = migrateJournal(value, options.resolveLegacyConfirm)
|
|
326
336
|
assertOwnFields(migrated, JOURNAL_FIELDS, 'dsh-ptc-plus journal')
|
|
327
337
|
const languageSemantics = normalizeLanguageSemantics(migrated.languageSemantics)
|
|
338
|
+
const moduleTransform = normalizeModuleTransform(migrated.moduleTransform, languageSemantics)
|
|
328
339
|
const bindingPolicy = normalizeBindingPolicy(migrated.bindingPolicy)
|
|
329
340
|
const rewritePolicy = normalizeRewritePolicy(migrated.rewritePolicy)
|
|
330
341
|
const moduleSemantics = normalizeModuleSemantics(migrated.moduleSemantics)
|
|
@@ -355,6 +366,7 @@ export function normalizeJournal(value, options = {}) {
|
|
|
355
366
|
return Object.freeze({
|
|
356
367
|
version: JOURNAL_VERSION,
|
|
357
368
|
languageSemantics,
|
|
369
|
+
moduleTransform,
|
|
358
370
|
bindingPolicy,
|
|
359
371
|
rewritePolicy,
|
|
360
372
|
moduleSemantics,
|
|
@@ -583,7 +595,8 @@ export function liveToolCallSeq(session, callId, toolName) {
|
|
|
583
595
|
}
|
|
584
596
|
|
|
585
597
|
/** Start a mutable journal for one live cell. */
|
|
586
|
-
export function createJournal(confirms = [], bindingPolicy, rewritePolicy, languageSemantics = LEGACY_LANGUAGE_SEMANTICS
|
|
598
|
+
export function createJournal(confirms = [], bindingPolicy, rewritePolicy, languageSemantics = LEGACY_LANGUAGE_SEMANTICS,
|
|
599
|
+
moduleTransform = moduleTransformForLanguage(languageSemantics)) {
|
|
587
600
|
if (typeof bindingPolicy === 'string') {
|
|
588
601
|
if (!BINDING_MODES.has(bindingPolicy)) throw new TypeError('invalid dsh-ptc-plus journal binding mode')
|
|
589
602
|
bindingPolicy = {
|
|
@@ -591,9 +604,11 @@ export function createJournal(confirms = [], bindingPolicy, rewritePolicy, langu
|
|
|
591
604
|
functionClassRedeclarations: false,
|
|
592
605
|
}
|
|
593
606
|
}
|
|
607
|
+
languageSemantics = normalizeLanguageSemantics(languageSemantics)
|
|
594
608
|
return {
|
|
595
609
|
version: JOURNAL_VERSION,
|
|
596
|
-
languageSemantics
|
|
610
|
+
languageSemantics,
|
|
611
|
+
moduleTransform: normalizeModuleTransform(moduleTransform, languageSemantics),
|
|
597
612
|
bindingPolicy: normalizeBindingPolicy(bindingPolicy),
|
|
598
613
|
rewritePolicy: normalizeRewritePolicy(rewritePolicy),
|
|
599
614
|
moduleSemantics: normalizeModuleSemantics(LIVE_MODULE_SEMANTICS),
|
|
@@ -117,6 +117,25 @@ export function sourceOffsetAt(sourceMap, generatedOffset) {
|
|
|
117
117
|
return segmentOffsetAt(segment, generatedOffset)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/** Whether a complete generated interval still contains its exact original text. */
|
|
121
|
+
export function sourceRangeHasOriginalText(sourceMap, generatedSource, originalSource, generatedStart, generatedEnd) {
|
|
122
|
+
if (typeof generatedSource !== 'string' || typeof originalSource !== 'string'
|
|
123
|
+
|| generatedEnd <= generatedStart || generatedStart < 0 || generatedEnd > generatedSource.length) return false
|
|
124
|
+
let cursor = generatedStart
|
|
125
|
+
for (let index = segmentIndexAt(sourceMap, generatedStart); index < sourceMap.length && cursor < generatedEnd; index += 1) {
|
|
126
|
+
const segment = sourceMap.at(index)
|
|
127
|
+
if (segment.generatedStart > cursor || segment.generatedEnd <= cursor) break
|
|
128
|
+
const end = Math.min(generatedEnd, segment.generatedEnd)
|
|
129
|
+
const length = end - cursor
|
|
130
|
+
const originalStart = segmentOffsetAt(segment, cursor)
|
|
131
|
+
if (segment.originalEnd <= segment.originalStart
|
|
132
|
+
|| originalStart + length > originalSource.length
|
|
133
|
+
|| generatedSource.slice(cursor, end) !== originalSource.slice(originalStart, originalStart + length)) return false
|
|
134
|
+
cursor = end
|
|
135
|
+
}
|
|
136
|
+
return cursor === generatedEnd
|
|
137
|
+
}
|
|
138
|
+
|
|
120
139
|
function segmentOffsetAt(segment, generatedOffset) {
|
|
121
140
|
const generatedLength = segment.generatedEnd - segment.generatedStart
|
|
122
141
|
const originalLength = segment.originalEnd - segment.originalStart
|
|
@@ -191,8 +191,10 @@ function rewriteRootReferences(code, sourceMap, runtime, candidateNames, candida
|
|
|
191
191
|
}
|
|
192
192
|
handled.add(path.node.start)
|
|
193
193
|
} })
|
|
194
|
+
const classificationSource = applySourceEdits(code, sourceMap, classificationEdits)
|
|
194
195
|
return { ...applySourceEdits(code, sourceMap, edits),
|
|
195
|
-
classificationCode:
|
|
196
|
+
classificationCode: classificationSource.code,
|
|
197
|
+
classificationSourceMap: classificationSource.sourceMap,
|
|
196
198
|
implicitDeclarations: [...implicitDeclarations.values()],
|
|
197
199
|
readNames: [...readNames] }
|
|
198
200
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import loadAmaro from './compiler-amaro.cjs'
|
|
2
2
|
|
|
3
|
-
export { LEGACY_USER_BINDING_TRANSFORM,
|
|
4
|
-
|
|
3
|
+
export { LEGACY_USER_BINDING_TRANSFORM, PREVIOUS_USER_BINDING_TRANSFORM, USER_BINDING_TRANSFORM,
|
|
4
|
+
PROTECTED_MODULE_TRANSFORM, isStatefulUserBindingTransform,
|
|
5
|
+
historicalModuleTransformForLanguage, moduleTransformForLanguage, moduleTransformMatchesLanguage,
|
|
6
|
+
normalizeModuleTransform, supportedUserBindingTransform } from './module-transform-contract.js'
|
|
5
7
|
|
|
6
8
|
/** Keep binding-module lowering independent of the Host's experimental transform API. */
|
|
7
9
|
export function transformTypeScriptModule(source) {
|