@cplieger/deadset-ts 8.0.0-dev.16 → 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.
Files changed (131) hide show
  1. package/dist/src/alias-chain.js +0 -5
  2. package/dist/src/amd.js +81 -0
  3. package/dist/src/analysis.js +58 -22
  4. package/dist/src/augmentations.js +23 -24
  5. package/dist/src/bindings.js +382 -0
  6. package/dist/src/calls.js +25 -8
  7. package/dist/src/commands/tools.js +5 -9
  8. package/dist/src/component-files.js +3 -2
  9. package/dist/src/conformance-record.js +1 -1
  10. package/dist/src/consumers.js +6 -9
  11. package/dist/src/contextual-uses.js +1 -17
  12. package/dist/src/contract/config.generated.js +4 -1
  13. package/dist/src/contract/report.generated.js +6 -2
  14. package/dist/src/dependencies.js +25 -29
  15. package/dist/src/destructuring.js +1 -19
  16. package/dist/src/element-access.js +179 -164
  17. package/dist/src/entries/build-scripts.js +2 -2
  18. package/dist/src/entries/configuration-files.js +3 -7
  19. package/dist/src/entries/conventions.js +2 -2
  20. package/dist/src/entries/html-entries.js +7 -10
  21. package/dist/src/entries/mdx-entries.js +2 -2
  22. package/dist/src/entries/static-module.js +2 -1
  23. package/dist/src/facts.js +4 -4
  24. package/dist/src/findings/completion.js +40 -4
  25. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  26. package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
  27. package/dist/src/framework-lifecycle.js +41 -14
  28. package/dist/src/graph.js +12 -4
  29. package/dist/src/import-bindings.js +73 -28
  30. package/dist/src/index/sites.js +557 -0
  31. package/dist/src/indexed-access.js +523 -478
  32. package/dist/src/interface-satisfaction.js +1 -1
  33. package/dist/src/keyof-comparisons.js +124 -103
  34. package/dist/src/load/expected-module.js +2 -2
  35. package/dist/src/load/specifiers.js +2 -4
  36. package/dist/src/load/synthesize.js +5 -0
  37. package/dist/src/load/workspace-resolution.js +2 -2
  38. package/dist/src/matrix.js +6 -4
  39. package/dist/src/module-declarations.js +70 -85
  40. package/dist/src/overrides.js +134 -112
  41. package/dist/src/paths.js +46 -7
  42. package/dist/src/platform-calls.js +2 -2
  43. package/dist/src/platform-symbols.js +13 -19
  44. package/dist/src/references/read-rule.js +1 -0
  45. package/dist/src/references/read-rules.js +48 -0
  46. package/dist/src/references/sink.js +151 -0
  47. package/dist/src/references/sources.js +450 -0
  48. package/dist/src/references.js +110 -1285
  49. package/dist/src/roots/configured-declarations.js +3 -0
  50. package/dist/src/roots/root-set.js +1 -1
  51. package/dist/src/roots/unseen-loads.js +38 -10
  52. package/dist/src/serialization-contract.js +8 -3
  53. package/dist/src/stores.js +4 -2
  54. package/dist/src/sweep.js +25 -13
  55. package/dist/src/symbol-keys.js +89 -83
  56. package/dist/src/tests/file-class.js +76 -0
  57. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  58. package/dist/src/{test-support.js → tests/support.js} +2 -11
  59. package/dist/src/type-parameter-reads.js +178 -139
  60. package/dist/src/unimplemented-callees.js +262 -242
  61. package/dist/src/verbs/analyze.js +3 -3
  62. package/dist/src/verbs/explain.js +50 -28
  63. package/dist/src/verbs/print-retained.js +2 -2
  64. package/jsr.json +1 -1
  65. package/package.json +2 -2
  66. package/src/alias-chain.ts +0 -7
  67. package/src/amd.ts +130 -0
  68. package/src/analysis.ts +86 -23
  69. package/src/augmentations.ts +41 -27
  70. package/src/bindings.ts +460 -0
  71. package/src/calls.ts +25 -7
  72. package/src/commands/tools.ts +5 -11
  73. package/src/component-files.ts +4 -2
  74. package/src/conformance-record.ts +1 -1
  75. package/src/consumers.ts +8 -11
  76. package/src/contextual-uses.ts +2 -22
  77. package/src/contract/config.generated.ts +4 -1
  78. package/src/contract/report.generated.ts +6 -2
  79. package/src/dependencies.ts +27 -28
  80. package/src/destructuring.ts +1 -31
  81. package/src/element-access.ts +188 -182
  82. package/src/entries/build-scripts.ts +2 -2
  83. package/src/entries/configuration-files.ts +11 -8
  84. package/src/entries/conventions.ts +2 -1
  85. package/src/entries/html-entries.ts +15 -14
  86. package/src/entries/mdx-entries.ts +2 -2
  87. package/src/entries/static-module.ts +2 -1
  88. package/src/facts.ts +5 -3
  89. package/src/findings/boundary.ts +2 -0
  90. package/src/findings/completion.ts +43 -4
  91. package/src/findings/emitter.ts +1 -1
  92. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  93. package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
  94. package/src/framework-lifecycle.ts +42 -14
  95. package/src/graph.ts +24 -6
  96. package/src/import-bindings.ts +98 -29
  97. package/src/index/sites.ts +781 -0
  98. package/src/indexed-access.ts +570 -527
  99. package/src/interface-satisfaction.ts +1 -1
  100. package/src/keyof-comparisons.ts +131 -116
  101. package/src/load/expected-module.ts +8 -2
  102. package/src/load/specifiers.ts +8 -5
  103. package/src/load/synthesize.ts +6 -0
  104. package/src/load/workspace-resolution.ts +9 -2
  105. package/src/matrix.ts +6 -3
  106. package/src/module-declarations.ts +74 -98
  107. package/src/overrides.ts +162 -134
  108. package/src/paths.ts +54 -8
  109. package/src/platform-calls.ts +3 -3
  110. package/src/platform-symbols.ts +11 -27
  111. package/src/references/read-rule.ts +60 -0
  112. package/src/references/read-rules.ts +55 -0
  113. package/src/references/sink.ts +213 -0
  114. package/src/references/sources.ts +632 -0
  115. package/src/references.ts +168 -1733
  116. package/src/report.ts +1 -1
  117. package/src/roots/configured-declarations.ts +3 -0
  118. package/src/roots/root-set.ts +1 -1
  119. package/src/roots/unseen-loads.ts +49 -11
  120. package/src/serialization-contract.ts +8 -3
  121. package/src/stores.ts +13 -2
  122. package/src/sweep.ts +37 -14
  123. package/src/symbol-keys.ts +102 -102
  124. package/src/tests/file-class.ts +118 -0
  125. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  126. package/src/{test-support.ts → tests/support.ts} +9 -20
  127. package/src/type-parameter-reads.ts +187 -158
  128. package/src/unimplemented-callees.ts +297 -280
  129. package/src/verbs/analyze.ts +3 -2
  130. package/src/verbs/explain.ts +74 -31
  131. package/src/verbs/print-retained.ts +2 -2
