@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.17
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/dist/src/alias-chain.js +0 -5
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +94 -54
- package/dist/src/augmentations.js +23 -24
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +25 -8
- package/dist/src/commands/read.js +6 -7
- package/dist/src/commands/tools.js +5 -9
- package/dist/src/component-files.js +3 -2
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +9 -10
- package/dist/src/contextual-uses.js +1 -17
- package/dist/src/contract/config.generated.js +5 -2
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/contract/report.generated.js +6 -2
- package/dist/src/dependencies.js +98 -71
- package/dist/src/destructuring.js +1 -19
- package/dist/src/element-access.js +179 -164
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +22 -64
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
- package/dist/src/entries/conventions.js +739 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +9 -12
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +3 -3
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +684 -0
- package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/findings/completion.js +40 -4
- package/dist/src/findings/emitters.js +5 -8
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
- package/dist/src/findings/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +42 -15
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +14 -8
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/inventory/commonjs.js +62 -17
- package/dist/src/inventory/enumerate.js +2 -1
- package/dist/src/javascript-file.js +26 -11
- package/dist/src/keyof-comparisons.js +124 -103
- package/dist/src/load/classify.js +28 -9
- package/dist/src/load/diagnostics.js +8 -1
- package/dist/src/load/discover.js +15 -7
- package/dist/src/load/expected-module.js +2 -2
- package/dist/src/load/plan.js +2 -2
- package/dist/src/load/specifiers.js +2 -4
- package/dist/src/load/synthesize.js +10 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/load/workspace-resolution.js +2 -2
- package/dist/src/matrix.js +12 -17
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/paths.js +56 -1
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +151 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +111 -1116
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +7 -4
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
- package/dist/src/{manifest.js → roots/manifest.js} +4 -4
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +489 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/serialization-contract.js +9 -4
- package/dist/src/source-files.js +5 -9
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress.js +30 -32
- package/dist/src/sweep.js +25 -13
- package/dist/src/symbol-keys.js +89 -83
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/verbs/analyze.js +15 -3
- package/dist/src/verbs/describe.js +5 -3
- package/dist/src/verbs/explain.js +50 -28
- package/dist/src/verbs/print-retained.js +2 -2
- package/jsr.json +1 -1
- package/package.json +3 -3
- package/src/alias-chain.ts +0 -7
- package/src/amd.ts +130 -0
- package/src/analysis.ts +156 -70
- package/src/augmentations.ts +41 -27
- package/src/automatic-types.ts +1 -1
- package/src/bindings.ts +460 -0
- package/src/calls.ts +25 -7
- package/src/commands/read.ts +6 -8
- package/src/commands/tools.ts +5 -11
- package/src/component-files.ts +4 -2
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +12 -11
- package/src/contextual-uses.ts +2 -22
- package/src/contract/config.generated.ts +5 -2
- package/src/contract/contract.generated.ts +138 -2
- package/src/contract/report.generated.ts +6 -2
- package/src/dependencies.ts +117 -71
- package/src/destructuring.ts +1 -31
- package/src/element-access.ts +188 -182
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +33 -82
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +349 -523
- package/src/{html-entries.ts → entries/html-entries.ts} +19 -18
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +5 -5
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +868 -0
- package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
- package/src/exempt.ts +3 -2
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/file-facts.ts +1 -1
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +43 -4
- package/src/findings/emitter.ts +1 -1
- package/src/findings/emitters.ts +14 -10
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- package/src/findings/self-check.ts +41 -22
- package/src/findings/visibility-narrowing.ts +1 -1
- package/src/findings-pass.ts +5 -12
- package/src/framework-lifecycle.ts +43 -15
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +27 -11
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +1 -1
- package/src/inventory/commonjs.ts +102 -17
- package/src/inventory/enumerate.ts +2 -1
- package/src/javascript-file.ts +29 -12
- package/src/keyof-comparisons.ts +131 -116
- package/src/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +27 -11
- package/src/load/expected-module.ts +8 -2
- package/src/load/plan.ts +11 -2
- package/src/load/specifiers.ts +8 -5
- package/src/load/synthesize.ts +12 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-resolution.ts +9 -2
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +13 -17
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/paths.ts +65 -1
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +213 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +174 -1492
- package/src/report.ts +2 -2
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +10 -7
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
- package/src/{manifest.ts → roots/manifest.ts} +5 -5
- package/src/roots/published-reach.ts +481 -0
- package/src/{roots.ts → roots/root-set.ts} +203 -630
- package/src/roots/unseen-loads.ts +345 -0
- package/src/serialization-contract.ts +9 -4
- package/src/source-files.ts +5 -10
- package/src/stores.ts +13 -2
- package/src/suppress.ts +48 -33
- package/src/sweep.ts +37 -14
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +118 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/verbs/analyze.ts +19 -5
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +75 -32
- package/src/verbs/print-retained.ts +2 -2
- package/dist/src/build-scripts.js +0 -418
- package/dist/src/conventions.js +0 -907
- package/dist/src/entry-points.js +0 -444
- package/dist/src/own-body.js +0 -28
- package/dist/src/roots.js +0 -865
- package/dist/src/unseen-loads.js +0 -189
- package/src/build-scripts.ts +0 -536
- package/src/entry-points.ts +0 -584
- package/src/own-body.ts +0 -42
- package/src/unseen-loads.ts +0 -282
|
@@ -10,7 +10,7 @@ import { isClassDeclaration, isClassExpression, isConstructorDeclaration, isGetA
|
|
|
10
10
|
import { aliasChains } from "./alias-chain.js";
|
|
11
11
|
import { calleeName, callsOf, classesPassed, decoratorsOf, spelledDecorator } from "./calls.js";
|
|
12
12
|
import { classMembers } from "./class-members.js";
|
|
13
|
-
import { entriesAt, namesADeclaration, resolveEntries, spelledEntry, } from "./configured-declarations.js";
|
|
13
|
+
import { entriesAt, namesADeclaration, resolveEntries, spelledEntry, } from "./roots/configured-declarations.js";
|
|
14
14
|
import { isParameterProperty, nodeKey } from "./inventory.js";
|
|
15
15
|
import { renderPosition } from "./position.js";
|
|
16
16
|
/** Whether one member declaration is a parameter property, or a property or accessor carrying a decorator. */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isHeritageClause, isMethodDeclaration, isNewExpression, isObjectLiteralExpression, isSetAccessorDeclaration, isTypeLiteralNode, ModifierFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
10
10
|
import { SymbolFlags } from "@typescript/native/sync";
|
|
11
11
|
import { aliasChains } from "./alias-chain.js";
|
|
12
|
-
import { emptyImplementation } from "./implementations.js";
|
|
12
|
+
import { emptyImplementation } from "./findings/implementations.js";
|
|
13
13
|
import { nodeKey } from "./inventory.js";
|
|
14
14
|
import { renderPosition } from "./position.js";
|
|
15
15
|
import { must } from "./query.js";
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { isArrayBindingPattern, isArrowFunction, isAssignmentOperator, isAwaitExpression, isBinaryExpression, isBindingElement, isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isComputedPropertyName, isDeleteExpression, isElementAccessExpression, isEqualityOperator, isExpressionStatement, isForOfStatement, isFunctionDeclaration, isFunctionExpression, isFunctionLikeDeclaration, isGetAccessorDeclaration, isIdentifier, isIfStatement, isMetaProperty, isMethodDeclaration, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyAssignment, isSetAccessorDeclaration, isShorthandPropertyAssignment, isSourceFile, isSpreadAssignment, isStringLiteral, isTypeOfExpression, isVariableDeclaration, isVariableDeclarationList, isVariableStatement, ModifierFlags, NodeFlags, SyntaxKind, } from "@typescript/native/ast";
|
|
2
2
|
import { componentOf, modifiersOf, } from "../inventory.js";
|
|
3
|
+
import { callsPlatformBy, lexicalBinding, writtenName } from "../platform-calls.js";
|
|
3
4
|
import { spellsNoBinding } from "../spelled-names.js";
|
|
4
5
|
import { unwrapped } from "../unwrap.js";
|
|
5
6
|
/**
|
|
6
7
|
* The export table of a CommonJS file: the module value `module.exports` is assigned and
|
|
7
8
|
* the properties written on it, read from the top-level unconditional statements in order,
|
|
8
9
|
* as Node runs them (https://nodejs.org/api/modules.html#moduleexports). Each entry is
|
|
9
|
-
* keyed by the node that writes it,
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* keyed by the node that writes it, the checker's declaration of the export where it binds
|
|
11
|
+
* one. Any other write of the exports opens the table: its entries are kept and the file is
|
|
12
|
+
* listed open. `declarationOf` reads a `require()` call through the file's own scopes.
|
|
12
13
|
*/
|
|
13
|
-
export function commonJS(typeIsModule, resolved) {
|
|
14
|
+
export function commonJS(typeIsModule, resolved, declarationOf) {
|
|
14
15
|
return {
|
|
15
16
|
declare(file, owner, into) {
|
|
16
17
|
if (!isCommonJS(file, owner.position.path, typeIsModule)) {
|
|
@@ -18,7 +19,7 @@ export function commonJS(typeIsModule, resolved) {
|
|
|
18
19
|
}
|
|
19
20
|
const bound = boundOccurrences(file, resolved);
|
|
20
21
|
const free = (node) => !bound.has(node);
|
|
21
|
-
const table = readTable(file, free, topLevelDeclarations(file));
|
|
22
|
+
const table = readTable(file, free, topLevelDeclarations(file), lexicalBinding(declarationOf));
|
|
22
23
|
const open = table.open || opens(file, free, table.modelled);
|
|
23
24
|
for (const entry of table.entries.values()) {
|
|
24
25
|
const record = into.declare(entry.node, owner, entry.kind, entry.name, {
|
|
@@ -176,24 +177,33 @@ function topLevelDeclarations(file) {
|
|
|
176
177
|
}
|
|
177
178
|
const DEFAULT = { text: "default", computed: false };
|
|
178
179
|
/** The table one file's top-level unconditional statements write, in order. */
|
|
179
|
-
function readTable(file, isFree, declarations) {
|
|
180
|
+
function readTable(file, isFree, declarations, bindingOf) {
|
|
180
181
|
const entries = new Map();
|
|
181
182
|
const modelled = new Set();
|
|
183
|
+
// Written inside the closures below, which the compiler's narrowing does not follow.
|
|
182
184
|
let open = false;
|
|
183
185
|
let aliasing = true;
|
|
186
|
+
let whole;
|
|
187
|
+
let wholeOpen = false;
|
|
184
188
|
const free = (node, name) => isIdentifier(node) && node.text === name && isFree(node);
|
|
185
189
|
const isModuleExports = (node) => isPropertyAccessExpression(node) &&
|
|
186
190
|
free(node.expression, "module") &&
|
|
187
191
|
node.name.text === "exports";
|
|
188
|
-
const isRequire = (node) =>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
const isRequire = (node) => {
|
|
193
|
+
if (!isCallExpression(node) || node.arguments.length !== 1) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
const [argument] = node.arguments;
|
|
197
|
+
const callee = writtenName(node.expression);
|
|
198
|
+
return (argument !== undefined &&
|
|
199
|
+
isLiteralText(argument) &&
|
|
200
|
+
callee !== undefined &&
|
|
201
|
+
callsPlatformBy("require", callee, bindingOf));
|
|
202
|
+
};
|
|
193
203
|
/** What a value written under one key declares. */
|
|
194
204
|
const entryOf = (component, node, name, value) => {
|
|
195
205
|
const held = value === undefined ? undefined : unwrapped(value);
|
|
196
|
-
const base = { node, name, component, localName: undefined };
|
|
206
|
+
const base = { node, name, component, localName: undefined, value };
|
|
197
207
|
if (held === undefined) {
|
|
198
208
|
return { ...base, kind: "variable" };
|
|
199
209
|
}
|
|
@@ -245,6 +255,7 @@ function readTable(file, isFree, declarations) {
|
|
|
245
255
|
/** The module value one assignment writes, placed at the `exports` name it assigns. */
|
|
246
256
|
const moduleValue = (node, name) => {
|
|
247
257
|
entries.clear();
|
|
258
|
+
whole = node.right;
|
|
248
259
|
const value = unwrapped(node.right);
|
|
249
260
|
if (isRequire(value)) {
|
|
250
261
|
return;
|
|
@@ -253,7 +264,7 @@ function readTable(file, isFree, declarations) {
|
|
|
253
264
|
value.properties.forEach(literalProperty);
|
|
254
265
|
return;
|
|
255
266
|
}
|
|
256
|
-
const base = { node, name, component: DEFAULT };
|
|
267
|
+
const base = { node, name, component: DEFAULT, value: node.right };
|
|
257
268
|
const target = isIdentifier(value) ? declarations.get(value.text) : undefined;
|
|
258
269
|
if (target !== undefined) {
|
|
259
270
|
entries.set("default", { ...base, localName: undefined, kind: "export-alias", target });
|
|
@@ -273,7 +284,7 @@ function readTable(file, isFree, declarations) {
|
|
|
273
284
|
});
|
|
274
285
|
}
|
|
275
286
|
else {
|
|
276
|
-
|
|
287
|
+
wholeOpen = true;
|
|
277
288
|
}
|
|
278
289
|
};
|
|
279
290
|
/** Whether one expression is the exports object a top-level write may name here. */
|
|
@@ -300,8 +311,17 @@ function readTable(file, isFree, declarations) {
|
|
|
300
311
|
}
|
|
301
312
|
else if (isModuleExports(left)) {
|
|
302
313
|
modelled.add(expression);
|
|
303
|
-
|
|
304
|
-
|
|
314
|
+
const inner = unwrapped(expression.right);
|
|
315
|
+
const chained = isBinaryExpression(inner) &&
|
|
316
|
+
inner.operatorToken.kind === SyntaxKind.EqualsToken &&
|
|
317
|
+
free(inner.left, "exports")
|
|
318
|
+
? inner
|
|
319
|
+
: undefined;
|
|
320
|
+
if (chained !== undefined) {
|
|
321
|
+
modelled.add(chained);
|
|
322
|
+
}
|
|
323
|
+
moduleValue(chained ?? expression, left.name);
|
|
324
|
+
aliasing = chained !== undefined;
|
|
305
325
|
}
|
|
306
326
|
else if (isPropertyAccessExpression(left) || isElementAccessExpression(left)) {
|
|
307
327
|
const object = exportsObject(left.expression);
|
|
@@ -332,7 +352,32 @@ function readTable(file, isFree, declarations) {
|
|
|
332
352
|
}
|
|
333
353
|
}
|
|
334
354
|
}
|
|
335
|
-
return { entries, open, modelled };
|
|
355
|
+
return { entries, open: open || wholeOpen, modelled, whole, membersOpen: open };
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* The module value one file leaves where Node runs it as CommonJS, read by the one table
|
|
359
|
+
* the inventory's export table reads, or undefined where the file writes module syntax.
|
|
360
|
+
* `declarationOf` names the declaration each name resolves to, undefined for none, as a
|
|
361
|
+
* lexical reading of a file outside every program answers it.
|
|
362
|
+
*/
|
|
363
|
+
export function commonJSModuleValue(file, declarationOf) {
|
|
364
|
+
if (writesModuleSyntax(file)) {
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
const free = (node) => {
|
|
368
|
+
const declaration = isIdentifier(node) ? declarationOf(node) : undefined;
|
|
369
|
+
return declaration === undefined || !bindsOwn(declaration, file);
|
|
370
|
+
};
|
|
371
|
+
const table = readTable(file, free, topLevelDeclarations(file), lexicalBinding(declarationOf));
|
|
372
|
+
const held = table.whole === undefined ? undefined : unwrapped(table.whole);
|
|
373
|
+
const members = [...table.entries.values()].flatMap((entry) => entry.component === DEFAULT && held !== undefined && !isObjectLiteralExpression(held)
|
|
374
|
+
? []
|
|
375
|
+
: [{ key: entry.component.text, value: entry.value, node: entry.node }]);
|
|
376
|
+
return {
|
|
377
|
+
whole: held === undefined || isObjectLiteralExpression(held) ? undefined : table.whole,
|
|
378
|
+
members,
|
|
379
|
+
open: table.membersOpen || opens(file, free, table.modelled),
|
|
380
|
+
};
|
|
336
381
|
}
|
|
337
382
|
/** Whether one node is `Object.defineProperty`. */
|
|
338
383
|
function isDefineProperty(node) {
|
|
@@ -4,6 +4,7 @@ import { packageScope, packageTypeIsModule } from "../load/package-scope.js";
|
|
|
4
4
|
import { relativePath } from "../paths.js";
|
|
5
5
|
import { renderPosition } from "../position.js";
|
|
6
6
|
import { isAnswered, UNANSWERED } from "../query.js";
|
|
7
|
+
import { declarationOf } from "../entries/static-module.js";
|
|
7
8
|
import { commonJS } from "./commonjs.js";
|
|
8
9
|
import { SYNTAX } from "./syntax.js";
|
|
9
10
|
/**
|
|
@@ -18,7 +19,7 @@ export function inventory(project, host, targetRoot) {
|
|
|
18
19
|
const moduleOf = packageScope(host, targetRoot);
|
|
19
20
|
const sources = [
|
|
20
21
|
SYNTAX,
|
|
21
|
-
commonJS(packageTypeIsModule(host, targetRoot), resolvedIn(project)),
|
|
22
|
+
commonJS(packageTypeIsModule(host, targetRoot), resolvedIn(project), declarationOf),
|
|
22
23
|
];
|
|
23
24
|
const into = new Builder(targetRoot);
|
|
24
25
|
for (const file of files) {
|
|
@@ -1,26 +1,41 @@
|
|
|
1
|
+
import { LANGUAGE_ROWS } from "./contract/contract.generated.js";
|
|
2
|
+
import { globExpression } from "./text/glob.js";
|
|
1
3
|
export const JAVASCRIPT_FILE = /\.(?:js|jsx|mjs|cjs)$/u;
|
|
2
|
-
/**
|
|
3
|
-
const
|
|
4
|
+
/** The patterns the TypeScript row of `languages.json` skips files by, each matched against a name alone. */
|
|
5
|
+
const MINIFIED_NAMES = LANGUAGE_ROWS.ts.skippedFiles.map((pattern) => ({
|
|
6
|
+
pattern,
|
|
7
|
+
expression: globExpression(pattern),
|
|
8
|
+
}));
|
|
4
9
|
const MINIFIED_BYTES = 10_240;
|
|
5
10
|
const MINIFIED_LINE = 500;
|
|
6
|
-
/**
|
|
11
|
+
/** What a minified file is decided by where its text is not read. */
|
|
12
|
+
const LONG_LINES = "long lines";
|
|
13
|
+
/** The skipped-file pattern one file's name matches, which decides it minified without its text. */
|
|
7
14
|
export function minifiedByName(fileName) {
|
|
8
|
-
|
|
15
|
+
const name = fileName.slice(fileName.lastIndexOf("/") + 1);
|
|
16
|
+
return MINIFIED_NAMES.find((one) => one.expression.test(name))?.pattern;
|
|
9
17
|
}
|
|
10
|
-
/**
|
|
11
|
-
|
|
18
|
+
/**
|
|
19
|
+
* What decides one JavaScript file minified: the skipped-file pattern its name matches, or
|
|
20
|
+
* {@link LONG_LINES} for a text of the size whose mean line is longer than the limit;
|
|
21
|
+
* undefined for a file that is not minified.
|
|
22
|
+
*/
|
|
23
|
+
export function minifiedBy(fileName, text) {
|
|
12
24
|
if (!JAVASCRIPT_FILE.test(fileName)) {
|
|
13
|
-
return
|
|
25
|
+
return undefined;
|
|
14
26
|
}
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
const named = minifiedByName(fileName);
|
|
28
|
+
if (named !== undefined) {
|
|
29
|
+
return named;
|
|
17
30
|
}
|
|
18
31
|
// A UTF-16 unit encodes to at most three UTF-8 bytes, so a shorter text is below the size.
|
|
19
32
|
if (text.length * 3 < MINIFIED_BYTES) {
|
|
20
|
-
return
|
|
33
|
+
return undefined;
|
|
21
34
|
}
|
|
22
35
|
const lines = text.split(/\r?\n/u).length;
|
|
23
|
-
return utf8Bytes(text) >= MINIFIED_BYTES && text.length / lines > MINIFIED_LINE
|
|
36
|
+
return utf8Bytes(text) >= MINIFIED_BYTES && text.length / lines > MINIFIED_LINE
|
|
37
|
+
? LONG_LINES
|
|
38
|
+
: undefined;
|
|
24
39
|
}
|
|
25
40
|
/** The length of a text in UTF-8, a lone surrogate counting as the three bytes of U+FFFD. */
|
|
26
41
|
function utf8Bytes(text) {
|
|
@@ -4,10 +4,8 @@
|
|
|
4
4
|
* that holds `keyof X`, the literal the other side has names the member of `X` under that
|
|
5
5
|
* key, because deleting the member makes the comparison a type error.
|
|
6
6
|
*/
|
|
7
|
-
import { isBinaryExpression, isCaseClause, isElementAccessExpression, isIdentifier, isPropertyAccessExpression, isSwitchStatement, isTypeOperatorNode, SyntaxKind, } from "@typescript/native/ast";
|
|
7
|
+
import { isBinaryExpression, isCaseClause, isElementAccessExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isPropertyAccessExpression, isStringLiteral, isSwitchStatement, isTypeOperatorNode, SyntaxKind, } from "@typescript/native/ast";
|
|
8
8
|
import { SymbolFlags } from "@typescript/native/sync";
|
|
9
|
-
import { nodeKey } from "./inventory.js";
|
|
10
|
-
import { renderPosition } from "./position.js";
|
|
11
9
|
import { UNANSWERED } from "./query.js";
|
|
12
10
|
import { parenthesesRemoved } from "./unwrap.js";
|
|
13
11
|
/** The operators that compare their operands for equality. */
|
|
@@ -55,114 +53,137 @@ function literalNames(parts) {
|
|
|
55
53
|
return names;
|
|
56
54
|
}
|
|
57
55
|
/**
|
|
58
|
-
* The
|
|
59
|
-
*
|
|
56
|
+
* The reads the key comparisons of a side's files make of the members their literal side
|
|
57
|
+
* names, each made by the declaration holding the comparison. A question the checker leaves
|
|
58
|
+
* unanswered holds what its answer could have read.
|
|
60
59
|
*/
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
60
|
+
export const keyofComparisons = {
|
|
61
|
+
start() {
|
|
62
|
+
const comparisons = [];
|
|
63
|
+
return {
|
|
64
|
+
visit(node, { file, from }) {
|
|
65
|
+
if (isBinaryExpression(node) && EQUALITIES.has(node.operatorToken.kind)) {
|
|
66
|
+
comparisons.push({ file, from, keyed: node.left, other: node.right });
|
|
67
|
+
comparisons.push({ file, from, keyed: node.right, other: node.left });
|
|
68
|
+
}
|
|
69
|
+
if (isSwitchStatement(node)) {
|
|
70
|
+
for (const clause of node.caseBlock.clauses) {
|
|
71
|
+
if (isCaseClause(clause)) {
|
|
72
|
+
comparisons.push({ file, from, keyed: node.expression, other: clause.expression });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
reads({ project, chains }) {
|
|
78
|
+
const queries = project.queries;
|
|
79
|
+
const found = [];
|
|
80
|
+
const named = comparisons.flatMap((one) => {
|
|
81
|
+
const name = nameOf(one.keyed);
|
|
82
|
+
return name === undefined || isElementAccessExpression(parenthesesRemoved(one.other))
|
|
83
|
+
? []
|
|
84
|
+
: [{ ...one, name }];
|
|
85
|
+
});
|
|
86
|
+
if (named.length === 0) {
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
// The operand's own declaration states the key type, which the checker resolves to
|
|
90
|
+
// the literals it admits and so no longer names the type the key indexes.
|
|
91
|
+
const symbols = queries.symbolsAt(named.map((one) => one.name));
|
|
92
|
+
const keyed = named.flatMap((one, at) => {
|
|
93
|
+
const asked = symbols[at];
|
|
94
|
+
const symbol = asked === UNANSWERED || asked === undefined || (asked.flags & SymbolFlags.Alias) === 0
|
|
95
|
+
? asked
|
|
96
|
+
: queries.aliased(asked);
|
|
97
|
+
if (symbol === UNANSWERED) {
|
|
98
|
+
const text = literalText(one.other);
|
|
99
|
+
found.push({
|
|
100
|
+
kind: "held",
|
|
101
|
+
from: one.from,
|
|
102
|
+
...(text === undefined ? {} : { names: [text] }),
|
|
83
103
|
});
|
|
104
|
+
return [];
|
|
84
105
|
}
|
|
106
|
+
if (symbol === undefined) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const operands = symbol.declarations.flatMap((handle) => {
|
|
110
|
+
const declared = project.declarationAt(handle)?.node?.type;
|
|
111
|
+
return declared === undefined ? [] : keyofOperands(declared);
|
|
112
|
+
});
|
|
113
|
+
return operands.length === 0 ? [] : [{ ...one, operands }];
|
|
114
|
+
});
|
|
115
|
+
if (keyed.length === 0) {
|
|
116
|
+
return found;
|
|
85
117
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
const named = comparisons.flatMap((one) => {
|
|
96
|
-
const name = nameOf(one.keyed);
|
|
97
|
-
return name === undefined || isElementAccessExpression(parenthesesRemoved(one.other))
|
|
98
|
-
? []
|
|
99
|
-
: [{ ...one, name }];
|
|
100
|
-
});
|
|
101
|
-
if (named.length === 0) {
|
|
102
|
-
return [];
|
|
103
|
-
}
|
|
104
|
-
// The operand's own declaration states the key type, which the checker resolves to
|
|
105
|
-
// the literals it admits and so no longer names the type the key indexes.
|
|
106
|
-
const symbols = queries.symbolsAt(named.map((one) => one.name));
|
|
107
|
-
const keyed = named.flatMap((one, at) => {
|
|
108
|
-
const asked = symbols[at];
|
|
109
|
-
const symbol = asked === UNANSWERED || asked === undefined || (asked.flags & SymbolFlags.Alias) === 0
|
|
110
|
-
? asked
|
|
111
|
-
: queries.aliased(asked);
|
|
112
|
-
if (symbol === UNANSWERED || symbol === undefined) {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
const operands = symbol.declarations.flatMap((handle) => {
|
|
116
|
-
const declared = project.declarationAt(handle)?.node?.type;
|
|
117
|
-
return declared === undefined ? [] : keyofOperands(declared);
|
|
118
|
-
});
|
|
119
|
-
return operands.length === 0 ? [] : [{ ...one, operands }];
|
|
120
|
-
});
|
|
121
|
-
if (keyed.length === 0) {
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
const nodes = keyed.flatMap((one) => [one.other, ...one.operands]);
|
|
125
|
-
const types = queries.typesAt(nodes);
|
|
126
|
-
const typeOf = new Map();
|
|
127
|
-
nodes.forEach((node, at) => {
|
|
128
|
-
const type = types[at];
|
|
129
|
-
if (type !== UNANSWERED && type !== undefined) {
|
|
130
|
-
typeOf.set(node, type);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
const partsOf = (type) => {
|
|
134
|
-
const parts = queries.constituents(type);
|
|
135
|
-
return parts === UNANSWERED ? [type] : parts;
|
|
136
|
-
};
|
|
137
|
-
const found = [];
|
|
138
|
-
for (const one of keyed) {
|
|
139
|
-
const literal = typeOf.get(one.other);
|
|
140
|
-
const names = literal === undefined ? [] : literalNames(partsOf(literal));
|
|
141
|
-
if (names.length === 0) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const position = renderPosition(one.file, root, one.other.getStart());
|
|
145
|
-
for (const operand of one.operands) {
|
|
146
|
-
const object = typeOf.get(operand);
|
|
147
|
-
for (const part of object === undefined ? [] : partsOf(object)) {
|
|
148
|
-
const properties = queries.propertiesOf(part);
|
|
149
|
-
for (const property of properties === UNANSWERED ? [] : properties) {
|
|
150
|
-
if (!names.includes(property.name)) {
|
|
151
|
-
continue;
|
|
118
|
+
const nodes = keyed.flatMap((one) => [one.other, ...one.operands]);
|
|
119
|
+
const types = queries.typesAt(nodes);
|
|
120
|
+
const typeOf = new Map();
|
|
121
|
+
nodes.forEach((node, at) => {
|
|
122
|
+
const type = types[at];
|
|
123
|
+
if (type !== undefined) {
|
|
124
|
+
typeOf.set(node, type);
|
|
152
125
|
}
|
|
153
|
-
|
|
126
|
+
});
|
|
127
|
+
const partsOf = (type) => {
|
|
128
|
+
const parts = queries.constituents(type);
|
|
129
|
+
return parts === UNANSWERED ? [type] : parts;
|
|
130
|
+
};
|
|
131
|
+
for (const one of keyed) {
|
|
132
|
+
const literal = typeOf.get(one.other);
|
|
133
|
+
const objects = one.operands.map((operand) => typeOf.get(operand));
|
|
134
|
+
if (literal === UNANSWERED) {
|
|
135
|
+
const known = objects.filter((type) => type !== undefined && type !== UNANSWERED);
|
|
154
136
|
found.push({
|
|
137
|
+
kind: "held",
|
|
155
138
|
from: one.from,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
use: "read",
|
|
159
|
-
resolution: "keyed",
|
|
160
|
-
test: testFiles.has(position.path),
|
|
139
|
+
types: known.flatMap(partsOf),
|
|
140
|
+
...(known.length < objects.length ? { members: true } : {}),
|
|
161
141
|
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const names = literal === undefined ? [] : literalNames(partsOf(literal));
|
|
145
|
+
if (names.length === 0) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
for (const object of objects) {
|
|
149
|
+
if (object === UNANSWERED) {
|
|
150
|
+
found.push({ kind: "held", from: one.from, names });
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
for (const part of object === undefined ? [] : partsOf(object)) {
|
|
154
|
+
const properties = queries.propertiesOf(part);
|
|
155
|
+
if (properties === UNANSWERED) {
|
|
156
|
+
found.push({ kind: "held", from: one.from, names });
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
for (const property of properties) {
|
|
160
|
+
if (!names.includes(property.name)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
for (const to of chains.declarationsOf(property)) {
|
|
164
|
+
found.push({
|
|
165
|
+
kind: "named",
|
|
166
|
+
from: one.from,
|
|
167
|
+
to,
|
|
168
|
+
file: one.file,
|
|
169
|
+
at: one.other,
|
|
170
|
+
use: "read",
|
|
171
|
+
via: "keyed",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
162
176
|
}
|
|
163
177
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
return found;
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
/** The text a string or number literal operand spells, where it is one. */
|
|
184
|
+
function literalText(node) {
|
|
185
|
+
const at = parenthesesRemoved(node);
|
|
186
|
+
return isStringLiteral(at) || isNumericLiteral(at) || isNoSubstitutionTemplateLiteral(at)
|
|
187
|
+
? at.text
|
|
188
|
+
: undefined;
|
|
168
189
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { conventionFailuresFor } from "../conventions.js";
|
|
1
|
+
import { conventionFailuresFor } from "../entries/conventions.js";
|
|
2
2
|
import { relativePath, resolvePath } from "../paths.js";
|
|
3
3
|
import { diagnosticsOf, ownedAs } from "../session.js";
|
|
4
4
|
import { skipAt } from "../type-errors.js";
|
|
5
5
|
import { classOf, MISSING_GLOBAL_TYPE, projectErrors, renderDiagnostic, } from "./diagnostics.js";
|
|
6
|
-
import { targetRelative } from "./discover.js";
|
|
6
|
+
import { targetRelative, unreadableDetail, } from "./discover.js";
|
|
7
7
|
import { missingModule, pathsOf } from "./expected-module.js";
|
|
8
8
|
import { FailureExit, failureLine } from "../failure.js";
|
|
9
9
|
import { JAVASCRIPT_FILE } from "../javascript-file.js";
|
|
@@ -80,7 +80,7 @@ function classifyTarget(engine, host, run, plan, view, unfound) {
|
|
|
80
80
|
const raw = projectErrors(diagnosticsOf(project));
|
|
81
81
|
const load = nonEmpty(raw.load);
|
|
82
82
|
if (load !== undefined) {
|
|
83
|
-
return { kind: "load", errors: load };
|
|
83
|
+
return { kind: "load", errors: load, unreadable: raw.unreadable };
|
|
84
84
|
}
|
|
85
85
|
const reading = readErrors(project, plan, ownErrors(raw.check, referenceOnly), {
|
|
86
86
|
host,
|
|
@@ -134,7 +134,7 @@ function classifyConsumer(engine, host, run, plan, consumer, project) {
|
|
|
134
134
|
const raw = projectErrors(diagnosticsOf(project));
|
|
135
135
|
const load = nonEmpty(raw.load);
|
|
136
136
|
if (load !== undefined) {
|
|
137
|
-
return { kind: "load", errors: load };
|
|
137
|
+
return { kind: "load", errors: load, unreadable: raw.unreadable };
|
|
138
138
|
}
|
|
139
139
|
let faulted;
|
|
140
140
|
const reading = readErrors(project, plan, raw.check, {
|
|
@@ -173,7 +173,7 @@ function ending(plan, failed, root) {
|
|
|
173
173
|
return plan.consumer === undefined
|
|
174
174
|
? [
|
|
175
175
|
{
|
|
176
|
-
failureClass: "no-program",
|
|
176
|
+
failureClass: failed.kind === "load" && failed.unreadable ? "unreadable-configuration" : "no-program",
|
|
177
177
|
detail: `${what}: correct the configuration, or name the configurations to analyze`,
|
|
178
178
|
},
|
|
179
179
|
]
|
|
@@ -184,6 +184,22 @@ function ending(plan, failed, root) {
|
|
|
184
184
|
},
|
|
185
185
|
];
|
|
186
186
|
}
|
|
187
|
+
/** The setup failures a dropped derived configuration counts as, where it counts as any. */
|
|
188
|
+
function droppedFailures(failed, plan, root) {
|
|
189
|
+
if (failed.kind === "setup") {
|
|
190
|
+
return { failures: failed.failures };
|
|
191
|
+
}
|
|
192
|
+
return failed.kind === "load" && failed.unreadable
|
|
193
|
+
? {
|
|
194
|
+
failures: [
|
|
195
|
+
{
|
|
196
|
+
failureClass: "unreadable-configuration",
|
|
197
|
+
detail: unreadableDetail(plan.id, `cannot be read as a compiler configuration: ${droppedBy(failed, root)}`),
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
}
|
|
201
|
+
: {};
|
|
202
|
+
}
|
|
187
203
|
/** The first line of the error that drops one derived configuration. */
|
|
188
204
|
function droppedBy(failed, root) {
|
|
189
205
|
return failed.kind === "load"
|
|
@@ -206,7 +222,6 @@ export function classify(engine, host, run, views) {
|
|
|
206
222
|
const analyzed = [];
|
|
207
223
|
const consumed = [];
|
|
208
224
|
const ended = new Map();
|
|
209
|
-
const dropped = [];
|
|
210
225
|
const unopened = run.plans.filter((plan) => !views.has(plan.configFile));
|
|
211
226
|
const outcomes = [
|
|
212
227
|
...run.plans.flatMap((plan) => {
|
|
@@ -237,8 +252,12 @@ export function classify(engine, host, run, views) {
|
|
|
237
252
|
ended.set(outcome.kind, [...(ended.get(outcome.kind) ?? []), { plan, failed: outcome }]);
|
|
238
253
|
}
|
|
239
254
|
else {
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
notBuilt.push({
|
|
256
|
+
id: plan.id,
|
|
257
|
+
configFile: plan.configFile,
|
|
258
|
+
error: droppedBy(outcome, root),
|
|
259
|
+
...droppedFailures(outcome, plan, root),
|
|
260
|
+
});
|
|
242
261
|
}
|
|
243
262
|
}
|
|
244
263
|
for (const kind of ["unopened", "setup", "load"]) {
|
|
@@ -248,7 +267,7 @@ export function classify(engine, host, run, views) {
|
|
|
248
267
|
throw new FailureExit(kind === "unopened" ? [failures[0]] : failures, all.flatMap(({ failed }) => (failed.kind === "load" ? failed.errors : [])));
|
|
249
268
|
}
|
|
250
269
|
}
|
|
251
|
-
const setupDropped = nonEmpty(
|
|
270
|
+
const setupDropped = nonEmpty(notBuilt.flatMap((one) => one.failures ?? []));
|
|
252
271
|
const [first] = notBuilt;
|
|
253
272
|
if (analyzed.length === 0 && first !== undefined) {
|
|
254
273
|
throw new FailureExit(setupDropped ?? [
|
|
@@ -68,12 +68,19 @@ function locatedIn(diagnostics, locate) {
|
|
|
68
68
|
export function diagnosticErrors(sets) {
|
|
69
69
|
return [...sets.configParsing, ...sets.syntactic, ...sets.semantic].filter(isError);
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The code of a configuration whose only parse error is that its inputs name no file: it reads
|
|
73
|
+
* as written and holds no program.
|
|
74
|
+
*/
|
|
75
|
+
const NO_INPUTS = 18003;
|
|
71
76
|
/** The errors one open project carries, each located in the file it names. */
|
|
72
77
|
export function projectErrors(sets) {
|
|
73
78
|
const unplaced = (kind) => sets.unplaced.filter((diagnostic) => classOf(diagnostic, false) === kind);
|
|
74
|
-
const
|
|
79
|
+
const parsing = sets.configParsing.filter(isError);
|
|
80
|
+
const load = [...parsing, ...unplaced("load")];
|
|
75
81
|
return {
|
|
76
82
|
load: locatedIn(load, sets.locate),
|
|
83
|
+
unreadable: parsing.some(({ code }) => code !== NO_INPUTS),
|
|
77
84
|
check: load.length > 0 ? [] : locatedIn(diagnosticErrors(sets), sets.locate),
|
|
78
85
|
unfound: load.length > 0 ? [] : locatedIn(unplaced("unfound-library"), sets.locate),
|
|
79
86
|
};
|