dsh-ptc-plus 0.3.1 → 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 +66 -73
- package/README.md +66 -73
- 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 +30610 -722
- 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 +6 -4
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +15 -3
- 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 +9 -3
- package/docs/adr/0014-persist-cell-rewrite-policy.md +11 -5
- 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 +8 -6
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +17 -3
- 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 +82 -22
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +96 -20
- package/docs/durability-design.md +61 -24
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/program-data-plane.md +6 -0
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +79 -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 +374 -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 +252 -242
- 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 -553
- 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 +91 -25
- 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 +28 -3
- 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 +911 -116
- 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 -201
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +21 -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 -51
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +455 -91
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +106 -0
- package/internal/session-journal.js +237 -440
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +325 -80
- package/internal/session-state.js +249 -40
- 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 +81 -11
- package/src/client-activity.js +109 -45
- 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
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
import { TraceMap, decodedMappings } from '@jridgewell/trace-mapping'
|
|
2
|
+
|
|
3
|
+
export const SOURCE_MAP_RUNS = Symbol.for('ptc.compiler.source-map-runs')
|
|
4
|
+
|
|
5
|
+
export class SourceMapRuns {
|
|
6
|
+
constructor(data) { this.data = data; this.length = data.length / 4; this[SOURCE_MAP_RUNS] = true }
|
|
7
|
+
at(index) {
|
|
8
|
+
if (index < 0) index += this.length
|
|
9
|
+
if (index < 0 || index >= this.length) return undefined
|
|
10
|
+
const offset = index * 4
|
|
11
|
+
return { generatedStart: this.data[offset], generatedEnd: this.data[offset + 1],
|
|
12
|
+
originalStart: this.data[offset + 2], originalEnd: this.data[offset + 3] }
|
|
13
|
+
}
|
|
14
|
+
*[Symbol.iterator]() { for (let index = 0; index < this.length; index++) yield this.at(index) }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const isSourceMap = value => Array.isArray(value) || value instanceof SourceMapRuns
|
|
18
|
+
|
|
19
|
+
const validMappingOffset = value => Number.isSafeInteger(value) && value >= 0 && value <= 0xffffffff
|
|
20
|
+
|
|
21
|
+
/** Numeric mapping runs avoid retaining an object for every copied token. */
|
|
22
|
+
export function createSourceMapBuilder() {
|
|
23
|
+
const blocks = []
|
|
24
|
+
const blockLength = 4096
|
|
25
|
+
let size = 0
|
|
26
|
+
// Positional writes keep the hot mapping paths from allocating a segment
|
|
27
|
+
// object that is immediately taken apart again.
|
|
28
|
+
const pushValues = (generatedStart, generatedEnd, originalStart, originalEnd) => {
|
|
29
|
+
if (!validMappingOffset(generatedStart) || !validMappingOffset(generatedEnd)
|
|
30
|
+
|| !validMappingOffset(originalStart) || !validMappingOffset(originalEnd)) {
|
|
31
|
+
throw new RangeError('source mapping offsets must fit a source buffer')
|
|
32
|
+
}
|
|
33
|
+
if (size % blockLength === 0) blocks.push(new Uint32Array(blockLength))
|
|
34
|
+
const block = blocks.at(-1), offset = size % blockLength
|
|
35
|
+
block[offset] = generatedStart
|
|
36
|
+
block[offset + 1] = generatedEnd
|
|
37
|
+
block[offset + 2] = originalStart
|
|
38
|
+
block[offset + 3] = originalEnd
|
|
39
|
+
size += 4
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
push({ generatedStart, generatedEnd, originalStart, originalEnd }) {
|
|
43
|
+
pushValues(generatedStart, generatedEnd, originalStart, originalEnd)
|
|
44
|
+
},
|
|
45
|
+
pushValues,
|
|
46
|
+
finish(compact = false) {
|
|
47
|
+
const data = new Uint32Array(size)
|
|
48
|
+
for (let index = 0; index < blocks.length; index++) {
|
|
49
|
+
data.set(blocks[index].subarray(0, Math.min(blockLength, size - index * blockLength)), index * blockLength)
|
|
50
|
+
}
|
|
51
|
+
const runs = new SourceMapRuns(data)
|
|
52
|
+
return !compact && runs.length < 4096 ? [...runs] : runs
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
1
57
|
export function identitySourceMap(length) {
|
|
2
58
|
return [{ generatedStart: 0, generatedEnd: length, originalStart: 0, originalEnd: length }]
|
|
3
59
|
}
|
|
@@ -42,16 +98,26 @@ export function createMappedTextBuilder(source, sourceOffset = 0) {
|
|
|
42
98
|
}
|
|
43
99
|
}
|
|
44
100
|
|
|
45
|
-
function
|
|
101
|
+
function segmentIndexAt(sourceMap, generatedOffset) {
|
|
46
102
|
let low = 0
|
|
47
103
|
let high = sourceMap.length
|
|
104
|
+
const packed = sourceMap instanceof SourceMapRuns ? sourceMap.data : undefined
|
|
48
105
|
while (low < high) {
|
|
49
106
|
const middle = (low + high) >>> 1
|
|
50
|
-
|
|
107
|
+
const end = packed === undefined ? sourceMap.at(middle).generatedEnd : packed[middle * 4 + 1]
|
|
108
|
+
if (generatedOffset < end) high = middle
|
|
51
109
|
else low = middle + 1
|
|
52
110
|
}
|
|
53
|
-
|
|
111
|
+
return low
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function sourceOffsetAt(sourceMap, generatedOffset) {
|
|
115
|
+
const segment = sourceMap.at(segmentIndexAt(sourceMap, generatedOffset)) ?? sourceMap.at(-1)
|
|
54
116
|
if (segment === undefined) return generatedOffset
|
|
117
|
+
return segmentOffsetAt(segment, generatedOffset)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function segmentOffsetAt(segment, generatedOffset) {
|
|
55
121
|
const generatedLength = segment.generatedEnd - segment.generatedStart
|
|
56
122
|
const originalLength = segment.originalEnd - segment.originalStart
|
|
57
123
|
const localOffset = Math.max(0, generatedOffset - segment.generatedStart)
|
|
@@ -62,51 +128,64 @@ function originalOffsetAt(sourceMap, generatedOffset) {
|
|
|
62
128
|
+ Math.floor((localOffset * (originalLength - 1)) / (generatedLength - 1))
|
|
63
129
|
}
|
|
64
130
|
|
|
131
|
+
/** A copied interval is already bounded by this segment. Its endpoints need
|
|
132
|
+
* no additional search through the complete source map. */
|
|
133
|
+
function copiedSegmentOriginal(segment, start, end) {
|
|
134
|
+
return [segmentOffsetAt(segment, start),
|
|
135
|
+
segmentOffsetAt(segment, end - 1) + (segment.originalEnd > segment.originalStart ? 1 : 0)]
|
|
136
|
+
}
|
|
137
|
+
|
|
65
138
|
function mappedOffsetRange(sourceMap, start, end) {
|
|
139
|
+
const lastOffset = Math.max(start, end - 1)
|
|
140
|
+
const last = sourceMap.at(segmentIndexAt(sourceMap, lastOffset)) ?? sourceMap.at(-1)
|
|
141
|
+
const hasSourceCharacter = last === undefined || lastOffset < last.generatedEnd && last.originalEnd > last.originalStart
|
|
142
|
+
const originalLast = last === undefined ? lastOffset : segmentOffsetAt(last, lastOffset)
|
|
66
143
|
return {
|
|
67
|
-
originalStart:
|
|
68
|
-
originalEnd:
|
|
144
|
+
originalStart: start === lastOffset ? originalLast : sourceOffsetAt(sourceMap, start),
|
|
145
|
+
originalEnd: originalLast + (end > start && hasSourceCharacter ? 1 : 0),
|
|
69
146
|
}
|
|
70
147
|
}
|
|
71
148
|
|
|
72
|
-
|
|
149
|
+
/** Replacement runs reach the mapping builder as positional writes. The
|
|
150
|
+
* generator this replaced allocated a segment object for every emitted run. */
|
|
151
|
+
function emitReplacementSegments(sourceMap, start, end, replacementLength, mappings, emit) {
|
|
73
152
|
const { originalStart: startOriginal, originalEnd: endOriginal } = mappedOffsetRange(sourceMap, start, end)
|
|
74
|
-
if (!
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
originalStart: startOriginal,
|
|
79
|
-
originalEnd: endOriginal,
|
|
80
|
-
}]
|
|
81
|
-
}
|
|
82
|
-
const segments = []
|
|
153
|
+
if (!isSourceMap(mappings) || mappings.length === 0) {
|
|
154
|
+
if (replacementLength !== 0) emit(start, start + replacementLength, startOriginal, endOriginal)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
83
157
|
let cursor = 0
|
|
158
|
+
let anchorOffset = start
|
|
84
159
|
for (const mapping of mappings) {
|
|
85
160
|
if (mapping.generatedStart > cursor) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
161
|
+
const nextAnchor = sourceOffsetAt(sourceMap, mapping.originalStart)
|
|
162
|
+
emit(start + cursor, start + mapping.generatedStart, nextAnchor, nextAnchor)
|
|
163
|
+
}
|
|
164
|
+
if (mapping.generatedEnd - mapping.generatedStart === mapping.originalEnd - mapping.originalStart
|
|
165
|
+
&& mapping.originalEnd > mapping.originalStart) {
|
|
166
|
+
// A verbatim copy retains every previous boundary, including inserted
|
|
167
|
+
// compiler text. Collapsing its endpoints would interpolate that text
|
|
168
|
+
// into source positions and corrupt later call/write provenance.
|
|
169
|
+
for (let index = segmentIndexAt(sourceMap, mapping.originalStart); index < sourceMap.length; index++) {
|
|
170
|
+
const segment = sourceMap.at(index)
|
|
171
|
+
if (segment.generatedStart >= mapping.originalEnd) break
|
|
172
|
+
const from = Math.max(mapping.originalStart, segment.generatedStart)
|
|
173
|
+
const to = Math.min(mapping.originalEnd, segment.generatedEnd)
|
|
174
|
+
const [originalStart, originalEnd] = copiedSegmentOriginal(segment, from, to)
|
|
175
|
+
emit(start + mapping.generatedStart + from - mapping.originalStart,
|
|
176
|
+
start + mapping.generatedStart + to - mapping.originalStart, originalStart, originalEnd)
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
const { originalStart, originalEnd } = mappedOffsetRange(sourceMap, mapping.originalStart, mapping.originalEnd)
|
|
180
|
+
emit(start + mapping.generatedStart, start + mapping.generatedEnd, originalStart, originalEnd)
|
|
92
181
|
}
|
|
93
|
-
const original = mappedOffsetRange(sourceMap, mapping.originalStart, mapping.originalEnd)
|
|
94
|
-
segments.push({
|
|
95
|
-
generatedStart: start + mapping.generatedStart,
|
|
96
|
-
generatedEnd: start + mapping.generatedEnd,
|
|
97
|
-
...original,
|
|
98
|
-
})
|
|
99
182
|
cursor = mapping.generatedEnd
|
|
183
|
+
anchorOffset = mapping.originalEnd
|
|
100
184
|
}
|
|
101
185
|
if (cursor < replacementLength) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
generatedEnd: start + replacementLength,
|
|
105
|
-
originalStart: startOriginal,
|
|
106
|
-
originalEnd: endOriginal,
|
|
107
|
-
})
|
|
186
|
+
const anchor = sourceOffsetAt(sourceMap, anchorOffset)
|
|
187
|
+
emit(start + cursor, start + replacementLength, anchor, anchor)
|
|
108
188
|
}
|
|
109
|
-
return segments
|
|
110
189
|
}
|
|
111
190
|
|
|
112
191
|
export function applySourceEdits(code, sourceMap, edits) {
|
|
@@ -120,12 +199,12 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
120
199
|
if (!Number.isSafeInteger(item.start) || !Number.isSafeInteger(item.end)
|
|
121
200
|
|| item.start < 0 || item.end < item.start || item.end > code.length
|
|
122
201
|
|| item.start < previousEnd || typeof text !== 'string'
|
|
123
|
-
|| (item.mappings !== undefined && !
|
|
202
|
+
|| (item.mappings !== undefined && !isSourceMap(item.mappings))
|
|
124
203
|
|| (item.start === item.end && previous?.start === item.start && previous.end === item.end)) {
|
|
125
204
|
throw new RangeError('source edits must be bounded, ordered, and non-overlapping')
|
|
126
205
|
}
|
|
127
|
-
const itemMappings =
|
|
128
|
-
.sort((left, right) => left.generatedStart - right.generatedStart)
|
|
206
|
+
const itemMappings = item.mappings instanceof SourceMapRuns ? item.mappings
|
|
207
|
+
: [...(item.mappings ?? [])].sort((left, right) => left.generatedStart - right.generatedStart)
|
|
129
208
|
let mappingEnd = 0
|
|
130
209
|
for (const mapping of itemMappings) {
|
|
131
210
|
if (!Number.isSafeInteger(mapping.generatedStart) || !Number.isSafeInteger(mapping.generatedEnd)
|
|
@@ -143,27 +222,23 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
143
222
|
}
|
|
144
223
|
|
|
145
224
|
const chunks = []
|
|
146
|
-
const mappings =
|
|
225
|
+
const mappings = createSourceMapBuilder()
|
|
147
226
|
let generatedOffset = 0
|
|
148
227
|
let sourceOffset = 0
|
|
149
228
|
let segmentIndex = 0
|
|
150
229
|
const appendUnchanged = end => {
|
|
151
230
|
if (end <= sourceOffset) return
|
|
152
231
|
chunks.push(code.slice(sourceOffset, end))
|
|
153
|
-
while (segmentIndex < sourceMap.length && sourceMap
|
|
232
|
+
while (segmentIndex < sourceMap.length && sourceMap.at(segmentIndex).generatedEnd <= sourceOffset) segmentIndex += 1
|
|
154
233
|
for (let index = segmentIndex; index < sourceMap.length; index += 1) {
|
|
155
|
-
const segment = sourceMap
|
|
234
|
+
const segment = sourceMap.at(index)
|
|
156
235
|
if (segment.generatedStart >= end) break
|
|
157
236
|
const start = Math.max(sourceOffset, segment.generatedStart)
|
|
158
237
|
const stop = Math.min(end, segment.generatedEnd)
|
|
159
238
|
if (stop <= start) continue
|
|
160
|
-
const
|
|
161
|
-
mappings.
|
|
162
|
-
|
|
163
|
-
generatedEnd: generatedOffset + stop - sourceOffset,
|
|
164
|
-
originalStart,
|
|
165
|
-
originalEnd,
|
|
166
|
-
})
|
|
239
|
+
const [originalStart, originalEnd] = copiedSegmentOriginal(segment, start, stop)
|
|
240
|
+
mappings.pushValues(generatedOffset + start - sourceOffset, generatedOffset + stop - sourceOffset,
|
|
241
|
+
originalStart, originalEnd)
|
|
167
242
|
}
|
|
168
243
|
generatedOffset += end - sourceOffset
|
|
169
244
|
sourceOffset = end
|
|
@@ -173,52 +248,117 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
173
248
|
appendUnchanged(item.start)
|
|
174
249
|
const { text } = item
|
|
175
250
|
chunks.push(text)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
251
|
+
emitReplacementSegments(sourceMap, item.start, item.end, text.length, item.mappings,
|
|
252
|
+
(generatedStart, generatedEnd, originalStart, originalEnd) => mappings.pushValues(
|
|
253
|
+
generatedStart - item.start + generatedOffset, generatedEnd - item.start + generatedOffset,
|
|
254
|
+
originalStart, originalEnd))
|
|
179
255
|
generatedOffset += text.length
|
|
180
256
|
sourceOffset = item.end
|
|
181
257
|
}
|
|
182
258
|
appendUnchanged(code.length)
|
|
183
|
-
return { code: chunks.join(''), sourceMap: mappings }
|
|
259
|
+
return { code: chunks.join(''), sourceMap: mappings.finish() }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const LINE_TERMINATORS = /\r\n|[\n\r\u2028\u2029]/gu
|
|
263
|
+
|
|
264
|
+
/** JavaScript source coordinates count CRLF as one line boundary. */
|
|
265
|
+
export function sourceLineStarts(source) {
|
|
266
|
+
const starts = [0]
|
|
267
|
+
for (const match of source.matchAll(LINE_TERMINATORS)) starts.push(match.index + match[0].length)
|
|
268
|
+
return starts
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Visit maintained emitter coordinates without re-encoding available raw maps.
|
|
272
|
+
* All line numbers at this boundary are zero-based; absent origins stay absent. */
|
|
273
|
+
export function visitSourceMappings(transformed, visit) {
|
|
274
|
+
const raw = transformed.rawMappings
|
|
275
|
+
if (raw !== undefined) {
|
|
276
|
+
for (const item of raw) visit(item.generated.line - 1, item.generated.column,
|
|
277
|
+
item.original === undefined ? undefined : item.original.line - 1, item.original?.column)
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
const nativeMap = new TraceMap(typeof transformed.map === 'string' ? JSON.parse(transformed.map) : transformed.map)
|
|
281
|
+
for (const [line, entries] of decodedMappings(nativeMap).entries()) {
|
|
282
|
+
for (const entry of entries) visit(line, entry[0], entry[2], entry[3])
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Compose a parser's line/column map with the existing source-offset map. */
|
|
287
|
+
export function mappedSourceTransform(code, sourceMap, transformed) {
|
|
288
|
+
const starts = sourceLineStarts(code)
|
|
289
|
+
const generatedStarts = sourceLineStarts(transformed.code)
|
|
290
|
+
const mappings = createSourceMapBuilder()
|
|
291
|
+
let previous
|
|
292
|
+
visitSourceMappings(transformed, (line, column, originalLine, originalColumn) => {
|
|
293
|
+
const generatedStart = Math.min(transformed.code.length, generatedStarts[line] + column)
|
|
294
|
+
if (previous !== undefined) {
|
|
295
|
+
previous.generatedEnd = generatedStart
|
|
296
|
+
mappings.push(previous)
|
|
297
|
+
}
|
|
298
|
+
if (starts[originalLine] === undefined) {
|
|
299
|
+
previous = undefined
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
const originalStart = Math.min(code.length, starts[originalLine] + originalColumn)
|
|
303
|
+
previous = { generatedStart, generatedEnd: transformed.code.length,
|
|
304
|
+
originalStart, originalEnd: Math.min(code.length, originalStart + 1) }
|
|
305
|
+
})
|
|
306
|
+
if (previous !== undefined) mappings.push(previous)
|
|
307
|
+
return applySourceEdits(code, sourceMap, [{ start: 0, end: code.length, text: transformed.code, mappings: mappings.finish(true) }])
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function lineStartOffset(source, line, starts) {
|
|
311
|
+
return starts[line - 1] ?? source.length
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function positionAtOffset(source, offset, starts) {
|
|
315
|
+
let low = 0, high = starts.length
|
|
316
|
+
while (low < high) {
|
|
317
|
+
const middle = (low + high) >>> 1
|
|
318
|
+
if (starts[middle] <= offset) low = middle + 1
|
|
319
|
+
else high = middle
|
|
320
|
+
}
|
|
321
|
+
const line = low - 1
|
|
322
|
+
return { line: line + 1, column: offset - starts[line] + 1 }
|
|
184
323
|
}
|
|
185
324
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
325
|
+
const coordinateIndexes = new WeakMap()
|
|
326
|
+
function coordinateIndex(sourceMap, generatedSource, originalSource) {
|
|
327
|
+
let index = coordinateIndexes.get(sourceMap)
|
|
328
|
+
if (index?.generatedSource !== generatedSource || index.originalSource !== originalSource) {
|
|
329
|
+
index = { generatedSource, originalSource, generatedStarts: sourceLineStarts(generatedSource),
|
|
330
|
+
originalStarts: sourceLineStarts(originalSource) }
|
|
331
|
+
coordinateIndexes.set(sourceMap, index)
|
|
192
332
|
}
|
|
193
|
-
return
|
|
333
|
+
return index
|
|
194
334
|
}
|
|
195
335
|
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const lastBreak = prefix.lastIndexOf('\n')
|
|
200
|
-
return { line, column: offset - lastBreak }
|
|
336
|
+
export function sourceTextAtSpan(source, span, starts = sourceLineStarts(source)) {
|
|
337
|
+
return source.slice(lineStartOffset(source, span.line, starts) + span.column - 1,
|
|
338
|
+
lineStartOffset(source, span.end.line, starts) + span.end.column - 1)
|
|
201
339
|
}
|
|
202
340
|
|
|
203
|
-
export function mapSourcePosition(position, generatedSource, originalSource, sourceMap) {
|
|
341
|
+
export function mapSourcePosition(position, generatedSource, originalSource, sourceMap, coordinates) {
|
|
204
342
|
if (position === undefined || sourceMap === undefined) return position
|
|
205
343
|
if (!Number.isSafeInteger(position.line) || position.line < 1
|
|
206
344
|
|| !Number.isSafeInteger(position.column) || position.column < 1) return position
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
345
|
+
const index = coordinates ?? coordinateIndex(sourceMap, generatedSource, originalSource)
|
|
346
|
+
const lineStart = lineStartOffset(generatedSource, position.line, index.generatedStarts)
|
|
347
|
+
const mappedOffset = sourceOffsetAt(sourceMap, lineStart + position.column - 1)
|
|
348
|
+
return positionAtOffset(originalSource, mappedOffset, index.originalStarts)
|
|
210
349
|
}
|
|
211
350
|
|
|
212
351
|
/** Map a complete generated-source span into original cell coordinates. */
|
|
213
|
-
export function mapSourceSpan(span, generatedSource, originalSource, sourceMap) {
|
|
352
|
+
export function mapSourceSpan(span, generatedSource, originalSource, sourceMap, coordinates) {
|
|
214
353
|
if (span === undefined) return undefined
|
|
215
|
-
const start = mapSourcePosition(span, generatedSource, originalSource, sourceMap)
|
|
354
|
+
const start = mapSourcePosition(span, generatedSource, originalSource, sourceMap, coordinates)
|
|
216
355
|
if (span.end === undefined) return start === span ? span : start
|
|
217
356
|
if (!Number.isSafeInteger(span.end.line) || span.end.line < 1
|
|
218
357
|
|| !Number.isSafeInteger(span.end.column) || span.end.column < 1) {
|
|
219
358
|
return { ...start, end: span.end }
|
|
220
359
|
}
|
|
221
|
-
const
|
|
360
|
+
const index = coordinates ?? coordinateIndex(sourceMap, generatedSource, originalSource)
|
|
361
|
+
const generatedEnd = lineStartOffset(generatedSource, span.end.line, index.generatedStarts) + span.end.column - 1
|
|
222
362
|
const original = mappedOffsetRange(sourceMap, Math.max(0, generatedEnd - 1), generatedEnd)
|
|
223
|
-
return { ...start, end: positionAtOffset(originalSource, original.originalEnd) }
|
|
363
|
+
return { ...start, end: positionAtOffset(originalSource, original.originalEnd, index.originalStarts) }
|
|
224
364
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { compilerModuleReference } from './compiler-module-links.js'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { createRequire, findPackageJSON } from 'node:module'
|
|
4
|
+
import { basename, extname } from 'node:path'
|
|
5
|
+
import { compileModuleSource, detectModuleSourceFormat, attachNamespaceSource,
|
|
6
|
+
linkCommonJsEvidenceSource } from './compiler-service.js'
|
|
7
|
+
import { managedModuleAdapter, loadManagedModuleAdapter, recordStatefulModuleResolution, reserveStatefulModule,
|
|
8
|
+
statefulModuleLink, resolveStatefulModuleLink } from './stateful-module-runtime.js'
|
|
9
|
+
import { createCommonJsEvidence } from './commonjs-export-evidence.js'
|
|
10
|
+
import { USER_BINDING_TRANSFORM } from './module-transform-contract.js'
|
|
11
|
+
import { createDynamicEnvironmentRuntime } from './dynamic-environment-runtime.js'
|
|
12
|
+
import { moduleRuntimeIntrinsics } from './compiler-intrinsics.js'
|
|
13
|
+
import { compilerPlatformBridge } from './compiler-platform.js'
|
|
14
|
+
|
|
15
|
+
const { Map, Set, Object, Reflect, mapGet, mapHas, mapSet, setHas, setAdd, includes, startsWith,
|
|
16
|
+
replaceAllString, includesString } = moduleRuntimeIntrinsics
|
|
17
|
+
const readSourceFile = readFileSync, nativeCreateRequire = createRequire, packageJsonPath = findPackageJSON
|
|
18
|
+
const pathBasename = basename, pathExtension = extname, parseJson = JSON.parse
|
|
19
|
+
const bufferFrom = Buffer.from, bufferToString = Buffer.prototype.toString
|
|
20
|
+
const sourceText = source => typeof source === 'string' ? source
|
|
21
|
+
: Reflect.apply(bufferToString, bufferFrom(source), ['utf8'])
|
|
22
|
+
const sourcePath = compilerPlatformBridge.fileURLToPath
|
|
23
|
+
|
|
24
|
+
// Dependencies installed under a package's node_modules belong to Node's
|
|
25
|
+
// module owner. Compiling them as if they were session source needlessly
|
|
26
|
+
// parses and retains large third-party programs (for example TypeScript),
|
|
27
|
+
// while providing no PTC binding continuity: only session-owned modules can
|
|
28
|
+
// publish logical bindings. Namespace adaptation still wraps their native
|
|
29
|
+
// result at the managed module boundary.
|
|
30
|
+
function isExternalDependency(url) {
|
|
31
|
+
if (!startsWith(url, 'file:')) return false
|
|
32
|
+
const path = replaceAllString(sourcePath(url), '\\', '/')
|
|
33
|
+
return includesString(path, '/node_modules/')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Source generation returns link facts; the runtime owns registration. */
|
|
37
|
+
export function compileStatefulModule(source, options) {
|
|
38
|
+
const prepared = compileModuleSource(source, options)
|
|
39
|
+
for (let index = 0; index < prepared.staticLinks.length; index++) {
|
|
40
|
+
const link = prepared.staticLinks[index]
|
|
41
|
+
statefulModuleLink(link.source, link.reference)
|
|
42
|
+
}
|
|
43
|
+
// Install reflection facts before Node can expose hoisted exports to a
|
|
44
|
+
// cyclic importer. Catalog data never enters the user's executable source.
|
|
45
|
+
if (prepared.callableSources?.length > 0) {
|
|
46
|
+
createDynamicEnvironmentRuntime().installIntrinsics().registerSources(prepared.callableSources)
|
|
47
|
+
}
|
|
48
|
+
return prepared
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function commonJsLoadFormat(url, source) {
|
|
52
|
+
if (!startsWith(url, 'file:')) return undefined
|
|
53
|
+
const extension = pathExtension(sourcePath(url))
|
|
54
|
+
if (extension === '.mjs' || extension === '.mts') return 'module'
|
|
55
|
+
if (extension === '.cjs' || extension === '.cts') return 'commonjs'
|
|
56
|
+
if (extension !== '.js' && extension !== '.ts' && extension !== '') return undefined
|
|
57
|
+
const packagePath = packageJsonPath(url)
|
|
58
|
+
if (packagePath !== undefined && pathBasename(packagePath) === 'package.json') {
|
|
59
|
+
const type = parseJson(readSourceFile(packagePath, 'utf8')).type
|
|
60
|
+
if (type === 'module' || type === 'commonjs') return type
|
|
61
|
+
}
|
|
62
|
+
return detectModuleSourceFormat(source, { extension })
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let nextNamespaceReference = 0
|
|
66
|
+
function attachModuleNamespace(url, source, attributes, references, sourceRegions) {
|
|
67
|
+
const reference = compilerModuleReference('self', ++nextNamespaceReference)
|
|
68
|
+
mapSet(references, reference, url)
|
|
69
|
+
const text = sourceText(source)
|
|
70
|
+
return attachNamespaceSource(text, attributes, reference, sourceRegions)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Track execution-owned module graphs without changing Node's URL identity. */
|
|
74
|
+
export function createUserModuleCompilationHooks({ transformForParent = () => undefined } = {}) {
|
|
75
|
+
const modules = new Map()
|
|
76
|
+
const compiled = new Set()
|
|
77
|
+
const loaded = new Set()
|
|
78
|
+
const interfaces = new Map()
|
|
79
|
+
const namespaceReferences = new Map()
|
|
80
|
+
const sourceRegionPlans = new Map()
|
|
81
|
+
const commonJsSources = new Map()
|
|
82
|
+
const commonJsEvidence = createCommonJsEvidence({ linkSource: linkCommonJsEvidenceSource })
|
|
83
|
+
const bootstrapFiles = new Set()
|
|
84
|
+
const bootstrapNames = Object.keys(nativeCreateRequire(import.meta.url).cache)
|
|
85
|
+
for (let index = 0; index < bootstrapNames.length; index++) setAdd(bootstrapFiles, bootstrapNames[index])
|
|
86
|
+
const internalRoot = compilerPlatformBridge.url('./', import.meta.url)
|
|
87
|
+
const mark = (url, { transform = USER_BINDING_TRANSFORM, compiled: prepared = false, moduleInterface, commonJsSource, sourceRegions } = {}) => {
|
|
88
|
+
if (!setHas(compiled, url) && !setHas(loaded, url)) mapSet(modules, url, transform)
|
|
89
|
+
if (prepared) {
|
|
90
|
+
setAdd(compiled, url)
|
|
91
|
+
mapSet(sourceRegionPlans, url, sourceRegions)
|
|
92
|
+
if (commonJsSource !== undefined) mapSet(commonJsSources, url, commonJsSource)
|
|
93
|
+
if (moduleInterface !== undefined) {
|
|
94
|
+
mapSet(interfaces, url, moduleInterface)
|
|
95
|
+
reserveStatefulModule(url, moduleInterface)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const recordResolution = (parentUrl, specifier, importAttributes, result) => {
|
|
100
|
+
recordStatefulModuleResolution(parentUrl, specifier, importAttributes, result.url)
|
|
101
|
+
const transform = mapGet(modules, parentUrl) ?? transformForParent(parentUrl)
|
|
102
|
+
// Runtime links are outside the user compilation graph. Skipping only
|
|
103
|
+
// their load would still propagate user transforms to their dependencies.
|
|
104
|
+
if (transform !== undefined && !startsWith(result.url, 'node:')
|
|
105
|
+
&& !startsWith(result.url, internalRoot) && !isExternalDependency(result.url)) mark(result.url, { transform })
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
mark,
|
|
109
|
+
resolve(specifier, context, nextResolve) {
|
|
110
|
+
const evidence = commonJsEvidence.resolve(specifier, context, recordResolution)
|
|
111
|
+
if (evidence !== undefined) return evidence
|
|
112
|
+
const link = resolveStatefulModuleLink(specifier, context)
|
|
113
|
+
if (link !== undefined) return link
|
|
114
|
+
const namespaceUrl = mapGet(namespaceReferences, specifier)
|
|
115
|
+
if (namespaceUrl !== undefined) return { url: namespaceUrl, shortCircuit: true }
|
|
116
|
+
const parentUrl = context.parentURL
|
|
117
|
+
const parentAdapter = managedModuleAdapter(parentUrl)
|
|
118
|
+
if (parentAdapter?.kind === 'module' && specifier === parentAdapter.source) {
|
|
119
|
+
return { ...parentAdapter.resolution, shortCircuit: true }
|
|
120
|
+
}
|
|
121
|
+
const importAttributes = { ...context.importAttributes }
|
|
122
|
+
const result = nextResolve(specifier, context)
|
|
123
|
+
recordResolution(parentUrl, specifier, importAttributes, result)
|
|
124
|
+
return result
|
|
125
|
+
},
|
|
126
|
+
load(url, context, nextLoad) {
|
|
127
|
+
const evidence = commonJsEvidence.load(url)
|
|
128
|
+
if (evidence !== undefined) return evidence
|
|
129
|
+
const attributes = { ...context.importAttributes }
|
|
130
|
+
const adapter = loadManagedModuleAdapter(url, attributes)
|
|
131
|
+
if (adapter !== undefined) return adapter
|
|
132
|
+
const result = nextLoad(url, context)
|
|
133
|
+
const transform = mapGet(modules, url)
|
|
134
|
+
if (transform === undefined
|
|
135
|
+
|| startsWith(url, internalRoot)
|
|
136
|
+
|| startsWith(url, 'file:') && setHas(bootstrapFiles, sourcePath(url))) return result
|
|
137
|
+
if (setHas(compiled, url)) return mapHas(interfaces, url)
|
|
138
|
+
? { ...result, source: attachModuleNamespace(url, result.source, attributes, namespaceReferences, mapGet(sourceRegionPlans, url)) }
|
|
139
|
+
: mapHas(commonJsSources, url) ? { ...result, source: commonJsEvidence.attach(url, result.source, mapGet(commonJsSources, url)) } : result
|
|
140
|
+
const formats = ['module', 'commonjs', 'module-typescript', 'commonjs-typescript']
|
|
141
|
+
if (result.format !== undefined && result.format !== 'typescript' && !includes(formats, result.format)) return result
|
|
142
|
+
const source = result.source ?? readSourceFile(sourcePath(url))
|
|
143
|
+
const text = sourceText(source)
|
|
144
|
+
const format = result.format === undefined || result.format === 'typescript' ? commonJsLoadFormat(url, text) : result.format
|
|
145
|
+
if (!includes(formats, format)) return result
|
|
146
|
+
const target = startsWith(format, 'commonjs') ? 'commonjs' : 'module'
|
|
147
|
+
const prepared = compileStatefulModule(text, { transform, target, url })
|
|
148
|
+
setAdd(loaded, url)
|
|
149
|
+
if (target === 'module') reserveStatefulModule(url, prepared.moduleInterface)
|
|
150
|
+
return { ...result, format: target, source: target === 'module' ? attachModuleNamespace(url, prepared.code, attributes, namespaceReferences, prepared.sourceRegions)
|
|
151
|
+
: commonJsEvidence.attach(url, prepared.code, prepared.commonJsSource) }
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
}
|