@stll/oxlint-config 1.9.0 → 2.0.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/README.md +93 -63
- package/dist/cloud-setup-cli.cjs +1 -2
- package/dist/cloud-setup-cli.cjs.map +1 -1
- package/dist/cloud-setup-cli.mjs +1 -2
- package/dist/cloud-setup-cli.mjs.map +1 -1
- package/dist/dependabot.d.cts +0 -19
- package/dist/dependabot.d.mts +0 -19
- package/dist/git-tracked-output.cjs +1 -1
- package/dist/git-tracked-output.mjs +1 -1
- package/dist/publish-artifact-syntax.cjs +1 -1
- package/dist/publish-artifact-syntax.mjs +1 -1
- package/dist/publish-contract-cli.cjs +2 -2
- package/dist/publish-contract-cli.mjs +2 -2
- package/dist/quarantine-cli.cjs +3 -2
- package/dist/quarantine-cli.cjs.map +1 -1
- package/dist/quarantine-cli.mjs +3 -2
- package/dist/quarantine-cli.mjs.map +1 -1
- package/dist/quarantine-policy.d.cts +25 -2
- package/dist/quarantine-policy.d.mts +25 -2
- package/dist/quarantine-policy2.cjs +177 -5
- package/dist/quarantine-policy2.cjs.map +1 -1
- package/dist/quarantine-policy2.mjs +166 -6
- package/dist/quarantine-policy2.mjs.map +1 -1
- package/dist/toolchain-changed-cli.cjs +1477 -2
- package/dist/toolchain-changed-cli.cjs.map +1 -1
- package/dist/toolchain-changed-cli.mjs +1474 -1
- package/dist/toolchain-changed-cli.mjs.map +1 -1
- package/dist/toolchain-check-cli.cjs +2 -0
- package/dist/toolchain-check-cli.cjs.map +1 -1
- package/dist/toolchain-check-cli.mjs +2 -0
- package/dist/toolchain-check-cli.mjs.map +1 -1
- package/dist/toolchain-guard.cjs +351 -242
- package/dist/toolchain-guard.cjs.map +1 -1
- package/dist/toolchain-guard.mjs +347 -244
- package/dist/toolchain-guard.mjs.map +1 -1
- package/dist/toolchain-inputs.cjs +13 -40
- package/dist/toolchain-inputs.cjs.map +1 -1
- package/dist/toolchain-inputs.mjs +13 -40
- package/dist/toolchain-inputs.mjs.map +1 -1
- package/dist/toolchain-schema.cjs +2 -44
- package/dist/toolchain-schema.cjs.map +1 -1
- package/dist/toolchain-schema.mjs +2 -44
- package/dist/toolchain-schema.mjs.map +1 -1
- package/dist/typecheck-probe-cli.cjs +40 -2
- package/dist/typecheck-probe-cli.cjs.map +1 -1
- package/dist/typecheck-probe-cli.mjs +39 -1
- package/dist/typecheck-probe-cli.mjs.map +1 -1
- package/package.json +3 -4
- package/toolchain.json +2 -28
- package/dist/toolchain-bun.cjs +0 -34
- package/dist/toolchain-bun.cjs.map +0 -1
- package/dist/toolchain-bun.mjs +0 -23
- package/dist/toolchain-bun.mjs.map +0 -1
- package/dist/toolchain-changed.cjs +0 -1484
- package/dist/toolchain-changed.cjs.map +0 -1
- package/dist/toolchain-changed.mjs +0 -1477
- package/dist/toolchain-changed.mjs.map +0 -1
- package/dist/typecheck-parity-cli.cjs +0 -71
- package/dist/typecheck-parity-cli.cjs.map +0 -1
- package/dist/typecheck-parity-cli.d.cts +0 -1
- package/dist/typecheck-parity-cli.d.mts +0 -1
- package/dist/typecheck-parity-cli.mjs +0 -71
- package/dist/typecheck-parity-cli.mjs.map +0 -1
- package/dist/typecheck-parity.cjs +0 -908
- package/dist/typecheck-parity.cjs.map +0 -1
- package/dist/typecheck-parity.mjs +0 -897
- package/dist/typecheck-parity.mjs.map +0 -1
|
@@ -1,908 +0,0 @@
|
|
|
1
|
-
const require_toolchain_bun = require("./toolchain-bun.cjs");
|
|
2
|
-
let node_fs_promises = require("node:fs/promises");
|
|
3
|
-
let node_path = require("node:path");
|
|
4
|
-
let node_fs = require("node:fs");
|
|
5
|
-
let node_child_process = require("node:child_process");
|
|
6
|
-
let node_util = require("node:util");
|
|
7
|
-
let node_os = require("node:os");
|
|
8
|
-
let node_module = require("node:module");
|
|
9
|
-
let node_perf_hooks = require("node:perf_hooks");
|
|
10
|
-
//#region src/typecheck-parity.ts
|
|
11
|
-
const fixtures = [
|
|
12
|
-
{
|
|
13
|
-
name: "module-detection",
|
|
14
|
-
flags: ["noUnusedLocals"],
|
|
15
|
-
files: { "input.ts": "const unused = 1;" },
|
|
16
|
-
codes: [6133]
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: "skip-declaration-check",
|
|
20
|
-
flags: ["skipLibCheck"],
|
|
21
|
-
files: { "input.d.ts": "export declare const value: MissingType;" },
|
|
22
|
-
codes: []
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "json-import",
|
|
26
|
-
flags: ["resolveJsonModule"],
|
|
27
|
-
files: {
|
|
28
|
-
"data.json": "{ \"name\": \"value\" }",
|
|
29
|
-
"input.ts": "import data from \"./data.json\"; export const value: string = data.name;"
|
|
30
|
-
},
|
|
31
|
-
codes: []
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: "interop-import",
|
|
35
|
-
flags: ["esModuleInterop"],
|
|
36
|
-
files: {
|
|
37
|
-
"types.d.cts": "declare const value: string; export = value;",
|
|
38
|
-
"input.ts": "import value from \"./types.cjs\"; export const result: string = value;"
|
|
39
|
-
},
|
|
40
|
-
codes: []
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: "valid-control",
|
|
44
|
-
flags: [],
|
|
45
|
-
files: { "input.ts": "export const value: string = \"correct\";" },
|
|
46
|
-
codes: []
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: "type-mismatch",
|
|
50
|
-
flags: [],
|
|
51
|
-
files: { "input.ts": "export const value: number = \"wrong\";" },
|
|
52
|
-
codes: [2322]
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: "missing-property",
|
|
56
|
-
flags: [],
|
|
57
|
-
files: { "input.ts": "export const value: { name: string } = {};" },
|
|
58
|
-
codes: [2741]
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "strict-null",
|
|
62
|
-
flags: ["strictNullChecks"],
|
|
63
|
-
files: { "input.ts": "export const value: string = null;" },
|
|
64
|
-
codes: [2322]
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: "unchecked-index",
|
|
68
|
-
flags: ["noUncheckedIndexedAccess"],
|
|
69
|
-
files: { "input.ts": "export const value: string = [\"value\"][1];" },
|
|
70
|
-
codes: [2322]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: "unused-local",
|
|
74
|
-
flags: ["noUnusedLocals"],
|
|
75
|
-
files: { "input.ts": "const unused = 1; export {};" },
|
|
76
|
-
codes: [6133]
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "unused-parameter",
|
|
80
|
-
flags: ["noUnusedParameters"],
|
|
81
|
-
files: { "input.ts": "export const value = (unused: string) => 1;" },
|
|
82
|
-
codes: [6133]
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: "implicit-any",
|
|
86
|
-
flags: ["noImplicitAny"],
|
|
87
|
-
files: { "input.ts": "export const value = (input) => input;" },
|
|
88
|
-
codes: [7006]
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
name: "missing-import",
|
|
92
|
-
flags: [],
|
|
93
|
-
files: { "input.ts": "import { value } from \"./missing.js\"; export { value };" },
|
|
94
|
-
codes: [2307]
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
name: "side-effect-import",
|
|
98
|
-
flags: ["noUncheckedSideEffectImports"],
|
|
99
|
-
files: { "input.ts": "import \"./missing.js\";" },
|
|
100
|
-
codes: [2882]
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: "generic-constraint",
|
|
104
|
-
flags: [],
|
|
105
|
-
files: { "input.ts": "type Box<T extends string> = { value: T }; export type Value = Box<number>;" },
|
|
106
|
-
codes: [2344]
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
name: "exact-optional",
|
|
110
|
-
flags: ["exactOptionalPropertyTypes"],
|
|
111
|
-
files: { "input.ts": "export const value: { optional?: string } = { optional: undefined };" },
|
|
112
|
-
codes: [2375]
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: "fallthrough",
|
|
116
|
-
flags: ["noFallthroughCasesInSwitch"],
|
|
117
|
-
files: { "input.ts": "export const run = (value: number) => { switch (value) { case 0: value++; case 1: return value; default: return 0; } };" },
|
|
118
|
-
codes: [7029]
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: "implicit-override",
|
|
122
|
-
flags: ["noImplicitOverride"],
|
|
123
|
-
files: { "input.ts": "class Base { value = 1; } export class Child extends Base { value = 2; }" },
|
|
124
|
-
codes: [4114]
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: "implicit-return",
|
|
128
|
-
flags: ["noImplicitReturns"],
|
|
129
|
-
files: { "input.ts": "export const run = (value: boolean) => { if (value) return 1; };" },
|
|
130
|
-
codes: [7030]
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: "unknown-catch",
|
|
134
|
-
flags: ["useUnknownInCatchVariables"],
|
|
135
|
-
files: { "input.ts": "export const run = () => { try { return 1; } catch (error) { return error.message; } };" },
|
|
136
|
-
codes: [18046]
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "index-property",
|
|
140
|
-
flags: ["noPropertyAccessFromIndexSignature"],
|
|
141
|
-
files: { "input.ts": "export const run = (value: Record<string, string>) => value.name;" },
|
|
142
|
-
codes: [4111]
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: "erasable-syntax",
|
|
146
|
-
flags: ["erasableSyntaxOnly"],
|
|
147
|
-
files: { "input.ts": "export enum Value { First }" },
|
|
148
|
-
codes: [1294]
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
name: "type-only-import",
|
|
152
|
-
flags: ["verbatimModuleSyntax"],
|
|
153
|
-
files: {
|
|
154
|
-
"types.ts": "export type Value = string;",
|
|
155
|
-
"input.ts": "import { Value } from \"./types.js\"; export const value: Value = \"value\";"
|
|
156
|
-
},
|
|
157
|
-
codes: [1484]
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
name: "checked-javascript",
|
|
161
|
-
flags: ["allowJs", "checkJs"],
|
|
162
|
-
files: { "input.js": "/** @type {number} */\nexport const value = \"wrong\";" },
|
|
163
|
-
codes: [2322]
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
name: "strict-function",
|
|
167
|
-
flags: ["strictFunctionTypes"],
|
|
168
|
-
files: { "input.ts": "export const value: (input: string | number) => void = (input: string) => { input.toUpperCase(); };" },
|
|
169
|
-
codes: [2322]
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: "strict-initialization",
|
|
173
|
-
flags: ["strictPropertyInitialization"],
|
|
174
|
-
files: { "input.ts": "export class Value { name: string; }" },
|
|
175
|
-
codes: [2564]
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: "strict-bind",
|
|
179
|
-
flags: ["strictBindCallApply"],
|
|
180
|
-
files: { "input.ts": "const value = (input: string) => input; export const result = value.call(undefined, 1);" },
|
|
181
|
-
codes: [2345]
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: "implicit-this",
|
|
185
|
-
flags: ["noImplicitThis"],
|
|
186
|
-
files: { "input.ts": "export function value() { return this.name; }" },
|
|
187
|
-
codes: [2683]
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
name: "strict-iterator",
|
|
191
|
-
flags: ["strictBuiltinIteratorReturn"],
|
|
192
|
-
files: { "input.ts": "export const value: string = [\"value\"].values().next().value;" },
|
|
193
|
-
codes: [2322]
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
name: "always-strict",
|
|
197
|
-
flags: ["alwaysStrict"],
|
|
198
|
-
files: { "input.ts": "export const value = (eval: string) => eval;" },
|
|
199
|
-
codes: [1215]
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
name: "file-casing",
|
|
203
|
-
flags: ["forceConsistentCasingInFileNames"],
|
|
204
|
-
files: {
|
|
205
|
-
"named.ts": "export const name = \"value\";",
|
|
206
|
-
"Named.ts": "export const name = \"value\";",
|
|
207
|
-
"input.ts": "import { name } from \"./named.js\"; import { name as other } from \"./Named.js\"; export const value = name + other;"
|
|
208
|
-
},
|
|
209
|
-
codes: [1149, 1261],
|
|
210
|
-
anyCode: true
|
|
211
|
-
}
|
|
212
|
-
];
|
|
213
|
-
const diagnosticCodes = (text) => [...new Set([...text.matchAll(/(?:\b(?:error|warning)\s+(?:TS)?|<error\b[^>]*\bcode="TS)(\d{4,5})(?=:|")/g)].map((match) => Number(match.at(1))))].sort((a, b) => a - b);
|
|
214
|
-
const diagnosticParity = ({ expected, match, baseline, candidate }) => {
|
|
215
|
-
const tscCodes = diagnosticCodes(baseline.output);
|
|
216
|
-
const bunCodes = diagnosticCodes(candidate.output);
|
|
217
|
-
const seeded = match === "any" ? expected.some((code) => tscCodes.includes(code)) : expected.every((code) => tscCodes.includes(code));
|
|
218
|
-
const missing = tscCodes.filter((code) => !bunCodes.includes(code));
|
|
219
|
-
const extra = bunCodes.filter((code) => !tscCodes.includes(code));
|
|
220
|
-
const exitsMatch = expected.length === 0 ? baseline.status === 0 && candidate.status === 0 && tscCodes.length === 0 && bunCodes.length === 0 : baseline.status !== null && baseline.status !== 0 && candidate.status !== null && candidate.status !== 0;
|
|
221
|
-
return {
|
|
222
|
-
tscCodes,
|
|
223
|
-
bunCodes,
|
|
224
|
-
missing,
|
|
225
|
-
extra,
|
|
226
|
-
passed: seeded && exitsMatch && baseline.status === candidate.status && missing.length === 0 && extra.length === 0
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
const configurationDiagnostics = (output, repo) => diagnosticSet(output, repo).filter((diagnostic) => /^(?:<config>:0:|.*\.json:[0-9]+:)(?:[56][0-9]{3}|1800[23]|2688)(?::|$)/.test(diagnostic) || /:1800[23](?::|$)/.test(diagnostic));
|
|
230
|
-
const fixtureParity = (options) => {
|
|
231
|
-
const result = diagnosticParity(options);
|
|
232
|
-
const { baseline, candidate, expected, match } = options;
|
|
233
|
-
const identityParity = compareDiagnosticSets({
|
|
234
|
-
status: baseline.status,
|
|
235
|
-
diagnostics: diagnosticSet(baseline.output, options.repo ?? process.cwd())
|
|
236
|
-
}, {
|
|
237
|
-
status: candidate.status,
|
|
238
|
-
diagnostics: diagnosticSet(candidate.output, options.repo ?? process.cwd())
|
|
239
|
-
});
|
|
240
|
-
const configDiagnostics = [...configurationDiagnostics(baseline.output, options.repo ?? process.cwd()).map((diagnostic) => `TypeScript: ${diagnostic}`), ...configurationDiagnostics(candidate.output, options.repo ?? process.cwd()).map((diagnostic) => `Bun: ${diagnostic}`)];
|
|
241
|
-
const seedFiles = new Set(options.seedFiles.map((file) => (0, node_path.resolve)(options.repo ?? process.cwd(), file)));
|
|
242
|
-
const seededCodes = new Set(diagnosticSet(baseline.output, options.repo ?? process.cwd()).flatMap((diagnostic) => {
|
|
243
|
-
const diagnosticMatch = /^(.*):[0-9]+:([0-9]+)$/.exec(diagnostic);
|
|
244
|
-
const file = diagnosticMatch?.at(1);
|
|
245
|
-
const code = diagnosticMatch?.at(2);
|
|
246
|
-
return file !== void 0 && code !== void 0 && seedFiles.has((0, node_path.resolve)(options.repo ?? process.cwd(), file)) ? [Number(code)] : [];
|
|
247
|
-
}));
|
|
248
|
-
const active = expected.length > 0 && (match === "any" ? expected.some((code) => seededCodes.has(code)) : expected.every((code) => seededCodes.has(code)));
|
|
249
|
-
const validExits = baseline.status !== null && candidate.status !== null && (result.tscCodes.length === 0 ? baseline.status === 0 : baseline.status !== 0) && (result.bunCodes.length === 0 ? candidate.status === 0 : candidate.status !== 0);
|
|
250
|
-
return {
|
|
251
|
-
...result,
|
|
252
|
-
active,
|
|
253
|
-
configurationDiagnostics: configDiagnostics,
|
|
254
|
-
identityMissing: identityParity.missing,
|
|
255
|
-
identityExtra: identityParity.extra,
|
|
256
|
-
passed: configDiagnostics.length === 0 && identityParity.passed && validExits && baseline.status === candidate.status && result.missing.length === 0 && result.extra.length === 0
|
|
257
|
-
};
|
|
258
|
-
};
|
|
259
|
-
const fixtureRunPassed = (results) => results.some(({ active }) => active) && results.every(({ passed }) => passed);
|
|
260
|
-
const diagnosticLocation = (file, repo) => {
|
|
261
|
-
const normalized = file.replaceAll("\\", "/");
|
|
262
|
-
const bundled = /^bundled:\/\/\/libs\/(lib\.[^/]+\.d\.ts)$/.exec(normalized);
|
|
263
|
-
const installed = /(?:^|\/)node_modules\/(?:typescript|@typescript\/(?:native|typescript-[^/]+))\/(?:.*\/)?(lib\.[^/]+\.d\.ts)$/.exec(normalized);
|
|
264
|
-
const library = bundled?.at(1) ?? installed?.at(1);
|
|
265
|
-
return library === void 0 ? (0, node_path.relative)(repo, (0, node_path.resolve)(repo, file)).replaceAll("\\", "/") : `<lib>/${library}`;
|
|
266
|
-
};
|
|
267
|
-
const globalDiagnosticKey = (code, message) => `<config>:0:${code}:${message.trim().replaceAll(/\s+/g, " ")}`;
|
|
268
|
-
const diagnosticSet = (output, repo) => {
|
|
269
|
-
const clean = (0, node_util.stripVTControlCharacters)(output);
|
|
270
|
-
const diagnostics = /* @__PURE__ */ new Set();
|
|
271
|
-
for (const block of clean.matchAll(/<error\b([^>]*)>([\s\S]*?)<\/error>/g)) {
|
|
272
|
-
const attributes = new Map([...(block.at(1) ?? "").matchAll(/(\w+)="([^"]*)"/g)].map((match) => [match.at(1), match.at(2)]));
|
|
273
|
-
const file = attributes.get("file");
|
|
274
|
-
const row = attributes.get("line");
|
|
275
|
-
const code = attributes.get("code");
|
|
276
|
-
if (code === void 0 || !/^TS\d+$/.test(code)) continue;
|
|
277
|
-
if (file !== void 0 && row !== void 0 && row !== "0") diagnostics.add(`${diagnosticLocation(file, repo)}:${row}:${code.slice(2)}`);
|
|
278
|
-
else {
|
|
279
|
-
const message = (block.at(2) ?? "").split(/<(?:source|related)\b/).at(0) ?? "";
|
|
280
|
-
diagnostics.add(globalDiagnosticKey(code.slice(2), message));
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
for (const rawLine of clean.split("\n")) {
|
|
284
|
-
const line = rawLine.replace(/^(?!(?:error|warning) TS\d+:)(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]* [a-zA-Z0-9_.:-]+: /, "");
|
|
285
|
-
if (line.startsWith("<error ")) continue;
|
|
286
|
-
const match = /^(.*?)\((\d+),\d+\):\s*(?:error|warning) TS(\d+)/.exec(line) ?? /^(.*?):(\d+):\d+:\s*(?:error|warning) (?:TS)?(\d+)/.exec(line);
|
|
287
|
-
if (match) {
|
|
288
|
-
const [, file = "", row = "", code = ""] = match;
|
|
289
|
-
diagnostics.add(`${diagnosticLocation(file, repo)}:${row}:${code}`);
|
|
290
|
-
} else {
|
|
291
|
-
const global = /^(?:error|warning) TS(\d+):\s*(.*)/.exec(line);
|
|
292
|
-
if (global) diagnostics.add(globalDiagnosticKey(global.at(1) ?? "", global.at(2) ?? ""));
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return [...diagnostics].sort();
|
|
296
|
-
};
|
|
297
|
-
const compareDiagnosticSets = (baseline, candidate) => {
|
|
298
|
-
const missing = baseline.diagnostics.filter((item) => !candidate.diagnostics.includes(item));
|
|
299
|
-
const extra = candidate.diagnostics.filter((item) => !baseline.diagnostics.includes(item));
|
|
300
|
-
const valid = (result) => result.status !== null && (result.diagnostics.length === 0 ? result.status === 0 : result.status !== 0);
|
|
301
|
-
return {
|
|
302
|
-
missing,
|
|
303
|
-
extra,
|
|
304
|
-
passed: valid(baseline) && valid(candidate) && baseline.status === candidate.status && missing.length === 0 && extra.length === 0
|
|
305
|
-
};
|
|
306
|
-
};
|
|
307
|
-
const assertUnshadowedCheck = async (repo) => {
|
|
308
|
-
const manifest = JSON.parse(await (0, node_fs_promises.readFile)((0, node_path.join)(repo, "package.json"), "utf8"));
|
|
309
|
-
if (typeof manifest !== "object" || manifest === null) throw new Error("Invalid repository package.json");
|
|
310
|
-
if ("scripts" in manifest && typeof manifest.scripts === "object" && manifest.scripts !== null && "check" in manifest.scripts) throw new Error("Repository package.json must not define a \"check\" script: it shadows Bun typechecking; rename that script before running parity");
|
|
311
|
-
};
|
|
312
|
-
const resolveCompiler = async (repo, policy) => {
|
|
313
|
-
if (typeof policy !== "object" || policy === null || !("typescriptInstallLayouts" in policy) || !Array.isArray(policy.typescriptInstallLayouts)) throw new Error("toolchain.json must define typescriptInstallLayouts");
|
|
314
|
-
const manifest = JSON.parse(await (0, node_fs_promises.readFile)((0, node_path.join)(repo, "package.json"), "utf8"));
|
|
315
|
-
if (typeof manifest !== "object" || manifest === null) throw new Error("Invalid repository package.json");
|
|
316
|
-
const dependencies = /* @__PURE__ */ new Map();
|
|
317
|
-
for (const key of ["dependencies", "devDependencies"]) {
|
|
318
|
-
if (!(key in manifest)) continue;
|
|
319
|
-
const section = Reflect.get(manifest, key);
|
|
320
|
-
if (typeof section === "object" && section !== null) for (const [name, specifier] of Object.entries(section)) dependencies.set(name, specifier);
|
|
321
|
-
}
|
|
322
|
-
const require$1 = (0, node_module.createRequire)((0, node_path.join)(repo, "package.json"));
|
|
323
|
-
for (const layout of [...policy.typescriptInstallLayouts].reverse()) {
|
|
324
|
-
if (typeof layout !== "object" || layout === null || !("compilerPackage" in layout) || typeof layout.compilerPackage !== "string") throw new Error("Invalid TypeScript install layout");
|
|
325
|
-
if (!dependencies.has(layout.compilerPackage)) continue;
|
|
326
|
-
const packagePath = require$1.resolve(`${layout.compilerPackage}/package.json`);
|
|
327
|
-
const installed = JSON.parse(await (0, node_fs_promises.readFile)(packagePath, "utf8"));
|
|
328
|
-
if (typeof installed !== "object" || installed === null || !("bin" in installed) || typeof installed.bin !== "object" || installed.bin === null || !("tsc" in installed.bin) || typeof installed.bin.tsc !== "string") throw new Error(`${layout.compilerPackage} must expose a tsc binary`);
|
|
329
|
-
if (!("compilerSpecifier" in layout) || typeof layout.compilerSpecifier !== "string") throw new Error("TypeScript install layout must define compilerSpecifier");
|
|
330
|
-
const expectedVersion = layout.compilerSpecifier.replace(/^npm:typescript@/, "");
|
|
331
|
-
if (!("version" in installed) || installed.version !== expectedVersion) throw new Error(`${layout.compilerPackage} must install TypeScript ${expectedVersion}`);
|
|
332
|
-
return (0, node_path.resolve)(packagePath, "..", installed.bin.tsc);
|
|
333
|
-
}
|
|
334
|
-
throw new Error("Repository must declare a compiler from typescriptInstallLayouts");
|
|
335
|
-
};
|
|
336
|
-
const assertBunVersion = (bun, policy) => {
|
|
337
|
-
if (typeof policy !== "object" || policy === null || !("bun" in policy) || typeof policy.bun !== "string") throw new Error("toolchain.json must define bun");
|
|
338
|
-
const result = (0, node_child_process.spawnSync)(bun, ["--version"], { encoding: "utf8" });
|
|
339
|
-
if (result.error) throw result.error;
|
|
340
|
-
const installed = result.stdout.trim();
|
|
341
|
-
if (result.status !== 0 || !require_toolchain_bun.satisfiesBunFloor(installed, policy.bun)) throw new Error(`Bun must be ${policy.bun} or later; selected runtime reports ${installed || "no version"}`);
|
|
342
|
-
};
|
|
343
|
-
const bunCheckArgs = (project, build = false) => [
|
|
344
|
-
"check",
|
|
345
|
-
"--no-pretty",
|
|
346
|
-
"--all",
|
|
347
|
-
...build ? ["--build"] : [],
|
|
348
|
-
...project === void 0 ? [] : [`--project=${project}`]
|
|
349
|
-
];
|
|
350
|
-
const canonicalOptions = (value) => {
|
|
351
|
-
if (Array.isArray(value)) return `[${value.map(canonicalOptions).join(",")}]`;
|
|
352
|
-
if (typeof value === "object" && value !== null) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalOptions(Reflect.get(value, key))}`).join(",")}}`;
|
|
353
|
-
if (value !== null && typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") throw new Error("Invalid effective compiler option");
|
|
354
|
-
return JSON.stringify(value);
|
|
355
|
-
};
|
|
356
|
-
const EMIT_ONLY_OPTIONS = /* @__PURE__ */ new Set([
|
|
357
|
-
"composite",
|
|
358
|
-
"declaration",
|
|
359
|
-
"declarationDir",
|
|
360
|
-
"declarationMap",
|
|
361
|
-
"emitDeclarationOnly",
|
|
362
|
-
"outDir",
|
|
363
|
-
"outFile",
|
|
364
|
-
"rootDir",
|
|
365
|
-
"sourceMap",
|
|
366
|
-
"inlineSourceMap",
|
|
367
|
-
"inlineSources",
|
|
368
|
-
"incremental",
|
|
369
|
-
"tsBuildInfoFile",
|
|
370
|
-
"noEmitOnError",
|
|
371
|
-
"importHelpers",
|
|
372
|
-
"noEmitHelpers",
|
|
373
|
-
"emitBOM",
|
|
374
|
-
"mapRoot",
|
|
375
|
-
"sourceRoot",
|
|
376
|
-
"newLine",
|
|
377
|
-
"preserveConstEnums",
|
|
378
|
-
"removeComments",
|
|
379
|
-
"stripInternal",
|
|
380
|
-
"downlevelIteration",
|
|
381
|
-
"isolatedDeclarations",
|
|
382
|
-
"noEmit"
|
|
383
|
-
]);
|
|
384
|
-
const resolvedCompilerOptions = ({ compilerOptions, configPath }) => {
|
|
385
|
-
if (typeof compilerOptions !== "object" || compilerOptions === null || Array.isArray(compilerOptions)) throw new Error(`Invalid compiler options: ${configPath}`);
|
|
386
|
-
const options = Object.fromEntries(Object.entries(compilerOptions));
|
|
387
|
-
const directory = (0, node_path.dirname)(configPath);
|
|
388
|
-
const rootDir = options["rootDir"];
|
|
389
|
-
if (rootDir !== void 0 && typeof rootDir !== "string") throw new Error(`Invalid rootDir: ${configPath}`);
|
|
390
|
-
if (typeof rootDir === "string") options["rootDir"] = (0, node_path.resolve)(directory, rootDir);
|
|
391
|
-
let resolutionDirectory = directory;
|
|
392
|
-
const absolutePaths = (value) => {
|
|
393
|
-
if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) throw new Error(`Invalid compiler path option: ${configPath}`);
|
|
394
|
-
return value.map((entry) => (0, node_path.resolve)(resolutionDirectory, entry));
|
|
395
|
-
};
|
|
396
|
-
for (const name of ["rootDirs", "typeRoots"]) if (name in options) options[name] = absolutePaths(options[name]);
|
|
397
|
-
if ("baseUrl" in options) {
|
|
398
|
-
const baseUrl = options["baseUrl"];
|
|
399
|
-
if (typeof baseUrl !== "string") throw new Error(`Invalid baseUrl: ${configPath}`);
|
|
400
|
-
resolutionDirectory = (0, node_path.resolve)(directory, baseUrl);
|
|
401
|
-
options["baseUrl"] = resolutionDirectory;
|
|
402
|
-
}
|
|
403
|
-
if ("paths" in options) {
|
|
404
|
-
const paths = options["paths"];
|
|
405
|
-
if (typeof paths !== "object" || paths === null || Array.isArray(paths)) throw new Error(`Invalid paths: ${configPath}`);
|
|
406
|
-
options["paths"] = Object.fromEntries(Object.entries(paths).map(([key, value]) => [key, absolutePaths(value)]));
|
|
407
|
-
}
|
|
408
|
-
return options;
|
|
409
|
-
};
|
|
410
|
-
const fixtureCompilerOptions = (args) => {
|
|
411
|
-
const options = Object.fromEntries(Object.entries(resolvedCompilerOptions(args)).filter(([name]) => !EMIT_ONLY_OPTIONS.has(name)));
|
|
412
|
-
options["noEmit"] = true;
|
|
413
|
-
return options;
|
|
414
|
-
};
|
|
415
|
-
const fixtureInputs = ({ files, compilerOptions }) => {
|
|
416
|
-
const inputs = files.filter((file) => /\.(?:[cm]?[jt]sx?|json)$/.test(file));
|
|
417
|
-
for (const input of inputs) {
|
|
418
|
-
if (/\.[cm]?jsx?$/.test(input) && compilerOptions["allowJs"] !== true) return {
|
|
419
|
-
status: "inapplicable",
|
|
420
|
-
reason: `${input} requires allowJs`
|
|
421
|
-
};
|
|
422
|
-
if (input.endsWith(".json") && compilerOptions["resolveJsonModule"] !== true) return {
|
|
423
|
-
status: "inapplicable",
|
|
424
|
-
reason: `${input} requires resolveJsonModule`
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
return {
|
|
428
|
-
status: "applicable",
|
|
429
|
-
files: inputs
|
|
430
|
-
};
|
|
431
|
-
};
|
|
432
|
-
const fixturePackageContext = (configPath) => {
|
|
433
|
-
for (let folder = (0, node_path.dirname)(configPath);; folder = (0, node_path.dirname)(folder)) {
|
|
434
|
-
try {
|
|
435
|
-
const manifest = JSON.parse((0, node_fs.readFileSync)((0, node_path.join)(folder, "package.json"), "utf8"));
|
|
436
|
-
if (typeof manifest !== "object" || manifest === null) throw new Error(`Invalid package.json: ${folder}`);
|
|
437
|
-
if (!("type" in manifest)) return {};
|
|
438
|
-
if (manifest.type !== "module" && manifest.type !== "commonjs") throw new Error(`Invalid package type: ${folder}`);
|
|
439
|
-
return { type: manifest.type };
|
|
440
|
-
} catch (error) {
|
|
441
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") throw error;
|
|
442
|
-
}
|
|
443
|
-
if ((0, node_path.dirname)(folder) === folder) return {};
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
const groupCompilerConfigs = (configs) => {
|
|
447
|
-
const groups = /* @__PURE__ */ new Map();
|
|
448
|
-
for (const config of configs) {
|
|
449
|
-
const compilerOptions = fixtureCompilerOptions({
|
|
450
|
-
compilerOptions: config.compilerOptions,
|
|
451
|
-
configPath: config.path
|
|
452
|
-
});
|
|
453
|
-
const key = canonicalOptions({
|
|
454
|
-
compilerOptions,
|
|
455
|
-
resolutionContext: "typeRoots" in compilerOptions ? null : (0, node_path.dirname)(config.path),
|
|
456
|
-
packageContext: config.packageContext ?? {}
|
|
457
|
-
});
|
|
458
|
-
const existing = groups.get(key);
|
|
459
|
-
if (existing) existing.projects.push(config.path);
|
|
460
|
-
else groups.set(key, {
|
|
461
|
-
path: config.path,
|
|
462
|
-
projects: [config.path],
|
|
463
|
-
compilerOptions: config.compilerOptions,
|
|
464
|
-
...config.packageContext === void 0 ? {} : { packageContext: config.packageContext }
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
return [...groups.values()];
|
|
468
|
-
};
|
|
469
|
-
const discoverConfigGroups = ({ repo, compiler, project }) => {
|
|
470
|
-
const configs = [];
|
|
471
|
-
const visited = /* @__PURE__ */ new Set();
|
|
472
|
-
const projects = [];
|
|
473
|
-
let build = false;
|
|
474
|
-
const visit = (inputPath) => {
|
|
475
|
-
const path = (0, node_fs.realpathSync)((0, node_fs.statSync)(inputPath).isDirectory() ? (0, node_path.join)(inputPath, "tsconfig.json") : inputPath);
|
|
476
|
-
(0, node_fs.readFileSync)(path, "utf8");
|
|
477
|
-
if (visited.has(path)) return;
|
|
478
|
-
visited.add(path);
|
|
479
|
-
const result = (0, node_child_process.spawnSync)(process.execPath, [
|
|
480
|
-
compiler,
|
|
481
|
-
"--showConfig",
|
|
482
|
-
"--project",
|
|
483
|
-
path
|
|
484
|
-
], {
|
|
485
|
-
cwd: repo,
|
|
486
|
-
encoding: "utf8",
|
|
487
|
-
maxBuffer: 67108864
|
|
488
|
-
});
|
|
489
|
-
if (result.error) throw result.error;
|
|
490
|
-
if (result.status !== 0) throw new Error(result.stdout + result.stderr);
|
|
491
|
-
const config = JSON.parse(result.stdout);
|
|
492
|
-
if (typeof config !== "object" || config === null) throw new Error(`Invalid resolved config: ${path}`);
|
|
493
|
-
const references = "references" in config && Array.isArray(config.references) ? config.references : [];
|
|
494
|
-
build ||= project === void 0 && references.length > 0;
|
|
495
|
-
const compilerOptions = "compilerOptions" in config ? config.compilerOptions : {};
|
|
496
|
-
if (typeof compilerOptions !== "object" || compilerOptions === null || Array.isArray(compilerOptions)) throw new Error(`Invalid compiler options: ${path}`);
|
|
497
|
-
const rawFiles = "files" in config ? config.files : [];
|
|
498
|
-
if (!Array.isArray(rawFiles)) throw new Error(`Invalid project files: ${path}`);
|
|
499
|
-
const files = rawFiles.map((file) => {
|
|
500
|
-
if (typeof file !== "string") throw new Error(`Invalid project file: ${path}`);
|
|
501
|
-
return (0, node_path.resolve)((0, node_path.dirname)(path), file);
|
|
502
|
-
});
|
|
503
|
-
if (files.length === 0 && (project !== void 0 || references.length === 0)) throw new Error(`Project resolves to zero input files: ${path}`);
|
|
504
|
-
const referencePaths = [];
|
|
505
|
-
const resolvedReferences = [];
|
|
506
|
-
projects.push({
|
|
507
|
-
path,
|
|
508
|
-
compilerOptions,
|
|
509
|
-
files,
|
|
510
|
-
references: referencePaths,
|
|
511
|
-
resolvedReferences
|
|
512
|
-
});
|
|
513
|
-
if (files.length > 0 || references.length === 0) configs.push({
|
|
514
|
-
path,
|
|
515
|
-
compilerOptions,
|
|
516
|
-
packageContext: fixturePackageContext(path)
|
|
517
|
-
});
|
|
518
|
-
for (const reference of references) {
|
|
519
|
-
if (typeof reference !== "object" || reference === null || !("path" in reference) || typeof reference.path !== "string") throw new Error(`Invalid project reference: ${path}`);
|
|
520
|
-
const referencedProject = (0, node_path.resolve)((0, node_path.dirname)(path), reference.path);
|
|
521
|
-
const referencePath = (0, node_fs.realpathSync)((0, node_fs.statSync)(referencedProject).isDirectory() ? (0, node_path.join)(referencedProject, "tsconfig.json") : referencedProject);
|
|
522
|
-
referencePaths.push(referencePath);
|
|
523
|
-
resolvedReferences.push({
|
|
524
|
-
...reference,
|
|
525
|
-
path: referencePath
|
|
526
|
-
});
|
|
527
|
-
if (project === void 0) visit(referencePath);
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
const selected = (0, node_path.resolve)(repo, project ?? "tsconfig.json");
|
|
531
|
-
const root = (0, node_fs.realpathSync)((0, node_fs.statSync)(selected).isDirectory() ? (0, node_path.join)(selected, "tsconfig.json") : selected);
|
|
532
|
-
visit(root);
|
|
533
|
-
const groups = groupCompilerConfigs(configs);
|
|
534
|
-
if (groups.length === 0) throw new Error("No consumer compiler configurations to compare");
|
|
535
|
-
return {
|
|
536
|
-
build,
|
|
537
|
-
groups,
|
|
538
|
-
projects,
|
|
539
|
-
root
|
|
540
|
-
};
|
|
541
|
-
};
|
|
542
|
-
const discoverProjectGraphs = ({ repo, compiler, projects }) => {
|
|
543
|
-
if (projects === void 0) return [discoverConfigGroups({
|
|
544
|
-
repo,
|
|
545
|
-
compiler
|
|
546
|
-
})];
|
|
547
|
-
if (projects.length === 0) throw new Error("Select at least one project");
|
|
548
|
-
const graphs = /* @__PURE__ */ new Map();
|
|
549
|
-
for (const project of projects) {
|
|
550
|
-
const graph = discoverConfigGroups({
|
|
551
|
-
repo,
|
|
552
|
-
compiler,
|
|
553
|
-
project
|
|
554
|
-
});
|
|
555
|
-
if (!graphs.has(graph.root)) graphs.set(graph.root, graph);
|
|
556
|
-
}
|
|
557
|
-
return [...graphs.values()];
|
|
558
|
-
};
|
|
559
|
-
const timedCommand = ({ command, args, repo }) => {
|
|
560
|
-
const started = node_perf_hooks.performance.now();
|
|
561
|
-
const timerFlag = process.platform === "darwin" ? "-l" : "-v";
|
|
562
|
-
const result = (0, node_child_process.spawnSync)("/usr/bin/time", [
|
|
563
|
-
timerFlag,
|
|
564
|
-
command,
|
|
565
|
-
...args
|
|
566
|
-
], {
|
|
567
|
-
cwd: repo,
|
|
568
|
-
encoding: "utf8",
|
|
569
|
-
maxBuffer: 67108864
|
|
570
|
-
});
|
|
571
|
-
if (result.error) throw result.error;
|
|
572
|
-
const rss = process.platform === "darwin" ? /([0-9]+)\s+maximum resident set size/.exec(result.stderr) : /Maximum resident set size \(kbytes\):\s*([0-9]+)/.exec(result.stderr);
|
|
573
|
-
if (!rss) throw new Error("Cannot measure maximum RSS with /usr/bin/time");
|
|
574
|
-
return {
|
|
575
|
-
status: result.status,
|
|
576
|
-
output: result.stdout + result.stderr,
|
|
577
|
-
wall: (node_perf_hooks.performance.now() - started) / 1e3,
|
|
578
|
-
maxRssKiB: Number(rss[1]) / (process.platform === "darwin" ? 1024 : 1)
|
|
579
|
-
};
|
|
580
|
-
};
|
|
581
|
-
const NO_WORK_MAX_RSS_KIB = 16384;
|
|
582
|
-
const NO_WORK_MAX_WALL_SECONDS = .25;
|
|
583
|
-
const sourceDiagnosticSet = ({ output, repo, scratch, configPaths }) => {
|
|
584
|
-
const configs = new Set(configPaths.map((path) => (0, node_path.resolve)(path)));
|
|
585
|
-
const invalid = new Set(configurationDiagnostics(output, repo));
|
|
586
|
-
return diagnosticSet(output, repo).filter((diagnostic) => {
|
|
587
|
-
if (invalid.has(diagnostic)) return false;
|
|
588
|
-
if (diagnostic.startsWith("<config>:")) return true;
|
|
589
|
-
const file = /^(.*):[0-9]+:[0-9]+$/.exec(diagnostic)?.at(1);
|
|
590
|
-
if (file === void 0) return false;
|
|
591
|
-
const path = (0, node_path.resolve)(repo, file);
|
|
592
|
-
return !configs.has(path) && path !== scratch && !path.startsWith(scratch + "/");
|
|
593
|
-
});
|
|
594
|
-
};
|
|
595
|
-
const diagnosticExitStatus = ({ status, output, repo }) => status === 2 && configurationDiagnostics(output, repo).length === 0 && diagnosticSet(output, repo).some((diagnostic) => !diagnostic.startsWith("<config>:")) ? 1 : status;
|
|
596
|
-
const repositoryDiagnosticComparison = ({ baseline, candidate, repo, scratch, configPaths }) => {
|
|
597
|
-
const configs = new Set(configPaths.map((path) => (0, node_path.resolve)(path)));
|
|
598
|
-
const configurationErrors = (output) => [.../* @__PURE__ */ new Set([...configurationDiagnostics(output, repo), ...diagnosticSet(output, repo).filter((diagnostic) => {
|
|
599
|
-
const file = /^(.*):[0-9]+:[0-9]+$/.exec(diagnostic)?.at(1);
|
|
600
|
-
return file !== void 0 && configs.has((0, node_path.resolve)(repo, file));
|
|
601
|
-
})])];
|
|
602
|
-
const configurationErrorsFound = [...configurationErrors(baseline.output).map((diagnostic) => `TypeScript: ${diagnostic}`), ...configurationErrors(candidate.output).map((diagnostic) => `Bun: ${diagnostic}`)];
|
|
603
|
-
const diagnostics = (output) => sourceDiagnosticSet({
|
|
604
|
-
output,
|
|
605
|
-
repo,
|
|
606
|
-
scratch,
|
|
607
|
-
configPaths
|
|
608
|
-
});
|
|
609
|
-
const comparison = compareDiagnosticSets({
|
|
610
|
-
status: baseline.status,
|
|
611
|
-
diagnostics: diagnostics(baseline.output)
|
|
612
|
-
}, {
|
|
613
|
-
status: candidate.status,
|
|
614
|
-
diagnostics: diagnostics(candidate.output)
|
|
615
|
-
});
|
|
616
|
-
return {
|
|
617
|
-
...comparison,
|
|
618
|
-
passed: configurationErrorsFound.length === 0 && comparison.passed,
|
|
619
|
-
configurationDiagnostics: configurationErrorsFound
|
|
620
|
-
};
|
|
621
|
-
};
|
|
622
|
-
const temporaryProjectTree = async ({ scratch, projects }) => {
|
|
623
|
-
const contexts = /* @__PURE__ */ new Map();
|
|
624
|
-
const linkedFolders = /* @__PURE__ */ new Set();
|
|
625
|
-
for (const project of projects) {
|
|
626
|
-
const path = (0, node_path.join)(scratch, "projects", (0, node_path.relative)((0, node_path.resolve)("/"), project));
|
|
627
|
-
const folder = (0, node_path.dirname)(path);
|
|
628
|
-
await (0, node_fs_promises.mkdir)(folder, { recursive: true });
|
|
629
|
-
for (let original = (0, node_path.dirname)(project);; original = (0, node_path.dirname)(original)) {
|
|
630
|
-
if (!linkedFolders.has(original)) {
|
|
631
|
-
linkedFolders.add(original);
|
|
632
|
-
const modules = (0, node_path.join)(original, "node_modules");
|
|
633
|
-
try {
|
|
634
|
-
if ((0, node_fs.statSync)(modules).isDirectory()) {
|
|
635
|
-
const destination = (0, node_path.join)(scratch, "projects", (0, node_path.relative)((0, node_path.resolve)("/"), original));
|
|
636
|
-
await (0, node_fs_promises.mkdir)(destination, { recursive: true });
|
|
637
|
-
await (0, node_fs_promises.symlink)(modules, (0, node_path.join)(destination, "node_modules"), "dir");
|
|
638
|
-
}
|
|
639
|
-
} catch (error) {
|
|
640
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") throw error;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
if ((0, node_path.dirname)(original) === original) break;
|
|
644
|
-
}
|
|
645
|
-
contexts.set(project, {
|
|
646
|
-
path,
|
|
647
|
-
folder,
|
|
648
|
-
outputFolder: (0, node_path.join)(folder, `${(0, node_path.basename)(path)}.parity-output`)
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
return contexts;
|
|
652
|
-
};
|
|
653
|
-
const compareRepository = async ({ repo, compiler, bun, graph }) => {
|
|
654
|
-
const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "parity-repository-"));
|
|
655
|
-
try {
|
|
656
|
-
const contexts = await temporaryProjectTree({
|
|
657
|
-
scratch,
|
|
658
|
-
projects: graph.projects.map(({ path }) => path)
|
|
659
|
-
});
|
|
660
|
-
const configPaths = new Map([...contexts].map(([original, context]) => [original, context.path]));
|
|
661
|
-
const requiredOutputs = new Set(graph.projects.flatMap(({ references }) => references));
|
|
662
|
-
for (const project of graph.projects) {
|
|
663
|
-
const context = contexts.get(project.path);
|
|
664
|
-
if (context === void 0) throw new Error(`Missing temporary project: ${project.path}`);
|
|
665
|
-
const { path: configPath, outputFolder } = context;
|
|
666
|
-
const options = resolvedCompilerOptions({
|
|
667
|
-
configPath: project.path,
|
|
668
|
-
compilerOptions: project.compilerOptions
|
|
669
|
-
});
|
|
670
|
-
const declarationsRequired = graph.build && requiredOutputs.has(project.path) && options["composite"] === true;
|
|
671
|
-
options["noEmit"] = !graph.build || options["noEmit"] === true && !declarationsRequired;
|
|
672
|
-
const relocatesOutput = options["noEmit"] !== true || "outDir" in options || "declarationDir" in options;
|
|
673
|
-
if (!("rootDir" in options) && relocatesOutput) options["rootDir"] = (0, node_path.dirname)(project.path);
|
|
674
|
-
if (relocatesOutput) options["outDir"] = (0, node_path.join)(outputFolder, "output");
|
|
675
|
-
const emitsDeclarations = options["declaration"] === true || options["composite"] === true && options["declaration"] !== false;
|
|
676
|
-
if (graph.build && emitsDeclarations || "declarationDir" in options) options["declarationDir"] = (0, node_path.join)(outputFolder, "declarations");
|
|
677
|
-
if (graph.build || options["incremental"] === true || options["composite"] === true) options["tsBuildInfoFile"] = (0, node_path.join)(outputFolder, "project.tsbuildinfo");
|
|
678
|
-
if (graph.build) {
|
|
679
|
-
options["declarationMap"] = false;
|
|
680
|
-
if (emitsDeclarations) options["emitDeclarationOnly"] = true;
|
|
681
|
-
options["noEmitOnError"] = false;
|
|
682
|
-
}
|
|
683
|
-
if ("outFile" in options) options["outFile"] = (0, node_path.join)(outputFolder, "bundle.js");
|
|
684
|
-
await (0, node_fs_promises.writeFile)(configPath, JSON.stringify({
|
|
685
|
-
compilerOptions: options,
|
|
686
|
-
files: project.files,
|
|
687
|
-
include: [],
|
|
688
|
-
references: graph.build ? project.references.map((path) => {
|
|
689
|
-
const temporary = configPaths.get(path);
|
|
690
|
-
if (temporary === void 0) throw new Error(`Missing referenced temporary project: ${path}`);
|
|
691
|
-
return { path: temporary };
|
|
692
|
-
}) : project.resolvedReferences
|
|
693
|
-
}));
|
|
694
|
-
}
|
|
695
|
-
const root = configPaths.get(graph.root);
|
|
696
|
-
if (root === void 0) throw new Error("Missing temporary root config");
|
|
697
|
-
const baselineRaw = timedCommand({
|
|
698
|
-
command: process.execPath,
|
|
699
|
-
args: [
|
|
700
|
-
compiler,
|
|
701
|
-
...graph.build ? [
|
|
702
|
-
"--build",
|
|
703
|
-
"--force",
|
|
704
|
-
root
|
|
705
|
-
] : [
|
|
706
|
-
"--noEmit",
|
|
707
|
-
"--project",
|
|
708
|
-
root
|
|
709
|
-
],
|
|
710
|
-
"--pretty",
|
|
711
|
-
"false"
|
|
712
|
-
],
|
|
713
|
-
repo
|
|
714
|
-
});
|
|
715
|
-
const candidate = timedCommand({
|
|
716
|
-
command: bun,
|
|
717
|
-
args: bunCheckArgs(root, graph.build),
|
|
718
|
-
repo
|
|
719
|
-
});
|
|
720
|
-
const sourceDiagnostics = (output) => sourceDiagnosticSet({
|
|
721
|
-
output,
|
|
722
|
-
repo,
|
|
723
|
-
scratch,
|
|
724
|
-
configPaths: graph.projects.map(({ path }) => path)
|
|
725
|
-
});
|
|
726
|
-
const baselineDiagnostics = sourceDiagnostics(baselineRaw.output);
|
|
727
|
-
const baseline = {
|
|
728
|
-
...baselineRaw,
|
|
729
|
-
rawStatus: baselineRaw.status,
|
|
730
|
-
status: diagnosticExitStatus({
|
|
731
|
-
status: baselineRaw.status,
|
|
732
|
-
output: baselineRaw.output,
|
|
733
|
-
repo
|
|
734
|
-
}),
|
|
735
|
-
diagnostics: baselineDiagnostics
|
|
736
|
-
};
|
|
737
|
-
const repository = repositoryDiagnosticComparison({
|
|
738
|
-
baseline,
|
|
739
|
-
candidate,
|
|
740
|
-
repo,
|
|
741
|
-
scratch,
|
|
742
|
-
configPaths: [...graph.projects.map(({ path }) => path), ...configPaths.values()]
|
|
743
|
-
});
|
|
744
|
-
return {
|
|
745
|
-
baseline,
|
|
746
|
-
candidate: {
|
|
747
|
-
...candidate,
|
|
748
|
-
rawStatus: candidate.status,
|
|
749
|
-
diagnostics: sourceDiagnostics(candidate.output)
|
|
750
|
-
},
|
|
751
|
-
repository
|
|
752
|
-
};
|
|
753
|
-
} finally {
|
|
754
|
-
await (0, node_fs_promises.rm)(scratch, {
|
|
755
|
-
recursive: true,
|
|
756
|
-
force: true
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
const runTypecheckParity = async ({ repo, policy, bun = process.versions.bun ? process.execPath : "bun", projects }) => {
|
|
761
|
-
await assertUnshadowedCheck(repo);
|
|
762
|
-
assertBunVersion(bun, policy);
|
|
763
|
-
const compiler = await resolveCompiler(repo, policy);
|
|
764
|
-
const graphs = discoverProjectGraphs({
|
|
765
|
-
repo,
|
|
766
|
-
compiler,
|
|
767
|
-
projects
|
|
768
|
-
});
|
|
769
|
-
const results = [];
|
|
770
|
-
for (const graph of graphs) results.push(await runConfigParity({
|
|
771
|
-
repo,
|
|
772
|
-
compiler,
|
|
773
|
-
bun,
|
|
774
|
-
graph
|
|
775
|
-
}));
|
|
776
|
-
return results.every((passed) => passed);
|
|
777
|
-
};
|
|
778
|
-
const runConfigParity = async ({ repo, compiler, bun, graph }) => {
|
|
779
|
-
const { groups } = graph;
|
|
780
|
-
const { baseline, candidate, repository } = await compareRepository({
|
|
781
|
-
repo,
|
|
782
|
-
compiler,
|
|
783
|
-
bun,
|
|
784
|
-
graph
|
|
785
|
-
});
|
|
786
|
-
console.log("Class | TypeScript diagnostics | Bun diagnostics | Result");
|
|
787
|
-
console.log(`repository | ${baseline.diagnostics.join(",")} | ${candidate.diagnostics.join(",")} | ${repository.passed ? "PASS" : "FAIL"}`);
|
|
788
|
-
console.log(`repository tsc: wall=${baseline.wall.toFixed(3)}s maxRSS=${baseline.maxRssKiB}KiB exit=${baseline.rawStatus}`);
|
|
789
|
-
console.log(`repository bun: wall=${candidate.wall.toFixed(3)}s maxRSS=${candidate.maxRssKiB}KiB exit=${candidate.rawStatus}`);
|
|
790
|
-
for (const diagnostic of repository.configurationDiagnostics) console.error(`FAIL: invalid repository configuration: ${diagnostic}`);
|
|
791
|
-
const scratch = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "typecheck-parity-"));
|
|
792
|
-
const groupResults = [];
|
|
793
|
-
try {
|
|
794
|
-
for (const [index, group] of groups.entries()) {
|
|
795
|
-
console.log(`Config group ${index + 1}: ${(0, node_path.relative)(repo, group.path)} (${group.projects.length} projects)`);
|
|
796
|
-
const results = [];
|
|
797
|
-
let tscWall = 0;
|
|
798
|
-
let bunWall = 0;
|
|
799
|
-
let tscRss = 0;
|
|
800
|
-
let bunRss = 0;
|
|
801
|
-
const context = (await temporaryProjectTree({
|
|
802
|
-
scratch: (0, node_path.join)(scratch, `config-${index + 1}`),
|
|
803
|
-
projects: [group.path]
|
|
804
|
-
})).get(group.path);
|
|
805
|
-
if (context === void 0) throw new Error(`Missing temporary fixture context: ${group.path}`);
|
|
806
|
-
const groupFolder = context.folder;
|
|
807
|
-
const compilerOptions = fixtureCompilerOptions({
|
|
808
|
-
compilerOptions: group.compilerOptions,
|
|
809
|
-
configPath: group.path
|
|
810
|
-
});
|
|
811
|
-
await (0, node_fs_promises.writeFile)((0, node_path.join)(groupFolder, "package.json"), JSON.stringify(group.packageContext ?? fixturePackageContext(group.path)));
|
|
812
|
-
for (const fixture of fixtures) {
|
|
813
|
-
const inputs = fixtureInputs({
|
|
814
|
-
files: Object.keys(fixture.files),
|
|
815
|
-
compilerOptions
|
|
816
|
-
});
|
|
817
|
-
if (inputs.status === "inapplicable") {
|
|
818
|
-
console.log(`${fixture.name} (inactive under this config: ${inputs.reason}) | | | INACTIVE`);
|
|
819
|
-
continue;
|
|
820
|
-
}
|
|
821
|
-
const folder = (0, node_path.join)(groupFolder, fixture.name);
|
|
822
|
-
await (0, node_fs_promises.mkdir)(folder);
|
|
823
|
-
await (0, node_fs_promises.writeFile)((0, node_path.join)(folder, "tsconfig.json"), JSON.stringify({
|
|
824
|
-
compilerOptions,
|
|
825
|
-
files: inputs.files,
|
|
826
|
-
include: [],
|
|
827
|
-
exclude: []
|
|
828
|
-
}));
|
|
829
|
-
for (const [name, content] of Object.entries(fixture.files)) await (0, node_fs_promises.writeFile)((0, node_path.join)(folder, name), content);
|
|
830
|
-
const tsc = timedCommand({
|
|
831
|
-
command: process.execPath,
|
|
832
|
-
args: [
|
|
833
|
-
compiler,
|
|
834
|
-
"--noEmit",
|
|
835
|
-
"--pretty",
|
|
836
|
-
"false",
|
|
837
|
-
"-p",
|
|
838
|
-
folder
|
|
839
|
-
],
|
|
840
|
-
repo: folder
|
|
841
|
-
});
|
|
842
|
-
const checked = timedCommand({
|
|
843
|
-
command: bun,
|
|
844
|
-
args: [...bunCheckArgs(folder), "--threads=1"],
|
|
845
|
-
repo: folder
|
|
846
|
-
});
|
|
847
|
-
const result = fixtureParity({
|
|
848
|
-
seedFiles: inputs.files,
|
|
849
|
-
expected: fixture.codes,
|
|
850
|
-
match: fixture.anyCode ? "any" : "all",
|
|
851
|
-
repo: folder,
|
|
852
|
-
baseline: {
|
|
853
|
-
...tsc,
|
|
854
|
-
status: diagnosticExitStatus({
|
|
855
|
-
status: tsc.status,
|
|
856
|
-
output: tsc.output,
|
|
857
|
-
repo: folder
|
|
858
|
-
})
|
|
859
|
-
},
|
|
860
|
-
candidate: checked
|
|
861
|
-
});
|
|
862
|
-
results.push(result);
|
|
863
|
-
tscWall += tsc.wall;
|
|
864
|
-
bunWall += checked.wall;
|
|
865
|
-
tscRss = Math.max(tscRss, tsc.maxRssKiB);
|
|
866
|
-
bunRss = Math.max(bunRss, checked.maxRssKiB);
|
|
867
|
-
if (result.configurationDiagnostics.length > 0) {
|
|
868
|
-
console.error(`FAIL: invalid fixture configuration for ${fixture.name}: ${result.configurationDiagnostics.join("; ")}`);
|
|
869
|
-
console.log(`${fixture.name} | configuration error | configuration error | FAIL`);
|
|
870
|
-
continue;
|
|
871
|
-
}
|
|
872
|
-
let outcome = "INACTIVE";
|
|
873
|
-
if (result.active) outcome = result.passed ? "PASS" : "FAIL";
|
|
874
|
-
console.log(`${fixture.name}${result.active ? "" : " (inactive under this config)"} | ${result.tscCodes.join(",")} | ${result.bunCodes.join(",")} | ${outcome}`);
|
|
875
|
-
if (!result.active && !result.passed) console.error(`FAIL: diagnostic comparison differs for inactive class ${fixture.name}: TypeScript exit=${tsc.status}, Bun exit=${checked.status}; missing=${result.identityMissing.join(",")}; extra=${result.identityExtra.join(",")}`);
|
|
876
|
-
if (result.active && result.bunCodes.length === 0) {
|
|
877
|
-
console.error(`FAIL: Bun returned zero diagnostics for active class ${fixture.name} (exit ${checked.status})`);
|
|
878
|
-
if (checked.maxRssKiB <= NO_WORK_MAX_RSS_KIB && checked.wall <= NO_WORK_MAX_WALL_SECONDS) console.error(`Bun measured little checker work: wall=${checked.wall.toFixed(3)}s maxRSS=${checked.maxRssKiB}KiB; verify the checker invocation`);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
console.log(`fixtures tsc: wall=${tscWall.toFixed(3)}s maxRSS=${tscRss}KiB`);
|
|
882
|
-
console.log(`fixtures bun: wall=${bunWall.toFixed(3)}s maxRSS=${bunRss}KiB`);
|
|
883
|
-
if (!results.some(({ active }) => active)) console.error(`FAIL: zero seeded fixture classes active under config group ${index + 1}`);
|
|
884
|
-
groupResults.push(fixtureRunPassed(results));
|
|
885
|
-
}
|
|
886
|
-
} finally {
|
|
887
|
-
await (0, node_fs_promises.rm)(scratch, {
|
|
888
|
-
recursive: true,
|
|
889
|
-
force: true
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
return repository.passed && groupResults.every((passed) => passed);
|
|
893
|
-
};
|
|
894
|
-
//#endregion
|
|
895
|
-
Object.defineProperty(exports, "diagnosticSet", {
|
|
896
|
-
enumerable: true,
|
|
897
|
-
get: function() {
|
|
898
|
-
return diagnosticSet;
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
Object.defineProperty(exports, "runTypecheckParity", {
|
|
902
|
-
enumerable: true,
|
|
903
|
-
get: function() {
|
|
904
|
-
return runTypecheckParity;
|
|
905
|
-
}
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
//# sourceMappingURL=typecheck-parity.cjs.map
|