supercov 0.0.44 → 0.0.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +21 -12
  2. package/docs/agent-loop.md +12 -8
  3. package/docs/assertion-agent.md +156 -0
  4. package/docs/assertion-evidence.md +9 -694
  5. package/docs/assertion-maps.md +252 -0
  6. package/docs/assertions.md +82 -0
  7. package/docs/cli.md +23 -8
  8. package/docs/coverage-model.md +12 -0
  9. package/package.json +34 -35
  10. package/runtime/javascript/runtime.mjs +18 -33
  11. package/schemas/assertions.schema.json +276 -0
  12. package/analyzers/typescript/README.md +0 -59
  13. package/analyzers/typescript/bin/compiler-identity.mjs +0 -78
  14. package/analyzers/typescript/bin/identity.mjs +0 -71
  15. package/analyzers/typescript/bin/query.mjs +0 -29
  16. package/analyzers/typescript/dist/analyze.js +0 -5273
  17. package/analyzers/typescript/dist/archive.js +0 -337
  18. package/analyzers/typescript/dist/awaited-observations.js +0 -376
  19. package/analyzers/typescript/dist/build-identity.json +0 -1
  20. package/analyzers/typescript/dist/compiler.js +0 -32
  21. package/analyzers/typescript/dist/frontend.js +0 -75
  22. package/analyzers/typescript/dist/mock-counts.js +0 -2517
  23. package/analyzers/typescript/dist/native-frontend.js +0 -271
  24. package/analyzers/typescript/dist/pragmas.js +0 -186
  25. package/analyzers/typescript/dist/types.js +0 -1
  26. package/analyzers/typescript/package.json +0 -27
  27. package/analyzers/typescript/src/analyze.ts +0 -6180
  28. package/analyzers/typescript/src/archive.ts +0 -471
  29. package/analyzers/typescript/src/awaited-observations.ts +0 -561
  30. package/analyzers/typescript/src/compiler.ts +0 -49
  31. package/analyzers/typescript/src/frontend.ts +0 -136
  32. package/analyzers/typescript/src/mock-counts.ts +0 -3219
  33. package/analyzers/typescript/src/native-frontend.ts +0 -315
  34. package/analyzers/typescript/src/pragmas.ts +0 -284
  35. package/analyzers/typescript/src/types.ts +0 -45
  36. package/analyzers/typescript/tsconfig.json +0 -12
  37. package/docs/code-verification.md +0 -4
