@cplieger/deadset-ts 8.0.0-dev.14 → 8.0.0-dev.15

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 (46) hide show
  1. package/dist/src/alias-chain.js +2 -2
  2. package/dist/src/analysis.js +2 -1
  3. package/dist/src/conformance-record.js +1 -1
  4. package/dist/src/consumers.js +1 -1
  5. package/dist/src/contract/contract.generated.js +1 -0
  6. package/dist/src/dependencies.js +2 -1
  7. package/dist/src/entry-points.js +26 -95
  8. package/dist/src/file-facts.js +1 -1
  9. package/dist/src/graph.js +0 -1
  10. package/dist/src/inventory/commonjs.js +462 -0
  11. package/dist/src/inventory/enumerate.js +166 -0
  12. package/dist/src/inventory/syntax.js +236 -0
  13. package/dist/src/inventory.js +305 -705
  14. package/dist/src/load/discover.js +1 -1
  15. package/dist/src/load/package-scope.js +56 -0
  16. package/dist/src/own-body.js +28 -0
  17. package/dist/src/position.js +41 -0
  18. package/dist/src/ref.js +11 -20
  19. package/dist/src/references.js +91 -30
  20. package/dist/src/session.js +3 -0
  21. package/dist/src/suppress-inline.js +33 -81
  22. package/dist/src/unseen-loads.js +106 -17
  23. package/jsr.json +1 -1
  24. package/package.json +2 -2
  25. package/src/alias-chain.ts +2 -2
  26. package/src/analysis.ts +2 -1
  27. package/src/conformance-record.ts +1 -1
  28. package/src/consumers.ts +1 -1
  29. package/src/contract/contract.generated.ts +1 -0
  30. package/src/dependencies.ts +2 -1
  31. package/src/entry-points.ts +30 -107
  32. package/src/file-facts.ts +1 -1
  33. package/src/graph.ts +0 -1
  34. package/src/inventory/commonjs.ts +611 -0
  35. package/src/inventory/enumerate.ts +202 -0
  36. package/src/inventory/syntax.ts +311 -0
  37. package/src/inventory.ts +424 -878
  38. package/src/load/discover.ts +1 -1
  39. package/src/load/package-scope.ts +74 -0
  40. package/src/own-body.ts +42 -0
  41. package/src/position.ts +42 -0
  42. package/src/ref.ts +11 -20
  43. package/src/references.ts +116 -53
  44. package/src/session.ts +17 -1
  45. package/src/suppress-inline.ts +53 -89
  46. package/src/unseen-loads.ts +166 -18
@@ -1,17 +1,20 @@
1
1
  /**
2
- * The loads of a project's production files whose target the analysis cannot resolve: an
3
- * `import()` or `require()` call whose path is computed and starts with no relative literal
4
- * naming a directory below the calling file's. The files such a load runs are roots the
5
- * analysis does not see, so the configuration's roots are never complete.
2
+ * The loads by a computed path: those whose files the analysis resolves, and those of a
3
+ * project's production files it cannot resolve, an `import()` or `require()` call whose
4
+ * path starts with no relative literal naming a directory below the calling file's. The
5
+ * files such a load runs are roots the analysis does not see, so the configuration's
6
+ * roots are never complete.
6
7
  */
7
- import { isBinaryExpression, isCallExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isStringLiteral, isTemplateExpression, SyntaxKind, } from "@typescript/native/ast";
8
+ import { isBinaryExpression, isCallExpression, isIdentifier, isMetaProperty, isNoSubstitutionTemplateLiteral, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isStringLiteral, isTemplateExpression, SyntaxKind, } from "@typescript/native/ast";
9
+ import { literalsOf } from "./entry-points.js";
10
+ import { hasOwnBody } from "./own-body.js";
8
11
  import { dirnamePath, relativePath, resolvePath } from "./paths.js";
9
12
  import { renderPosition } from "./position.js";
10
- import { UNANSWERED } from "./query.js";
11
13
  import { sourceFilesOf } from "./source-files.js";
12
14
  import { unwrapped } from "./unwrap.js";