@@ -19,7 +19,6 @@ export function aliasChains(project, held) {
19
19
  const ownFiles = project.ownPaths();
20
20
  const steps = new Map();
21
21
  const chains = new Map();
22
- let asked = 0;
23
22
  const declarationsOf = (symbol) => {
24
23
  const ids = [];
25
24
  for (const handle of symbol.declarations) {
@@ -52,7 +51,6 @@ export function aliasChains(project, held) {
52
51
  return steps.get(symbol.id);
53
52
  }
54
53
  const next = project.aliasStepOf(symbol);
55
- asked += 1;
56
54
  steps.set(symbol.id, next);
57
55
  return next;
58
56
  };
@@ -145,8 +143,5 @@ export function aliasChains(project, held) {
145
143
  declarationsOf,
146
144
  chainOf,
147
145
  nextDeclared,
148
- get steps() {
149
- return asked;
150
- },
151
146
  };
152
147
  }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * AMD's module forms (references-ts.37), read from the syntax because the binder declares
3
+ * none of them: `define([<ids>], factory)`, `define("<name>", [<ids>], factory)` and
4
+ * `require([<ids>], callback)` (https://github.com/amdjs/amdjs-api/blob/master/AMD.md).
5
+ */
6
+ import { isArrayLiteralExpression, isArrowFunction, isFunctionExpression, isCallExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isStringLiteral, } from "@typescript/native/ast";
7
+ import { hasURLScheme, isAbsolutePath, resolvePath, startsRelativePath } from "./paths.js";
8
+ import { parenthesesRemoved } from "./unwrap.js";
9
+ /** The ids AMD binds to the factory's CommonJS parameters, which load no module. */
10
+ const FREE_VARIABLES = new Set(["require", "exports", "module"]);
11
+ /** The platform function `callee` is written as. */
12
+ export function amdPlatform(callee) {
13
+ return callee.text === "define" ? "define" : "require";
14
+ }
15
+ /**
16
+ * The dependency list one call writes, where it is a call of a bare `define` or `require` in
17
+ * one of AMD's forms. A `define` with no list, of a factory or a value alone, loads nothing;
18
+ * a `require` whose first argument is no array literal is CommonJS's.
19
+ */
20
+ export function amdLoadOf(node) {
21
+ if (!isCallExpression(node)) {
22
+ return undefined;
23
+ }
24
+ const callee = parenthesesRemoved(node.expression);
25
+ if (!isIdentifier(callee) || (callee.text !== "define" && callee.text !== "require")) {
26
+ return undefined;
27
+ }
28
+ const written = node.arguments.map((one) => parenthesesRemoved(one));
29
+ const [first] = written;
30
+ if (first === undefined) {
31
+ return undefined;
32
+ }
33
+ const define = callee.text === "define";
34
+ const named = define && isLiteralText(first);
35
+ const list = written[named ? 1 : 0];
36
+ if (list !== undefined && isArrayLiteralExpression(list)) {
37
+ const elements = list.elements.map((one) => parenthesesRemoved(one));
38
+ const factory = written[named ? 2 : 1];
39
+ const ids = elements.flatMap((one, at) => isLiteralText(one) && !FREE_VARIABLES.has(one.text)
40
+ ? [{ id: one, received: receives(factory, at) }]
41
+ : []);
42
+ return { callee, ids, computed: elements.some((one) => !isLiteralText(one)) };
43
+ }
44
+ if (!define) {
45
+ return undefined;
46
+ }
47
+ // A factory after the list's place makes what stands there a list, here a computed one.
48
+ return { callee, ids: [], computed: written.length > (named ? 2 : 1) };
49
+ }
50
+ function isLiteralText(node) {
51
+ return isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node);
52
+ }
53
+ /** Whether a factory may receive the dependency at place `at` of its list. */
54
+ function receives(factory, at) {
55
+ if (factory === undefined) {
56
+ return false;
57
+ }
58
+ if (!isFunctionExpression(factory) && !isArrowFunction(factory)) {
59
+ return true;
60
+ }
61
+ const { parameters } = factory;
62
+ return at < parameters.length || parameters.some((one) => one.dotDotDotToken !== undefined);
63
+ }
64
+ /**
65
+ * The path a dependency id names against the calling file's directory: a relative module id,
66
+ * `./` or `../` with no `.js` ending, with `.js` appended. RequireJS reads any other id
67
+ * through its configuration or as a URL against the page, which the analysis does not know.
68
+ */
69
+ export function amdPath(dir, id) {
70
+ return startsRelativePath(id) && !id.endsWith(".js") ? resolvePath(dir, `${id}.js`) : undefined;
71
+ }
72
+ /**
73
+ * Whether one call may load a file the analysis cannot name: a computed list, or an id that
74
+ * RequireJS reads as a URL, one ending in `.js`, starting with `/` or carrying a scheme. Any
75
+ * other id {@link amdPath} reads no path from is a package's.
76
+ */
77
+ export function amdUnresolved(load) {
78
+ return (load.computed ||
79
+ load.ids.some(({ id }) => amdPath("/", id.text) === undefined &&
80
+ (id.text.endsWith(".js") || isAbsolutePath(id.text) || hasURLScheme(id.text))));
81
+ }
@@ -19,15 +19,16 @@ import { readSources } from "./entries/sources.js";
19
19
  import { readWorkflows } from "./entries/workflow-steps.js";
20
20
  import { readEdgeSides } from "./edges.js";
21
21
  import { enumGroup } from "./enum-group.js";
22
+ import { bindingsOf, distinctBindings } from "./bindings.js";
22
23
  import { generatedFile, generatedFilesOf } from "./generated-file.js";
23
- import { inOperandNames } from "./in-operands.js";
24
+ import { inOperandNames } from "./findings/in-operands.js";
24
25
  import { sourceFilesOf } from "./source-files.js";
25
26
  import { evidenceRecords, heldRecords, disabledClasses, exemptionsOf, holdingWhile, isUnansweredRecord, retainedIn, writtenRecords, } from "./exempt.js";
26
27
  import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.js";
27
28
  import { findingsPass, recordedFindings, rowKey } from "./findings-pass.js";
28
29
  import { unmatchedRootFindings } from "./findings/self-check.js";
29
30
  import { frameworkLifecycle } from "./framework-lifecycle.js";
30
- import { implementations, mergeImplementations } from "./implementations.js";
31
+ import { implementations, mergeImplementations } from "./findings/implementations.js";
31
32
  import { injectionContainer } from "./injection-container.js";
32
33
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.js";
33
34
  import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
@@ -39,12 +40,14 @@ import { ancestors, dirnamePath, extensionOf, joinPath, relativePath, resolvePat
39
40
  import { byPosition, isComponentFile } from "./position.js";
40
41
  import { skippedUnits } from "./type-errors.js";
41
42
  import { reflectiveLookup } from "./reflective-lookup.js";
42
- import { references, testFileRulesOf } from "./references.js";
43
+ import { references } from "./references.js";
43
44
  import { rootSet, unmatchedEverywhere, } from "./roots/root-set.js";
44
45
  import { decodedMembers, serializationContract } from "./serialization-contract.js";
45
- import { outsideTestReferences, testFilesAt } from "./outside-tests.js";
46
+ import { outsideTestReferences, testFilesAt } from "./tests/outside.js";
47
+ import { formedForNode } from "./load/synthesize.js";
46
48
  import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.js";
47
- import { supportReferences, testSupportFiles } from "./test-support.js";
49
+ import { targetTestFile, testFilePaths, testFileRulesOf, withheldBy, } from "./tests/file-class.js";
50
+ import { testSupportFiles } from "./tests/support.js";
48
51
  import { accessorsOf, storesOf } from "./stores.js";
49
52
  import { isPartKind } from "./suppress.js";
50
53
  import { bindRows, readBaseline, readIgnoreFile } from "./suppress-file.js";
@@ -109,6 +112,7 @@ function readProjects(engine, host, scope, config, stage) {
109
112
  workflows,
110
113
  });
111
114
  const rooted = rootSet(project, held, targetRoot, { ...options, sources, skips });
115
+ const generated = generatedFilesOf(own, sources.generated);
112
116
  return {
113
117
  configuration: planned.id,
114
118
  configFile: project.configFile,
@@ -120,8 +124,12 @@ function readProjects(engine, host, scope, config, stage) {
120
124
  .ownSourceFiles()
121
125
  .filter((file) => referenceOnly(file.fileName))
122
126
  .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
123
- generated: generatedFilesOf(own, sources.generated),
127
+ generated,
128
+ bindings: bindingsOf(own.byPath, generated, new Map(held.symbols
129
+ .filter((one) => one.kind === "file")
130
+ .map((one) => [one.position.path, one.ref]))),
124
131
  sources,
132
+ formedForNode: formedForNode(planned),
125
133
  };
126
134
  };
127
135
  for (const file of project.ownSourceFiles()) {
@@ -130,14 +138,25 @@ function readProjects(engine, host, scope, config, stage) {
130
138
  return stage(project, { configuration: planned.id, read });
131
139
  });
132
140
  const consumed = new Map();
141
+ const consumerHeld = new Set();
133
142
  for (const { project, consumer } of classified.consumed) {
134
143
  const side = { id: consumer.id, root: consumer.path };
135
- for (const reference of consumerReferences(project, host, targetRoot, side, config, parse)) {
144
+ const read = consumerReferences(project, host, targetRoot, side, config, parse);
145
+ for (const reference of read.references) {
136
146
  consumed.set(referenceKey(reference), reference);
137
147
  }
148
+ for (const id of read.held) {
149
+ consumerHeld.add(id);
150
+ }
138
151
  }
139
152
  const outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
140
- return { answers, references: [...consumed.values()], outsideTests, workflows };
153
+ return {
154
+ answers,
155
+ references: [...consumed.values()],
156
+ consumerHeld: [...consumerHeld],
157
+ outsideTests,
158
+ workflows,
159
+ };
141
160
  });
