@scriptc/compiler 0.0.33 → 0.0.34

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.
Files changed (102) hide show
  1. package/dist/backend/cc-cache.test.js +122 -0
  2. package/dist/backend/cc-cache.test.js.map +1 -1
  3. package/dist/backend/cc.d.ts +19 -0
  4. package/dist/backend/cc.js +111 -20
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-exprs.js +26 -1
  7. package/dist/backend/emission/emit-exprs.js.map +1 -1
  8. package/dist/backend/emission/emit-shapes.js +37 -4
  9. package/dist/backend/emission/emit-shapes.js.map +1 -1
  10. package/dist/backend/emission/emitter.d.ts +11 -2
  11. package/dist/backend/emission/emitter.js +11 -5
  12. package/dist/backend/emission/emitter.js.map +1 -1
  13. package/dist/backend/library-identity.d.ts +22 -0
  14. package/dist/backend/library-identity.js +103 -0
  15. package/dist/backend/library-identity.js.map +1 -0
  16. package/dist/backend/llvm/emitter.d.ts +3 -0
  17. package/dist/backend/llvm/emitter.js +35 -5
  18. package/dist/backend/llvm/emitter.js.map +1 -1
  19. package/dist/backend/llvm/shapes.d.ts +1 -0
  20. package/dist/backend/llvm/shapes.js +25 -1
  21. package/dist/backend/llvm/shapes.js.map +1 -1
  22. package/dist/backend/mangle.d.ts +1 -0
  23. package/dist/backend/mangle.js +3 -0
  24. package/dist/backend/mangle.js.map +1 -1
  25. package/dist/backend/object-localize.d.ts +5 -5
  26. package/dist/backend/object-localize.js +19 -16
  27. package/dist/backend/object-localize.js.map +1 -1
  28. package/dist/backend/object-localize.test.js +37 -13
  29. package/dist/backend/object-localize.test.js.map +1 -1
  30. package/dist/frontend/input-tracker.d.ts +82 -0
  31. package/dist/frontend/input-tracker.js +380 -0
  32. package/dist/frontend/input-tracker.js.map +1 -0
  33. package/dist/frontend/input-tracker.test.d.ts +1 -0
  34. package/dist/frontend/input-tracker.test.js +137 -0
  35. package/dist/frontend/input-tracker.test.js.map +1 -0
  36. package/dist/frontend/lowering/lower-builtins.js +2 -8
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.js +155 -140
  39. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  40. package/dist/frontend/lowering/lower-classes.js +3 -0
  41. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  42. package/dist/frontend/lowering/lower-containers.js +48 -9
  43. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  44. package/dist/frontend/lowering/lower-exprs.js +67 -1
  45. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  46. package/dist/frontend/lowering/lower-inspect.js +45 -26
  47. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  48. package/dist/frontend/lowering/lower-modules.js +1 -1
  49. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  50. package/dist/frontend/lowering/lower-stmts.js +48 -3
  51. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  52. package/dist/frontend/lowering/lowerer.d.ts +67 -29
  53. package/dist/frontend/lowering/lowerer.js +410 -87
  54. package/dist/frontend/lowering/lowerer.js.map +1 -1
  55. package/dist/frontend/npm-static-rewrite.js +25 -26
  56. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  57. package/dist/frontend/npm-static.js +29 -30
  58. package/dist/frontend/npm-static.js.map +1 -1
  59. package/dist/frontend/npm-static.test.d.ts +1 -0
  60. package/dist/frontend/npm-static.test.js +15 -0
  61. package/dist/frontend/npm-static.test.js.map +1 -0
  62. package/dist/frontend/npm.js +5 -17
  63. package/dist/frontend/npm.js.map +1 -1
  64. package/dist/frontend/program.js +2 -6
  65. package/dist/frontend/program.js.map +1 -1
  66. package/dist/frontend/resolve.js +8 -29
  67. package/dist/frontend/resolve.js.map +1 -1
  68. package/dist/frontend/ts7/program.js +17 -18
  69. package/dist/frontend/ts7/program.js.map +1 -1
  70. package/dist/frontend/types.d.ts +33 -0
  71. package/dist/frontend/types.js +114 -3
  72. package/dist/frontend/types.js.map +1 -1
  73. package/dist/index.d.ts +1 -1
  74. package/dist/index.js +241 -42
  75. package/dist/index.js.map +1 -1
  76. package/dist/ir/nodes.d.ts +21 -4
  77. package/dist/ir/nodes.js.map +1 -1
  78. package/dist/ir/serialize.d.ts +1 -1
  79. package/dist/ir/serialize.js +1 -1
  80. package/dist/ir/validate.js +31 -1
  81. package/dist/ir/validate.js.map +1 -1
  82. package/dist/library/early-cache.d.ts +65 -0
  83. package/dist/library/early-cache.js +380 -0
  84. package/dist/library/early-cache.js.map +1 -0
  85. package/dist/library/early-cache.test.d.ts +1 -0
  86. package/dist/library/early-cache.test.js +528 -0
  87. package/dist/library/early-cache.test.js.map +1 -0
  88. package/dist/library/int-infer.js +14 -0
  89. package/dist/library/int-infer.js.map +1 -1
  90. package/dist/library/int-infer.test.js +21 -4
  91. package/dist/library/int-infer.test.js.map +1 -1
  92. package/dist/library/semantic-source.d.ts +13 -0
  93. package/dist/library/semantic-source.js +257 -0
  94. package/dist/library/semantic-source.js.map +1 -0
  95. package/dist/library/semantic-source.test.d.ts +1 -0
  96. package/dist/library/semantic-source.test.js +113 -0
  97. package/dist/library/semantic-source.test.js.map +1 -0
  98. package/dist/library/sidecar.d.ts +6 -0
  99. package/dist/library/sidecar.js +11 -0
  100. package/dist/library/sidecar.js.map +1 -1
  101. package/package.json +2 -2
  102. package/surface-manifest.json +1 -1
