dsh-ptc-plus 0.3.2 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +63 -80
- package/README.md +63 -80
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +30827 -742
- package/compiler-amaro.cjs +5 -0
- package/compiler-amaro.cjs.map +6 -0
- package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
- package/compiler-assets.json +3 -0
- package/compiler-core.cjs +556 -0
- package/compiler-core.cjs.map +6 -0
- package/compiler-platform.cjs +2 -0
- package/compiler-platform.cjs.map +6 -0
- package/compiler-typescript.cjs +388 -0
- package/compiler-typescript.cjs.map +6 -0
- package/docs/README.md +7 -0
- package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
- package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
- package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
- package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
- package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
- package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
- package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
- package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
- package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
- package/docs/adr/0023-global-user-bindings.md +104 -0
- package/docs/adr/0024-repl-console-observation.md +33 -0
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
- package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
- package/docs/architecture.md +77 -21
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +95 -19
- package/docs/durability-design.md +28 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +76 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +759 -0
- package/docs/user-bindings.en.md +66 -0
- package/docs/user-bindings.md +66 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +71 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/async-local-storage-intrinsics.js +38 -0
- package/internal/binding-declaration-contract.js +8 -0
- package/internal/binding-descriptors.js +1 -0
- package/internal/binding-pattern-traversal.js +25 -0
- package/internal/binding-pattern.js +26 -29
- package/internal/binding-source-analysis.js +708 -0
- package/internal/binding-update-policy.js +72 -0
- package/internal/bounded-worker-round.js +56 -0
- package/internal/callable-definition-environment.js +42 -0
- package/internal/callable-source-catalog.js +129 -0
- package/internal/callable-source-encoding.js +47 -0
- package/internal/callable-source-facts.js +459 -0
- package/internal/callable-source-format.js +2 -0
- package/internal/callable-source-lowering.js +123 -0
- package/internal/cell-analysis-contract.js +25 -0
- package/internal/cell-analysis.js +253 -290
- package/internal/cell-completion.js +15 -0
- package/internal/cell-error.js +7 -0
- package/internal/cell-parser.js +66 -0
- package/internal/cell-rewriter.js +3 -677
- package/internal/commonjs-export-evidence.js +63 -0
- package/internal/commonjs-source-evidence.js +72 -0
- package/internal/compiler-amaro.cjs +2 -0
- package/internal/compiler-compression.js +12 -0
- package/internal/compiler-data.js +58 -0
- package/internal/compiler-descriptors.js +54 -0
- package/internal/compiler-dynamic-cache.js +48 -0
- package/internal/compiler-entry.js +35 -0
- package/internal/compiler-generated-names.js +17 -0
- package/internal/compiler-intrinsics.js +50 -0
- package/internal/compiler-module-links.js +37 -0
- package/internal/compiler-operations.js +61 -0
- package/internal/compiler-platform-factory.js +84 -0
- package/internal/compiler-platform.js +136 -0
- package/internal/compiler-record-roles.js +53 -0
- package/internal/compiler-region-output.js +259 -0
- package/internal/compiler-resource-lowering.js +103 -0
- package/internal/compiler-scope-facts.js +115 -0
- package/internal/compiler-service.js +109 -0
- package/internal/compiler-source-cache.js +32 -0
- package/internal/compiler-source-pieces.js +93 -0
- package/internal/compiler-source-regions.js +132 -0
- package/internal/compiler-storage-source.js +54 -0
- package/internal/compiler-text.js +15 -0
- package/internal/compiler-typescript.cjs +2 -0
- package/internal/config-spec.js +83 -27
- package/internal/cordis-tools-owner.js +130 -21
- package/internal/diagnostic.js +27 -1
- package/internal/direct-surface-owner.js +76 -23
- package/internal/dynamic-binding-evidence.js +16 -0
- package/internal/dynamic-environment-compiler.js +779 -0
- package/internal/dynamic-environment-integration.js +91 -0
- package/internal/dynamic-environment-runtime.js +383 -0
- package/internal/dynamic-native-calls.js +153 -0
- package/internal/dynamic-native-runtime.js +262 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +27 -2
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +136 -28
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +555 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +1179 -233
- package/internal/language-semantics.js +14 -0
- package/internal/legacy-binding-catalog.js +48 -0
- package/internal/legacy-cell-analysis.js +600 -0
- package/internal/legacy-cell-parser.js +50 -0
- package/internal/legacy-cell-rewriter.js +631 -0
- package/internal/legacy-repl-convenience.js +291 -0
- package/internal/managed-module-operations.js +170 -0
- package/internal/module-compilation.js +322 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +42 -0
- package/internal/native-await-declarations.js +68 -0
- package/internal/native-root-compilation.js +54 -0
- package/internal/native-root-dynamic.js +67 -0
- package/internal/record-utils.js +24 -15
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -289
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +6 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +117 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -52
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +402 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +123 -0
- package/internal/session-journal.js +199 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +257 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +230 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +600 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +31 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +244 -0
- package/internal/user-binding-console.js +148 -0
- package/internal/user-binding-draft-projection.js +335 -0
- package/internal/user-binding-model-context.js +31 -0
- package/internal/user-binding-runner.js +56 -0
- package/internal/user-bindings-owner.js +1065 -0
- package/internal/user-bindings-store.js +293 -0
- package/internal/user-bindings.js +361 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +130 -91
- package/internal/worker-client.js +57 -67
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +65 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-repl-realm.js +134 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +76 -7
- package/src/client-activity.js +95 -53
- package/src/client-authoring-view.js +580 -0
- package/src/client-binding-review.js +230 -0
- package/src/client-bindings-data.js +29 -0
- package/src/client-catalog.js +127 -0
- package/src/client-code-editor.js +84 -0
- package/src/client-console.js +112 -0
- package/src/client-copy.js +370 -0
- package/src/client-feature-gates.js +62 -0
- package/src/client-host-compat.js +150 -0
- package/src/client-indicator-view.js +267 -0
- package/src/client-repl-view.js +292 -0
- package/src/client-rpc.js +20 -0
- package/src/client-settings-view.js +221 -0
- package/src/client-styles.js +106 -0
- package/src/client-tool-view.js +108 -0
- package/src/client-transport.js +159 -0
- package/src/client-workbench.js +521 -0
- package/src/client.js +233 -615
|
@@ -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,45 @@ 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
|
+
/** 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
|
+
|
|
139
|
+
function segmentOffsetAt(segment, generatedOffset) {
|
|
55
140
|
const generatedLength = segment.generatedEnd - segment.generatedStart
|
|
56
141
|
const originalLength = segment.originalEnd - segment.originalStart
|
|
57
142
|
const localOffset = Math.max(0, generatedOffset - segment.generatedStart)
|
|
@@ -62,51 +147,64 @@ function originalOffsetAt(sourceMap, generatedOffset) {
|
|
|
62
147
|
+ Math.floor((localOffset * (originalLength - 1)) / (generatedLength - 1))
|
|
63
148
|
}
|
|
64
149
|
|
|
150
|
+
/** A copied interval is already bounded by this segment. Its endpoints need
|
|
151
|
+
* no additional search through the complete source map. */
|
|
152
|
+
function copiedSegmentOriginal(segment, start, end) {
|
|
153
|
+
return [segmentOffsetAt(segment, start),
|
|
154
|
+
segmentOffsetAt(segment, end - 1) + (segment.originalEnd > segment.originalStart ? 1 : 0)]
|
|
155
|
+
}
|
|
156
|
+
|
|
65
157
|
function mappedOffsetRange(sourceMap, start, end) {
|
|
158
|
+
const lastOffset = Math.max(start, end - 1)
|
|
159
|
+
const last = sourceMap.at(segmentIndexAt(sourceMap, lastOffset)) ?? sourceMap.at(-1)
|
|
160
|
+
const hasSourceCharacter = last === undefined || lastOffset < last.generatedEnd && last.originalEnd > last.originalStart
|
|
161
|
+
const originalLast = last === undefined ? lastOffset : segmentOffsetAt(last, lastOffset)
|
|
66
162
|
return {
|
|
67
|
-
originalStart:
|
|
68
|
-
originalEnd:
|
|
163
|
+
originalStart: start === lastOffset ? originalLast : sourceOffsetAt(sourceMap, start),
|
|
164
|
+
originalEnd: originalLast + (end > start && hasSourceCharacter ? 1 : 0),
|
|
69
165
|
}
|
|
70
166
|
}
|
|
71
167
|
|
|
72
|
-
|
|
168
|
+
/** Replacement runs reach the mapping builder as positional writes. The
|
|
169
|
+
* generator this replaced allocated a segment object for every emitted run. */
|
|
170
|
+
function emitReplacementSegments(sourceMap, start, end, replacementLength, mappings, emit) {
|
|
73
171
|
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 = []
|
|
172
|
+
if (!isSourceMap(mappings) || mappings.length === 0) {
|
|
173
|
+
if (replacementLength !== 0) emit(start, start + replacementLength, startOriginal, endOriginal)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
83
176
|
let cursor = 0
|
|
177
|
+
let anchorOffset = start
|
|
84
178
|
for (const mapping of mappings) {
|
|
85
179
|
if (mapping.generatedStart > cursor) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
180
|
+
const nextAnchor = sourceOffsetAt(sourceMap, mapping.originalStart)
|
|
181
|
+
emit(start + cursor, start + mapping.generatedStart, nextAnchor, nextAnchor)
|
|
182
|
+
}
|
|
183
|
+
if (mapping.generatedEnd - mapping.generatedStart === mapping.originalEnd - mapping.originalStart
|
|
184
|
+
&& mapping.originalEnd > mapping.originalStart) {
|
|
185
|
+
// A verbatim copy retains every previous boundary, including inserted
|
|
186
|
+
// compiler text. Collapsing its endpoints would interpolate that text
|
|
187
|
+
// into source positions and corrupt later call/write provenance.
|
|
188
|
+
for (let index = segmentIndexAt(sourceMap, mapping.originalStart); index < sourceMap.length; index++) {
|
|
189
|
+
const segment = sourceMap.at(index)
|
|
190
|
+
if (segment.generatedStart >= mapping.originalEnd) break
|
|
191
|
+
const from = Math.max(mapping.originalStart, segment.generatedStart)
|
|
192
|
+
const to = Math.min(mapping.originalEnd, segment.generatedEnd)
|
|
193
|
+
const [originalStart, originalEnd] = copiedSegmentOriginal(segment, from, to)
|
|
194
|
+
emit(start + mapping.generatedStart + from - mapping.originalStart,
|
|
195
|
+
start + mapping.generatedStart + to - mapping.originalStart, originalStart, originalEnd)
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
const { originalStart, originalEnd } = mappedOffsetRange(sourceMap, mapping.originalStart, mapping.originalEnd)
|
|
199
|
+
emit(start + mapping.generatedStart, start + mapping.generatedEnd, originalStart, originalEnd)
|
|
92
200
|
}
|
|
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
201
|
cursor = mapping.generatedEnd
|
|
202
|
+
anchorOffset = mapping.originalEnd
|
|
100
203
|
}
|
|
101
204
|
if (cursor < replacementLength) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
generatedEnd: start + replacementLength,
|
|
105
|
-
originalStart: startOriginal,
|
|
106
|
-
originalEnd: endOriginal,
|
|
107
|
-
})
|
|
205
|
+
const anchor = sourceOffsetAt(sourceMap, anchorOffset)
|
|
206
|
+
emit(start + cursor, start + replacementLength, anchor, anchor)
|
|
108
207
|
}
|
|
109
|
-
return segments
|
|
110
208
|
}
|
|
111
209
|
|
|
112
210
|
export function applySourceEdits(code, sourceMap, edits) {
|
|
@@ -120,12 +218,12 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
120
218
|
if (!Number.isSafeInteger(item.start) || !Number.isSafeInteger(item.end)
|
|
121
219
|
|| item.start < 0 || item.end < item.start || item.end > code.length
|
|
122
220
|
|| item.start < previousEnd || typeof text !== 'string'
|
|
123
|
-
|| (item.mappings !== undefined && !
|
|
221
|
+
|| (item.mappings !== undefined && !isSourceMap(item.mappings))
|
|
124
222
|
|| (item.start === item.end && previous?.start === item.start && previous.end === item.end)) {
|
|
125
223
|
throw new RangeError('source edits must be bounded, ordered, and non-overlapping')
|
|
126
224
|
}
|
|
127
|
-
const itemMappings =
|
|
128
|
-
.sort((left, right) => left.generatedStart - right.generatedStart)
|
|
225
|
+
const itemMappings = item.mappings instanceof SourceMapRuns ? item.mappings
|
|
226
|
+
: [...(item.mappings ?? [])].sort((left, right) => left.generatedStart - right.generatedStart)
|
|
129
227
|
let mappingEnd = 0
|
|
130
228
|
for (const mapping of itemMappings) {
|
|
131
229
|
if (!Number.isSafeInteger(mapping.generatedStart) || !Number.isSafeInteger(mapping.generatedEnd)
|
|
@@ -143,27 +241,23 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
143
241
|
}
|
|
144
242
|
|
|
145
243
|
const chunks = []
|
|
146
|
-
const mappings =
|
|
244
|
+
const mappings = createSourceMapBuilder()
|
|
147
245
|
let generatedOffset = 0
|
|
148
246
|
let sourceOffset = 0
|
|
149
247
|
let segmentIndex = 0
|
|
150
248
|
const appendUnchanged = end => {
|
|
151
249
|
if (end <= sourceOffset) return
|
|
152
250
|
chunks.push(code.slice(sourceOffset, end))
|
|
153
|
-
while (segmentIndex < sourceMap.length && sourceMap
|
|
251
|
+
while (segmentIndex < sourceMap.length && sourceMap.at(segmentIndex).generatedEnd <= sourceOffset) segmentIndex += 1
|
|
154
252
|
for (let index = segmentIndex; index < sourceMap.length; index += 1) {
|
|
155
|
-
const segment = sourceMap
|
|
253
|
+
const segment = sourceMap.at(index)
|
|
156
254
|
if (segment.generatedStart >= end) break
|
|
157
255
|
const start = Math.max(sourceOffset, segment.generatedStart)
|
|
158
256
|
const stop = Math.min(end, segment.generatedEnd)
|
|
159
257
|
if (stop <= start) continue
|
|
160
|
-
const
|
|
161
|
-
mappings.
|
|
162
|
-
|
|
163
|
-
generatedEnd: generatedOffset + stop - sourceOffset,
|
|
164
|
-
originalStart,
|
|
165
|
-
originalEnd,
|
|
166
|
-
})
|
|
258
|
+
const [originalStart, originalEnd] = copiedSegmentOriginal(segment, start, stop)
|
|
259
|
+
mappings.pushValues(generatedOffset + start - sourceOffset, generatedOffset + stop - sourceOffset,
|
|
260
|
+
originalStart, originalEnd)
|
|
167
261
|
}
|
|
168
262
|
generatedOffset += end - sourceOffset
|
|
169
263
|
sourceOffset = end
|
|
@@ -173,52 +267,117 @@ export function applySourceEdits(code, sourceMap, edits) {
|
|
|
173
267
|
appendUnchanged(item.start)
|
|
174
268
|
const { text } = item
|
|
175
269
|
chunks.push(text)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
270
|
+
emitReplacementSegments(sourceMap, item.start, item.end, text.length, item.mappings,
|
|
271
|
+
(generatedStart, generatedEnd, originalStart, originalEnd) => mappings.pushValues(
|
|
272
|
+
generatedStart - item.start + generatedOffset, generatedEnd - item.start + generatedOffset,
|
|
273
|
+
originalStart, originalEnd))
|
|
179
274
|
generatedOffset += text.length
|
|
180
275
|
sourceOffset = item.end
|
|
181
276
|
}
|
|
182
277
|
appendUnchanged(code.length)
|
|
183
|
-
return { code: chunks.join(''), sourceMap: mappings }
|
|
278
|
+
return { code: chunks.join(''), sourceMap: mappings.finish() }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const LINE_TERMINATORS = /\r\n|[\n\r\u2028\u2029]/gu
|
|
282
|
+
|
|
283
|
+
/** JavaScript source coordinates count CRLF as one line boundary. */
|
|
284
|
+
export function sourceLineStarts(source) {
|
|
285
|
+
const starts = [0]
|
|
286
|
+
for (const match of source.matchAll(LINE_TERMINATORS)) starts.push(match.index + match[0].length)
|
|
287
|
+
return starts
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Visit maintained emitter coordinates without re-encoding available raw maps.
|
|
291
|
+
* All line numbers at this boundary are zero-based; absent origins stay absent. */
|
|
292
|
+
export function visitSourceMappings(transformed, visit) {
|
|
293
|
+
const raw = transformed.rawMappings
|
|
294
|
+
if (raw !== undefined) {
|
|
295
|
+
for (const item of raw) visit(item.generated.line - 1, item.generated.column,
|
|
296
|
+
item.original === undefined ? undefined : item.original.line - 1, item.original?.column)
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
const nativeMap = new TraceMap(typeof transformed.map === 'string' ? JSON.parse(transformed.map) : transformed.map)
|
|
300
|
+
for (const [line, entries] of decodedMappings(nativeMap).entries()) {
|
|
301
|
+
for (const entry of entries) visit(line, entry[0], entry[2], entry[3])
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Compose a parser's line/column map with the existing source-offset map. */
|
|
306
|
+
export function mappedSourceTransform(code, sourceMap, transformed) {
|
|
307
|
+
const starts = sourceLineStarts(code)
|
|
308
|
+
const generatedStarts = sourceLineStarts(transformed.code)
|
|
309
|
+
const mappings = createSourceMapBuilder()
|
|
310
|
+
let previous
|
|
311
|
+
visitSourceMappings(transformed, (line, column, originalLine, originalColumn) => {
|
|
312
|
+
const generatedStart = Math.min(transformed.code.length, generatedStarts[line] + column)
|
|
313
|
+
if (previous !== undefined) {
|
|
314
|
+
previous.generatedEnd = generatedStart
|
|
315
|
+
mappings.push(previous)
|
|
316
|
+
}
|
|
317
|
+
if (starts[originalLine] === undefined) {
|
|
318
|
+
previous = undefined
|
|
319
|
+
return
|
|
320
|
+
}
|
|
321
|
+
const originalStart = Math.min(code.length, starts[originalLine] + originalColumn)
|
|
322
|
+
previous = { generatedStart, generatedEnd: transformed.code.length,
|
|
323
|
+
originalStart, originalEnd: Math.min(code.length, originalStart + 1) }
|
|
324
|
+
})
|
|
325
|
+
if (previous !== undefined) mappings.push(previous)
|
|
326
|
+
return applySourceEdits(code, sourceMap, [{ start: 0, end: code.length, text: transformed.code, mappings: mappings.finish(true) }])
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function lineStartOffset(source, line, starts) {
|
|
330
|
+
return starts[line - 1] ?? source.length
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function positionAtOffset(source, offset, starts) {
|
|
334
|
+
let low = 0, high = starts.length
|
|
335
|
+
while (low < high) {
|
|
336
|
+
const middle = (low + high) >>> 1
|
|
337
|
+
if (starts[middle] <= offset) low = middle + 1
|
|
338
|
+
else high = middle
|
|
339
|
+
}
|
|
340
|
+
const line = low - 1
|
|
341
|
+
return { line: line + 1, column: offset - starts[line] + 1 }
|
|
184
342
|
}
|
|
185
343
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
344
|
+
const coordinateIndexes = new WeakMap()
|
|
345
|
+
function coordinateIndex(sourceMap, generatedSource, originalSource) {
|
|
346
|
+
let index = coordinateIndexes.get(sourceMap)
|
|
347
|
+
if (index?.generatedSource !== generatedSource || index.originalSource !== originalSource) {
|
|
348
|
+
index = { generatedSource, originalSource, generatedStarts: sourceLineStarts(generatedSource),
|
|
349
|
+
originalStarts: sourceLineStarts(originalSource) }
|
|
350
|
+
coordinateIndexes.set(sourceMap, index)
|
|
192
351
|
}
|
|
193
|
-
return
|
|
352
|
+
return index
|
|
194
353
|
}
|
|
195
354
|
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const lastBreak = prefix.lastIndexOf('\n')
|
|
200
|
-
return { line, column: offset - lastBreak }
|
|
355
|
+
export function sourceTextAtSpan(source, span, starts = sourceLineStarts(source)) {
|
|
356
|
+
return source.slice(lineStartOffset(source, span.line, starts) + span.column - 1,
|
|
357
|
+
lineStartOffset(source, span.end.line, starts) + span.end.column - 1)
|
|
201
358
|
}
|
|
202
359
|
|
|
203
|
-
export function mapSourcePosition(position, generatedSource, originalSource, sourceMap) {
|
|
360
|
+
export function mapSourcePosition(position, generatedSource, originalSource, sourceMap, coordinates) {
|
|
204
361
|
if (position === undefined || sourceMap === undefined) return position
|
|
205
362
|
if (!Number.isSafeInteger(position.line) || position.line < 1
|
|
206
363
|
|| !Number.isSafeInteger(position.column) || position.column < 1) return position
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
364
|
+
const index = coordinates ?? coordinateIndex(sourceMap, generatedSource, originalSource)
|
|
365
|
+
const lineStart = lineStartOffset(generatedSource, position.line, index.generatedStarts)
|
|
366
|
+
const mappedOffset = sourceOffsetAt(sourceMap, lineStart + position.column - 1)
|
|
367
|
+
return positionAtOffset(originalSource, mappedOffset, index.originalStarts)
|
|
210
368
|
}
|
|
211
369
|
|
|
212
370
|
/** Map a complete generated-source span into original cell coordinates. */
|
|
213
|
-
export function mapSourceSpan(span, generatedSource, originalSource, sourceMap) {
|
|
371
|
+
export function mapSourceSpan(span, generatedSource, originalSource, sourceMap, coordinates) {
|
|
214
372
|
if (span === undefined) return undefined
|
|
215
|
-
const start = mapSourcePosition(span, generatedSource, originalSource, sourceMap)
|
|
373
|
+
const start = mapSourcePosition(span, generatedSource, originalSource, sourceMap, coordinates)
|
|
216
374
|
if (span.end === undefined) return start === span ? span : start
|
|
217
375
|
if (!Number.isSafeInteger(span.end.line) || span.end.line < 1
|
|
218
376
|
|| !Number.isSafeInteger(span.end.column) || span.end.column < 1) {
|
|
219
377
|
return { ...start, end: span.end }
|
|
220
378
|
}
|
|
221
|
-
const
|
|
379
|
+
const index = coordinates ?? coordinateIndex(sourceMap, generatedSource, originalSource)
|
|
380
|
+
const generatedEnd = lineStartOffset(generatedSource, span.end.line, index.generatedStarts) + span.end.column - 1
|
|
222
381
|
const original = mappedOffsetRange(sourceMap, Math.max(0, generatedEnd - 1), generatedEnd)
|
|
223
|
-
return { ...start, end: positionAtOffset(originalSource, original.originalEnd) }
|
|
382
|
+
return { ...start, end: positionAtOffset(originalSource, original.originalEnd, index.originalStarts) }
|
|
224
383
|
}
|
|
@@ -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
|
+
}
|