@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
package/dist/parser.js
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import { NATIVE_TARGETS, nativePackageName, nativeTargetForHost } from "./native-targets.js";
|
|
2
|
+
import { isTsrxBinaryProgram, parseTrustedTsrxProgram, parseTsrxProgram } from "./tsrx-transfer.js";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
//#region src/parser.ts
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const PACKAGE_VERSION = "0.8.0";
|
|
7
|
+
const parserManifest = Object.freeze({
|
|
8
|
+
name: "@tsrx/oxc",
|
|
9
|
+
version: PACKAGE_VERSION,
|
|
10
|
+
dependencies: Object.freeze({ "@oxc-project/types": "0.140.0" }),
|
|
11
|
+
optionalDependencies: Object.freeze(Object.fromEntries(NATIVE_TARGETS.map((target) => [nativePackageName(target), PACKAGE_VERSION])))
|
|
12
|
+
});
|
|
13
|
+
const API_VERSION = 1;
|
|
14
|
+
const TRANSPORT_ABI = 1;
|
|
15
|
+
const NODE_API = 8;
|
|
16
|
+
const NATIVE_PROTOCOL_VERSION = 2;
|
|
17
|
+
const OXC_REVISION = "8e0ed2ebb96137fb1611cdbd5742d5cb46037d40";
|
|
18
|
+
const NODE_ENGINE = "^20.19.0 || >=22.12.0";
|
|
19
|
+
const ADDON_FILE = "parser.node";
|
|
20
|
+
const ADDON_ROLE = "canonical-parser";
|
|
21
|
+
const NATIVE_FILES = Object.freeze([
|
|
22
|
+
"bin",
|
|
23
|
+
"parser.node",
|
|
24
|
+
"checksums.json",
|
|
25
|
+
"licenses",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"README.md",
|
|
28
|
+
"THIRD_PARTY_NOTICES.md"
|
|
29
|
+
]);
|
|
30
|
+
const NATIVE_KEYS = Object.freeze([
|
|
31
|
+
"nodeApi",
|
|
32
|
+
"parse",
|
|
33
|
+
"parseSync"
|
|
34
|
+
]);
|
|
35
|
+
const LANGUAGES = Object.freeze([
|
|
36
|
+
"js",
|
|
37
|
+
"jsx",
|
|
38
|
+
"ts",
|
|
39
|
+
"tsx",
|
|
40
|
+
"dts",
|
|
41
|
+
"tsrx"
|
|
42
|
+
]);
|
|
43
|
+
const ERROR_CODES = /* @__PURE__ */ new Set([
|
|
44
|
+
"ERR_TSRX_INVALID_ARGUMENT",
|
|
45
|
+
"ERR_TSRX_UNSUPPORTED_TARGET",
|
|
46
|
+
"ERR_TSRX_NATIVE_NOT_INSTALLED",
|
|
47
|
+
"ERR_TSRX_NATIVE_INTEGRITY",
|
|
48
|
+
"ERR_TSRX_NATIVE_VERSION",
|
|
49
|
+
"ERR_TSRX_CAPABILITY_RECOVERY",
|
|
50
|
+
"ERR_TSRX_CAPABILITY_CSS",
|
|
51
|
+
"ERR_TSRX_CAPABILITY_RAW_TRANSFER",
|
|
52
|
+
"ERR_TSRX_RESOURCE_EXHAUSTED",
|
|
53
|
+
"ERR_TSRX_CANCELLED"
|
|
54
|
+
]);
|
|
55
|
+
const ROUTE_INFER_ORDINARY = 0;
|
|
56
|
+
const ROUTE_JAVASCRIPT = 1;
|
|
57
|
+
const ROUTE_JAVASCRIPT_REACT = 2;
|
|
58
|
+
const ROUTE_TYPESCRIPT = 3;
|
|
59
|
+
const ROUTE_TYPESCRIPT_REACT = 4;
|
|
60
|
+
const ROUTE_TYPESCRIPT_DEFINITION = 5;
|
|
61
|
+
const ROUTE_TSRX = 6;
|
|
62
|
+
const ROUTE_TSRX_CORE_COMPAT = 7;
|
|
63
|
+
const TSRX_CORE_COMPAT_EAGER = Symbol.for("@oxc-tsrx/parser/tsrx-core-compat-eager");
|
|
64
|
+
const ASCII_SOURCE = /^[\x00-\x7f]+$/u;
|
|
65
|
+
const ROUTES = Object.freeze({
|
|
66
|
+
js: ROUTE_JAVASCRIPT,
|
|
67
|
+
jsx: ROUTE_JAVASCRIPT_REACT,
|
|
68
|
+
ts: ROUTE_TYPESCRIPT,
|
|
69
|
+
tsx: ROUTE_TYPESCRIPT_REACT,
|
|
70
|
+
dts: ROUTE_TYPESCRIPT_DEFINITION,
|
|
71
|
+
tsrx: ROUTE_TSRX
|
|
72
|
+
});
|
|
73
|
+
var ParserOperationalError = class extends Error {
|
|
74
|
+
constructor(code, message, options) {
|
|
75
|
+
super(message, options);
|
|
76
|
+
Object.defineProperties(this, {
|
|
77
|
+
name: {
|
|
78
|
+
value: "ParserOperationalError",
|
|
79
|
+
configurable: true,
|
|
80
|
+
writable: true
|
|
81
|
+
},
|
|
82
|
+
code: {
|
|
83
|
+
value: code,
|
|
84
|
+
enumerable: true
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function linuxLibc() {
|
|
90
|
+
if (process.platform !== "linux") return void 0;
|
|
91
|
+
return (process.report?.getReport?.())?.header?.glibcVersionRuntime ? "glibc" : "musl";
|
|
92
|
+
}
|
|
93
|
+
function selectedHostTarget() {
|
|
94
|
+
try {
|
|
95
|
+
return nativeTargetForHost(process.platform, process.arch, linuxLibc());
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const hostTarget = selectedHostTarget();
|
|
101
|
+
const capabilities = Object.freeze({
|
|
102
|
+
apiVersion: API_VERSION,
|
|
103
|
+
languages: LANGUAGES,
|
|
104
|
+
target: hostTarget?.target ?? `${process.platform}-${process.arch}`,
|
|
105
|
+
nodeApi: NODE_API,
|
|
106
|
+
nodeEngine: NODE_ENGINE,
|
|
107
|
+
oxcRevision: OXC_REVISION,
|
|
108
|
+
lazy: true,
|
|
109
|
+
async: true,
|
|
110
|
+
editorRecovery: false,
|
|
111
|
+
cssMaterialization: false,
|
|
112
|
+
rawTransfer: false
|
|
113
|
+
});
|
|
114
|
+
function describe(value) {
|
|
115
|
+
if (value === void 0) return "undefined";
|
|
116
|
+
try {
|
|
117
|
+
return JSON.stringify(value);
|
|
118
|
+
} catch {
|
|
119
|
+
return String(value);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function operational(code, subject, expected, actual, cause) {
|
|
123
|
+
return new ParserOperationalError(code, `${subject}: expected ${describe(expected)}; actual ${describe(actual)}`, cause === void 0 ? void 0 : { cause });
|
|
124
|
+
}
|
|
125
|
+
function fail(code, subject, expected, actual, cause) {
|
|
126
|
+
throw operational(code, subject, expected, actual, cause);
|
|
127
|
+
}
|
|
128
|
+
function exactKeys(value, expected, subject, code = "ERR_TSRX_NATIVE_VERSION") {
|
|
129
|
+
const actual = value !== null && typeof value === "object" ? Object.keys(value).sort() : typeof value;
|
|
130
|
+
const sortedExpected = [...expected].sort();
|
|
131
|
+
if (!Array.isArray(actual) || JSON.stringify(actual) !== JSON.stringify(sortedExpected)) fail(code, subject, sortedExpected, actual);
|
|
132
|
+
}
|
|
133
|
+
function exactValue(actual, expected, subject, code = "ERR_TSRX_NATIVE_VERSION") {
|
|
134
|
+
const { isDeepStrictEqual } = require("node:util");
|
|
135
|
+
if (!isDeepStrictEqual(actual, expected)) fail(code, subject, expected, actual);
|
|
136
|
+
}
|
|
137
|
+
function requireBytes(contents, length, subject) {
|
|
138
|
+
if (contents.length < length) fail("ERR_TSRX_NATIVE_INTEGRITY", subject, `at least ${length} header bytes`, contents.length);
|
|
139
|
+
}
|
|
140
|
+
function cpuName(value, format) {
|
|
141
|
+
return {
|
|
142
|
+
"mach-o": /* @__PURE__ */ new Map([[16777223, "x64"], [16777228, "arm64"]]),
|
|
143
|
+
elf: /* @__PURE__ */ new Map([[62, "x64"], [183, "arm64"]]),
|
|
144
|
+
pe: /* @__PURE__ */ new Map([[34404, "x64"], [43620, "arm64"]])
|
|
145
|
+
}[format].get(value) ?? `unknown-0x${value.toString(16)}`;
|
|
146
|
+
}
|
|
147
|
+
function inspectMachO(contents, magic) {
|
|
148
|
+
const thin = (/* @__PURE__ */ new Map([
|
|
149
|
+
["cefaedfe", {
|
|
150
|
+
endian: "little",
|
|
151
|
+
bits: 32
|
|
152
|
+
}],
|
|
153
|
+
["cffaedfe", {
|
|
154
|
+
endian: "little",
|
|
155
|
+
bits: 64
|
|
156
|
+
}],
|
|
157
|
+
["feedface", {
|
|
158
|
+
endian: "big",
|
|
159
|
+
bits: 32
|
|
160
|
+
}],
|
|
161
|
+
["feedfacf", {
|
|
162
|
+
endian: "big",
|
|
163
|
+
bits: 64
|
|
164
|
+
}]
|
|
165
|
+
])).get(magic);
|
|
166
|
+
if (thin === void 0) return null;
|
|
167
|
+
requireBytes(contents, 16, "Mach-O parser addon");
|
|
168
|
+
const readU32 = thin.endian === "little" ? contents.readUInt32LE.bind(contents) : contents.readUInt32BE.bind(contents);
|
|
169
|
+
const fileType = readU32(12);
|
|
170
|
+
if (fileType !== 6 && fileType !== 8) fail("ERR_TSRX_NATIVE_INTEGRITY", "Mach-O parser addon image kind", "MH_DYLIB or MH_BUNDLE", fileType);
|
|
171
|
+
return {
|
|
172
|
+
format: "mach-o",
|
|
173
|
+
imageKind: "dynamic-library",
|
|
174
|
+
bits: thin.bits,
|
|
175
|
+
architectures: [cpuName(readU32(4), "mach-o")],
|
|
176
|
+
os: "darwin"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function inspectElf(contents) {
|
|
180
|
+
if (contents.subarray(0, 4).toString("hex") !== "7f454c46") return null;
|
|
181
|
+
requireBytes(contents, 20, "ELF parser addon");
|
|
182
|
+
const bits = contents[4] === 2 ? 64 : contents[4] === 1 ? 32 : null;
|
|
183
|
+
const endian = contents[5];
|
|
184
|
+
if (bits === null || endian !== 1 && endian !== 2) fail("ERR_TSRX_NATIVE_INTEGRITY", "ELF parser addon header", "supported class and byte order", {
|
|
185
|
+
class: contents[4],
|
|
186
|
+
endian
|
|
187
|
+
});
|
|
188
|
+
const readU16 = endian === 1 ? contents.readUInt16LE.bind(contents) : contents.readUInt16BE.bind(contents);
|
|
189
|
+
if (readU16(16) !== 3) fail("ERR_TSRX_NATIVE_INTEGRITY", "ELF parser addon image kind", "ET_DYN", readU16(16));
|
|
190
|
+
return {
|
|
191
|
+
format: "elf",
|
|
192
|
+
imageKind: "dynamic-library",
|
|
193
|
+
bits,
|
|
194
|
+
architectures: [cpuName(readU16(18), "elf")],
|
|
195
|
+
os: "linux"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function inspectPe(contents) {
|
|
199
|
+
if (contents.subarray(0, 2).toString("ascii") !== "MZ") return null;
|
|
200
|
+
requireBytes(contents, 64, "PE parser addon");
|
|
201
|
+
const header = contents.readUInt32LE(60);
|
|
202
|
+
requireBytes(contents, header + 26, "PE parser addon");
|
|
203
|
+
if (contents.subarray(header, header + 4).toString("hex") !== "50450000") fail("ERR_TSRX_NATIVE_INTEGRITY", "PE parser addon signature", "PE\\0\\0", "missing");
|
|
204
|
+
const characteristics = contents.readUInt16LE(header + 22);
|
|
205
|
+
if ((characteristics & 2) === 0 || (characteristics & 8192) === 0) fail("ERR_TSRX_NATIVE_INTEGRITY", "PE parser addon image kind", "executable DLL", `0x${characteristics.toString(16)}`);
|
|
206
|
+
return {
|
|
207
|
+
format: "pe",
|
|
208
|
+
imageKind: "dynamic-library",
|
|
209
|
+
bits: contents.readUInt16LE(header + 24) === 523 ? 64 : 32,
|
|
210
|
+
architectures: [cpuName(contents.readUInt16LE(header + 4), "pe")],
|
|
211
|
+
os: "win32"
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function inspectAddon(contents, target) {
|
|
215
|
+
requireBytes(contents, 4, "parser addon");
|
|
216
|
+
const magic = contents.subarray(0, 4).toString("hex");
|
|
217
|
+
const object = inspectMachO(contents, magic) ?? inspectElf(contents) ?? inspectPe(contents);
|
|
218
|
+
if (object === null) fail("ERR_TSRX_NATIVE_INTEGRITY", "parser addon object format", "Mach-O, ELF, or PE", magic);
|
|
219
|
+
return {
|
|
220
|
+
...object,
|
|
221
|
+
libc: target.libc ?? null
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function expectedObject(target) {
|
|
225
|
+
return {
|
|
226
|
+
format: {
|
|
227
|
+
darwin: "mach-o",
|
|
228
|
+
linux: "elf",
|
|
229
|
+
win32: "pe"
|
|
230
|
+
}[target.os],
|
|
231
|
+
imageKind: "dynamic-library",
|
|
232
|
+
bits: 64,
|
|
233
|
+
architectures: [target.cpu],
|
|
234
|
+
os: target.os,
|
|
235
|
+
libc: target.libc ?? null
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function expectedCapabilities() {
|
|
239
|
+
return {
|
|
240
|
+
lazy: true,
|
|
241
|
+
async: true,
|
|
242
|
+
editorRecovery: false,
|
|
243
|
+
cssMaterialization: false,
|
|
244
|
+
rawTransfer: false
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function expectedBinaries(target) {
|
|
248
|
+
return [`oxc-tsrx${target.os === "win32" ? ".exe" : ""}`];
|
|
249
|
+
}
|
|
250
|
+
function validateAddonRecord(record, target, subject) {
|
|
251
|
+
exactKeys(record, [
|
|
252
|
+
"packageVersion",
|
|
253
|
+
"target",
|
|
254
|
+
"bytes",
|
|
255
|
+
"sha256",
|
|
256
|
+
"object",
|
|
257
|
+
"nodeApi",
|
|
258
|
+
"oxcRevision",
|
|
259
|
+
"capabilities",
|
|
260
|
+
"role",
|
|
261
|
+
"file",
|
|
262
|
+
"apiVersion",
|
|
263
|
+
"transportAbi"
|
|
264
|
+
], `${subject} fields`);
|
|
265
|
+
exactValue(record.packageVersion, parserManifest.version, `${subject} package version`);
|
|
266
|
+
exactValue(record.target, target.target, `${subject} target`);
|
|
267
|
+
if (!Number.isSafeInteger(record.bytes) || record.bytes <= 0) fail("ERR_TSRX_NATIVE_INTEGRITY", `${subject} byte length`, "a positive safe integer", record.bytes);
|
|
268
|
+
if (!/^[0-9a-f]{64}$/u.test(record.sha256 ?? "")) fail("ERR_TSRX_NATIVE_INTEGRITY", `${subject} SHA-256`, "64 lowercase hex characters", record.sha256);
|
|
269
|
+
exactValue(record.object, expectedObject(target), `${subject} object identity`, "ERR_TSRX_NATIVE_INTEGRITY");
|
|
270
|
+
exactValue(record.nodeApi, NODE_API, `${subject} Node-API`);
|
|
271
|
+
exactValue(record.oxcRevision, OXC_REVISION, `${subject} OXC revision`);
|
|
272
|
+
exactValue(record.capabilities, expectedCapabilities(), `${subject} capabilities`);
|
|
273
|
+
exactValue(record.role, ADDON_ROLE, `${subject} role`);
|
|
274
|
+
exactValue(record.file, ADDON_FILE, `${subject} filename`);
|
|
275
|
+
exactValue(record.apiVersion, API_VERSION, `${subject} API version`);
|
|
276
|
+
exactValue(record.transportAbi, TRANSPORT_ABI, `${subject} transport ABI`);
|
|
277
|
+
}
|
|
278
|
+
function validateParserManifest(target) {
|
|
279
|
+
const expectedName = nativePackageName(target);
|
|
280
|
+
exactValue(parserManifest.optionalDependencies?.[expectedName], parserManifest.version, "parser optional native dependency version");
|
|
281
|
+
const dependencyNames = Object.keys(parserManifest.dependencies ?? {});
|
|
282
|
+
if (dependencyNames.some((name) => name.includes("compat"))) fail("ERR_TSRX_NATIVE_INTEGRITY", "parser dependency family", "no compatibility dependency", dependencyNames);
|
|
283
|
+
}
|
|
284
|
+
function readJson(path, subject) {
|
|
285
|
+
const { readFileSync } = require("node:fs");
|
|
286
|
+
try {
|
|
287
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
288
|
+
} catch (cause) {
|
|
289
|
+
fail("ERR_TSRX_NATIVE_INTEGRITY", subject, "readable valid JSON", cause?.message, cause);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function loadAddon(path, target, expectedRecord = null) {
|
|
293
|
+
const { createHash } = require("node:crypto");
|
|
294
|
+
const { lstatSync, readFileSync } = require("node:fs");
|
|
295
|
+
let stat;
|
|
296
|
+
let contents;
|
|
297
|
+
try {
|
|
298
|
+
stat = lstatSync(path);
|
|
299
|
+
contents = readFileSync(path);
|
|
300
|
+
} catch (cause) {
|
|
301
|
+
fail("ERR_TSRX_NATIVE_INTEGRITY", "parser addon file", "a readable regular file", cause?.message, cause);
|
|
302
|
+
}
|
|
303
|
+
if (!stat.isFile() || stat.isSymbolicLink()) fail("ERR_TSRX_NATIVE_INTEGRITY", "parser addon file kind", "a regular non-symbolic-link file", {
|
|
304
|
+
file: stat.isFile(),
|
|
305
|
+
symlink: stat.isSymbolicLink()
|
|
306
|
+
});
|
|
307
|
+
exactValue(inspectAddon(contents, target), expectedObject(target), "parser addon object identity", "ERR_TSRX_NATIVE_INTEGRITY");
|
|
308
|
+
if (expectedRecord !== null) {
|
|
309
|
+
exactValue(contents.length, expectedRecord.bytes, "parser addon byte length", "ERR_TSRX_NATIVE_INTEGRITY");
|
|
310
|
+
exactValue(createHash("sha256").update(contents).digest("hex"), expectedRecord.sha256, "parser addon SHA-256", "ERR_TSRX_NATIVE_INTEGRITY");
|
|
311
|
+
}
|
|
312
|
+
let binding;
|
|
313
|
+
try {
|
|
314
|
+
binding = require(path);
|
|
315
|
+
} catch (cause) {
|
|
316
|
+
fail("ERR_TSRX_NATIVE_INTEGRITY", "parser addon load", "a loadable Node-API addon", cause?.message, cause);
|
|
317
|
+
}
|
|
318
|
+
exactValue(Object.keys(binding).sort(), NATIVE_KEYS, "parser addon exports");
|
|
319
|
+
let actualNodeApi;
|
|
320
|
+
try {
|
|
321
|
+
actualNodeApi = binding.nodeApi();
|
|
322
|
+
} catch (cause) {
|
|
323
|
+
fail("ERR_TSRX_NATIVE_VERSION", "parser addon Node-API export", NODE_API, cause?.message, cause);
|
|
324
|
+
}
|
|
325
|
+
exactValue(actualNodeApi, NODE_API, "parser addon Node-API export");
|
|
326
|
+
return binding;
|
|
327
|
+
}
|
|
328
|
+
function loadAdjacentAddon(path, target) {
|
|
329
|
+
const record = readJson(`${path}.json`, "adjacent parser addon identity record");
|
|
330
|
+
validateAddonRecord(record, target, "adjacent parser addon");
|
|
331
|
+
return loadAddon(path, target, record);
|
|
332
|
+
}
|
|
333
|
+
function validateNativePackage(packageName, manifestPath, target) {
|
|
334
|
+
const { dirname, join } = require("node:path");
|
|
335
|
+
const manifest = readJson(manifestPath, `${packageName} manifest`);
|
|
336
|
+
exactValue(manifest.name, packageName, "native package name");
|
|
337
|
+
exactValue(manifest.version, parserManifest.version, "native package version");
|
|
338
|
+
exactValue(manifest.os, [target.os], "native package OS");
|
|
339
|
+
exactValue(manifest.cpu, [target.cpu], "native package CPU");
|
|
340
|
+
exactValue(manifest.libc, target.libc === void 0 ? void 0 : [target.libc], "native package libc");
|
|
341
|
+
exactValue(manifest.files, NATIVE_FILES, "native package files", "ERR_TSRX_NATIVE_INTEGRITY");
|
|
342
|
+
for (const field of [
|
|
343
|
+
"dependencies",
|
|
344
|
+
"optionalDependencies",
|
|
345
|
+
"peerDependencies"
|
|
346
|
+
]) {
|
|
347
|
+
const names = Object.keys(manifest[field] ?? {});
|
|
348
|
+
if (names.length !== 0) fail("ERR_TSRX_NATIVE_INTEGRITY", `native package ${field}`, [], names);
|
|
349
|
+
}
|
|
350
|
+
const metadata = manifest.oxcTsrx;
|
|
351
|
+
exactKeys(metadata, [
|
|
352
|
+
"schemaVersion",
|
|
353
|
+
"nativeProtocolVersion",
|
|
354
|
+
"target",
|
|
355
|
+
"vscodeTarget",
|
|
356
|
+
"oxcRevision",
|
|
357
|
+
"binaries",
|
|
358
|
+
"addons"
|
|
359
|
+
], "native package metadata fields");
|
|
360
|
+
exactValue(metadata.schemaVersion, 2, "native package schema version");
|
|
361
|
+
exactValue(metadata.nativeProtocolVersion, NATIVE_PROTOCOL_VERSION, "native protocol version");
|
|
362
|
+
exactValue(metadata.target, target.target, "native package Rust target");
|
|
363
|
+
exactValue(metadata.vscodeTarget, target.vscodeTarget, "native package VS Code target");
|
|
364
|
+
exactValue(metadata.oxcRevision, OXC_REVISION, "native package OXC revision");
|
|
365
|
+
exactValue(metadata.binaries, expectedBinaries(target), "native package binaries");
|
|
366
|
+
exactKeys(metadata.addons, [ADDON_FILE], "native package addon entries");
|
|
367
|
+
validateAddonRecord(metadata.addons[ADDON_FILE], target, "native manifest addon");
|
|
368
|
+
const packageRoot = dirname(manifestPath);
|
|
369
|
+
const checksums = readJson(join(packageRoot, "checksums.json"), `${packageName} checksums`);
|
|
370
|
+
exactValue(checksums.schemaVersion, 2, "native checksum schema version");
|
|
371
|
+
exactValue(checksums.packageName, packageName, "native checksum package name");
|
|
372
|
+
exactValue(checksums.version, parserManifest.version, "native checksum package version");
|
|
373
|
+
exactValue(checksums.target, target.target, "native checksum Rust target");
|
|
374
|
+
exactValue(checksums.oxcRevision, OXC_REVISION, "native checksum OXC revision");
|
|
375
|
+
exactKeys(checksums.addons, [ADDON_FILE], "native checksum addon entries", "ERR_TSRX_NATIVE_INTEGRITY");
|
|
376
|
+
const checksumRecord = checksums.addons[ADDON_FILE];
|
|
377
|
+
validateAddonRecord(checksumRecord, target, "native checksum addon");
|
|
378
|
+
for (const field of [
|
|
379
|
+
"bytes",
|
|
380
|
+
"sha256",
|
|
381
|
+
"object"
|
|
382
|
+
]) exactValue(checksumRecord[field], metadata.addons[ADDON_FILE][field], `native addon ${field} metadata agreement`, "ERR_TSRX_NATIVE_INTEGRITY");
|
|
383
|
+
for (const field of [
|
|
384
|
+
"packageVersion",
|
|
385
|
+
"target",
|
|
386
|
+
"nodeApi",
|
|
387
|
+
"oxcRevision",
|
|
388
|
+
"capabilities",
|
|
389
|
+
"role",
|
|
390
|
+
"file",
|
|
391
|
+
"apiVersion",
|
|
392
|
+
"transportAbi"
|
|
393
|
+
]) exactValue(checksumRecord[field], metadata.addons[ADDON_FILE][field], `native addon ${field} metadata agreement`);
|
|
394
|
+
return loadAddon(join(packageRoot, ADDON_FILE), target, checksumRecord);
|
|
395
|
+
}
|
|
396
|
+
let nativeBinding;
|
|
397
|
+
function binding() {
|
|
398
|
+
if (nativeBinding !== void 0) return nativeBinding;
|
|
399
|
+
if (hostTarget === null) fail("ERR_TSRX_UNSUPPORTED_TARGET", "parser host target", "one of the eight supported Node targets", `${process.platform}-${process.arch}${linuxLibc() ? `-${linuxLibc()}` : ""}`);
|
|
400
|
+
const { existsSync } = require("node:fs");
|
|
401
|
+
const { dirname, join, resolve } = require("node:path");
|
|
402
|
+
const { fileURLToPath } = require("node:url");
|
|
403
|
+
const explicit = process.env.OXC_TSRX_PARSER_ADDON;
|
|
404
|
+
if (explicit) {
|
|
405
|
+
nativeBinding = loadAdjacentAddon(resolve(explicit), hostTarget);
|
|
406
|
+
return nativeBinding;
|
|
407
|
+
}
|
|
408
|
+
const adjacent = join(dirname(fileURLToPath(import.meta.url)), "..", ADDON_FILE);
|
|
409
|
+
if (existsSync(adjacent)) {
|
|
410
|
+
nativeBinding = loadAdjacentAddon(adjacent, hostTarget);
|
|
411
|
+
return nativeBinding;
|
|
412
|
+
}
|
|
413
|
+
validateParserManifest(hostTarget);
|
|
414
|
+
const packageName = nativePackageName(hostTarget);
|
|
415
|
+
let manifestPath;
|
|
416
|
+
try {
|
|
417
|
+
manifestPath = require.resolve(`${packageName}/package.json`);
|
|
418
|
+
} catch (cause) {
|
|
419
|
+
fail("ERR_TSRX_NATIVE_NOT_INSTALLED", "canonical parser native package", `${packageName}@${parserManifest.version}`, cause?.code ?? cause?.message, cause);
|
|
420
|
+
}
|
|
421
|
+
nativeBinding = validateNativePackage(packageName, manifestPath, hostTarget);
|
|
422
|
+
return nativeBinding;
|
|
423
|
+
}
|
|
424
|
+
function translateNativeError(error) {
|
|
425
|
+
if (error instanceof ParserOperationalError) return error;
|
|
426
|
+
const message = typeof error?.message === "string" ? error.message : String(error);
|
|
427
|
+
const match = /\b(ERR_TSRX_[A-Z_]+):\s*([^\n]*)/u.exec(message);
|
|
428
|
+
if (match !== null && ERROR_CODES.has(match[1])) return new ParserOperationalError(match[1], match[2] || message, { cause: error });
|
|
429
|
+
return error;
|
|
430
|
+
}
|
|
431
|
+
function route(filename, options) {
|
|
432
|
+
if (options?.experimentalRawTransfer) fail("ERR_TSRX_CAPABILITY_RAW_TRANSFER", "experimental raw transfer capability", true, capabilities.rawTransfer);
|
|
433
|
+
if (options?.experimentalLazy) fail("ERR_TSRX_CAPABILITY_RAW_TRANSFER", "experimental lazy transport capability", true, capabilities.rawTransfer);
|
|
434
|
+
const explicit = options?.lang;
|
|
435
|
+
const explicitRoute = ROUTES[explicit];
|
|
436
|
+
if (explicitRoute !== void 0) return explicitRoute === ROUTE_TSRX && options?.[TSRX_CORE_COMPAT_EAGER] === true ? ROUTE_TSRX_CORE_COMPAT : explicitRoute;
|
|
437
|
+
return typeof filename === "string" && filename.endsWith(".tsrx") ? options?.[TSRX_CORE_COMPAT_EAGER] === true ? ROUTE_TSRX_CORE_COMPAT : ROUTE_TSRX : ROUTE_INFER_ORDINARY;
|
|
438
|
+
}
|
|
439
|
+
function applyFix(program, path) {
|
|
440
|
+
let node = program;
|
|
441
|
+
for (const key of path) node = node[key];
|
|
442
|
+
if (node.bigint) node.value = BigInt(node.bigint);
|
|
443
|
+
else try {
|
|
444
|
+
node.value = RegExp(node.regex.pattern, node.regex.flags);
|
|
445
|
+
} catch {}
|
|
446
|
+
}
|
|
447
|
+
function parseOrdinaryProgram(programJson) {
|
|
448
|
+
const { node: program, fixes } = JSON.parse(programJson);
|
|
449
|
+
for (const path of fixes) applyFix(program, path);
|
|
450
|
+
return program;
|
|
451
|
+
}
|
|
452
|
+
const RESULT_STATE = Symbol("@oxc-tsrx/parser result state");
|
|
453
|
+
const PROGRAM_READY = 1;
|
|
454
|
+
const MODULE_READY = 2;
|
|
455
|
+
const COMMENTS_READY = 4;
|
|
456
|
+
const ERRORS_READY = 8;
|
|
457
|
+
function initializeResult(state, ready, property, convert) {
|
|
458
|
+
if ((state.ready & ready) === 0) {
|
|
459
|
+
try {
|
|
460
|
+
state[property] = convert(state.nativeResult[property]);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
throw translateNativeError(error);
|
|
463
|
+
}
|
|
464
|
+
state.ready |= ready;
|
|
465
|
+
}
|
|
466
|
+
return state[property];
|
|
467
|
+
}
|
|
468
|
+
function programGetter() {
|
|
469
|
+
const state = this[RESULT_STATE];
|
|
470
|
+
return initializeResult(state, PROGRAM_READY, "program", state.ordinary ? parseOrdinaryProgram : parseTsrxProgram);
|
|
471
|
+
}
|
|
472
|
+
function moduleGetter() {
|
|
473
|
+
return initializeResult(this[RESULT_STATE], MODULE_READY, "module", (value) => value);
|
|
474
|
+
}
|
|
475
|
+
function commentsGetter() {
|
|
476
|
+
return initializeResult(this[RESULT_STATE], COMMENTS_READY, "comments", (value) => value);
|
|
477
|
+
}
|
|
478
|
+
function errorsGetter() {
|
|
479
|
+
return initializeResult(this[RESULT_STATE], ERRORS_READY, "errors", (value) => value);
|
|
480
|
+
}
|
|
481
|
+
const RESULT_DESCRIPTORS = Object.freeze({
|
|
482
|
+
[RESULT_STATE]: Object.freeze({
|
|
483
|
+
configurable: false,
|
|
484
|
+
enumerable: false,
|
|
485
|
+
writable: true,
|
|
486
|
+
value: void 0
|
|
487
|
+
}),
|
|
488
|
+
program: Object.freeze({
|
|
489
|
+
configurable: true,
|
|
490
|
+
enumerable: true,
|
|
491
|
+
get: programGetter
|
|
492
|
+
}),
|
|
493
|
+
module: Object.freeze({
|
|
494
|
+
configurable: true,
|
|
495
|
+
enumerable: true,
|
|
496
|
+
get: moduleGetter
|
|
497
|
+
}),
|
|
498
|
+
comments: Object.freeze({
|
|
499
|
+
configurable: true,
|
|
500
|
+
enumerable: true,
|
|
501
|
+
get: commentsGetter
|
|
502
|
+
}),
|
|
503
|
+
errors: Object.freeze({
|
|
504
|
+
configurable: true,
|
|
505
|
+
enumerable: true,
|
|
506
|
+
get: errorsGetter
|
|
507
|
+
})
|
|
508
|
+
});
|
|
509
|
+
function wrap(nativeResult, ordinary) {
|
|
510
|
+
const result = Object.create(Object.prototype, RESULT_DESCRIPTORS);
|
|
511
|
+
result[RESULT_STATE] = {
|
|
512
|
+
nativeResult,
|
|
513
|
+
ordinary,
|
|
514
|
+
ready: 0,
|
|
515
|
+
program: void 0,
|
|
516
|
+
module: void 0,
|
|
517
|
+
comments: void 0,
|
|
518
|
+
errors: void 0
|
|
519
|
+
};
|
|
520
|
+
return result;
|
|
521
|
+
}
|
|
522
|
+
function invoke(method, filename, sourceText, options, selectedRoute) {
|
|
523
|
+
const native = binding();
|
|
524
|
+
if (selectedRoute === ROUTE_TSRX || selectedRoute === ROUTE_TSRX_CORE_COMPAT) {
|
|
525
|
+
const nativeOptions = selectedRoute === ROUTE_TSRX_CORE_COMPAT ? void 0 : options;
|
|
526
|
+
if (ASCII_SOURCE.test(sourceText)) return native[method](filename, sourceText, void 0, nativeOptions, selectedRoute);
|
|
527
|
+
return native[method](filename, "", sourceText, nativeOptions, selectedRoute);
|
|
528
|
+
}
|
|
529
|
+
return native[method](filename, sourceText, void 0, options, selectedRoute);
|
|
530
|
+
}
|
|
531
|
+
function parseSync(filename, sourceText, options) {
|
|
532
|
+
try {
|
|
533
|
+
const selectedRoute = route(filename, options);
|
|
534
|
+
const nativeResult = invoke("parseSync", filename, sourceText, options, selectedRoute);
|
|
535
|
+
if (selectedRoute === ROUTE_TSRX_CORE_COMPAT) {
|
|
536
|
+
if (typeof nativeResult === "string" || isTsrxBinaryProgram(nativeResult)) return parseTrustedTsrxProgram(nativeResult, true);
|
|
537
|
+
return {
|
|
538
|
+
program: parseTsrxProgram(nativeResult.program),
|
|
539
|
+
errors: nativeResult.errors
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return wrap(nativeResult, selectedRoute !== ROUTE_TSRX);
|
|
543
|
+
} catch (error) {
|
|
544
|
+
throw translateNativeError(error);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async function parse(filename, sourceText, options) {
|
|
548
|
+
try {
|
|
549
|
+
const routed = route(filename, options);
|
|
550
|
+
const selectedRoute = routed === ROUTE_TSRX_CORE_COMPAT ? ROUTE_TSRX : routed;
|
|
551
|
+
return wrap(await invoke("parse", filename, sourceText, options, selectedRoute), selectedRoute !== ROUTE_TSRX);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
throw translateNativeError(error);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
//#endregion
|
|
557
|
+
export { ParserOperationalError, capabilities, parse, parseSync };
|
package/dist/process.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { appendFileSync } from "node:fs";
|
|
3
|
+
//#region src/process.ts
|
|
4
|
+
function traceRunStart(trace, started, executable, args) {
|
|
5
|
+
appendFileSync(trace, `${JSON.stringify({
|
|
6
|
+
event: "start",
|
|
7
|
+
pid: process.pid,
|
|
8
|
+
ppid: process.ppid,
|
|
9
|
+
started,
|
|
10
|
+
executable,
|
|
11
|
+
args,
|
|
12
|
+
host: {
|
|
13
|
+
vpVersion: process.env.VP_VERSION ?? null,
|
|
14
|
+
vpCommand: process.env.VP_COMMAND ?? null,
|
|
15
|
+
packageManager: process.env.NODE_PACKAGE_MANAGER ?? null,
|
|
16
|
+
tsgolint: process.env.OXLINT_TSGOLINT_PATH ?? null
|
|
17
|
+
}
|
|
18
|
+
})}\n`);
|
|
19
|
+
}
|
|
20
|
+
function traceRunEnd(trace, started, executable, args, status, signal) {
|
|
21
|
+
appendFileSync(trace, `${JSON.stringify({
|
|
22
|
+
event: "end",
|
|
23
|
+
pid: process.pid,
|
|
24
|
+
ppid: process.ppid,
|
|
25
|
+
started,
|
|
26
|
+
ended: Date.now(),
|
|
27
|
+
executable,
|
|
28
|
+
args,
|
|
29
|
+
status,
|
|
30
|
+
signal
|
|
31
|
+
})}\n`);
|
|
32
|
+
}
|
|
33
|
+
function runCaptured(executable, args, options = {}) {
|
|
34
|
+
return new Promise((resolveRun, rejectRun) => {
|
|
35
|
+
const trace = process.env.OXC_TSRX_TRACE_FILE;
|
|
36
|
+
const started = Date.now();
|
|
37
|
+
if (trace) traceRunStart(trace, started, executable, args);
|
|
38
|
+
const child = spawn(executable, args, {
|
|
39
|
+
cwd: options.cwd,
|
|
40
|
+
env: options.env ?? process.env,
|
|
41
|
+
stdio: [
|
|
42
|
+
"pipe",
|
|
43
|
+
"pipe",
|
|
44
|
+
"pipe"
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
let stdout = "";
|
|
48
|
+
let stderr = "";
|
|
49
|
+
child.stdout.setEncoding("utf8");
|
|
50
|
+
child.stderr.setEncoding("utf8");
|
|
51
|
+
child.stdout.on("data", (chunk) => stdout += chunk);
|
|
52
|
+
child.stderr.on("data", (chunk) => stderr += chunk);
|
|
53
|
+
child.on("error", rejectRun);
|
|
54
|
+
child.on("close", (status, signal) => {
|
|
55
|
+
if (trace) traceRunEnd(trace, started, executable, args, status, signal);
|
|
56
|
+
resolveRun({
|
|
57
|
+
status: status ?? 2,
|
|
58
|
+
signal,
|
|
59
|
+
stdout,
|
|
60
|
+
stderr
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
if (options.input === void 0) child.stdin.end();
|
|
64
|
+
else child.stdin.end(options.input);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function runPassthrough(executable, args, options = {}) {
|
|
68
|
+
return new Promise((resolveRun, rejectRun) => {
|
|
69
|
+
const trace = process.env.OXC_TSRX_TRACE_FILE;
|
|
70
|
+
const started = Date.now();
|
|
71
|
+
if (trace) traceRunStart(trace, started, executable, args);
|
|
72
|
+
const child = spawn(executable, args, {
|
|
73
|
+
cwd: options.cwd,
|
|
74
|
+
env: options.env ?? process.env,
|
|
75
|
+
stdio: "inherit"
|
|
76
|
+
});
|
|
77
|
+
child.on("error", rejectRun);
|
|
78
|
+
child.on("close", (status, signal) => {
|
|
79
|
+
if (trace) traceRunEnd(trace, started, executable, args, status, signal);
|
|
80
|
+
resolveRun({
|
|
81
|
+
status: status ?? 2,
|
|
82
|
+
signal
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { runCaptured, runPassthrough };
|