142
161
  }
143
162
  /**
@@ -202,6 +221,13 @@ export function runRoots(engine, host, scope, config, provenance) {
202
221
  unanswered: read.unanswered,
203
222
  };
204
223
  }
224
+ /** The production mode a configuration sets: a consumer's test reference is classed as `analysis.consumer_tests` says. */
225
+ export function productionMode(config) {
226
+ return {
227
+ production: true,
228
+ consumerTestsProduction: config.analysis.consumer_tests === "production",
229
+ };
230
+ }
205
231
  /** The exemption classes this analyzer detects, each by its detector; any other retains nothing. */
206
232
  export const DETECTORS = new Map([
207
233
  ["interface-satisfaction", interfaceSatisfaction],
@@ -268,11 +294,13 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
268
294
  const directories = runDirectories(host, targetRoot, (fileName, text) => engine.parseSourceFile(fileName, text));
269
295
  const read = readProjects(engine, host, scope, config, (project, opened) => {
270
296
  const projectRead = opened.read();
297
+ const testFile = targetTestFile(projectRead.sources.testFiles);
271
298
  const resolved = references(project, projectRead.held, targetRoot, {
272
- testFiles: config.ts.test_files,
273
- testFileNames: projectRead.sources.testFiles,
299
+ testFile,
274
300
  directories,
301
+ formedForNode: projectRead.formedForNode,
275
302
  });
303
+ const testFiles = testFilePaths(project, targetRoot, testFile);
276
304
  const evidence = evidenceRecords({
277
305
  project,
278
306
  held: projectRead.held,
@@ -292,7 +320,9 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
292
320
  return {
293
321
  projectRead,
294
322
  references: resolved.references,
295
- testFiles: resolved.testFilePaths,
323
+ held: resolved.held,
324
+ possiblyLoaded: resolved.possiblyLoaded,
325
+ testFiles,
296
326
  evidence,
297
327
  componentFiles: components.map(pathOf),
298
328
  imports: new Map(project.ownSourceFiles().flatMap((file) => {
@@ -316,8 +346,8 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
316
346
  line: lineOf(file.originalText, warning.offset),
317
347
  reason: warning.reason,
318
348
  }))),
319
- decoded: decodedMembers(project, projectRead.held, productionFiles(project, targetRoot, resolved.testFilePaths), consumers),
320
- extra: extra(project, projectRead, resolved.references, resolved.testFilePaths, resolved.unseenLoads.map((position) => ({
349
+ decoded: decodedMembers(project, projectRead.held, productionFiles(project, targetRoot, testFiles), consumers),
350
+ extra: extra(project, projectRead, resolved.references, testFiles, resolved.unseenLoads.map((position) => ({
321
351
  configuration: projectRead.configuration,
322
352
  position,
323
353
  }))),
@@ -359,7 +389,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
359
389
  testFiles: new Set([...one.testFiles, ...support]),
360
390
  });
361
391
  const exempt = detected.records;
362
- const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
392
+ const made = [...one.references, ...(satisfied?.references ?? [])];
363
393
  const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
364
394
  const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
365
395
  const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
@@ -386,13 +416,13 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
386
416
  unanswered: [
387
417
  ...projectRead.held.unanswered,
388
418
  ...projectRead.rooted.unanswered,
389
- ...made
390
- .filter((reference) => reference.resolution === "by-name")
391
- .map((reference) => reference.to),
419
+ ...made.filter((reference) => reference.guessed === true).map((reference) => reference.to),
420
+ ...one.held,
392
421
  ...exempt.filter(isUnansweredRecord).map((record) => record.id),
393
422
  ...one.decoded.unanswered,
394
423
  ],
395
424
  filledOutside: one.decoded.filled,
425
+ possiblyLoaded: one.possiblyLoaded,
396
426
  typeErrorSkips: projectRead.typeErrorSkips,
397
427
  unmappedEntries: projectRead.rooted.unmappedEntries,
398
428
  heldScripts: projectRead.rooted.heldScripts,
@@ -418,7 +448,8 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
418
448
  unansweredHeld: [
419
449
  ...new Set([
420
450
  ...answers.flatMap((one) => one.unanswered),
421
- ...consumed.filter((one) => one.resolution === "by-name").map((one) => one.to),
451
+ ...consumed.filter((one) => one.guessed === true).map((one) => one.to),
452
+ ...read.result.consumerHeld,
422
453
  ]),
423
454
  ],
424
455
  projects,
@@ -491,7 +522,7 @@ function evidenceReferences(symbols, inTestFiles) {
491
522
  * makes being a test's.
492
523
  */
493
524
  function countedWrites(references, support, mode) {
494
- return new Set(supportReferences(references, support).flatMap((reference) => reference.use === "write" && !(mode.production && reference.test) ? [reference.to] : []));
525
+ return new Set(references.flatMap((reference) => reference.use === "write" && !withheldBy(mode, reference, support) ? [reference.to] : []));
495
526
  }
496
527
  /**
497
528
  * The declarations every reference the mode counts stores into, a loaded consumer's
@@ -501,8 +532,9 @@ function writtenOnly(read, mode) {
501
532
  const written = new Set();
502
533
  const readSome = new Set();
503
534
  for (const { configured } of read.projects) {
535
+ const support = new Set(configured.supportFiles ?? []);
504
536
  for (const reference of configured.references) {
505
- if (mode.production && reference.test) {
537
+ if (withheldBy(mode, reference, support)) {
506
538
  continue;
507
539
  }
508
540
  if (reference.use === "write" && reference.consumer === undefined) {
@@ -531,7 +563,7 @@ function sweptOf(read, input) {
531
563
  // over what it reads, the test of dead code among them, cannot judge it.
532
564
  for (const { configured } of read.projects) {
533
565
  for (const reference of configured.references) {
534
- if (reference.resolution === "by-name") {
566
+ if (reference.guessed === true) {
535
567
  held.add(reference.from);
536
568
  }
537
569
  }
@@ -539,7 +571,7 @@ function sweptOf(read, input) {
539
571
  const dead = new Map(result.candidates.map((candidate) => [candidate.id, candidate]));
540
572
  const answered = matrixOf(read.projects.map(({ configured }) => ({
541
573
  ...configured,
542
- references: configured.references.filter((one) => one.resolution !== "by-name"),
574
+ references: configured.references.filter((one) => one.guessed !== true),
543
575
  })));
544
576
  const bare = {
545
577
  ...swept,
@@ -592,6 +624,7 @@ export function readEmitterRun(engine, host, scope, config, mode, detectors) {
592
624
  implementations: implementations(project, read.held),
593
625
  heldByInclusion: heldByInclusion(project, targetRoot),
594
626
  generated: read.generated,
627
+ bindings: read.bindings,
595
628
  inOperands: inOperandNames(project, targetRoot, testFiles),
596
629
  rooted: read.rooted,
597
630
  directives: inlineDirectives(project, read.held, targetRoot).filter((directive) => !read.referenceOnly.includes(directive.site.path)),
@@ -659,6 +692,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
659
692
  deprecated: new Set(projects.flatMap((one) => one.extra.deprecation.deprecated)),
660
693
  stores: storesOf(projects.map((one) => ({
661
694
  references: one.configured.references,
695
+ support: new Set(one.configured.supportFiles ?? []),
662
696
  accessors: one.extra.accessors,
663
697
  })), swept.exempt, input.mode),
664
698
  dependencies: dependenciesOf(host, targetRoot, read.workflows, [...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)], swept.sweep.candidates.map((candidate) => candidate.id), members.read, members.unbuilt, read.nestedDirs),
@@ -678,6 +712,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
678
712
  encapsulated: readManifest(host, targetRoot).declaresExports,
679
713
  edges: readEdgeSides(host, targetRoot),
680
714
  filledOutside: new Set(projects.flatMap((one) => one.filledOutside)),
715
+ possiblyLoaded: new Set(projects.flatMap((one) => one.possiblyLoaded)),
681
716
  },
682
717
  selfCheck,
683
718
  intraFunction: intraFunctionFacts(projects.map((one) => one.extra.parts), projects.flatMap((one) => one.configured.references), new Set([...swept.exempt.map((one) => one.id), ...swept.heldByUnanswered])),
@@ -725,6 +760,7 @@ function readAnalysis(engine, host, scope, config, provenance, mode, detectors)
725
760
  heldScripts: read.projects.flatMap((one) => one.heldScripts.map((held) => ({ ...held, configFile: one.configFile }))),
726
761
  unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
727
762
  generated: new Map(read.projects.flatMap((one) => [...one.extra.generated])),
763
+ bindings: distinctBindings(read.projects.flatMap((one) => one.extra.bindings)),
728
764
  },
729
765
  configured: read.projects.map((one) => one.configured),
730
766
  symbols,
@@ -50,19 +50,15 @@ function holdersOf(held, scripts) {
50
50
  * file or a `declare` holds that a `declare global` block, or the top level of a file in
51
51
  * `scripts`, declares, directly or inside a namespace there.
52
52
  */
53
- export function ambientGlobalInterfaces(held, interfaces, scripts) {
53
+ function ambientGlobalInterfaces(held, interfaces, scripts) {
54
54
  const holders = holdersOf(held, scripts);
55
55
  return holders === undefined
56
56
  ? []
57
57
  : interfaces.filter((id) => held.ambient.has(id) && holders(id).global);
58
58
  }
59
59
  /**
60
- * Each ambient global interface of the project's own files that merges into an interface
61
- * declared outside them, with every interface, namespace and block between it and the
62
- * global scope: the outside declaration names it wherever a value is typed by it. Where
63
- * every outside declaration is a package's, not the compiler's library, and declares no
64
- * member, each member it declares as well: such an interface is a slot the package reads
65
- * by type, as `keyof` does, in declarations the analysis does not walk.
60
+ * Which ambient global interfaces of the project's own files, `files`, merge into an interface
61
+ * declared outside them, and what each merge keeps.
66
62
  */
67
63
  export function mergedGlobalInterfaces(project, held, files) {
68
64
  const scripts = new Set();
@@ -88,7 +84,7 @@ export function mergedGlobalInterfaces(project, held, files) {
88
84
  const global = new Set(ambientGlobalInterfaces(held, [...names.keys()], scripts));
89
85
  const asked = [...names].filter(([id]) => global.has(id));
90
86
  if (asked.length === 0) {
91
- return [];
87
+ return { scripts, interfaces: new Set(), kept: [] };
92
88
  }
93
89
  const answers = project.symbolsAt(asked.map(([, name]) => project.handle(name)));
94
90
  const holders = holdersOf(held, scripts);
@@ -99,22 +95,25 @@ export function mergedGlobalInterfaces(project, held, files) {
99
95
  const node = project.declarationAt(handle)?.node;
100
96
  return node !== undefined && isInterfaceDeclaration(node) && node.members.length === 0;
101
97
  };
102
- return [
103
- ...new Set(asked.flatMap(([id], at) => {
104
- const symbol = answers[at];
105
- if (typeof symbol !== "object") {
106
- return [];
107
- }
108
- const outside = symbol.declarations.filter((handle) => !files.byName.has(handle.path));
109
- if (outside.length === 0) {
110
- return [];
111
- }
112
- const members = outside.every(empty)
113
- ? held.symbols.filter((one) => one.parent === id).map((one) => one.id)
114
- : [];
115
- return [id, ...(holders?.(id).ids ?? []), ...members];
116
- })),
117
- ];
98
+ const interfaces = new Set();
99
+ const kept = new Set();
100
+ asked.forEach(([id], at) => {
101
+ const symbol = answers[at];
102
+ const outside = typeof symbol === "object"
103
+ ? symbol.declarations.filter((handle) => !files.byName.has(handle.path))
104
+ : [];
105
+ if (outside.length === 0) {
106
+ return;
107
+ }
108
+ interfaces.add(id);
109
+ const members = outside.every(empty)
110
+ ? held.symbols.filter((one) => one.parent === id).map((one) => one.id)
111
+ : [];
112
+ for (const one of [id, ...(holders?.(id).ids ?? []), ...members]) {
113
+ kept.add(one);
114
+ }
115
+ });
116
+ return { scripts, interfaces, kept: [...kept] };
118
117
  }
119
118
  /**
120
119
  * For each reference to a declaration an augmentation block, or the global scope of a