@@ -1,376 +0,0 @@
1
- /**
2
- * Recognize a direct awaited factory method which polls an append-only native
3
- * child capture. Names, paths, regex and timeout values come from bindings/source.
4
- * Unsupported control flow or aliases are not evidence of a missing assertion.
5
- * Native APIs and absence of external monkey-patching remain model premises.
6
- */
7
- export function awaitedObservationSource(context, callback, call) {
8
- const { syntax: t, declaration: decl, rawDeclaration: raw } = context;
9
- function require(value) {
10
- if (!value)
11
- throw unsupported;
12
- }
13
- const unsupported = Symbol("unsupported awaited observation");
14
- const nodes = (root, predicate) => {
15
- const found = [];
16
- const visit = (n) => {
17
- if (predicate(n))
18
- found.push(n);
19
- t.forEachChild(n, visit);
20
- };
21
- visit(root);
22
- return found;
23
- };
24
- const one = (values) => {
25
- require(values.length === 1);
26
- return values[0];
27
- };
28
- const at = (node) => {
29
- const sf = node.getSourceFile(), p = sf.getLineAndCharacterOfPosition(node.getStart(sf));
30
- return `${context.relativeFile(sf)}:${p.line + 1}:${p.character + 1}`;
31
- };
32
- const importedFrom = (node, name) => {
33
- const d = raw(node);
34
- return !!d &&
35
- t.isImportSpecifier(d) &&
36
- !d.isTypeOnly &&
37
- !d.parent.parent.isTypeOnly &&
38
- (d.propertyName ?? d.name).text === name &&
39
- t.isStringLiteral(d.parent.parent.parent.moduleSpecifier)
40
- ? d.parent.parent.parent.moduleSpecifier.text
41
- : undefined;
42
- };
43
- const constant = (node) => t.isVariableDeclaration(node) &&
44
- t.isIdentifier(node.name) &&
45
- t.isVariableDeclarationList(node.parent) &&
46
- !!(node.parent.flags & t.NodeFlags.Const) &&
47
- node.parent.declarations.length === 1;
48
- const simpleArrow = (node) => t.isArrowFunction(node) &&
49
- node.parameters.length === 0 &&
50
- !node.modifiers?.length;
51
- const bodyExpression = (node) => {
52
- if (!t.isBlock(node.body))
53
- return node.body;
54
- require(node.body.statements.length === 1);
55
- const returned = node.body.statements[0];
56
- require(t.isReturnStatement(returned) && returned.expression);
57
- return returned.expression;
58
- };
59
- const positiveNumber = (node) => t.isNumericLiteral(node) &&
60
- Number.isFinite(Number(node.text)) &&
61
- Number(node.text) > 0;
62
- const global = (node, name) => {
63
- const d = decl(node);
64
- return (t.isIdentifier(node) &&
65
- node.text === name &&
66
- (!d || d.getSourceFile().isDeclarationFile));
67
- };
68
- const dateNow = (node) => t.isCallExpression(node) &&
69
- !node.questionDotToken &&
70
- node.arguments.length === 0 &&
71
- t.isPropertyAccessExpression(node.expression) &&
72
- node.expression.name.text === "now" &&
73
- global(node.expression.expression, "Date");
74
- const references = (root, binding) => nodes(root, (n) => t.isIdentifier(n) && decl(n) === binding);
75
- try {
76
- require(t.isArrowFunction(callback) &&
77
- t.isBlock(callback.body) &&
78
- callback.modifiers?.some((m) => m.kind === t.SyntaxKind.AsyncKeyword));
79
- const registration = callback.parent;
80
- require(t.isCallExpression(registration) &&
81
- registration.arguments.at(-1) === callback &&
82
- importedFrom(registration.expression, "test") === "node:test" &&
83
- t.isExpressionStatement(registration.parent) &&
84
- t.isSourceFile(registration.parent.parent));
85
- require(callback.body.statements.every((s) => t.isVariableStatement(s) || t.isExpressionStatement(s)));
86
- require(t.isAwaitExpression(call.parent) &&
87
- t.isExpressionStatement(call.parent.parent) &&
88
- call.parent.parent.parent === callback.body &&
89
- call.arguments.length === 0 &&
90
- !call.questionDotToken &&
91
- t.isPropertyAccessExpression(call.expression) &&
92
- !call.expression.questionDotToken);
93
- const member = call.expression.name.text, receiver = decl(call.expression.expression);
94
- require(receiver &&
95
- constant(receiver) &&
96
- receiver.initializer &&
97
- t.isCallExpression(receiver.initializer));
98
- const launch = receiver.initializer, factory = decl(launch.expression);
99
- require(factory &&
100
- t.isFunctionDeclaration(factory) &&
101
- factory.body &&
102
- !factory.asteriskToken &&
103
- !factory.modifiers?.some((m) => m.kind === t.SyntaxKind.AsyncKeyword) &&
104
- factory.parameters.every((p) => t.isIdentifier(p.name) && !p.initializer && !p.dotDotDotToken));
105
- require(receiver.parent.parent.parent === callback.body);
106
- const statements = callback.body.statements;
107
- require(statements.indexOf(call.parent.parent) ===
108
- statements.indexOf(receiver.parent.parent) + 1);
109
- require(nodes(callback, (n) => t.isCallExpression(n) && decl(n.expression) === factory).length === 1);
110
- require(nodes(callback, (n) => t.isCallExpression(n) &&
111
- t.isPropertyAccessExpression(n.expression) &&
112
- decl(n.expression.expression) === receiver &&
113
- n.expression.name.text === member).length === 1);
114
- require(nodes(callback, (n) => t.isIdentifier(n) && ["eval", "Function"].includes(n.text)).length === 0);
115
- const factoryBody = factory.body;
116
- require(factoryBody.statements.every((s) => t.isVariableStatement(s) ||
117
- t.isExpressionStatement(s) ||
118
- t.isReturnStatement(s)));
119
- const returned = one(factoryBody.statements.filter(t.isReturnStatement));
120
- require(returned === factoryBody.statements.at(-1) &&
121
- returned.expression &&
122
- t.isObjectLiteralExpression(returned.expression));
123
- const members = returned.expression.properties;
124
- require(members.every((p) => (t.isPropertyAssignment(p) || t.isShorthandPropertyAssignment(p)) &&
125
- t.isIdentifier(p.name)));
126
- require(new Set(members.map((p) => p.name.getText())).size === members.length);
127
- const property = one(members.filter((p) => p.name?.getText() === member));
128
- require(t.isPropertyAssignment(property) && simpleArrow(property.initializer));
129
- const pollCall = bodyExpression(property.initializer);
130
- require(t.isCallExpression(pollCall) &&
131
- !pollCall.questionDotToken &&
132
- pollCall.arguments.length >= 1);
133
- const poll = decl(pollCall.expression);
134
- require(poll &&
135
- constant(poll) &&
136
- poll.parent.parent.parent === factoryBody &&
137
- poll.initializer &&
138
- t.isArrowFunction(poll.initializer) &&
139
- t.isBlock(poll.initializer.body) &&
140
- poll.initializer.modifiers?.some((m) => m.kind === t.SyntaxKind.AsyncKeyword));
141
- const pollFn = poll.initializer, pollBody = pollFn.body;
142
- require(pollFn.parameters.length === pollCall.arguments.length &&
143
- pollFn.parameters.every((p) => t.isIdentifier(p.name) && !p.initializer && !p.dotDotDotToken));
144
- require(pollBody.statements.length === 2 &&
145
- t.isVariableStatement(pollBody.statements[0]));
146
- const deadline = one(pollBody.statements[0].declarationList.declarations);
147
- require(constant(deadline) &&
148
- deadline.initializer &&
149
- t.isBinaryExpression(deadline.initializer) &&
150
- deadline.initializer.operatorToken.kind === t.SyntaxKind.PlusToken &&
151
- dateNow(deadline.initializer.left) &&
152
- positiveNumber(deadline.initializer.right));
153
- const loop = pollBody.statements[1];
154
- require(t.isWhileStatement(loop) &&
155
- t.isPrefixUnaryExpression(loop.expression) &&
156
- loop.expression.operator === t.SyntaxKind.ExclamationToken &&
157
- t.isCallExpression(loop.expression.operand));
158
- const predicateCall = loop.expression.operand;
159
- require(predicateCall.arguments.length === 0 &&
160
- decl(predicateCall.expression) === pollFn.parameters[0] &&
161
- !predicateCall.questionDotToken &&
162
- t.isBlock(loop.statement) &&
163
- loop.statement.statements.length === 2);
164
- require(references(pollFn, pollFn.parameters[0]).every((n) => n === pollFn.parameters[0].name || n === predicateCall.expression));
165
- const [guard, pause] = loop.statement.statements;
166
- require(t.isIfStatement(guard) &&
167
- !guard.elseStatement &&
168
- t.isBlock(guard.thenStatement) &&
169
- guard.thenStatement.statements.length === 1 &&
170
- t.isThrowStatement(guard.thenStatement.statements[0]));
171
- require(t.isExpressionStatement(pause) &&
172
- t.isAwaitExpression(pause.expression) &&
173
- t.isCallExpression(pause.expression.expression));
174
- const delay = pause.expression.expression;
175
- require(importedFrom(delay.expression, "setTimeout") === "node:timers/promises" &&
176
- !delay.questionDotToken &&
177
- delay.arguments.length === 1 &&
178
- positiveNumber(delay.arguments[0]));
179
- const predicate = pollCall.arguments[0];
180
- require(simpleArrow(predicate));
181
- const read = bodyExpression(predicate);
182
- require(t.isCallExpression(read) &&
183
- !read.questionDotToken &&
184
- read.arguments.length === 1 &&
185
- t.isPropertyAccessExpression(read.expression) &&
186
- read.expression.name.text === "test" &&
187
- t.isRegularExpressionLiteral(read.expression.expression));
188
- const regex = read.expression.expression.text;
189
- require(!/[gy]/.test(regex.slice(regex.lastIndexOf("/") + 1)));
190
- const input = read.arguments[0];
191
- const operands = t.isBinaryExpression(input) &&
192
- input.operatorToken.kind === t.SyntaxKind.PlusToken
193
- ? [input.left, input.right]
194
- : [input];
195
- const buffers = operands.map((o) => decl(o));
196
- require(buffers.every((b) => b && t.isVariableDeclaration(b)) &&
197
- new Set(buffers).size === buffers.length);
198
- let child;
199
- const captures = [];
200
- for (const [index, maybeBuffer] of buffers.entries()) {
201
- const buffer = maybeBuffer;
202
- require(buffer.parent.parent.parent === factoryBody &&
203
- t.isVariableDeclarationList(buffer.parent) &&
204
- !!(buffer.parent.flags & t.NodeFlags.Let) &&
205
- t.isIdentifier(buffer.name) &&
206
- buffer.initializer &&
207
- t.isStringLiteral(buffer.initializer) &&
208
- buffer.initializer.text === "");
209
- const append = one(nodes(factoryBody, (n) => t.isBinaryExpression(n) &&
210
- decl(n.left) === buffer &&
211
- n.operatorToken.kind >= t.SyntaxKind.FirstAssignment &&
212
- n.operatorToken.kind <= t.SyntaxKind.LastAssignment));
213
- require(t.isBinaryExpression(append) &&
214
- append.operatorToken.kind === t.SyntaxKind.PlusEqualsToken &&
215
- t.isExpressionStatement(append.parent) &&
216
- t.isBlock(append.parent.parent));
217
- const capture = append.parent.parent.parent;
218
- require(t.isArrowFunction(capture) &&
219
- !capture.modifiers?.length &&
220
- capture.parameters.length === 1 &&
221
- !capture.parameters[0].initializer &&
222
- !capture.parameters[0].dotDotDotToken &&
223
- decl(append.right) === capture.parameters[0] &&
224
- t.isBlock(capture.body) &&
225
- capture.body.statements.length === 1);
226
- const on = capture.parent;
227
- require(t.isCallExpression(on) &&
228
- on.arguments.length === 2 &&
229
- on.arguments[1] === capture &&
230
- !on.questionDotToken &&
231
- t.isStringLiteral(on.arguments[0]) &&
232
- on.arguments[0].text === "data" &&
233
- t.isPropertyAccessExpression(on.expression) &&
234
- !on.expression.questionDotToken &&
235
- on.expression.name.text === "on" &&
236
- t.isCallExpression(on.expression.expression));
237
- const encoding = on.expression.expression;
238
- require(!encoding.questionDotToken &&
239
- encoding.arguments.length === 1 &&
240
- t.isStringLiteral(encoding.arguments[0]) &&
241
- encoding.arguments[0].text === "utf8" &&
242
- t.isPropertyAccessExpression(encoding.expression) &&
243
- encoding.expression.name.text === "setEncoding" &&
244
- !encoding.expression.questionDotToken &&
245
- t.isPropertyAccessExpression(encoding.expression.expression));
246
- const stream = encoding.expression.expression;
247
- require(!stream.questionDotToken &&
248
- (stream.name.text === "stdout" || stream.name.text === "stderr"));
249
- const streamChild = decl(stream.expression);
250
- require(streamChild &&
251
- constant(streamChild) &&
252
- (!child || child === streamChild));
253
- child = streamChild;
254
- require(t.isExpressionStatement(on.parent) && on.parent.parent === factoryBody);
255
- // Only initialization, append, the predicate, trivial accessors and the
256
- // throw diagnostic can read this binding. No transformed/escaped capture.
257
- const allowed = new Set([
258
- buffer.name,
259
- append.left,
260
- operands[index],
261
- ...references(guard.thenStatement, buffer),
262
- ]);
263
- for (const p of members)
264
- if (t.isPropertyAssignment(p) && simpleArrow(p.initializer)) {
265
- const value = bodyExpression(p.initializer);
266
- if (decl(value) === buffer)
267
- allowed.add(value);
268
- }
269
- require(references(factoryBody, buffer).every((n) => allowed.has(n)));
270
- const streamRefs = nodes(factoryBody, (n) => t.isPropertyAccessExpression(n) &&
271
- decl(n.expression) === child &&
272
- n.name.text === stream.name.text);
273
- require(streamRefs.length === 1);
274
- captures.push({ stream: stream.name.text, source: at(append) });
275
- }
276
- require(child &&
277
- child.initializer &&
278
- t.isCallExpression(child.initializer) &&
279
- child.parent.parent.parent === factoryBody &&
280
- importedFrom(child.initializer.expression, "spawn") ===
281
- "node:child_process");
282
- const spawn = child.initializer;
283
- require(!spawn.questionDotToken &&
284
- spawn.arguments.length === 3 &&
285
- t.isObjectLiteralExpression(spawn.arguments[2]));
286
- const options = spawn.arguments[2].properties;
287
- require(options.every((p) => t.isPropertyAssignment(p) && t.isIdentifier(p.name)) &&
288
- new Set(options.map((p) => p.name.getText())).size === options.length);
289
- const stdio = one(options.filter((p) => p.name?.getText() === "stdio"));
290
- require(t.isPropertyAssignment(stdio) &&
291
- t.isStringLiteral(stdio.initializer) &&
292
- stdio.initializer.text === "pipe");
293
- for (const ref of references(factoryBody, child)) {
294
- if (ref === child.name ||
295
- (t.isShorthandPropertyAssignment(ref.parent) &&
296
- ref.parent.parent === returned.expression))
297
- continue;
298
- require(t.isPropertyAccessExpression(ref.parent) &&
299
- ref.parent.expression === ref);
300
- const access = ref.parent;
301
- require([
302
- "stdout",
303
- "stderr",
304
- "exitCode",
305
- "signalCode",
306
- "pid",
307
- "once",
308
- "kill",
309
- ].includes(access.name.text));
310
- require(!(t.isBinaryExpression(access.parent) &&
311
- access.parent.left === access &&
312
- access.parent.operatorToken.kind >= t.SyntaxKind.FirstAssignment &&
313
- access.parent.operatorToken.kind <= t.SyntaxKind.LastAssignment) &&
314
- !t.isDeleteExpression(access.parent) &&
315
- !t.isPostfixUnaryExpression(access.parent) &&
316
- !(t.isPrefixUnaryExpression(access.parent) &&
317
- [t.SyntaxKind.PlusPlusToken, t.SyntaxKind.MinusMinusToken].includes(access.parent.operator)));
318
- if (["once", "kill"].includes(access.name.text))
319
- require(t.isCallExpression(access.parent) &&
320
- access.parent.expression === access);
321
- }
322
- const disjuncts = (n) => t.isBinaryExpression(n) &&
323
- n.operatorToken.kind === t.SyntaxKind.BarBarToken
324
- ? [...disjuncts(n.left), ...disjuncts(n.right)]
325
- : [n];
326
- const checks = disjuncts(guard.expression);
327
- require(checks.length === 3);
328
- for (const [index, name] of ["exitCode", "signalCode"].entries()) {
329
- const check = checks[index];
330
- require(t.isBinaryExpression(check) &&
331
- check.operatorToken.kind ===
332
- t.SyntaxKind.ExclamationEqualsEqualsToken &&
333
- check.right.kind === t.SyntaxKind.NullKeyword &&
334
- t.isPropertyAccessExpression(check.left) &&
335
- check.left.name.text === name &&
336
- decl(check.left.expression) === child);
337
- }
338
- const expired = checks[2];
339
- require(t.isBinaryExpression(expired) &&
340
- expired.operatorToken.kind === t.SyntaxKind.GreaterThanToken &&
341
- dateNow(expired.left) &&
342
- decl(expired.right) === deadline);
343
- require(references(factoryBody, poll).every((n) => n === poll.name ||
344
- n === pollCall.expression ||
345
- (t.isShorthandPropertyAssignment(n.parent) &&
346
- n.parent.parent === returned.expression)));
347
- for (const ref of references(callback, receiver)) {
348
- if (ref === receiver.name)
349
- continue;
350
- require(t.isPropertyAccessExpression(ref.parent) &&
351
- ref.parent.expression === ref);
352
- const use = ref.parent;
353
- require(t.isCallExpression(use.parent) && use.parent.expression === use);
354
- const usedProperty = one(members.filter((p) => p.name?.getText() === use.name.text));
355
- require(usedProperty === property ||
356
- (t.isShorthandPropertyAssignment(usedProperty) &&
357
- decl(usedProperty.name) === poll) ||
358
- (t.isPropertyAssignment(usedProperty) &&
359
- simpleArrow(usedProperty.initializer) &&
360
- buffers.includes(decl(bodyExpression(usedProperty.initializer)))));
361
- }
362
- require(nodes(factoryBody, (n) => t.isIdentifier(n) && ["eval", "Function"].includes(n.text)).length === 0);
363
- return {
364
- model: "node-child-capture-poll-v1",
365
- factorySource: at(factory),
366
- predicateSource: at(read),
367
- captures,
368
- pattern: regex,
369
- };
370
- }
371
- catch (error) {
372
- if (error === unsupported)
373
- return undefined;
374
- throw error;
375
- }
376
- }
@@ -1 +0,0 @@
1
- {"schema":1,"sourceSha256":"b9f0ed836fd8bda03ee3793896da9769e70e9a4b56f6b8716ad683c84cf77680","compiledSha256":"80ce9da5db394e7958b1e2c67dc2b12434c539c3890e32ac6fd0f40fc509df5d"}
@@ -1,32 +0,0 @@
1
- import { createRequire } from "node:module";
2
- import { resolve } from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- /** Canonical Rust paths may carry a Windows namespace prefix. Node/compiler paths do not. */
5
- export function analysisPath(path) {
6
- return fileURLToPath(pathToFileURL(resolve(path)));
7
- }
8
- /** Use the project's semantics rather than silently substituting the analyzer's compiler version. */
9
- export function projectCompilerPath(projectRoot) {
10
- try {
11
- return createRequire(pathToFileURL(resolve(projectRoot, "package.json"))).resolve("typescript");
12
- }
13
- catch (error) {
14
- throw new Error(`Assertion analysis requires the project's TypeScript compiler API, including for JavaScript projects. TypeScript 5.8.3 and native 7.0.2 are tested; install a compatible compiler in ${projectRoot}, rerun the tests, then query again.`, { cause: error });
15
- }
16
- }
17
- /** Legacy API loader; createFrontend selects the separate native backend. */
18
- export function loadProjectCompiler(projectRoot) {
19
- const require = createRequire(pathToFileURL(resolve(projectRoot, "package.json")));
20
- let compiler;
21
- try {
22
- compiler = require(projectCompilerPath(projectRoot));
23
- }
24
- catch (error) {
25
- throw new Error(`Cannot load the TypeScript compiler API from ${projectRoot}; install TypeScript in that project or supply options.typescript.`, { cause: error });
26
- }
27
- if (typeof compiler.createProgram !== "function" ||
28
- typeof compiler.parseJsonConfigFileContent !== "function") {
29
- throw new Error(`The TypeScript installation in ${projectRoot} does not expose the compiler API required by this analyzer (createProgram and parseJsonConfigFileContent). TypeScript 5.8.3 is tested; TypeScript 7's different API is not supported. No fallback compiler was substituted.`);
30
- }
31
- return compiler;
32
- }
@@ -1,75 +0,0 @@
1
- import { existsSync, readdirSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
3
- import { createRequire } from "node:module";
4
- import { pathToFileURL } from "node:url";
5
- import { analysisPath, loadProjectCompiler, projectCompilerPath, } from "./compiler.js";
6
- import { nativeFrontend } from "./native-frontend.js";
7
- export function selectedRootFiles(options, configured) {
8
- const root = analysisPath(options.projectRoot);
9
- if (options.sourceFiles)
10
- return [...options.sourceFiles, ...(options.testFiles ?? [])].map((f) => resolve(root, f));
11
- if (!options.sourceDir)
12
- return configured;
13
- function walk(dir) {
14
- if (!existsSync(dir))
15
- return [];
16
- return readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
17
- if (e.name === "node_modules" || e.name.startsWith("."))
18
- return [];
19
- const file = resolve(dir, e.name);
20
- return e.isDirectory()
21
- ? walk(file)
22
- : /\.(ts|tsx|mts)$/.test(e.name) && !e.name.endsWith(".d.ts")
23
- ? [file]
24
- : [];
25
- });
26
- }
27
- return [
28
- ...walk(resolve(root, options.sourceDir)),
29
- ...walk(resolve(root, options.testDir ?? "tests")),
30
- ...(existsSync(resolve(root, "env.d.ts"))
31
- ? [resolve(root, "env.d.ts")]
32
- : []),
33
- ];
34
- }
35
- function legacyFrontend(compiler) {
36
- return {
37
- kind: "typescript-legacy",
38
- version: compiler.version,
39
- syntax: compiler,
40
- limitations: new Set(),
41
- close() { },
42
- openProgram(options) {
43
- const root = analysisPath(options.projectRoot);
44
- const configPath = resolve(root, options.tsconfig ?? "tsconfig.json");
45
- const cfg = options.sourceFiles && !existsSync(configPath)
46
- ? { config: { compilerOptions: { allowJs: true, checkJs: true } } }
47
- : compiler.readConfigFile(configPath, compiler.sys.readFile);
48
- if (cfg.error)
49
- throw new Error(compiler.flattenDiagnosticMessageText(cfg.error.messageText, "\n"));
50
- const parsed = compiler.parseJsonConfigFileContent(cfg.config, compiler.sys, dirname(configPath));
51
- const program = compiler.createProgram(selectedRootFiles(options, parsed.fileNames), {
52
- ...parsed.options,
53
- ...(options.sourceFiles ? { allowJs: true, checkJs: true } : {}),
54
- noEmit: true,
55
- });
56
- return {
57
- files: program.getSourceFiles(),
58
- checker: program.getTypeChecker(),
59
- resolveModule: (spec, from) => compiler.resolveModuleName(spec, from, parsed.options, compiler.sys)
60
- .resolvedModule?.resolvedFileName,
61
- };
62
- },
63
- parseSource: (file, text) => compiler.createSourceFile(file, text, compiler.ScriptTarget.Latest, true),
64
- };
65
- }
66
- export function createFrontend(root, supplied) {
67
- if (supplied)
68
- return legacyFrontend(supplied);
69
- const entry = projectCompilerPath(root);
70
- const require = createRequire(pathToFileURL(entry));
71
- const version = require(entry).version;
72
- if (version === "7.0.2")
73
- return nativeFrontend(entry, root);
74
- return legacyFrontend(loadProjectCompiler(root));
75
- }