@tsrx/oxc 0.0.0-trusted-publishing-bootstrap → 0.8.0
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/LICENSE +21 -0
- package/README.md +141 -0
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/bin/oxc-tsrx +2 -0
- package/bin/oxc-tsrx-fmt +2 -0
- package/bin/oxc-tsrx-lint +2 -0
- package/bin/oxc-tsrx-lsp +2 -0
- package/bin/oxfmt +2 -0
- package/bin/oxlint +2 -0
- package/dist/bin/oxc-tsrx-fmt.js +13 -0
- package/dist/bin/oxc-tsrx-lint.js +13 -0
- package/dist/bin/oxc-tsrx-lsp.js +13 -0
- package/dist/bin/oxc-tsrx.js +115 -0
- package/dist/bin/oxfmt.js +24 -0
- package/dist/bin/oxlint.js +33 -0
- package/dist/canonical-command.d.ts +50 -0
- package/dist/canonical-command.js +196 -0
- package/dist/compat.d.ts +149 -0
- package/dist/compat.js +1615 -0
- package/dist/editor-resolution.js +508 -0
- package/dist/format-cli.js +276 -0
- package/dist/format-invocation.js +97 -0
- package/dist/format.d.ts +1 -0
- package/dist/format.js +56 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +16 -0
- package/dist/lint-cli.js +487 -0
- package/dist/lint-invocation.js +192 -0
- package/dist/lint-js-plugins.js +819 -0
- package/dist/lint-plugins-dev.d.ts +1 -0
- package/dist/lint-plugins-dev.js +2 -0
- package/dist/lint-prestart.js +16 -0
- package/dist/lint.d.ts +1 -0
- package/dist/lint.js +2 -0
- package/dist/native-targets.js +76 -0
- package/dist/oxlint-lsp-multiplexer.js +622 -0
- package/dist/package-binary.js +29 -0
- package/dist/parser.d.ts +216 -0
- package/dist/parser.js +557 -0
- package/dist/process.js +88 -0
- package/dist/provider-resolve.d.ts +160 -0
- package/dist/provider-resolve.js +471 -0
- package/dist/providers-report.js +49 -0
- package/dist/runtime.js +323 -0
- package/dist/spawn-command.d.ts +20 -0
- package/dist/spawn-command.js +87 -0
- package/dist/tsrx-core-compat/facade.js +1184 -0
- package/dist/tsrx-core-compat/index.d.ts +6 -0
- package/dist/tsrx-core-compat/index.js +9 -0
- package/dist/tsrx-core-compat/style.js +525 -0
- package/dist/tsrx-core-compat/types/estree.d.ts +20 -0
- package/dist/tsrx-core-compat/types/index.d.ts +50 -0
- package/dist/tsrx-transfer.js +352 -0
- package/package.json +144 -5
|
@@ -0,0 +1,1184 @@
|
|
|
1
|
+
import { parse_style } from "./style.js";
|
|
2
|
+
//#region src/facade.ts
|
|
3
|
+
const PARSER_OPTIONS = Object.freeze({
|
|
4
|
+
lang: "tsrx",
|
|
5
|
+
sourceType: "module",
|
|
6
|
+
astType: "ts",
|
|
7
|
+
preserveParens: true
|
|
8
|
+
});
|
|
9
|
+
const TSRX_CORE_COMPAT_EAGER = Symbol.for("@oxc-tsrx/parser/tsrx-core-compat-eager");
|
|
10
|
+
const TSRX_CORE_COMPAT_DEFAULTS_STRIPPED = Symbol.for("@oxc-tsrx/parser/tsrx-core-compat-defaults-stripped");
|
|
11
|
+
const EAGER_PARSER_OPTIONS = Object.freeze(Object.defineProperty({ ...PARSER_OPTIONS }, TSRX_CORE_COMPAT_EAGER, { value: true }));
|
|
12
|
+
const EMPTY_ERRORS = Object.freeze([]);
|
|
13
|
+
function parserResultProgram(result) {
|
|
14
|
+
return result?.type === "Program" ? result : result?.program ?? null;
|
|
15
|
+
}
|
|
16
|
+
function parserResultErrors(result) {
|
|
17
|
+
return result?.type === "Program" ? EMPTY_ERRORS : result?.errors ?? EMPTY_ERRORS;
|
|
18
|
+
}
|
|
19
|
+
function tsrxRetry(parser, filename, source, eagerTsrx) {
|
|
20
|
+
const options = eagerTsrx ? EAGER_PARSER_OPTIONS : PARSER_OPTIONS;
|
|
21
|
+
const result = parser.parseSync(filename, source, options);
|
|
22
|
+
if (parserResultProgram(result) === null || parserResultErrors(result).length > 0) return null;
|
|
23
|
+
return {
|
|
24
|
+
result,
|
|
25
|
+
options
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function ordinaryParserOptions(lang) {
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
lang,
|
|
31
|
+
sourceType: "module",
|
|
32
|
+
astType: "js",
|
|
33
|
+
preserveParens: false,
|
|
34
|
+
showSemanticErrors: true
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const TYPESCRIPT_PARSER_OPTIONS = ordinaryParserOptions("ts");
|
|
38
|
+
const TYPESCRIPT_REACT_PARSER_OPTIONS = Object.freeze({
|
|
39
|
+
...ordinaryParserOptions("tsx"),
|
|
40
|
+
astType: "ts"
|
|
41
|
+
});
|
|
42
|
+
const TYPESCRIPT_DEFINITION_PARSER_OPTIONS = ordinaryParserOptions("dts");
|
|
43
|
+
function parserOptions(filename, eagerTsrx = false) {
|
|
44
|
+
let pathname = filename;
|
|
45
|
+
const query = pathname.indexOf("?");
|
|
46
|
+
const hash = pathname.indexOf("#");
|
|
47
|
+
const suffix = query === -1 ? hash : hash === -1 ? query : Math.min(query, hash);
|
|
48
|
+
if (suffix !== -1) pathname = pathname.slice(0, suffix);
|
|
49
|
+
if (pathname.endsWith(".tsrx")) return eagerTsrx ? EAGER_PARSER_OPTIONS : PARSER_OPTIONS;
|
|
50
|
+
if (pathname.endsWith(".d.ts") || pathname.endsWith(".d.mts") || pathname.endsWith(".d.cts")) return TYPESCRIPT_DEFINITION_PARSER_OPTIONS;
|
|
51
|
+
if (pathname.endsWith(".tsx")) return TYPESCRIPT_REACT_PARSER_OPTIONS;
|
|
52
|
+
if (pathname.endsWith(".object.ts")) return TYPESCRIPT_REACT_PARSER_OPTIONS;
|
|
53
|
+
if (pathname.endsWith(".ts") || pathname.endsWith(".mts") || pathname.endsWith(".cts")) return TYPESCRIPT_PARSER_OPTIONS;
|
|
54
|
+
if (pathname.endsWith(".jsx")) return TYPESCRIPT_REACT_PARSER_OPTIONS;
|
|
55
|
+
if (pathname.endsWith(".js") || pathname.endsWith(".mjs") || pathname.endsWith(".cjs")) return TYPESCRIPT_PARSER_OPTIONS;
|
|
56
|
+
return eagerTsrx ? EAGER_PARSER_OPTIONS : PARSER_OPTIONS;
|
|
57
|
+
}
|
|
58
|
+
const DYNAMIC_TAG_CANDIDATE_MESSAGE = /^TSRX dynamic tag \d+ at source byte \d+ must be an identifier, member, static string, or runtime expression without calls, construction, spreads, concatenation, interpolation, objects, or arrays$/u;
|
|
59
|
+
const DYNAMIC_TAG_REFERENCE_MESSAGE = "Dynamic element names must be an identifier, member expression, static string, or runtime expression; calls, spreads, string concatenation, string interpolation, and static null, undefined, boolean, number, object, and array literals are not valid tag names.";
|
|
60
|
+
const IDENTIFIER_START = /[$_\p{ID_Start}]/u;
|
|
61
|
+
const IDENTIFIER_CONTINUE = /[$_\u200c\u200d\p{ID_Continue}]/u;
|
|
62
|
+
const WHITESPACE = /\s/u;
|
|
63
|
+
const SOURCE_DECLARATION_TYPES = /* @__PURE__ */ new Set([
|
|
64
|
+
"ImportDeclaration",
|
|
65
|
+
"ExportNamedDeclaration",
|
|
66
|
+
"ExportAllDeclaration"
|
|
67
|
+
]);
|
|
68
|
+
const COMPLETION_PLACEHOLDER = "__markless_at__";
|
|
69
|
+
const RECOVERABLE_LOOSE_SHAPE_MESSAGE = "unsupported TSRX parser shape: failed TSRX result has no authored diagnostic";
|
|
70
|
+
const LOOSE_RENDER_ERRORS = /* @__PURE__ */ new Set([
|
|
71
|
+
"Adjacent JSX elements must be wrapped in an enclosing tag.",
|
|
72
|
+
"render expression precedes another statement",
|
|
73
|
+
RECOVERABLE_LOOSE_SHAPE_MESSAGE
|
|
74
|
+
]);
|
|
75
|
+
function createRecoverySource(source) {
|
|
76
|
+
return {
|
|
77
|
+
text: source,
|
|
78
|
+
boundaries: Array.from({ length: source.length + 1 }, (_value, index) => index)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function replaceRecoveryRange(recovery, start, end, replacement) {
|
|
82
|
+
const oldLength = end - start;
|
|
83
|
+
const replacementBoundaries = [];
|
|
84
|
+
if (replacement.length === oldLength) replacementBoundaries.push(...recovery.boundaries.slice(start, end + 1));
|
|
85
|
+
else {
|
|
86
|
+
const originalStart = recovery.boundaries[start];
|
|
87
|
+
const originalEnd = recovery.boundaries[end];
|
|
88
|
+
replacementBoundaries.push(originalStart);
|
|
89
|
+
for (let index = 1; index < replacement.length; index += 1) replacementBoundaries.push(originalStart);
|
|
90
|
+
replacementBoundaries.push(originalEnd);
|
|
91
|
+
}
|
|
92
|
+
recovery.text = recovery.text.slice(0, start) + replacement + recovery.text.slice(end);
|
|
93
|
+
recovery.boundaries.splice(start, oldLength + 1, ...replacementBoundaries);
|
|
94
|
+
}
|
|
95
|
+
function applyRecoveryEdits(recovery, edits) {
|
|
96
|
+
const ordered = [...edits].sort((left, right) => right.start - left.start);
|
|
97
|
+
for (const edit of ordered) replaceRecoveryRange(recovery, edit.start, edit.end, edit.replacement);
|
|
98
|
+
}
|
|
99
|
+
function remapRecoveredTree(root, boundaries) {
|
|
100
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
101
|
+
const stack = [root];
|
|
102
|
+
while (stack.length > 0) {
|
|
103
|
+
const value = stack.pop();
|
|
104
|
+
if (value === null || typeof value !== "object" || seen.has(value)) continue;
|
|
105
|
+
seen.add(value);
|
|
106
|
+
if (value.type === "StyleSheet") continue;
|
|
107
|
+
if (Number.isInteger(value.start)) value.start = boundaries[Math.max(0, Math.min(boundaries.length - 1, value.start))];
|
|
108
|
+
if (Number.isInteger(value.end)) value.end = boundaries[Math.max(0, Math.min(boundaries.length - 1, value.end))];
|
|
109
|
+
if (Array.isArray(value.range) && value.range.length === 2) {
|
|
110
|
+
value.range[0] = boundaries[Math.max(0, Math.min(boundaries.length - 1, value.range[0]))];
|
|
111
|
+
value.range[1] = boundaries[Math.max(0, Math.min(boundaries.length - 1, value.range[1]))];
|
|
112
|
+
}
|
|
113
|
+
for (const [key, child] of Object.entries(value)) {
|
|
114
|
+
if (key === "parent" || key === "loc" || child === null || typeof child !== "object") continue;
|
|
115
|
+
if (Array.isArray(child)) for (let index = child.length - 1; index >= 0; index -= 1) stack.push(child[index]);
|
|
116
|
+
else stack.push(child);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function isOperationalError(error) {
|
|
121
|
+
return error?.name === "ParserOperationalError" || typeof error?.code === "string" && error.code.startsWith("ERR_TSRX_");
|
|
122
|
+
}
|
|
123
|
+
function isRecoverableLooseShapeFailure(error) {
|
|
124
|
+
return isOperationalError(error) && error?.code === "ERR_TSRX_INVALID_ARGUMENT" && error?.message === RECOVERABLE_LOOSE_SHAPE_MESSAGE;
|
|
125
|
+
}
|
|
126
|
+
function isSyntaxErrorLike(error) {
|
|
127
|
+
return error instanceof SyntaxError || error?.name === "SyntaxError" || typeof error?.message === "string" && Array.isArray(error?.labels);
|
|
128
|
+
}
|
|
129
|
+
function positionLookup(source) {
|
|
130
|
+
const lineStarts = [0];
|
|
131
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
132
|
+
const code = source.charCodeAt(index);
|
|
133
|
+
if (code === 13) {
|
|
134
|
+
if (source.charCodeAt(index + 1) === 10) index += 1;
|
|
135
|
+
lineStarts.push(index + 1);
|
|
136
|
+
} else if (code === 10 || code === 8232 || code === 8233) lineStarts.push(index + 1);
|
|
137
|
+
}
|
|
138
|
+
return (rawOffset) => {
|
|
139
|
+
const offset = Math.max(0, Math.min(source.length, Number.isInteger(rawOffset) ? rawOffset : 0));
|
|
140
|
+
let low = 0;
|
|
141
|
+
let high = lineStarts.length;
|
|
142
|
+
while (low + 1 < high) {
|
|
143
|
+
const middle = low + high >>> 1;
|
|
144
|
+
if (lineStarts[middle] <= offset) low = middle;
|
|
145
|
+
else high = middle;
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
line: low + 1,
|
|
149
|
+
column: offset - lineStarts[low]
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function primarySpan(error) {
|
|
154
|
+
const label = Array.isArray(error?.labels) ? error.labels.find((candidate) => Number.isInteger(candidate?.start) && Number.isInteger(candidate?.end)) : void 0;
|
|
155
|
+
const start = label?.start ?? (Number.isInteger(error?.pos) ? error.pos : void 0);
|
|
156
|
+
return {
|
|
157
|
+
start,
|
|
158
|
+
end: label?.end ?? (Number.isInteger(error?.end) ? error.end : Number.isInteger(error?.raisedAt) ? error.raisedAt : start)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function compatibleDiagnosticSpan(error, source) {
|
|
162
|
+
const span = primarySpan(error);
|
|
163
|
+
if (error?.message !== "Unexpected token" || typeof source !== "string" || !Number.isInteger(span.start)) return span;
|
|
164
|
+
let extra = Math.min(span.start - 1, source.length - 1);
|
|
165
|
+
while (extra >= 0 && WHITESPACE.test(source[extra])) extra -= 1;
|
|
166
|
+
if (source[extra] !== ">" || source[extra - 1] !== ">") return span;
|
|
167
|
+
const closingStart = source.lastIndexOf("</", extra - 1);
|
|
168
|
+
if (closingStart === -1 || source.lastIndexOf("<", extra - 1) !== closingStart) return span;
|
|
169
|
+
const closingName = source.slice(closingStart + 2, extra - 1);
|
|
170
|
+
if (!/^(?:[A-Za-z_$][\w.$:-]*|\{[^{}\r\n]*\})?$/u.test(closingName)) return span;
|
|
171
|
+
return {
|
|
172
|
+
start: extra,
|
|
173
|
+
end: extra + 1
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function compatibleDiagnosticMessage(error) {
|
|
177
|
+
const message = typeof error?.message === "string" ? error.message : String(error);
|
|
178
|
+
return DYNAMIC_TAG_CANDIDATE_MESSAGE.test(message) ? DYNAMIC_TAG_REFERENCE_MESSAGE : message;
|
|
179
|
+
}
|
|
180
|
+
function toCompileError(error, filename, positionAt, type, source) {
|
|
181
|
+
const translated = new SyntaxError(compatibleDiagnosticMessage(error));
|
|
182
|
+
const { start, end } = compatibleDiagnosticSpan(error, source);
|
|
183
|
+
translated.code = typeof error?.code === "string" ? error.code : void 0;
|
|
184
|
+
translated.pos = start;
|
|
185
|
+
translated.raisedAt = end;
|
|
186
|
+
translated.end = end;
|
|
187
|
+
translated.fileName = filename;
|
|
188
|
+
translated.type = type;
|
|
189
|
+
translated.loc = start === void 0 ? void 0 : {
|
|
190
|
+
start: positionAt(start),
|
|
191
|
+
end: positionAt(end ?? start)
|
|
192
|
+
};
|
|
193
|
+
return translated;
|
|
194
|
+
}
|
|
195
|
+
function codePointAt(source, index) {
|
|
196
|
+
const value = source.codePointAt(index);
|
|
197
|
+
return value === void 0 ? {
|
|
198
|
+
character: "",
|
|
199
|
+
width: 0
|
|
200
|
+
} : {
|
|
201
|
+
character: String.fromCodePoint(value),
|
|
202
|
+
width: value > 65535 ? 2 : 1
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function readIdentifier(source, start) {
|
|
206
|
+
let point = codePointAt(source, start);
|
|
207
|
+
if (!IDENTIFIER_START.test(point.character)) return null;
|
|
208
|
+
let end = start + point.width;
|
|
209
|
+
while (end < source.length) {
|
|
210
|
+
point = codePointAt(source, end);
|
|
211
|
+
if (!IDENTIFIER_CONTINUE.test(point.character)) break;
|
|
212
|
+
end += point.width;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
start,
|
|
216
|
+
end,
|
|
217
|
+
name: source.slice(start, end)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function skipQuoted(source, start, quote) {
|
|
221
|
+
let index = start + 1;
|
|
222
|
+
while (index < source.length) {
|
|
223
|
+
const character = source[index];
|
|
224
|
+
if (character === "\\") index += 2;
|
|
225
|
+
else if (character === quote) return index + 1;
|
|
226
|
+
else index += codePointAt(source, index).width || 1;
|
|
227
|
+
}
|
|
228
|
+
return source.length;
|
|
229
|
+
}
|
|
230
|
+
function skipComment(source, start) {
|
|
231
|
+
if (source[start + 1] === "/") {
|
|
232
|
+
const newline = source.indexOf("\n", start + 2);
|
|
233
|
+
return newline === -1 ? source.length : newline + 1;
|
|
234
|
+
}
|
|
235
|
+
if (source[start + 1] === "*") {
|
|
236
|
+
const close = source.indexOf("*/", start + 2);
|
|
237
|
+
return close === -1 ? source.length : close + 2;
|
|
238
|
+
}
|
|
239
|
+
return start + 1;
|
|
240
|
+
}
|
|
241
|
+
function matchingBrace(source, open) {
|
|
242
|
+
let depth = 1;
|
|
243
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
244
|
+
const character = source[index];
|
|
245
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
246
|
+
index = skipQuoted(source, index, character) - 1;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (character === "/" && (source[index + 1] === "/" || source[index + 1] === "*")) {
|
|
250
|
+
index = skipComment(source, index) - 1;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (character === "{") depth += 1;
|
|
254
|
+
else if (character === "}" && --depth === 0) return index;
|
|
255
|
+
}
|
|
256
|
+
return -1;
|
|
257
|
+
}
|
|
258
|
+
function codeBlockRanges(source) {
|
|
259
|
+
const ranges = [];
|
|
260
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
261
|
+
const character = source[index];
|
|
262
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
263
|
+
index = skipQuoted(source, index, character) - 1;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (character === "/" && (source[index + 1] === "/" || source[index + 1] === "*")) {
|
|
267
|
+
index = skipComment(source, index) - 1;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (character !== "@" || source[index + 1] !== "{") continue;
|
|
271
|
+
const close = matchingBrace(source, index + 1);
|
|
272
|
+
if (close !== -1) ranges.push({
|
|
273
|
+
start: index,
|
|
274
|
+
open: index + 1,
|
|
275
|
+
close,
|
|
276
|
+
end: close + 1
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
return ranges;
|
|
280
|
+
}
|
|
281
|
+
function bareAtOffsets(source) {
|
|
282
|
+
const offsets = [];
|
|
283
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
284
|
+
const character = source[index];
|
|
285
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
286
|
+
index = skipQuoted(source, index, character) - 1;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (character === "/" && (source[index + 1] === "/" || source[index + 1] === "*")) {
|
|
290
|
+
index = skipComment(source, index) - 1;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (character !== "@") continue;
|
|
294
|
+
const next = source[index + 1] ?? "";
|
|
295
|
+
if (next !== "{" && !/[A-Za-z0-9_]/u.test(next)) offsets.push(index);
|
|
296
|
+
}
|
|
297
|
+
return offsets;
|
|
298
|
+
}
|
|
299
|
+
function incompleteConstructRecovery(source, blankExpressionLines = false) {
|
|
300
|
+
const edits = [];
|
|
301
|
+
const expressionLines = [];
|
|
302
|
+
for (const offset of bareAtOffsets(source)) {
|
|
303
|
+
const lineStart = source.lastIndexOf("\n", offset - 1) + 1;
|
|
304
|
+
const newline = source.indexOf("\n", offset);
|
|
305
|
+
const lineEnd = newline === -1 ? source.length : newline;
|
|
306
|
+
const lineBefore = source.slice(lineStart, offset);
|
|
307
|
+
const trimmedBefore = source.slice(Math.max(0, offset - 96), offset).trimEnd();
|
|
308
|
+
let replacement = " ";
|
|
309
|
+
if (/@try\b/u.test(lineBefore)) replacement = "@pending {}";
|
|
310
|
+
else if (/@switch\b/u.test(lineBefore)) replacement = "@default: {}";
|
|
311
|
+
else if ("=+-*/%?:,(".includes(trimmedBefore.at(-1) ?? "")) {
|
|
312
|
+
replacement = "0";
|
|
313
|
+
expressionLines.push({
|
|
314
|
+
start: lineStart,
|
|
315
|
+
end: lineEnd
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
edits.push({
|
|
319
|
+
start: offset,
|
|
320
|
+
end: offset + 1,
|
|
321
|
+
replacement
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const recovery = createRecoverySource(source);
|
|
325
|
+
if (blankExpressionLines && expressionLines.length > 0) {
|
|
326
|
+
const merged = [];
|
|
327
|
+
for (const line of expressionLines) if (!merged.some((candidate) => candidate.start === line.start && candidate.end === line.end)) merged.push(line);
|
|
328
|
+
const retained = edits.filter((edit) => !merged.some((line) => line.start <= edit.start && edit.end <= line.end));
|
|
329
|
+
retained.push(...merged.map((line) => ({
|
|
330
|
+
...line,
|
|
331
|
+
replacement: " ".repeat(line.end - line.start)
|
|
332
|
+
})));
|
|
333
|
+
applyRecoveryEdits(recovery, retained);
|
|
334
|
+
} else applyRecoveryEdits(recovery, edits);
|
|
335
|
+
blankStandaloneEmptyCodeBlocks(recovery);
|
|
336
|
+
return {
|
|
337
|
+
recovery,
|
|
338
|
+
expressionLines
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function blankStandaloneEmptyCodeBlocks(recovery) {
|
|
342
|
+
const ranges = codeBlockRanges(recovery.text);
|
|
343
|
+
const edits = [];
|
|
344
|
+
for (const range of ranges) {
|
|
345
|
+
if (recovery.text.slice(range.open + 1, range.close).trim() !== "") continue;
|
|
346
|
+
const nested = ranges.some((candidate) => candidate.start < range.start && range.end < candidate.end);
|
|
347
|
+
const lineStart = recovery.text.lastIndexOf("\n", range.start - 1) + 1;
|
|
348
|
+
const linePrefix = recovery.text.slice(lineStart, range.start).trim();
|
|
349
|
+
if (!nested && linePrefix !== "") continue;
|
|
350
|
+
edits.push({
|
|
351
|
+
start: range.start,
|
|
352
|
+
end: range.end,
|
|
353
|
+
replacement: " ".repeat(range.end - range.start)
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
applyRecoveryEdits(recovery, edits);
|
|
357
|
+
}
|
|
358
|
+
function outerCodeBlocks(ranges) {
|
|
359
|
+
return ranges.filter((range) => !ranges.some((candidate) => candidate.start < range.start && range.end < candidate.end));
|
|
360
|
+
}
|
|
361
|
+
function nestingAt(source, start, end) {
|
|
362
|
+
let braces = 0;
|
|
363
|
+
let parentheses = 0;
|
|
364
|
+
let brackets = 0;
|
|
365
|
+
for (let index = start; index < end; index += 1) {
|
|
366
|
+
const character = source[index];
|
|
367
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
368
|
+
index = skipQuoted(source, index, character) - 1;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (character === "/" && (source[index + 1] === "/" || source[index + 1] === "*")) {
|
|
372
|
+
index = skipComment(source, index) - 1;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (character === "{") braces += 1;
|
|
376
|
+
else if (character === "}") braces = Math.max(0, braces - 1);
|
|
377
|
+
else if (character === "(") parentheses += 1;
|
|
378
|
+
else if (character === ")") parentheses = Math.max(0, parentheses - 1);
|
|
379
|
+
else if (character === "[") brackets += 1;
|
|
380
|
+
else if (character === "]") brackets = Math.max(0, brackets - 1);
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
braces,
|
|
384
|
+
parentheses,
|
|
385
|
+
brackets
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function firstRenderStart(source, block, limit = block.close) {
|
|
389
|
+
let braces = 0;
|
|
390
|
+
let parentheses = 0;
|
|
391
|
+
let brackets = 0;
|
|
392
|
+
for (let index = block.open + 1; index < limit; index += 1) {
|
|
393
|
+
const character = source[index];
|
|
394
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
395
|
+
index = skipQuoted(source, index, character) - 1;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (character === "/" && (source[index + 1] === "/" || source[index + 1] === "*")) {
|
|
399
|
+
index = skipComment(source, index) - 1;
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (character === "{") {
|
|
403
|
+
braces += 1;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (character === "}") {
|
|
407
|
+
braces = Math.max(0, braces - 1);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (character === "(") {
|
|
411
|
+
parentheses += 1;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (character === ")") {
|
|
415
|
+
parentheses = Math.max(0, parentheses - 1);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (character === "[") {
|
|
419
|
+
brackets += 1;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (character === "]") {
|
|
423
|
+
brackets = Math.max(0, brackets - 1);
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (braces !== 0 || parentheses !== 0 || brackets !== 0) continue;
|
|
427
|
+
if ([
|
|
428
|
+
"@if",
|
|
429
|
+
"@for",
|
|
430
|
+
"@switch",
|
|
431
|
+
"@try"
|
|
432
|
+
].some((token) => source.startsWith(token, index))) return index;
|
|
433
|
+
if (character !== "<" || !/[A-Za-z>{/]/u.test(source[index + 1] ?? "")) continue;
|
|
434
|
+
let previous = index - 1;
|
|
435
|
+
while (previous > block.open && /\s/u.test(source[previous])) previous -= 1;
|
|
436
|
+
if (previous === block.open || ";{}".includes(source[previous])) return index;
|
|
437
|
+
}
|
|
438
|
+
return -1;
|
|
439
|
+
}
|
|
440
|
+
function isolateCompletionCandidate(recovery) {
|
|
441
|
+
const placeholder = recovery.text.indexOf(COMPLETION_PLACEHOLDER);
|
|
442
|
+
if (placeholder === -1) return;
|
|
443
|
+
const ranges = outerCodeBlocks(codeBlockRanges(recovery.text));
|
|
444
|
+
const target = ranges.find((range) => range.start < placeholder && placeholder < range.end);
|
|
445
|
+
const edits = [];
|
|
446
|
+
for (const range of ranges) {
|
|
447
|
+
if (range === target) continue;
|
|
448
|
+
edits.push({
|
|
449
|
+
start: range.open + 1,
|
|
450
|
+
end: range.close,
|
|
451
|
+
replacement: " ".repeat(range.close - range.open - 1)
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
if (target !== void 0) {
|
|
455
|
+
const placeholderEnd = placeholder + 15;
|
|
456
|
+
const lineStart = recovery.text.lastIndexOf("\n", placeholder - 1) + 1;
|
|
457
|
+
const newline = recovery.text.indexOf("\n", placeholderEnd);
|
|
458
|
+
const lineEnd = newline === -1 ? recovery.text.length : newline;
|
|
459
|
+
const linePrefix = recovery.text.slice(lineStart, placeholder);
|
|
460
|
+
if (/\b(?:const|let|var|return)\b/u.test(linePrefix) || "=+-*/%?:,(".includes(linePrefix.trimEnd().at(-1) ?? "")) {
|
|
461
|
+
edits.push({
|
|
462
|
+
start: target.open + 1,
|
|
463
|
+
end: lineStart,
|
|
464
|
+
replacement: " ".repeat(Math.max(0, lineStart - target.open - 1))
|
|
465
|
+
});
|
|
466
|
+
edits.push({
|
|
467
|
+
start: lineEnd,
|
|
468
|
+
end: target.close,
|
|
469
|
+
replacement: " ".repeat(Math.max(0, target.close - lineEnd))
|
|
470
|
+
});
|
|
471
|
+
} else {
|
|
472
|
+
const nesting = nestingAt(recovery.text, target.open + 1, placeholder);
|
|
473
|
+
if (nesting.braces === 0 && nesting.parentheses === 0 && nesting.brackets === 0) edits.push({
|
|
474
|
+
start: placeholderEnd,
|
|
475
|
+
end: target.close,
|
|
476
|
+
replacement: " ".repeat(target.close - placeholderEnd)
|
|
477
|
+
});
|
|
478
|
+
else {
|
|
479
|
+
const switchStart = recovery.text.lastIndexOf("@switch", placeholder);
|
|
480
|
+
if (switchStart > target.open) {
|
|
481
|
+
const switchOpen = recovery.text.indexOf("{", switchStart + 7);
|
|
482
|
+
const switchClose = switchOpen === -1 ? -1 : matchingBrace(recovery.text, switchOpen);
|
|
483
|
+
if (switchOpen < placeholder && placeholder < switchClose) edits.push({
|
|
484
|
+
start: switchClose + 1,
|
|
485
|
+
end: target.close,
|
|
486
|
+
replacement: " ".repeat(target.close - switchClose - 1)
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
applyRecoveryEdits(recovery, edits);
|
|
493
|
+
blankStandaloneEmptyCodeBlocks(recovery);
|
|
494
|
+
}
|
|
495
|
+
function forwardOffset(offset, edits) {
|
|
496
|
+
let delta = 0;
|
|
497
|
+
for (const edit of edits) if (edit.start < offset) delta += edit.replacement.length - (edit.end - edit.start);
|
|
498
|
+
return offset + delta;
|
|
499
|
+
}
|
|
500
|
+
function wrapRenderBlocks(recovery) {
|
|
501
|
+
const ranges = outerCodeBlocks(codeBlockRanges(recovery.text));
|
|
502
|
+
const wrappers = [];
|
|
503
|
+
const edits = [];
|
|
504
|
+
for (const block of ranges) {
|
|
505
|
+
const first = firstRenderStart(recovery.text, block);
|
|
506
|
+
if (first === -1) continue;
|
|
507
|
+
const placeholder = recovery.text.indexOf(COMPLETION_PLACEHOLDER, first);
|
|
508
|
+
if (placeholder !== -1 && placeholder < block.close) {
|
|
509
|
+
const nesting = nestingAt(recovery.text, block.open + 1, placeholder);
|
|
510
|
+
let previous = placeholder - 1;
|
|
511
|
+
while (previous > block.open && /\s/u.test(recovery.text[previous])) previous -= 1;
|
|
512
|
+
if (nesting.braces === 0 && nesting.parentheses === 0 && nesting.brackets === 0 && recovery.text[previous] !== "{") {
|
|
513
|
+
edits.push({
|
|
514
|
+
start: placeholder,
|
|
515
|
+
end: placeholder,
|
|
516
|
+
replacement: "{"
|
|
517
|
+
});
|
|
518
|
+
edits.push({
|
|
519
|
+
start: placeholder + 15,
|
|
520
|
+
end: placeholder + 15,
|
|
521
|
+
replacement: "}"
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
edits.push({
|
|
526
|
+
start: first,
|
|
527
|
+
end: first,
|
|
528
|
+
replacement: "<>"
|
|
529
|
+
});
|
|
530
|
+
edits.push({
|
|
531
|
+
start: block.close,
|
|
532
|
+
end: block.close,
|
|
533
|
+
replacement: "</>"
|
|
534
|
+
});
|
|
535
|
+
wrappers.push({
|
|
536
|
+
first,
|
|
537
|
+
close: block.close
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
if (wrappers.length === 0) return [];
|
|
541
|
+
const fragments = wrappers.map((wrapper) => ({
|
|
542
|
+
start: forwardOffset(wrapper.first, edits),
|
|
543
|
+
end: forwardOffset(wrapper.close, edits) + 3
|
|
544
|
+
}));
|
|
545
|
+
applyRecoveryEdits(recovery, edits);
|
|
546
|
+
return fragments;
|
|
547
|
+
}
|
|
548
|
+
function isRecoveryLayoutText(node) {
|
|
549
|
+
if (node?.type !== "JSXText" || typeof node.value !== "string") return false;
|
|
550
|
+
return node.value.replace(/\/\/[^\r\n]*|\/\*[\s\S]*?\*\//gu, "").trim() === "";
|
|
551
|
+
}
|
|
552
|
+
function placeholderStatement(node) {
|
|
553
|
+
if (node?.type !== "JSXExpressionContainer" || node.expression?.type !== "Identifier" || node.expression.name !== COMPLETION_PLACEHOLDER) return null;
|
|
554
|
+
return {
|
|
555
|
+
type: "ExpressionStatement",
|
|
556
|
+
start: node.start,
|
|
557
|
+
end: node.end,
|
|
558
|
+
expression: node.expression
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function flattenSyntheticFragments(program, fragments) {
|
|
562
|
+
const expected = new Set(fragments.map((fragment) => `${fragment.start}:${fragment.end}`));
|
|
563
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
564
|
+
const stack = [program];
|
|
565
|
+
while (stack.length > 0) {
|
|
566
|
+
const node = stack.pop();
|
|
567
|
+
if (node === null || typeof node !== "object" || seen.has(node)) continue;
|
|
568
|
+
seen.add(node);
|
|
569
|
+
if (node.type === "JSXCodeBlock" && node.render?.type === "JSXFragment" && expected.has(`${node.render.start}:${node.render.end}`)) {
|
|
570
|
+
const converted = (node.render.children ?? []).filter((child) => !isRecoveryLayoutText(child)).map((child) => placeholderStatement(child) ?? child);
|
|
571
|
+
const last = converted.at(-1);
|
|
572
|
+
if (last?.type === "ExpressionStatement" && last.expression?.name === COMPLETION_PLACEHOLDER) {
|
|
573
|
+
node.body.push(...converted);
|
|
574
|
+
node.render = null;
|
|
575
|
+
} else {
|
|
576
|
+
node.body.push(...converted.slice(0, -1));
|
|
577
|
+
node.render = last ?? null;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
for (const [key, value] of Object.entries(node)) {
|
|
581
|
+
if (key === "parent" || value === null || typeof value !== "object") continue;
|
|
582
|
+
if (Array.isArray(value)) for (let index = value.length - 1; index >= 0; index -= 1) stack.push(value[index]);
|
|
583
|
+
else stack.push(value);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function repairIncompleteElement(program, openingStart) {
|
|
588
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
589
|
+
const stack = [program];
|
|
590
|
+
while (stack.length > 0) {
|
|
591
|
+
const node = stack.pop();
|
|
592
|
+
if (node === null || typeof node !== "object" || seen.has(node)) continue;
|
|
593
|
+
seen.add(node);
|
|
594
|
+
if (node.type === "JSXElement" && node.openingElement?.start === openingStart) {
|
|
595
|
+
node.closingElement = null;
|
|
596
|
+
node.unclosed = true;
|
|
597
|
+
node.end = node.openingElement.end;
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
for (const [key, value] of Object.entries(node)) {
|
|
601
|
+
if (key === "parent" || value === null || typeof value !== "object") continue;
|
|
602
|
+
if (Array.isArray(value)) for (let index = value.length - 1; index >= 0; index -= 1) stack.push(value[index]);
|
|
603
|
+
else stack.push(value);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
function tryIncompleteClosingRecovery(parser, filename, recovery, errors) {
|
|
609
|
+
const diagnostic = errors.find((error) => /^unterminated JSX element starting at byte \d+$/u.test(error?.message));
|
|
610
|
+
if (diagnostic === void 0) return null;
|
|
611
|
+
const match = /byte (?<start>\d+)$/u.exec(diagnostic.message);
|
|
612
|
+
const openingStart = Number(match?.groups?.start);
|
|
613
|
+
if (!Number.isInteger(openingStart)) return null;
|
|
614
|
+
const opening = /^<(?<name>[A-Za-z][\w.:-]*)\b[^>]*>/u.exec(recovery.text.slice(openingStart));
|
|
615
|
+
if (opening?.groups?.name === void 0 || opening[0].endsWith("/>")) return null;
|
|
616
|
+
const block = codeBlockRanges(recovery.text).filter((candidate) => candidate.start < openingStart && openingStart < candidate.close).sort((left, right) => left.end - left.start - (right.end - right.start))[0];
|
|
617
|
+
if (block === void 0) return null;
|
|
618
|
+
replaceRecoveryRange(recovery, block.close, block.close, `</${opening.groups.name}>`);
|
|
619
|
+
const result = parser.parseSync(filename, recovery.text, PARSER_OPTIONS);
|
|
620
|
+
if (result?.program === null || (result?.errors?.length ?? 0) > 0) return null;
|
|
621
|
+
if (!repairIncompleteElement(result.program, openingStart)) return null;
|
|
622
|
+
remapRecoveredTree(result.program, recovery.boundaries);
|
|
623
|
+
if (Array.isArray(result.comments)) remapRecoveredTree(result.comments, recovery.boundaries);
|
|
624
|
+
return result;
|
|
625
|
+
}
|
|
626
|
+
function normalizeCompletionPlaceholderSiblings(program) {
|
|
627
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
628
|
+
const stack = [program];
|
|
629
|
+
while (stack.length > 0) {
|
|
630
|
+
const node = stack.pop();
|
|
631
|
+
if (node === null || typeof node !== "object" || seen.has(node)) continue;
|
|
632
|
+
seen.add(node);
|
|
633
|
+
if (Array.isArray(node.children)) for (let index = 0; index < node.children.length; index += 1) {
|
|
634
|
+
if (node.children[index]?.expression?.name !== COMPLETION_PLACEHOLDER) continue;
|
|
635
|
+
while (index > 0 && node.children[index - 1]?.type === "JSXText") {
|
|
636
|
+
const previous = node.children[index - 1];
|
|
637
|
+
if (typeof previous.value !== "string" || previous.value.trim() !== "") break;
|
|
638
|
+
node.children.splice(index - 1, 1);
|
|
639
|
+
index -= 1;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
for (const [key, value] of Object.entries(node)) {
|
|
643
|
+
if (key === "parent" || value === null || typeof value !== "object") continue;
|
|
644
|
+
if (Array.isArray(value)) for (let index = value.length - 1; index >= 0; index -= 1) stack.push(value[index]);
|
|
645
|
+
else stack.push(value);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
function parseLooseCandidate(parser, filename, recovery) {
|
|
650
|
+
let result;
|
|
651
|
+
try {
|
|
652
|
+
result = parser.parseSync(filename, recovery.text, PARSER_OPTIONS);
|
|
653
|
+
} catch (error) {
|
|
654
|
+
if (!isRecoverableLooseShapeFailure(error)) throw error;
|
|
655
|
+
return {
|
|
656
|
+
result: null,
|
|
657
|
+
program: null,
|
|
658
|
+
errors: [{ message: error.message }]
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
return {
|
|
662
|
+
result,
|
|
663
|
+
program: result?.program ?? null,
|
|
664
|
+
errors: result?.errors ?? []
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
function recoveredResult(result, recovery, fragments = []) {
|
|
668
|
+
if (fragments.length > 0) flattenSyntheticFragments(result.program, fragments);
|
|
669
|
+
remapRecoveredTree(result.program, recovery.boundaries);
|
|
670
|
+
if (Array.isArray(result.comments)) remapRecoveredTree(result.comments, recovery.boundaries);
|
|
671
|
+
if (result.program !== null) normalizeCompletionPlaceholderSiblings(result.program);
|
|
672
|
+
return result;
|
|
673
|
+
}
|
|
674
|
+
function looseRecovery(parser, filename, source) {
|
|
675
|
+
const prepared = incompleteConstructRecovery(source, false);
|
|
676
|
+
const variants = [{
|
|
677
|
+
recovery: prepared.recovery,
|
|
678
|
+
allowRenderWrapping: prepared.expressionLines.length === 0
|
|
679
|
+
}];
|
|
680
|
+
if (prepared.expressionLines.length > 0) variants.push({
|
|
681
|
+
recovery: incompleteConstructRecovery(source, true).recovery,
|
|
682
|
+
allowRenderWrapping: true
|
|
683
|
+
});
|
|
684
|
+
for (const { recovery, allowRenderWrapping } of variants) {
|
|
685
|
+
isolateCompletionCandidate(recovery);
|
|
686
|
+
let parsed = parseLooseCandidate(parser, filename, recovery);
|
|
687
|
+
if (parsed.program !== null && parsed.errors.length === 0) return recoveredResult(parsed.result, recovery);
|
|
688
|
+
const closing = tryIncompleteClosingRecovery(parser, filename, recovery, parsed.errors);
|
|
689
|
+
if (closing !== null) return closing;
|
|
690
|
+
if (!allowRenderWrapping || !parsed.errors.some((error) => LOOSE_RENDER_ERRORS.has(error?.message))) continue;
|
|
691
|
+
const fragments = wrapRenderBlocks(recovery);
|
|
692
|
+
if (fragments.length === 0) continue;
|
|
693
|
+
parsed = parseLooseCandidate(parser, filename, recovery);
|
|
694
|
+
if (parsed.program !== null && parsed.errors.length === 0) return recoveredResult(parsed.result, recovery, fragments);
|
|
695
|
+
}
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
function findSubmoduleSources(source) {
|
|
699
|
+
const candidates = [];
|
|
700
|
+
let index = 0;
|
|
701
|
+
while (index < source.length) {
|
|
702
|
+
const character = source[index];
|
|
703
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
704
|
+
index = skipQuoted(source, index, character);
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
if (character === "/" && source[index + 1] === "/") {
|
|
708
|
+
const newline = source.indexOf("\n", index + 2);
|
|
709
|
+
index = newline === -1 ? source.length : newline + 1;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
if (character === "/" && source[index + 1] === "*") {
|
|
713
|
+
const close = source.indexOf("*/", index + 2);
|
|
714
|
+
index = close === -1 ? source.length : close + 2;
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const identifier = readIdentifier(source, index);
|
|
718
|
+
if (identifier === null) {
|
|
719
|
+
index += codePointAt(source, index).width || 1;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
index = identifier.end;
|
|
723
|
+
if (identifier.name !== "from") continue;
|
|
724
|
+
const replaceStart = index;
|
|
725
|
+
while (index < source.length && WHITESPACE.test(source[index])) index += 1;
|
|
726
|
+
if (index === replaceStart) continue;
|
|
727
|
+
const moduleSource = readIdentifier(source, index);
|
|
728
|
+
if (moduleSource === null) continue;
|
|
729
|
+
candidates.push({
|
|
730
|
+
replaceStart,
|
|
731
|
+
replaceEnd: moduleSource.end,
|
|
732
|
+
name: moduleSource.name,
|
|
733
|
+
start: moduleSource.start,
|
|
734
|
+
end: moduleSource.end
|
|
735
|
+
});
|
|
736
|
+
index = moduleSource.end;
|
|
737
|
+
}
|
|
738
|
+
return candidates;
|
|
739
|
+
}
|
|
740
|
+
function submoduleRecovery(source, errors) {
|
|
741
|
+
if (typeof source !== "string") return null;
|
|
742
|
+
const unexpectedStarts = /* @__PURE__ */ new Set();
|
|
743
|
+
for (const error of errors) {
|
|
744
|
+
if (error?.message !== "Unexpected token" || !Array.isArray(error?.labels)) continue;
|
|
745
|
+
for (const label of error.labels) if (Number.isInteger(label?.start)) unexpectedStarts.add(label.start);
|
|
746
|
+
}
|
|
747
|
+
if (unexpectedStarts.size === 0) return null;
|
|
748
|
+
const candidates = findSubmoduleSources(source);
|
|
749
|
+
if (!candidates.some((candidate) => unexpectedStarts.has(candidate.start))) return null;
|
|
750
|
+
let rewritten = source;
|
|
751
|
+
for (let index = candidates.length - 1; index >= 0; index -= 1) {
|
|
752
|
+
const candidate = candidates[index];
|
|
753
|
+
const length = candidate.replaceEnd - candidate.replaceStart;
|
|
754
|
+
const placeholder = `"${" ".repeat(length - 2)}"`;
|
|
755
|
+
rewritten = rewritten.slice(0, candidate.replaceStart) + placeholder + rewritten.slice(candidate.replaceEnd);
|
|
756
|
+
}
|
|
757
|
+
return {
|
|
758
|
+
source: rewritten,
|
|
759
|
+
candidates
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function restoreSubmoduleSources(program, candidates) {
|
|
763
|
+
const replacements = new Map(candidates.map((candidate) => [`${candidate.replaceStart}:${candidate.replaceEnd}`, candidate]));
|
|
764
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
765
|
+
const stack = [program];
|
|
766
|
+
while (stack.length > 0) {
|
|
767
|
+
const node = stack.pop();
|
|
768
|
+
if (node === null || typeof node !== "object" || seen.has(node)) continue;
|
|
769
|
+
seen.add(node);
|
|
770
|
+
if (SOURCE_DECLARATION_TYPES.has(node.type) && node.source !== null) {
|
|
771
|
+
const replacement = replacements.get(`${node.source?.start}:${node.source?.end}`);
|
|
772
|
+
if (replacement !== void 0) node.source = {
|
|
773
|
+
type: "Identifier",
|
|
774
|
+
name: replacement.name,
|
|
775
|
+
start: replacement.start,
|
|
776
|
+
end: replacement.end
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
for (const [key, value] of Object.entries(node)) {
|
|
780
|
+
if (key === "parent" || value === null || typeof value !== "object") continue;
|
|
781
|
+
if (Array.isArray(value)) for (let index = value.length - 1; index >= 0; index -= 1) stack.push(value[index]);
|
|
782
|
+
else stack.push(value);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function compatibleComment(comment, positionAt) {
|
|
787
|
+
return {
|
|
788
|
+
...comment,
|
|
789
|
+
loc: comment?.loc ?? {
|
|
790
|
+
start: positionAt(comment?.start),
|
|
791
|
+
end: positionAt(comment?.end)
|
|
792
|
+
},
|
|
793
|
+
context: comment?.context ?? null
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
function keywordSpan(source, keyword, start, end, positionAt) {
|
|
797
|
+
const offset = source.indexOf(keyword, Math.max(0, start));
|
|
798
|
+
if (offset === -1 || offset + keyword.length > end) return null;
|
|
799
|
+
return {
|
|
800
|
+
start: offset,
|
|
801
|
+
end: offset + keyword.length,
|
|
802
|
+
loc: {
|
|
803
|
+
start: positionAt(offset),
|
|
804
|
+
end: positionAt(offset + keyword.length)
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
function unwrapParenthesizedExpression(value) {
|
|
809
|
+
let expression = value;
|
|
810
|
+
let parenthesized = false;
|
|
811
|
+
while (expression?.type === "ParenthesizedExpression") {
|
|
812
|
+
expression = expression.expression;
|
|
813
|
+
parenthesized = true;
|
|
814
|
+
}
|
|
815
|
+
if (parenthesized && expression !== null && typeof expression === "object") {
|
|
816
|
+
expression.metadata ??= { path: [] };
|
|
817
|
+
expression.metadata.path ??= [];
|
|
818
|
+
expression.metadata.parenthesized = true;
|
|
819
|
+
}
|
|
820
|
+
return expression;
|
|
821
|
+
}
|
|
822
|
+
function isClosedTemplateElement(value) {
|
|
823
|
+
if (value?.type === "JSXFragment") return value.closingFragment != null;
|
|
824
|
+
return (value?.type === "JSXElement" || value?.type === "JSXStyleElement") && value.openingElement?.selfClosing === false && value.closingElement != null;
|
|
825
|
+
}
|
|
826
|
+
function normalizeTemplateTextChildren(value, positionAt, trimInitialLayout) {
|
|
827
|
+
if (value.type !== "JSXElement" && value.type !== "JSXFragment" || !Array.isArray(value.children)) return;
|
|
828
|
+
let write = 0;
|
|
829
|
+
for (let read = 0; read < value.children.length; read += 1) {
|
|
830
|
+
const child = value.children[read];
|
|
831
|
+
if (child?.type === "JSXText" && typeof child.value === "string") {
|
|
832
|
+
if (child.value.trim() === "" && /[\r\n]/u.test(child.value)) continue;
|
|
833
|
+
const previous = write === 0 ? null : value.children[write - 1];
|
|
834
|
+
if (write === 0 && trimInitialLayout || isClosedTemplateElement(previous)) {
|
|
835
|
+
const leading = /^[ \t\r\n]*/u.exec(child.value)?.[0] ?? "";
|
|
836
|
+
if (/[\r\n]/u.test(leading)) {
|
|
837
|
+
child.value = child.value.slice(leading.length);
|
|
838
|
+
if (typeof child.raw === "string") child.raw = child.raw.slice(leading.length);
|
|
839
|
+
if (Number.isInteger(child.start)) {
|
|
840
|
+
child.start += leading.length;
|
|
841
|
+
if (child.loc?.start != null) child.loc.start = positionAt(child.start);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
value.children[write] = child;
|
|
847
|
+
write += 1;
|
|
848
|
+
}
|
|
849
|
+
value.children.length = write;
|
|
850
|
+
}
|
|
851
|
+
function stampTemplateBlock(value) {
|
|
852
|
+
if (value?.type !== "BlockStatement") return;
|
|
853
|
+
value.metadata ??= { path: [] };
|
|
854
|
+
value.metadata.path ??= [];
|
|
855
|
+
value.metadata.native_tsrx_template_block = true;
|
|
856
|
+
value.metadata.templateMode = "script";
|
|
857
|
+
value.metadata.allows_native_return = false;
|
|
858
|
+
}
|
|
859
|
+
function materializeDirectiveBlockMetadata(value) {
|
|
860
|
+
if (value.type === "JSXIfExpression") {
|
|
861
|
+
stampTemplateBlock(value.consequent);
|
|
862
|
+
stampTemplateBlock(value.alternate);
|
|
863
|
+
} else if (value.type === "JSXForExpression") {
|
|
864
|
+
stampTemplateBlock(value.body);
|
|
865
|
+
stampTemplateBlock(value.empty);
|
|
866
|
+
} else if (value.type === "JSXTryExpression") {
|
|
867
|
+
stampTemplateBlock(value.block);
|
|
868
|
+
stampTemplateBlock(value.pending);
|
|
869
|
+
stampTemplateBlock(value.handler);
|
|
870
|
+
stampTemplateBlock(value.handler?.body);
|
|
871
|
+
} else if (value.type === "JSXSwitchExpression") for (const switchCase of value.cases ?? []) for (let index = 0; index < (switchCase?.consequent?.length ?? 0); index += 1) {
|
|
872
|
+
const statement = switchCase.consequent[index];
|
|
873
|
+
if (statement?.type === "BlockStatement" && statement.body?.length === 1 && statement.body[0]?.type === "ExpressionStatement") switchCase.consequent[index] = {
|
|
874
|
+
type: "JSXExpressionContainer",
|
|
875
|
+
start: statement.start,
|
|
876
|
+
end: statement.end,
|
|
877
|
+
expression: statement.body[0].expression
|
|
878
|
+
};
|
|
879
|
+
else stampTemplateBlock(statement);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function materializeDirectiveRange(value, positionAt) {
|
|
883
|
+
let finalBranch;
|
|
884
|
+
if (value.type === "JSXIfExpression") finalBranch = value.alternate ?? value.consequent;
|
|
885
|
+
else if (value.type === "JSXForExpression") finalBranch = value.empty ?? value.body;
|
|
886
|
+
else if (value.type === "JSXTryExpression") finalBranch = value.handler ?? value.pending ?? value.block;
|
|
887
|
+
else if (value.type === "JSXSwitchExpression") finalBranch = value.cases?.at(-1);
|
|
888
|
+
if (!Number.isInteger(finalBranch?.end) || finalBranch.end <= value.end) return;
|
|
889
|
+
value.end = finalBranch.end;
|
|
890
|
+
if (value.loc?.end != null) value.loc.end = positionAt(value.end);
|
|
891
|
+
}
|
|
892
|
+
function omitTsrxCoreCompatDefault(type, key, value) {
|
|
893
|
+
if (Array.isArray(value) && value.length === 0 && (key === "decorators" || key === "attributes" && (type === "ExportAllDeclaration" || type === "ExportNamedDeclaration" || type === "ImportDeclaration") || key === "implements" && (type === "ClassDeclaration" || type === "ClassExpression") || key === "extends" && type === "TSInterfaceDeclaration")) return true;
|
|
894
|
+
if (value == null && (key === "accessibility" || key === "directive" || key === "hashbang" || key === "options" || key === "phase" || key === "returnType" || key === "superTypeArguments" || key === "typeAnnotation" || key === "typeArguments" || key === "typeParameters" || type === "RestElement" && key === "value")) return true;
|
|
895
|
+
if (value !== false) return false;
|
|
896
|
+
if (key === "abstract" || key === "const" || key === "declare" || key === "definite" || key === "global" || key === "in" || key === "out" || key === "override" || key === "readonly" || key === "static") return true;
|
|
897
|
+
return key === "optional" && (type === "ArrayPattern" || type === "AssignmentPattern" || type === "Identifier" || type === "MethodDefinition" || type === "ObjectPattern" || type === "Property" || type === "PropertyDefinition" || type === "RestElement" || type === "TSMethodSignature" || type === "TSPropertySignature");
|
|
898
|
+
}
|
|
899
|
+
function stripOxcDefaultFields(value) {
|
|
900
|
+
for (const key in value) if (omitTsrxCoreCompatDefault(value.type, key, value[key])) delete value[key];
|
|
901
|
+
}
|
|
902
|
+
function materializeCompatibilityProgram(program, source, filename, loose, positionAt) {
|
|
903
|
+
if (typeof source !== "string") return;
|
|
904
|
+
const defaultsStripped = program[TSRX_CORE_COMPAT_DEFAULTS_STRIPPED] === true;
|
|
905
|
+
if (defaultsStripped) delete program[TSRX_CORE_COMPAT_DEFAULTS_STRIPPED];
|
|
906
|
+
const stack = [program];
|
|
907
|
+
const insideHeadStack = [false];
|
|
908
|
+
const scriptSetupStack = [false];
|
|
909
|
+
const templateElements = [];
|
|
910
|
+
while (stack.length > 0) {
|
|
911
|
+
const value = stack.pop();
|
|
912
|
+
const insideHead = insideHeadStack.pop();
|
|
913
|
+
const insideScriptSetup = scriptSetupStack.pop();
|
|
914
|
+
if (value === null || typeof value !== "object") continue;
|
|
915
|
+
if (value.type === "StyleSheet") continue;
|
|
916
|
+
if (value.type === "Program") {
|
|
917
|
+
value.start = 0;
|
|
918
|
+
value.end = source.length;
|
|
919
|
+
value.loc = {
|
|
920
|
+
start: positionAt(0),
|
|
921
|
+
end: positionAt(source.length)
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
if (!defaultsStripped) stripOxcDefaultFields(value);
|
|
925
|
+
if (Number.isInteger(value.start) && Number.isInteger(value.end) && value.loc == null) value.loc = {
|
|
926
|
+
start: positionAt(value.start),
|
|
927
|
+
end: positionAt(value.end)
|
|
928
|
+
};
|
|
929
|
+
if (value.type === "JSXElement" || value.type === "JSXFragment" || value.type === "JSXStyleElement") {
|
|
930
|
+
value.metadata ??= { path: [] };
|
|
931
|
+
value.metadata.path ??= [];
|
|
932
|
+
value.metadata.native_tsrx = true;
|
|
933
|
+
const elementName = value.openingElement?.name?.name;
|
|
934
|
+
value.metadata.templateMode = value.type === "JSXStyleElement" || elementName === "script" || value.openingElement?.selfClosing === true ? "script" : "template";
|
|
935
|
+
templateElements.push(value);
|
|
936
|
+
normalizeTemplateTextChildren(value, positionAt, insideScriptSetup);
|
|
937
|
+
}
|
|
938
|
+
if (value.type === "TSModuleDeclaration") {
|
|
939
|
+
value.metadata ??= { path: [] };
|
|
940
|
+
value.metadata.path ??= [];
|
|
941
|
+
value.metadata.module_keyword = value.kind;
|
|
942
|
+
}
|
|
943
|
+
materializeDirectiveBlockMetadata(value);
|
|
944
|
+
materializeDirectiveRange(value, positionAt);
|
|
945
|
+
if ((value.type === "JSXIfExpression" || value.type === "IfStatement") && value.alternate != null && value.alternateKeyword == null) value.alternateKeyword = keywordSpan(source, "@else", value.consequent?.end ?? value.start, value.alternate?.end ?? value.end, positionAt);
|
|
946
|
+
else if (value.type === "JSXForExpression" && value.empty != null && value.emptyKeyword == null) value.emptyKeyword = keywordSpan(source, "@empty", value.body?.end ?? value.start, value.empty?.end ?? value.end, positionAt);
|
|
947
|
+
else if (value.type === "SwitchCase" && value.keyword == null) value.keyword = keywordSpan(source, value.test == null ? "@default" : "@case", value.start, value.end, positionAt);
|
|
948
|
+
else if (value.type === "JSXTryExpression") {
|
|
949
|
+
if (value.pending != null && value.pendingKeyword == null) value.pendingKeyword = keywordSpan(source, "@pending", value.block?.end ?? value.start, value.pending?.end ?? value.end, positionAt);
|
|
950
|
+
if (value.handler != null && value.handlerKeyword == null) value.handlerKeyword = keywordSpan(source, "@catch", value.pending?.end ?? value.block?.end ?? value.start, value.handler?.end ?? value.end, positionAt);
|
|
951
|
+
}
|
|
952
|
+
if (value.type === "JSXStyleElement" && typeof value.css === "string") {
|
|
953
|
+
const style = parse_style(value.css, {
|
|
954
|
+
filename,
|
|
955
|
+
line: value.openingElement?.loc?.start?.line ?? value.loc?.start?.line ?? 1,
|
|
956
|
+
column: value.openingElement?.loc?.start?.column ?? value.loc?.start?.column ?? 0
|
|
957
|
+
}, { loose });
|
|
958
|
+
value.children = [style];
|
|
959
|
+
if (!insideHead) {
|
|
960
|
+
value.metadata ??= { path: [] };
|
|
961
|
+
value.metadata.styleScopeHash = style.hash;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const elementName = value.openingElement?.name?.name;
|
|
965
|
+
const childInsideHead = insideHead || value.type === "JSXElement" && elementName === "head";
|
|
966
|
+
for (const key in value) {
|
|
967
|
+
let child = value[key];
|
|
968
|
+
if (key === "parent" || key === "loc" || key === "metadata" || key.endsWith("Keyword") || child === null || typeof child !== "object") continue;
|
|
969
|
+
const childInsideScriptSetup = insideScriptSetup || value.type === "JSXCodeBlock" && key === "body";
|
|
970
|
+
if (Array.isArray(child)) for (let index = child.length - 1; index >= 0; index -= 1) {
|
|
971
|
+
const unwrapped = unwrapParenthesizedExpression(child[index]);
|
|
972
|
+
if (unwrapped !== child[index]) child[index] = unwrapped;
|
|
973
|
+
stack.push(unwrapped);
|
|
974
|
+
insideHeadStack.push(childInsideHead);
|
|
975
|
+
scriptSetupStack.push(childInsideScriptSetup);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
const unwrapped = unwrapParenthesizedExpression(child);
|
|
979
|
+
if (unwrapped !== child) {
|
|
980
|
+
value[key] = unwrapped;
|
|
981
|
+
child = unwrapped;
|
|
982
|
+
}
|
|
983
|
+
stack.push(child);
|
|
984
|
+
insideHeadStack.push(childInsideHead);
|
|
985
|
+
scriptSetupStack.push(childInsideScriptSetup);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
templateElements.sort((left, right) => left.start - right.start || right.end - left.end);
|
|
990
|
+
for (let index = 0; index < templateElements.length; index += 1) templateElements[index].metadata.commentContainerId = index + 1;
|
|
991
|
+
}
|
|
992
|
+
function missingProgramError(filename) {
|
|
993
|
+
const error = /* @__PURE__ */ new SyntaxError(`@tsrx/oxc/parser did not return a Program for ${filename}`);
|
|
994
|
+
error.code = void 0;
|
|
995
|
+
error.pos = void 0;
|
|
996
|
+
error.raisedAt = void 0;
|
|
997
|
+
error.end = void 0;
|
|
998
|
+
error.loc = void 0;
|
|
999
|
+
error.fileName = filename;
|
|
1000
|
+
error.type = "fatal";
|
|
1001
|
+
return error;
|
|
1002
|
+
}
|
|
1003
|
+
function addBindingNames(pattern, bindings) {
|
|
1004
|
+
if (pattern === null || typeof pattern !== "object") return;
|
|
1005
|
+
switch (pattern.type) {
|
|
1006
|
+
case "Identifier":
|
|
1007
|
+
bindings.add(pattern.name);
|
|
1008
|
+
break;
|
|
1009
|
+
case "RestElement":
|
|
1010
|
+
addBindingNames(pattern.argument, bindings);
|
|
1011
|
+
break;
|
|
1012
|
+
case "AssignmentPattern":
|
|
1013
|
+
addBindingNames(pattern.left, bindings);
|
|
1014
|
+
break;
|
|
1015
|
+
case "ArrayPattern":
|
|
1016
|
+
for (const element of pattern.elements ?? []) addBindingNames(element, bindings);
|
|
1017
|
+
break;
|
|
1018
|
+
case "ObjectPattern":
|
|
1019
|
+
for (const property of pattern.properties ?? []) addBindingNames(property?.type === "RestElement" ? property.argument : property?.value, bindings);
|
|
1020
|
+
break;
|
|
1021
|
+
case "TSParameterProperty": addBindingNames(pattern.parameter, bindings);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
function addDeclarationBindings(declaration, bindings) {
|
|
1025
|
+
if (declaration === null || typeof declaration !== "object") return;
|
|
1026
|
+
switch (declaration.type) {
|
|
1027
|
+
case "VariableDeclaration":
|
|
1028
|
+
for (const declarator of declaration.declarations ?? []) addBindingNames(declarator?.id, bindings);
|
|
1029
|
+
break;
|
|
1030
|
+
case "FunctionDeclaration":
|
|
1031
|
+
case "ClassDeclaration":
|
|
1032
|
+
case "TSDeclareFunction":
|
|
1033
|
+
case "TSEnumDeclaration":
|
|
1034
|
+
case "TSInterfaceDeclaration":
|
|
1035
|
+
case "TSModuleDeclaration":
|
|
1036
|
+
case "TSTypeAliasDeclaration":
|
|
1037
|
+
case "TSImportEqualsDeclaration": addBindingNames(declaration.id, bindings);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
function undefinedLocalExportDiagnostics(program) {
|
|
1041
|
+
if (!Array.isArray(program?.body)) return [];
|
|
1042
|
+
const bindings = /* @__PURE__ */ new Set();
|
|
1043
|
+
for (const statement of program.body) {
|
|
1044
|
+
if (statement?.type === "ImportDeclaration") {
|
|
1045
|
+
for (const specifier of statement.specifiers ?? []) addBindingNames(specifier?.local, bindings);
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (statement?.type === "ExportNamedDeclaration" || statement?.type === "ExportDefaultDeclaration") {
|
|
1049
|
+
addDeclarationBindings(statement.declaration, bindings);
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
addDeclarationBindings(statement, bindings);
|
|
1053
|
+
}
|
|
1054
|
+
const diagnostics = [];
|
|
1055
|
+
for (const statement of program.body) {
|
|
1056
|
+
if (statement?.type !== "ExportNamedDeclaration" || statement.declaration != null || statement.source != null) continue;
|
|
1057
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
1058
|
+
const local = specifier?.local;
|
|
1059
|
+
const name = local?.name ?? local?.value;
|
|
1060
|
+
if (typeof name !== "string" || bindings.has(name)) continue;
|
|
1061
|
+
diagnostics.push({
|
|
1062
|
+
severity: "Error",
|
|
1063
|
+
message: `Export '${name}' is not defined`,
|
|
1064
|
+
labels: [{
|
|
1065
|
+
start: Number.isInteger(local?.start) ? local.start : statement.start,
|
|
1066
|
+
end: Number.isInteger(local?.end) ? local.end : statement.end,
|
|
1067
|
+
message: ""
|
|
1068
|
+
}],
|
|
1069
|
+
helpMessage: null,
|
|
1070
|
+
codeframe: null
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return diagnostics;
|
|
1075
|
+
}
|
|
1076
|
+
function isEventAttribute(name) {
|
|
1077
|
+
return name.startsWith("on") && name.length > 2 && name[2] === name[2].toUpperCase();
|
|
1078
|
+
}
|
|
1079
|
+
function isCaptureEvent(name) {
|
|
1080
|
+
const lowered = name.toLowerCase();
|
|
1081
|
+
return name.endsWith("Capture") && lowered !== "gotpointercapture" && lowered !== "lostpointercapture";
|
|
1082
|
+
}
|
|
1083
|
+
function normalizeEventName(name) {
|
|
1084
|
+
const original = name.slice(2);
|
|
1085
|
+
return (isCaptureEvent(original) ? original.slice(0, -7) : original).toLowerCase();
|
|
1086
|
+
}
|
|
1087
|
+
function createTsrxCoreCompat(parser) {
|
|
1088
|
+
if (typeof parser?.parseSync !== "function") throw new TypeError("@tsrx/oxc-core-compat requires a parseSync function");
|
|
1089
|
+
return Object.freeze({
|
|
1090
|
+
isEventAttribute,
|
|
1091
|
+
normalizeEventName,
|
|
1092
|
+
parseModule(source, filename = "module.tsrx", options) {
|
|
1093
|
+
const resolvedFilename = filename || "module.tsrx";
|
|
1094
|
+
const collecting = Boolean(options?.collect || options?.loose);
|
|
1095
|
+
const wantsComments = Array.isArray(options?.comments);
|
|
1096
|
+
const eagerTsrx = !options?.loose && !wantsComments;
|
|
1097
|
+
let selectedParserOptions = parserOptions(resolvedFilename, eagerTsrx);
|
|
1098
|
+
let positionAt;
|
|
1099
|
+
const positions = () => positionAt ??= positionLookup(source);
|
|
1100
|
+
let result;
|
|
1101
|
+
try {
|
|
1102
|
+
try {
|
|
1103
|
+
result = parser.parseSync(resolvedFilename, source, selectedParserOptions);
|
|
1104
|
+
} catch (ordinaryError) {
|
|
1105
|
+
if (selectedParserOptions !== TYPESCRIPT_REACT_PARSER_OPTIONS || typeof source !== "string" || !source.includes("@{")) throw ordinaryError;
|
|
1106
|
+
try {
|
|
1107
|
+
const retry = tsrxRetry(parser, resolvedFilename, source, eagerTsrx);
|
|
1108
|
+
if (retry === null) throw ordinaryError;
|
|
1109
|
+
result = retry.result;
|
|
1110
|
+
selectedParserOptions = retry.options;
|
|
1111
|
+
} catch {
|
|
1112
|
+
throw ordinaryError;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
} catch (error) {
|
|
1116
|
+
if (options?.loose && typeof source === "string" && isRecoverableLooseShapeFailure(error)) {
|
|
1117
|
+
const recovered = looseRecovery(parser, resolvedFilename, source);
|
|
1118
|
+
if (recovered === null) throw error;
|
|
1119
|
+
result = recovered;
|
|
1120
|
+
} else {
|
|
1121
|
+
if (isOperationalError(error) || !isSyntaxErrorLike(error)) throw error;
|
|
1122
|
+
const translated = toCompileError(error, resolvedFilename, positions(), "fatal", source);
|
|
1123
|
+
if (collecting && Array.isArray(options?.errors)) options.errors.push(toCompileError(error, resolvedFilename, positions(), "usage", source));
|
|
1124
|
+
throw translated;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
if (selectedParserOptions === TYPESCRIPT_REACT_PARSER_OPTIONS && typeof source === "string" && source.includes("@{") && (parserResultProgram(result) === null || parserResultErrors(result).length > 0)) try {
|
|
1128
|
+
const retry = tsrxRetry(parser, resolvedFilename, source, eagerTsrx);
|
|
1129
|
+
if (retry !== null) {
|
|
1130
|
+
result = retry.result;
|
|
1131
|
+
selectedParserOptions = retry.options;
|
|
1132
|
+
}
|
|
1133
|
+
} catch {}
|
|
1134
|
+
let program;
|
|
1135
|
+
let comments;
|
|
1136
|
+
let nativeErrors;
|
|
1137
|
+
try {
|
|
1138
|
+
program = parserResultProgram(result);
|
|
1139
|
+
nativeErrors = parserResultErrors(result);
|
|
1140
|
+
if (program === null) {
|
|
1141
|
+
const recovery = submoduleRecovery(source, nativeErrors);
|
|
1142
|
+
if (recovery !== null) {
|
|
1143
|
+
result = parser.parseSync(resolvedFilename, recovery.source, selectedParserOptions);
|
|
1144
|
+
program = parserResultProgram(result);
|
|
1145
|
+
nativeErrors = parserResultErrors(result);
|
|
1146
|
+
if (program !== null) restoreSubmoduleSources(program, recovery.candidates);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (program === null && options?.loose && typeof source === "string") {
|
|
1150
|
+
const recovered = looseRecovery(parser, resolvedFilename, source);
|
|
1151
|
+
if (recovered !== null) {
|
|
1152
|
+
result = recovered;
|
|
1153
|
+
program = recovered.program;
|
|
1154
|
+
nativeErrors = recovered.errors ?? [];
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
if (program !== null && options?.loose && typeof source === "string" && source.includes(COMPLETION_PLACEHOLDER)) normalizeCompletionPlaceholderSiblings(program);
|
|
1158
|
+
if (program !== null && selectedParserOptions.showSemanticErrors === true) {
|
|
1159
|
+
const compatibilityErrors = undefinedLocalExportDiagnostics(program);
|
|
1160
|
+
if (compatibilityErrors.length > 0) nativeErrors = [...nativeErrors, ...compatibilityErrors];
|
|
1161
|
+
}
|
|
1162
|
+
comments = wantsComments ? result?.comments ?? [] : [];
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
if (isOperationalError(error) || !isSyntaxErrorLike(error)) throw error;
|
|
1165
|
+
const translated = toCompileError(error, resolvedFilename, positions(), "fatal", source);
|
|
1166
|
+
if (collecting && Array.isArray(options?.errors)) options.errors.push(toCompileError(error, resolvedFilename, positions(), "usage", source));
|
|
1167
|
+
throw translated;
|
|
1168
|
+
}
|
|
1169
|
+
if (nativeErrors.length > 0) {
|
|
1170
|
+
if (!collecting) throw toCompileError(nativeErrors[0], resolvedFilename, positions(), "fatal", source);
|
|
1171
|
+
if (Array.isArray(options?.errors)) for (const error of nativeErrors) options.errors.push(toCompileError(error, resolvedFilename, positions(), "usage", source));
|
|
1172
|
+
}
|
|
1173
|
+
if (program === null) {
|
|
1174
|
+
if (nativeErrors.length > 0) throw toCompileError(nativeErrors[0], resolvedFilename, positions(), "fatal", source);
|
|
1175
|
+
throw missingProgramError(resolvedFilename);
|
|
1176
|
+
}
|
|
1177
|
+
materializeCompatibilityProgram(program, source, resolvedFilename, Boolean(options?.loose), positions());
|
|
1178
|
+
if (wantsComments) for (const comment of comments) options.comments.push(compatibleComment(comment, positions()));
|
|
1179
|
+
return program;
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
//#endregion
|
|
1184
|
+
export { createTsrxCoreCompat, isEventAttribute, normalizeEventName };
|