15
+ import { globExpression } from "./text/glob.js";
13
16
  /** The literal text a computed path starts with: a template's head, or a concatenation's first literal. */
14
- export function leadingLiteral(node) {
17
+ function leadingLiteral(node) {
15
18
  const at = unwrapped(node);
16
19
  if (isTemplateExpression(at)) {
17
20
  return at.head.text;
@@ -25,17 +28,107 @@ export function leadingLiteral(node) {
25
28
  return undefined;
26
29
  }
27
30
  /**
28
- * The directory below `dir` a computed load's leading literal names, which the entry
29
- * rules root every file of, or none where it names a package, `dir` itself or a
30
- * directory holding it, each of which would name files no rule roots.
31
+ * The directory below `dir` a computed load's leading literal names, every file of which
32
+ * the load reaches, or none where it names a package, `dir` itself or a directory holding
33
+ * it, each of which would name every sibling.
31
34
  */
32
- export function computedLoadDirectory(dir, prefix) {
35
+ function computedLoadDirectory(dir, prefix) {
33
36
  if (!(prefix.startsWith("./") || prefix.startsWith("../")) || !prefix.endsWith("/")) {
34
37
  return undefined;
35
38
  }
36
39
  const target = resolvePath(dir, prefix);
37
40
  return target === dir || relativePath(target, dir) !== undefined ? undefined : target;
38
41
  }
42
+ /** Whether one node is a call that may load a module by a computed path. */
43
+ export function isLoadCall(node) {
44
+ if (!isCallExpression(node)) {
45
+ return false;
46
+ }
47
+ const callee = node.expression;
48
+ return (callee.kind === SyntaxKind.ImportKeyword ||
49
+ (isIdentifier(callee) && callee.text === "require") ||
50
+ isMetaGlob(node));
51
+ }
52
+ /**
53
+ * The resolved computed loads among one file's load calls, each loading the `candidates`
54
+ * but the file itself: an `import()` or `require()` whose path starts with a relative
55
+ * literal naming a directory below the file's, every candidate below it, and an
56
+ * `import.meta.glob` of relative literal globs, every candidate one matches, each read
57
+ * against the file's directory, as a bundler's context module reads them.
58
+ */
59
+ export function computedLoadsOf(file, calls, candidates) {
60
+ const dir = dirnamePath(file.fileName);
61
+ const others = candidates.filter((candidate) => candidate.file !== file);
62
+ return calls.flatMap(({ call, from }) => {
63
+ const [first, options] = call.arguments;
64
+ if (first === undefined) {
65
+ return [];
66
+ }
67
+ if (isMetaGlob(call)) {
68
+ const globs = (literalsOf(first) ?? [])
69
+ .filter((pattern) => pattern.startsWith("./") || pattern.startsWith("../"))
70
+ .map((pattern) => globExpression(resolvePath(dir, pattern)));
71
+ const files = others.filter((candidate) => globs.some((glob) => glob.test(candidate.file.fileName)));
72
+ const asset = readsAsAsset(options);
73
+ return [{ call, from, require: undefined, files, asset, eager: isEager(options) }];
74
+ }
75
+ const prefix = leadingLiteral(first);
76
+ const target = prefix === undefined ? undefined : computedLoadDirectory(dir, prefix);
77
+ if (target === undefined) {
78
+ return [];
79
+ }
80
+ const files = others.filter((candidate) => relativePath(target, candidate.file.fileName) !== undefined);
81
+ const callee = call.expression;
82
+ const require = isIdentifier(callee) ? callee : undefined;
83
+ return [{ call, from, require, files, asset: false, eager: false }];
84
+ });
85
+ }
86
+ /** Whether one call is `import.meta.glob(...)`. */
87
+ function isMetaGlob(node) {
88
+ if (!isPropertyAccessExpression(node.expression)) {
89
+ return false;
90
+ }
91
+ const { expression, name } = node.expression;
92
+ return (isIdentifier(name) &&
93
+ name.text === "glob" &&
94
+ isMetaProperty(expression) &&
95
+ expression.keywordToken === SyntaxKind.ImportKeyword);
96
+ }
97
+ /** The values an `import.meta.glob` options object assigns, each by its literal key. */
98
+ function globOptions(options) {
99
+ const literal = options === undefined ? undefined : unwrapped(options);
100
+ if (literal === undefined || !isObjectLiteralExpression(literal)) {
101
+ return [];
102
+ }
103
+ return literal.properties.flatMap((property) => isPropertyAssignment(property) &&
104
+ (isIdentifier(property.name) || isStringLiteral(property.name))
105
+ ? [[property.name.text, unwrapped(property.initializer)]]
106
+ : []);
107
+ }
108
+ /** Whether the options of an `import.meta.glob` set `eager` to `true`. */
109
+ function isEager(options) {
110
+ return globOptions(options).some(([key, value]) => key === "eager" && value.kind === SyntaxKind.TrueKeyword);
111
+ }
112
+ /** The query parameters that make Vite load a file as its text or its URL, each written bare. */
113
+ const ASSET_QUERY = /(?:^\?|&)(?:raw|url|inline)(?:&|$)/u;
114
+ /**
115
+ * Whether the options of an `import.meta.glob` read each file as text or as a URL: a
116
+ * `query` string holding a bare `raw`, `url` or `inline`, or an `as` of `raw` or `url`,
117
+ * which Vite reads as that query (https://vite.dev/guide/features.html#glob-import). Any
118
+ * other query is read as loading the module, which keeps more than it may.
119
+ */
120
+ function readsAsAsset(options) {
121
+ return globOptions(options).some(([key, value]) => {
122
+ if (!isStringLiteral(value) && !isNoSubstitutionTemplateLiteral(value)) {
123
+ return false;
124
+ }
125
+ if (key === "as") {
126
+ return value.text === "raw" || value.text === "url";
127
+ }
128
+ return (key === "query" &&
129
+ ASSET_QUERY.test(value.text.startsWith("?") ? value.text : `?${value.text}`));
130
+ });
131
+ }
39
132
  /** Whether a computed path's leading literal names a package, whose files are none of the target's. */
40
133
  function namesPackage(prefix) {
41
134
  return (prefix !== undefined &&
@@ -47,8 +140,7 @@ function namesPackage(prefix) {
47
140
  /**
48
141
  * Every unresolved load the project's production files write, in file then source order.
49
142
  * `testFiles` holds the test files by their path below the target root. A `require` call
50
- * loads a module only where the name resolves to no declaration of the project's own
51
- * files: one the project declares is its own function.
143
+ * loads a module unless {@link hasOwnBody} reads it as the project's own function.
52
144
  */
53
145
  export function unseenLoadsOf(project, configuration, targetRoot, testFiles) {
54
146
  const tests = new Set(testFiles);
@@ -84,13 +176,10 @@ export function unseenLoadsOf(project, configuration, targetRoot, testFiles) {
84
176
  file.forEachChild(visit);
85
177
  }
86
178
  const requires = sites.flatMap((site) => (site.require === undefined ? [] : [site.require]));
87
- const own = project.ownPaths();
88
179
  const local = new Set();
89
180
  project.symbolsAt(requires.map((node) => project.handle(node))).forEach((symbol, at) => {
90
181
  const node = requires[at];
91
- if (node !== undefined &&
92
- symbol !== UNANSWERED &&
93
- symbol?.declarations.some((handle) => own.has(handle.path)) === true) {
182
+ if (node !== undefined && typeof symbol === "object" && hasOwnBody(project, symbol)) {
94
183
  local.add(node);
95
184
  }
96
185
  });
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "8.0.0-dev.14",
3
+ "version": "8.0.0-dev.15",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "8.0.0-dev.14",
3
+ "version": "8.0.0-dev.15",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Deterministic dead-code analysis for TypeScript, class and type members included",
@@ -43,7 +43,7 @@
43
43
  "@stryker-mutator/typescript-checker": "10.1.1",
44
44
  "@stryker-mutator/vitest-runner": "10.1.1",
45
45
  "@types/node": "24.19.2",
46
- "eslint": "10.13.0",
46
+ "eslint": "10.14.0",
47
47
  "fast-check": "4.10.2",
48
48
  "prettier": "3.9.10",
49
49
  "typescript": "npm:@typescript/typescript6@6.0.2",
@@ -14,7 +14,7 @@ import {
14
14
  isNamespaceImport,
15
15
  } from "@typescript/native/ast";
16
16
  import { SymbolFlags, type Symbol as TSSymbol } from "@typescript/native/sync";
17
- import { declarationsByName, isParameterProperty, nodeKey, type Inventory } from "./inventory.ts";
17
+ import { isParameterProperty, nodeKey, type Inventory } from "./inventory.ts";
18
18
  import { UNANSWERED, type Answer } from "./query.ts";
19
19
  import type { ProjectView } from "./session.ts";
20
20
 
@@ -132,7 +132,7 @@ export function aliasChains<Brand>(project: ProjectView<Brand>, held: Inventory)
132
132
  names.add(node.expression.text);
133
133
  }
134
134
  }
135
- const byName = declarationsByName(held);
135
+ const byName = held.byName;
136
136
  const ids = [...names].flatMap((name) => byName.get(name) ?? []);
137
137
  return [...new Set([...ids, ...(module ? files : [])])].map((id) => ({
138
138
  id,
package/src/analysis.ts CHANGED
@@ -51,7 +51,8 @@ import { implementations, mergeImplementations } from "./implementations.ts";
51
51
  import { injectionContainer } from "./injection-container.ts";
52
52
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.ts";
53
53
  import { intraFunctionFacts, projectParts, type ProjectParts } from "./intra-function-parts.ts";
54
- import { inventory, type Inventory, type InventorySymbol } from "./inventory.ts";
54
+ import { type Inventory, type InventorySymbol } from "./inventory.ts";
55
+ import { inventory } from "./inventory/enumerate.ts";
55
56
  import { readManifest, type ManifestEntry } from "./manifest.ts";
56
57
  import {
57
58
  liveFilesAt,
@@ -4,7 +4,7 @@ export const RECORD = {
4
4
  conformance: {
5
5
  corpusVersion: "6.0.0",
6
6
  result: "pass",
7
- digest: "sha256:58ac31fa90fcbefdbbcbcbd6d2c7a8af6dd4cd883c04d79abfe96f979ffe10e1",
7
+ digest: "sha256:4a66f7f01b0f1a23cf843b77ef48d762f2dcf486153e665560f107f10b0ea838",
8
8
  },
9
9
  gaps: [],
10
10
  } as const;
package/src/consumers.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { PartialConfig } from "./config.ts";
2
2
  import type { Host } from "./host.ts";
3
- import { inventory } from "./inventory.ts";
3
+ import { inventory } from "./inventory/enumerate.ts";
4
4
  import { relativePath } from "./paths.ts";
5
5
  import { references, type ConsumerSide, type Reference } from "./references.ts";
6
6
  import { narrowedTo, type ProjectView } from "./session.ts";
@@ -1297,6 +1297,7 @@ export const FAILURE_CLASSES = {
1297
1297
  "unreadable-document": "setup",
1298
1298
  "missing-import-path": "setup",
1299
1299
  "binding-undecodable": "setup",
1300
+ "unsupported-language": "setup",
1300
1301
  "unwritten-output": "run",
1301
1302
  "unreportable-path": "run",
1302
1303
  "memory-exhausted": "run",
@@ -41,7 +41,8 @@ import {
41
41
  } from "./configuration-files.ts";
42
42
  import type { FindingPosition } from "./finding.ts";
43
43
  import type { Host } from "./host.ts";
44
- import { nodeKey, packageScope, type Inventory } from "./inventory.ts";
44
+ import { nodeKey, type Inventory } from "./inventory.ts";
45
+ import { packageScope } from "./load/package-scope.ts";
45
46
  import {
46
47
  ancestors,
47
48
  dirnamePath,
@@ -1,14 +1,7 @@
1
1
  /**
2
- * The files a tool or the platform enters without any import naming them: the
3
- * configuration files a tool loads by their file name and the files their strings
4
- * name, the test files the runner executes, and a worker a call addresses by a string
5
- * literal.
6
- *
7
- * Each rule is read from the program and nothing else: a file name the tool
8
- * itself looks for, a literal written in a configuration file, or a literal
9
- * argument of a call the checker resolves to the platform's own declaration. A
10
- * value that is not a literal is not evaluated and not guessed, so a file it would
11
- * have named is entered by nothing here.
2
+ * The files a tool or the platform enters without any import naming them, each by a name
3
+ * the tool looks for or a literal it reads. A value that is not a literal is not evaluated
4
+ * or guessed, so a file it would have named is entered by nothing here.
12
5
  */
13
6
 
14
7
  import {
@@ -23,7 +16,6 @@ import {
23
16
  isPropertyAccessExpression,
24
17
  isPropertyAssignment,
25
18
  isStringLiteral,
26
- SyntaxKind,
27
19
  type Node,
28
20
  type SourceFile,
29
21
  } from "@typescript/native/ast";
@@ -39,11 +31,11 @@ import { buildScriptEntries } from "./build-scripts.ts";
39
31
  import type { Host } from "./host.ts";
40
32
  import { htmlEntries } from "./html-entries.ts";
41
33
  import { documentEntries } from "./mdx-entries.ts";
34
+ import { hasOwnBody } from "./own-body.ts";
42
35
  import { dirnamePath, relativePath, resolvePath } from "./paths.ts";
43
36
  import { UNANSWERED } from "./query.ts";
44
37
  import type { ProjectView } from "./session.ts";
45
38
  import type { SourceFiles } from "./source-files.ts";
46
- import { computedLoadDirectory, leadingLiteral } from "./unseen-loads.ts";
47
39
  import { workflowEntries } from "./workflow-steps.ts";
48
40
  import { unwrapped } from "./unwrap.ts";
49
41
  import { globExpression } from "./text/glob.ts";
@@ -66,12 +58,6 @@ export type EntryRule =
66
58
  | "html-entry"
67
59
  /** A file a `run:` step of a workflow in the target root's `.github/workflows` names. */
68
60
  | "workflow-step"
69
- /**
70
- * A file a load whose path is computed may name: below the directory the literal
71
- * start of an `import()` or `require()` argument names, or matched by the literal
72
- * glob of `import.meta.glob`.
73
- */
74
- | "computed-import"
75
61
  /** A file an import line of a Markdown or MDX document below the target root names. */
76
62
  | "document-import";
77
63
 
@@ -216,7 +202,7 @@ function memberOf(object: Node, name: string): Node | undefined {
216
202
  * The strings one member holds, when it is written as a literal or an array of
217
203
  * literals. `undefined` is a value the text does not state.
218
204
  */
219
- function literalsOf(value: Node): readonly string[] | undefined {
205
+ export function literalsOf(value: Node): readonly string[] | undefined {
220
206
  const at = unwrapped(value);
221
207
  const single = literalOf(at);
222
208
  if (single !== undefined) {
@@ -244,11 +230,6 @@ function isRelative(text: string): boolean {
244
230
  return text !== "" && !text.startsWith("/") && !URL_SCHEME.test(text);
245
231
  }
246
232
 
247
- /** Whether a module specifier is relative, which a bare name is not: it names a package. */
248
- function isModuleRelative(text: string): boolean {
249
- return text.startsWith("./") || text.startsWith("../");
250
- }
251
-
252
233
  /** A URL reference with its query and its fragment removed, which name no part of the file. */
253
234
  function pathPart(text: string): string {
254
235
  const cut = text.search(/[?#]/u);
@@ -396,6 +377,8 @@ function browserTestsOf(file: SourceFile, files: SourceFiles): readonly EntryPoi
396
377
  interface WorkerSite {
397
378
  readonly literal: string;
398
379
  readonly platformNames: readonly Node[];
380
+ /** The `URL` the address is built with; {@link hasOwnBody} owns which one names no file. */
381
+ readonly url: Node | undefined;
399
382
  }
400
383
 
401
384
  /**
@@ -405,14 +388,14 @@ interface WorkerSite {
405
388
  */
406
389
  function workerAddress(
407
390
  argument: Node | undefined,
408
- ): { readonly literal: string; readonly names: readonly Node[] } | undefined {
391
+ ): { readonly literal: string; readonly url: Node | undefined } | undefined {
409
392
  if (argument === undefined) {
410
393
  return undefined;
411
394
  }
412
395
  const at = unwrapped(argument);
413
396
  const literal = literalOf(at);
414
397
  if (literal !== undefined) {
415
- return { literal, names: [] };
398
+ return { literal, url: undefined };
416
399
  }
417
400
  if (!isNewExpression(at) || !isIdentifier(at.expression) || at.expression.text !== "URL") {
418
401
  return undefined;
@@ -431,7 +414,7 @@ function workerAddress(
431
414
  ) {
432
415
  return undefined;
433
416
  }
434
- return { literal: text, names: [at.expression] };
417
+ return { literal: text, url: at.expression };
435
418
  }
436
419
 
437
420
  /**
@@ -451,7 +434,8 @@ function workerSitesOf(file: SourceFile): readonly WorkerSite[] {
451
434
  if (address !== undefined) {
452
435
  found.push({
453
436
  literal: address.literal,
454
- platformNames: [node.expression, ...address.names],
437
+ platformNames: [node.expression],
438
+ url: address.url,
455
439
  });
456
440
  }
457
441
  }
@@ -471,7 +455,8 @@ function workerSitesOf(file: SourceFile): readonly WorkerSite[] {
471
455
  if (address !== undefined) {
472
456
  found.push({
473
457
  literal: address.literal,
474
- platformNames: [callee.expression.expression, ...address.names],
458
+ platformNames: [callee.expression.expression],
459
+ url: address.url,
475
460
  });
476
461
  }
477
462
  }
@@ -483,10 +468,10 @@ function workerSitesOf(file: SourceFile): readonly WorkerSite[] {
483
468
  }
484
469
 
485
470
  /**
486
- * The workers one file addresses. A call's names must resolve to a symbol the platform
487
- * declares, which a file of the target may augment and no import brings in; a name only
488
- * the target declares is the target's own constructor or object, which addresses no
489
- * worker this rule knows. One batch per file that writes such a call.
471
+ * The workers one file addresses. A call's `Worker`, `SharedWorker` or `navigator` must
472
+ * resolve to a symbol the platform declares, which a file of the target may augment and no
473
+ * import brings in; a name only the target declares is the target's own constructor or
474
+ * object, which addresses no worker this rule knows. One batch per file that writes such a call.
490
475
  */
491
476
  function workersOf<Brand>(
492
477
  project: ProjectView<Brand>,
@@ -498,7 +483,8 @@ function workersOf<Brand>(
498
483
  return [];
499
484
  }
500
485
  const names = sites.flatMap((site) => site.platformNames);
501
- const symbols = project.symbolsAt(names.map((name) => project.handle(name)));
486
+ const urls = sites.flatMap((site) => site.url ?? []);
487
+ const symbols = project.symbolsAt([...names, ...urls].map((name) => project.handle(name)));
502
488
  const platform = new Set<Node>();
503
489
  // A name the checker could not resolve is read as the platform's, so a worker it
504
490
  // stands on is rooted rather than reported.
@@ -516,10 +502,19 @@ function workersOf<Brand>(
516
502
  platform.add(name);
517
503
  }
518
504
  });
505
+ urls.forEach((url, index) => {
506
+ const symbol = symbols[names.length + index];
507
+ if (typeof symbol !== "object" || !hasOwnBody(project, symbol)) {
508
+ platform.add(url);
509
+ }
510
+ });
519
511
  const dir = dirnamePath(file.fileName);
520
512
  const found: EntryPoint[] = [];
521
513
  for (const site of sites) {
522
- if (!site.platformNames.every((name) => platform.has(name))) {
514
+ if (
515
+ !site.platformNames.every((name) => platform.has(name)) ||
516
+ (site.url !== undefined && !platform.has(site.url))
517
+ ) {
523
518
  continue;
524
519
  }
525
520
  for (const named of filesNamed(files, dir, site.literal)) {
@@ -529,77 +524,6 @@ function workersOf<Brand>(
529
524
  return found;
530
525
  }
531
526
 
532
- /** Whether one call is `import.meta.glob(...)`. */
533
- function isMetaGlob(node: Node): boolean {
534
- if (!isCallExpression(node) || !isPropertyAccessExpression(node.expression)) {
535
- return false;
536
- }
537
- const { expression, name } = node.expression;
538
- return (
539
- isIdentifier(name) &&
540
- name.text === "glob" &&
541
- isMetaProperty(expression) &&
542
- expression.keywordToken === SyntaxKind.ImportKeyword
543
- );
544
- }
545
-
546
- /**
547
- * The files one file loads by a computed path, each with what exports: every own file
548
- * below the directory a relative literal start of an `import()` or `require()` argument
549
- * names, other than the calling file's own directory or one holding it, which would name
550
- * every sibling, and
551
- * every own file a relative literal glob of `import.meta.glob` matches, both read against
552
- * the calling file's directory, as a bundler's context module reads them.
553
- */
554
- function computedImportsOf(file: SourceFile, files: SourceFiles): readonly EntryPoint[] {
555
- const dir = dirnamePath(file.fileName);
556
- const found: EntryPoint[] = [];
557
- const below = (prefix: string): void => {
558
- const target = computedLoadDirectory(dir, prefix);
559
- if (target === undefined) {
560
- return;
561
- }
562
- for (const candidate of files.byName.values()) {
563
- if (candidate !== file && relativePath(target, candidate.fileName) !== undefined) {
564
- found.push({ file: candidate, rule: "computed-import", source: prefix, exports: true });
565
- }
566
- }
567
- };
568
- const globbed = (pattern: string): void => {
569
- if (!isModuleRelative(pattern)) {
570
- return;
571
- }
572
- const expression = globExpression(resolvePath(dir, pattern));
573
- for (const candidate of files.byName.values()) {
574
- if (candidate !== file && expression.test(candidate.fileName)) {
575
- found.push({ file: candidate, rule: "computed-import", source: pattern, exports: true });
576
- }
577
- }
578
- };
579
- const visit = (node: Node): void => {
580
- if (isCallExpression(node)) {
581
- const [first] = node.arguments;
582
- const callee = node.expression;
583
- const loads =
584
- callee.kind === SyntaxKind.ImportKeyword ||
585
- (isIdentifier(callee) && callee.text === "require");
586
- if (loads && first !== undefined) {
587
- const prefix = leadingLiteral(first);
588
- if (prefix !== undefined) {
589
- below(prefix);
590
- }
591
- } else if (isMetaGlob(node) && first !== undefined) {
592
- for (const pattern of literalsOf(first) ?? []) {
593
- globbed(pattern);
594
- }
595
- }
596
- }
597
- node.forEachChild(visit);
598
- };
599
- file.forEachChild(visit);
600
- return found;
601
- }
602
-
603
527
  /**
604
528
  * Every file of one project the rules enter, in no particular order and possibly more
605
529
  * than once: a file two rules enter appears once per rule.
@@ -637,7 +561,6 @@ export function entryPoints<Brand>(
637
561
  }
638
562
  }
639
563
  found.push(...workersOf(project, file, files));
640
- found.push(...computedImportsOf(file, files));
641
564
  }
642
565
  for (const { file, source } of htmlEntries(host, targetRoot, files, parse)) {
643
566
  found.push({ file, rule: "html-entry", source, exports: true });
package/src/file-facts.ts CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  import type { SourceFile } from "@typescript/native/ast";
8
8
  import type { Host } from "./host.ts";
9
- import { packageScope } from "./inventory.ts";
9
+ import { packageScope } from "./load/package-scope.ts";
10
10
  import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
11
11
  import { renderRef } from "./ref.ts";
12
12
  import type { ProjectView } from "./session.ts";
package/src/graph.ts CHANGED
@@ -65,7 +65,6 @@ const NAMES_A_CALLER: Readonly<Record<RootKind, boolean>> = {
65
65
  worker: true,
66
66
  "html-entry": true,
67
67
  "workflow-step": true,
68
- "computed-import": true,
69
68
  "document-import": true,
70
69
  };
71
70