@@ -0,0 +1,257 @@
1
+ import { createHash } from "node:crypto";
2
+ import { extname } from "node:path";
3
+ import ts from "typescript5";
4
+ const TOKEN_PATTERN = /(?:\s+|\/\/[^\r\n\u2028\u2029]*|\/\*[\s\S]*?\*\/|(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)|(?:0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)|(?:(?:[$_\p{ID_Start}]|\\u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]+\}))(?:(?:[$_\u200C\u200D\p{ID_Continue}]|\\u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]+\})))*)|(?:===|!==|>>>|>>=|<<=|\*\*=|&&=|\|\|=|\?\?=|=>|==|!=|<=|>=|\+\+|--|&&|\|\||\?\?|\?\.|\*\*|<<|>>>|>>|\+=|-=|\*=|\/=|%=|&=|\|=|\^=)|[^\s])/guy;
5
+ const LINE_BREAK_PATTERN = /[\r\n\u2028\u2029]/;
6
+ function commentCanAffectCompilation(path, text) {
7
+ const extension = extname(path).toLowerCase();
8
+ // JavaScript's checker surface is JSDoc-driven, so every comment remains
9
+ // semantic there. JSON and unknown source spellings stay conservative too.
10
+ if (extension !== ".ts" && extension !== ".mts" && extension !== ".cts")
11
+ return true;
12
+ // TypeScript comments are ordinary trivia except for compiler directives,
13
+ // triple-slash references, and the pure annotations consumed by lowering.
14
+ return text.startsWith("///") || text.includes("@") || text.includes("#");
15
+ }
16
+ function semanticTokens(path, source) {
17
+ // Slash is context-sensitive in JavaScript: after `else`, for example,
18
+ // `/[//a]/` is one regex token even though a standalone scanner can see
19
+ // the inner `//` as a comment. Use TypeScript's parser as the authority for
20
+ // both syntax validity (including a shebang's byte-zero requirement) and
21
+ // exact regular-expression spans, then keep the cheap scanner for trivia
22
+ // equivalence and location mapping.
23
+ const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);
24
+ const parseDiagnostics = sourceFile.parseDiagnostics;
25
+ if (parseDiagnostics.length > 0)
26
+ return null;
27
+ const regexEnds = new Map();
28
+ const collectRegex = (node) => {
29
+ if (ts.isRegularExpressionLiteral(node))
30
+ regexEnds.set(node.getStart(sourceFile), node.end);
31
+ ts.forEachChild(node, collectRegex);
32
+ };
33
+ collectRegex(sourceFile);
34
+ const tokens = [];
35
+ let lineBreakBefore = false;
36
+ TOKEN_PATTERN.lastIndex = 0;
37
+ while (TOKEN_PATTERN.lastIndex < source.length) {
38
+ const match = TOKEN_PATTERN.exec(source);
39
+ if (match === null)
40
+ throw new Error(`semantic scanner stopped at ${TOKEN_PATTERN.lastIndex}`);
41
+ let text = match[0];
42
+ const start = match.index;
43
+ let end = start + text.length;
44
+ if (/^\s+$/.test(text)) {
45
+ if (LINE_BREAK_PATTERN.test(text))
46
+ lineBreakBefore = true;
47
+ continue;
48
+ }
49
+ const regexEnd = regexEnds.get(start);
50
+ if (regexEnd !== undefined) {
51
+ end = regexEnd;
52
+ text = source.slice(start, end);
53
+ TOKEN_PATTERN.lastIndex = end;
54
+ tokens.push({ kind: "token", text, lineBreakBefore, start, end });
55
+ lineBreakBefore = false;
56
+ continue;
57
+ }
58
+ const comment = text.startsWith("//") || text.startsWith("/*");
59
+ if (comment) {
60
+ if (!commentCanAffectCompilation(path, text)) {
61
+ if (LINE_BREAK_PATTERN.test(text))
62
+ lineBreakBefore = true;
63
+ continue;
64
+ }
65
+ }
66
+ tokens.push({ kind: comment ? "comment" : "token", text, lineBreakBefore, start, end });
67
+ lineBreakBefore = false;
68
+ }
69
+ return tokens;
70
+ }
71
+ function tokensEqual(left, right) {
72
+ return left.length === right.length && left.every((token, index) => {
73
+ const other = right[index];
74
+ return token.kind === other.kind &&
75
+ token.text === other.text &&
76
+ (index === 0 || token.lineBreakBefore === other.lineBreakBefore);
77
+ });
78
+ }
79
+ /** Content identity after discarding TypeScript comments proven to be trivia. */
80
+ export function semanticSourceDigest(path, source) {
81
+ const hash = createHash("sha256").update("scriptc-semantic-source-v1\0");
82
+ const tokens = semanticTokens(path, source);
83
+ if (tokens === null)
84
+ return hash.update("invalid\0").update(source).digest("hex");
85
+ for (const token of tokens) {
86
+ hash.update(String(token.kind)).update("\0")
87
+ .update(token.lineBreakBefore ? "nl" : "same-line").update("\0")
88
+ .update(token.text).update("\0");
89
+ }
90
+ return hash.digest("hex");
91
+ }
92
+ export function semanticallyEqualSource(path, previous, current) {
93
+ const left = semanticTokens(path, previous);
94
+ const right = semanticTokens(path, current);
95
+ return left !== null && right !== null && tokensEqual(left, right);
96
+ }
97
+ function offsetMapper(path, previous, current) {
98
+ const oldTokens = semanticTokens(path, previous);
99
+ const newTokens = semanticTokens(path, current);
100
+ if (oldTokens === null || newTokens === null || !tokensEqual(oldTokens, newTokens)) {
101
+ return { start: (offset) => offset, end: (offset) => offset };
102
+ }
103
+ const map = (offset, bias) => {
104
+ if (offset <= 0)
105
+ return 0;
106
+ if (offset >= previous.length)
107
+ return current.length;
108
+ let lo = 0;
109
+ let hi = oldTokens.length - 1;
110
+ while (lo <= hi) {
111
+ const mid = (lo + hi) >> 1;
112
+ const token = oldTokens[mid];
113
+ if (bias === "start" ? offset < token.start : offset <= token.start)
114
+ hi = mid - 1;
115
+ else if (bias === "start" ? offset >= token.end : offset > token.end)
116
+ lo = mid + 1;
117
+ else
118
+ return newTokens[mid].start + Math.min(offset - token.start, token.end - token.start);
119
+ }
120
+ const before = hi >= 0 ? oldTokens[hi] : undefined;
121
+ const after = lo < oldTokens.length ? oldTokens[lo] : undefined;
122
+ if (before === undefined) {
123
+ return Math.max(0, newTokens[lo].start - (after.start - offset));
124
+ }
125
+ if (after === undefined) {
126
+ return Math.min(current.length, newTokens[hi].end + (offset - before.end));
127
+ }
128
+ const oldGap = after.start - before.end;
129
+ const newBefore = newTokens[hi];
130
+ const newAfter = newTokens[lo];
131
+ if (oldGap <= 0)
132
+ return newBefore.end;
133
+ const fraction = (offset - before.end) / oldGap;
134
+ return Math.round(newBefore.end + fraction * (newAfter.start - newBefore.end));
135
+ };
136
+ return {
137
+ start: (offset) => map(offset, "start"),
138
+ end: (offset) => map(offset, "end"),
139
+ };
140
+ }
141
+ function lineStarts(source) {
142
+ const starts = [0];
143
+ for (let offset = 0; offset < source.length; offset++) {
144
+ if (source[offset] === "\n")
145
+ starts.push(offset + 1);
146
+ }
147
+ return starts;
148
+ }
149
+ function lineAt(starts, offset) {
150
+ let lo = 0;
151
+ let hi = starts.length - 1;
152
+ while (lo < hi) {
153
+ const mid = (lo + hi + 1) >> 1;
154
+ if (starts[mid] <= offset)
155
+ lo = mid;
156
+ else
157
+ hi = mid - 1;
158
+ }
159
+ return lo + 1;
160
+ }
161
+ /** Build a cheap old-line to current-line mapper for semantically identical
162
+ * sources. C emission records only a location's line, not its byte offset, so
163
+ * representative semantic tokens anchor each old line across trivia edits. */
164
+ export function createSourceLineRebaser(path, previous, current) {
165
+ const oldTokens = semanticTokens(path, previous);
166
+ const newTokens = semanticTokens(path, current);
167
+ if (oldTokens === null || newTokens === null || !tokensEqual(oldTokens, newTokens)) {
168
+ return (line) => line;
169
+ }
170
+ const oldStarts = lineStarts(previous);
171
+ const newStarts = lineStarts(current);
172
+ const firstTokenByLine = new Map();
173
+ for (let index = 0; index < oldTokens.length; index++) {
174
+ const line = lineAt(oldStarts, oldTokens[index].start);
175
+ if (!firstTokenByLine.has(line))
176
+ firstTokenByLine.set(line, index);
177
+ }
178
+ const mapper = offsetMapper(path, previous, current);
179
+ return (line) => {
180
+ if (!Number.isSafeInteger(line) || line < 1 || line > oldStarts.length)
181
+ return line;
182
+ const tokenIndex = firstTokenByLine.get(line);
183
+ const offset = tokenIndex === undefined
184
+ ? mapper.start(oldStarts[line - 1])
185
+ : newTokens[tokenIndex].start;
186
+ return lineAt(newStarts, offset);
187
+ };
188
+ }
189
+ /** True when every existing source line keeps its physical line number. This
190
+ * is the safe subset for reusing a C TU whose annotations retain line numbers
191
+ * but not enough provenance to distinguish synthetic byte-zero locations. */
192
+ export function sourceLineRebaseIsIdentity(path, previous, current) {
193
+ const oldTokens = semanticTokens(path, previous);
194
+ const newTokens = semanticTokens(path, current);
195
+ if (oldTokens === null || newTokens === null || !tokensEqual(oldTokens, newTokens)) {
196
+ return false;
197
+ }
198
+ const oldStarts = lineStarts(previous);
199
+ const newStarts = lineStarts(current);
200
+ // The C emitter counts only LF bytes. TypeScript also treats bare CR and
201
+ // the Unicode separators as line breaks, so normalizing one of those to LF
202
+ // preserves semantic tokens while moving later annotations to a different
203
+ // emitter line. Check every corresponding token, including multiple
204
+ // TypeScript lines that the emitter previously collapsed into one.
205
+ for (let index = 0; index < oldTokens.length; index++) {
206
+ if (lineAt(oldStarts, oldTokens[index].start) !==
207
+ lineAt(newStarts, newTokens[index].start))
208
+ return false;
209
+ }
210
+ const rebase = createSourceLineRebaser(path, previous, current);
211
+ let line = 1;
212
+ if (rebase(line) !== line)
213
+ return false;
214
+ for (let offset = 0; offset < previous.length; offset++) {
215
+ if (previous[offset] !== "\n")
216
+ continue;
217
+ line++;
218
+ if (rebase(line) !== line)
219
+ return false;
220
+ }
221
+ return true;
222
+ }
223
+ /** Rebase every SrcLoc-shaped object in a deserialized cache payload. */
224
+ export function rebaseSourceLocations(value, previousSources, currentSources) {
225
+ const mappers = new Map();
226
+ for (const [path, previous] of previousSources) {
227
+ const current = currentSources.get(path);
228
+ if (current !== undefined)
229
+ mappers.set(path, offsetMapper(path, previous, current));
230
+ }
231
+ const visit = (node) => {
232
+ if (node === null || typeof node !== "object")
233
+ return;
234
+ const record = node;
235
+ if (typeof record["file"] === "string" &&
236
+ typeof record["start"] === "number" &&
237
+ typeof record["end"] === "number") {
238
+ const map = mappers.get(record["file"]);
239
+ if (map !== undefined) {
240
+ const start = record["start"];
241
+ const end = record["end"];
242
+ record["start"] = map.start(start);
243
+ record["end"] = start === end ? record["start"] : map.end(end);
244
+ }
245
+ return;
246
+ }
247
+ for (const child of Object.values(record)) {
248
+ if (Array.isArray(child))
249
+ child.forEach(visit);
250
+ else
251
+ visit(child);
252
+ }
253
+ };
254
+ visit(value);
255
+ return value;
256
+ }
257
+ //# sourceMappingURL=semantic-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-source.js","sourceRoot":"","sources":["../../src/library/semantic-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,113 @@
1
+ import { expect, test } from "vitest";
2
+ import { createSourceLineRebaser, rebaseSourceLocations, semanticallyEqualSource, semanticSourceDigest, sourceLineRebaseIsIdentity } from "./semantic-source.js";
3
+ test("ordinary TypeScript comments and formatting preserve semantic identity", () => {
4
+ const before = "// old note\nexport function value(): number { return 1; }\n";
5
+ const after = "/* a longer replacement note */\n\nexport function value(): number { return 1; }\n";
6
+ expect(semanticallyEqualSource("entry.ts", before, after)).toBe(true);
7
+ expect(semanticSourceDigest("entry.ts", before)).toBe(semanticSourceDigest("entry.ts", after));
8
+ });
9
+ test("directives, pure annotations, JavaScript comments, and tokens remain semantic", () => {
10
+ expect(semanticallyEqualSource("entry.ts", "// @ts-expect-error\nconst x: number = 'x';\n", "// harmless\nconst x: number = 'x';\n")).toBe(false);
11
+ expect(semanticallyEqualSource("entry.ts", "const x = /* @__PURE__ */ make();\n", "const x = /* ordinary */ make();\n")).toBe(false);
12
+ expect(semanticallyEqualSource("entry.js", "/** @returns {number} */\nexport function value() { return 1; }\n", "/* ordinary */\nexport function value() { return 1; }\n")).toBe(false);
13
+ expect(semanticallyEqualSource("entry.ts", "return 1;\n", "return 2;\n")).toBe(false);
14
+ });
15
+ test("line breaks introduced by comments retain ASI-sensitive identity", () => {
16
+ expect(semanticallyEqualSource("entry.ts", "function f() { return /* same line */ value; }\n", "function f() { return /* split\nline */ value; }\n")).toBe(false);
17
+ });
18
+ test("comments cannot merge keywords with Unicode or escaped identifiers", () => {
19
+ for (const [before, after] of [
20
+ [
21
+ "const π = 1, typeofπ = 0; export const value = typeof/**/π ? 1 : 0;\n",
22
+ "const π = 1, typeofπ = 0; export const value = typeofπ ? 1 : 0;\n",
23
+ ],
24
+ [
25
+ String.raw `const π = 1, typeofπ = 0; export const value = typeof/**/\u03c0 ? 1 : 0;` + "\n",
26
+ String.raw `const π = 1, typeofπ = 0; export const value = typeof\u03c0 ? 1 : 0;` + "\n",
27
+ ],
28
+ ]) {
29
+ expect(semanticallyEqualSource("entry.ts", before, after)).toBe(false);
30
+ expect(semanticSourceDigest("entry.ts", before)).not.toBe(semanticSourceDigest("entry.ts", after));
31
+ }
32
+ });
33
+ test("ECMAScript line separators retain ASI and single-line-comment boundaries", () => {
34
+ for (const separator of ["\u2028", "\u2029"]) {
35
+ expect(semanticallyEqualSource("entry.ts", "function f() { return value; }\n", `function f() { return${separator}value; }\n`)).toBe(false);
36
+ expect(semanticallyEqualSource("entry.ts", `export const a = 1; // note${separator}export const b = 1;\n`, `export const a = 1; // note${separator}export const b = 2;\n`)).toBe(false);
37
+ }
38
+ });
39
+ test("source locations rebase across changed comment trivia", () => {
40
+ const before = "// old\nexport function value() { return 1; }\n";
41
+ const after = "/* much longer\n * note\n */\nexport function value() { return 1; }\n";
42
+ const oldStart = before.indexOf("return");
43
+ const oldEnd = oldStart + "return 1".length;
44
+ const payload = { loc: { file: "/entry.ts", start: oldStart, end: oldEnd } };
45
+ rebaseSourceLocations(payload, new Map([["/entry.ts", before]]), new Map([["/entry.ts", after]]));
46
+ expect(payload.loc.start).toBe(after.indexOf("return"));
47
+ expect(payload.loc.end).toBe(after.indexOf("return") + "return 1".length);
48
+ });
49
+ test("source lines rebase across changed comment trivia", () => {
50
+ const before = "// old\nexport function value() {\n return 1;\n}\n";
51
+ const after = "/* much longer\n * note\n */\n\nexport function value() {\n return 1;\n}\n";
52
+ const rebase = createSourceLineRebaser("/entry.ts", before, after);
53
+ expect(rebase(2)).toBe(5);
54
+ expect(rebase(3)).toBe(6);
55
+ expect(rebase(4)).toBe(7);
56
+ expect(sourceLineRebaseIsIdentity("/entry.ts", before, after)).toBe(false);
57
+ expect(sourceLineRebaseIsIdentity("/entry.ts", "// old\nexport function value() { return 1; }\n", "/* replacement */\nexport function value() { return 1; }\n")).toBe(true);
58
+ });
59
+ test("C source lines reject normalization of non-LF separators", () => {
60
+ for (const separator of ["\r", "\u2028", "\u2029"]) {
61
+ const before = `export const first = 1;${separator}export const second = 2;\n`;
62
+ const after = before.replace(separator, "\n");
63
+ expect(semanticallyEqualSource("/entry.ts", before, after)).toBe(true);
64
+ expect(sourceLineRebaseIsIdentity("/entry.ts", before, after)).toBe(false);
65
+ }
66
+ });
67
+ test("source locations at adjacent token boundaries rebase past inserted comments", () => {
68
+ const before = "export function value() { return left+right; }\n";
69
+ const after = "export function value() { return left+/* note */right; }\n";
70
+ const oldStart = before.indexOf("right");
71
+ const payload = {
72
+ loc: { file: "/entry.ts", start: oldStart, end: oldStart + "right".length },
73
+ empty: { file: "/entry.ts", start: oldStart, end: oldStart },
74
+ };
75
+ rebaseSourceLocations(payload, new Map([["/entry.ts", before]]), new Map([["/entry.ts", after]]));
76
+ expect(payload.loc.start).toBe(after.indexOf("right"));
77
+ expect(payload.loc.end).toBe(after.indexOf("right") + "right".length);
78
+ expect(payload.empty).toEqual({ file: "/entry.ts", start: after.indexOf("right"), end: after.indexOf("right") });
79
+ });
80
+ test("comment markers inside strings, templates, and regex literals are tokens", () => {
81
+ for (const [before, after] of [
82
+ ['const value = "/* old */";\n', 'const value = "/* new */";\n'],
83
+ ["const value = `// old`;\n", "const value = `// new`;\n"],
84
+ ["const value = /a\\/\\/*old/;\n", "const value = /a\\/\\/*new/;\n"],
85
+ ]) {
86
+ expect(semanticallyEqualSource("entry.ts", before, after)).toBe(false);
87
+ }
88
+ });
89
+ test("contextual regex literals cannot hide token edits as comments", () => {
90
+ for (const [before, after] of [
91
+ [
92
+ "if (flag) {} else /[//a]/.test(value);\n",
93
+ "if (flag) {} else /[//b]/.test(value);\n",
94
+ ],
95
+ [
96
+ "if (flag) /[//a]/.test(value);\n",
97
+ "if (flag) /[//b]/.test(value);\n",
98
+ ],
99
+ [
100
+ "do /[//a]/.test(value); while (flag);\n",
101
+ "do /[//b]/.test(value); while (flag);\n",
102
+ ],
103
+ ]) {
104
+ expect(semanticallyEqualSource("entry.ts", before, after)).toBe(false);
105
+ }
106
+ });
107
+ test("trivia cannot move a shebang away from the start of the file", () => {
108
+ const before = "#!/usr/bin/env node\nexport const value = 1;\n";
109
+ const after = `// inserted comment\n${before}`;
110
+ expect(semanticallyEqualSource("entry.ts", before, after)).toBe(false);
111
+ expect(semanticallyEqualSource("entry.ts", "export const value = 1;\n", "// inserted comment\nexport const value = 1;\n")).toBe(true);
112
+ });
113
+ //# sourceMappingURL=semantic-source.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-source.test.js","sourceRoot":"","sources":["../../src/library/semantic-source.test.ts"],"names":[],"mappings":"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"}
@@ -244,3 +244,9 @@ export type SidecarBuildResult = {
244
244
  diagnostics: ScrDiagnostic[];
245
245
  };
246
246
  export declare function buildSidecar(input: SidecarBuildInput): SidecarBuildResult;
247
+ /**
248
+ * A semantic-cache hit has already validated/projected the sidecar. Only the
249
+ * exact-source identity fields may change after comment trivia edits; retain
250
+ * the established property order and replace those two values in place.
251
+ */
252
+ export declare function updateSidecarIdentity(json: string, buildId: string, sourceHash: string): string;
@@ -1220,4 +1220,15 @@ export function buildSidecar(input) {
1220
1220
  throw e;
1221
1221
  }
1222
1222
  }
1223
+ /**
1224
+ * A semantic-cache hit has already validated/projected the sidecar. Only the
1225
+ * exact-source identity fields may change after comment trivia edits; retain
1226
+ * the established property order and replace those two values in place.
1227
+ */
1228
+ export function updateSidecarIdentity(json, buildId, sourceHash) {
1229
+ const doc = JSON.parse(json);
1230
+ doc.source_hash = sourceHash;
1231
+ doc.build_id = buildId;
1232
+ return JSON.stringify(doc, null, 2) + "\n";
1233
+ }
1223
1234
  //# sourceMappingURL=sidecar.js.map