@cplieger/deadset-ts 8.0.0-dev.5 → 8.0.0-dev.7

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 (201) hide show
  1. package/dist/bin/mapper-connection.js +2 -1
  2. package/dist/bin/node-host.js +3 -2
  3. package/dist/src/analysis.js +28 -46
  4. package/dist/src/automatic-types.js +10 -29
  5. package/dist/src/build-scripts.js +17 -29
  6. package/dist/src/component-layer.js +4 -2
  7. package/dist/src/components.js +2 -3
  8. package/dist/src/config.js +3 -2
  9. package/dist/src/configuration-files.js +27 -168
  10. package/dist/src/conformance-record.js +1 -1
  11. package/dist/src/contract/contract.generated.js +1084 -0
  12. package/dist/src/contract/report.generated.js +796 -0
  13. package/dist/src/conventions.js +20 -60
  14. package/dist/src/dependencies.js +25 -43
  15. package/dist/src/discover.js +13 -39
  16. package/dist/src/edges.js +7 -15
  17. package/dist/src/element-access.js +4 -6
  18. package/dist/src/entry-point-gaps.js +2 -8
  19. package/dist/src/entry-points.js +3 -10
  20. package/dist/src/enum-group.js +3 -10
  21. package/dist/src/erased-stores.js +4 -6
  22. package/dist/src/exempt-classes.js +3 -63
  23. package/dist/src/exempt.js +13 -40
  24. package/dist/src/file-facts.js +2 -25
  25. package/dist/src/findings/completion.js +11 -20
  26. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  27. package/dist/src/findings/emitters.js +4 -4
  28. package/dist/src/findings/interfaces.js +4 -5
  29. package/dist/src/findings/intra-function.js +8 -7
  30. package/dist/src/findings/non-code-artifacts.js +5 -6
  31. package/dist/src/findings/reads-and-writes.js +11 -9
  32. package/dist/src/findings/self-check.js +10 -12
  33. package/dist/src/findings/unused-declarations.js +28 -27
  34. package/dist/src/findings/visibility-narrowing.js +9 -11
  35. package/dist/src/findings-pass.js +7 -14
  36. package/dist/src/fs/manifest.js +43 -0
  37. package/dist/src/fs/tree.js +88 -0
  38. package/dist/src/git-ignore.js +34 -25
  39. package/dist/src/html-entries.js +6 -33
  40. package/dist/src/in-operands.js +2 -1
  41. package/dist/src/index.js +1 -1
  42. package/dist/src/intra-function-parts.js +18 -26
  43. package/dist/src/inventory.js +2 -21
  44. package/dist/src/json-document.js +4 -0
  45. package/dist/src/keyof-comparisons.js +4 -6
  46. package/dist/src/kinds.js +4 -360
  47. package/dist/src/manifest.js +5 -43
  48. package/dist/src/mdx-entries.js +3 -26
  49. package/dist/src/partial.js +2 -1
  50. package/dist/src/paths.js +26 -15
  51. package/dist/src/position.js +2 -1
  52. package/dist/src/print.js +3 -2
  53. package/dist/src/product.js +13 -0
  54. package/dist/src/references.js +14 -27
  55. package/dist/src/report-schema.js +272 -0
  56. package/dist/src/report.js +39 -42
  57. package/dist/src/reporters/sarif.js +4 -2
  58. package/dist/src/reporters/template.js +4 -19
  59. package/dist/src/resolve.js +12 -26
  60. package/dist/src/roots.js +7 -17
  61. package/dist/src/run.js +10 -8
  62. package/dist/src/schema.js +4 -3
  63. package/dist/src/scope.js +4 -5
  64. package/dist/src/serialization-contract.js +4 -8
  65. package/dist/src/session.js +2 -1
  66. package/dist/src/setup-failure.js +2 -6
  67. package/dist/src/suppress-file.js +12 -13
  68. package/dist/src/suppress-inline.js +3 -2
  69. package/dist/src/suppress.js +29 -48
  70. package/dist/src/symbol-keys.js +3 -5
  71. package/dist/src/template-field.js +5 -15
  72. package/dist/src/test-globals.js +6 -28
  73. package/dist/src/test-joins.js +6 -6
  74. package/dist/src/text/compare.js +26 -0
  75. package/dist/src/text/glob.js +194 -0
  76. package/dist/src/text/shell.js +159 -0
  77. package/dist/src/{yaml-document.js → text/yaml.js} +38 -0
  78. package/dist/src/type-errors.js +14 -38
  79. package/dist/src/unseen-loads.js +2 -9
  80. package/dist/src/unwrap.js +23 -0
  81. package/dist/src/verbs/analyze.js +22 -15
  82. package/dist/src/verbs/describe.js +7 -7
  83. package/dist/src/verbs/explain.js +7 -4
  84. package/dist/src/verbs/print-config.js +2 -1
  85. package/dist/src/verbs/print-projects.js +4 -2
  86. package/dist/src/verbs/print-retained.js +4 -2
  87. package/dist/src/verbs/print-roots.js +4 -2
  88. package/dist/src/verbs/verb.js +1 -5
  89. package/dist/src/verbs/version.js +4 -3
  90. package/dist/src/workflow-steps.js +9 -46
  91. package/dist/src/workspace-manifests.js +2 -2
  92. package/dist/src/workspace-programs.js +5 -3
  93. package/dist/src/workspace-resolution.js +13 -17
  94. package/dist/src/workspace.js +28 -116
  95. package/jsr.json +1 -1
  96. package/package.json +2 -1
  97. package/src/analysis.ts +29 -54
  98. package/src/automatic-types.ts +11 -29
  99. package/src/build-scripts.ts +17 -38
  100. package/src/component-layer.ts +4 -2
  101. package/src/components.ts +2 -4
  102. package/src/config.ts +11 -15
  103. package/src/configuration-files.ts +27 -170
  104. package/src/conformance-record.ts +1 -1
  105. package/src/contract/contract.generated.ts +1148 -0
  106. package/src/contract/report.generated.ts +1157 -0
  107. package/src/conventions.ts +26 -74
  108. package/src/dependencies.ts +32 -50
  109. package/src/discover.ts +14 -39
  110. package/src/edges.ts +7 -21
  111. package/src/element-access.ts +4 -7
  112. package/src/entry-point-gaps.ts +3 -9
  113. package/src/entry-points.ts +2 -13
  114. package/src/enum-group.ts +2 -11
  115. package/src/erased-stores.ts +3 -7
  116. package/src/exempt-classes.ts +5 -74
  117. package/src/exempt.ts +17 -47
  118. package/src/file-facts.ts +6 -24
  119. package/src/finding.ts +9 -9
  120. package/src/findings/completion.ts +22 -23
  121. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  122. package/src/findings/emitter.ts +6 -7
  123. package/src/findings/emitters.ts +6 -6
  124. package/src/findings/interfaces.ts +4 -6
  125. package/src/findings/intra-function.ts +8 -8
  126. package/src/findings/non-code-artifacts.ts +5 -7
  127. package/src/findings/reads-and-writes.ts +15 -12
  128. package/src/findings/self-check.ts +11 -17
  129. package/src/findings/unused-declarations.ts +28 -27
  130. package/src/findings/visibility-narrowing.ts +9 -12
  131. package/src/findings-pass.ts +7 -16
  132. package/src/fs/manifest.ts +52 -0
  133. package/src/fs/tree.ts +110 -0
  134. package/src/git-ignore.ts +38 -25
  135. package/src/html-entries.ts +6 -33
  136. package/src/in-operands.ts +2 -1
  137. package/src/index.ts +1 -1
  138. package/src/intra-function-parts.ts +18 -28
  139. package/src/inventory.ts +2 -20
  140. package/src/json-document.ts +5 -0
  141. package/src/keyof-comparisons.ts +3 -7
  142. package/src/kinds.ts +6 -406
  143. package/src/manifest.ts +5 -46
  144. package/src/mdx-entries.ts +3 -26
  145. package/src/partial.ts +2 -1
  146. package/src/paths.ts +27 -15
  147. package/src/position.ts +2 -1
  148. package/src/print.ts +3 -2
  149. package/src/product.ts +18 -0
  150. package/src/references.ts +14 -29
  151. package/src/report-schema.ts +364 -0
  152. package/src/report.ts +66 -229
  153. package/src/reporters/annotations.ts +2 -2
  154. package/src/reporters/json.ts +1 -1
  155. package/src/reporters/reporter.ts +2 -2
  156. package/src/reporters/reporters.ts +1 -1
  157. package/src/reporters/sarif.ts +17 -12
  158. package/src/reporters/template.ts +4 -20
  159. package/src/reporters/text.ts +3 -3
  160. package/src/resolve.ts +31 -38
  161. package/src/roots.ts +7 -20
  162. package/src/run.ts +10 -14
  163. package/src/schema.ts +4 -3
  164. package/src/scope.ts +4 -10
  165. package/src/serialization-contract.ts +4 -9
  166. package/src/session.ts +2 -1
  167. package/src/setup-failure.ts +5 -7
  168. package/src/suppress-file.ts +11 -15
  169. package/src/suppress-inline.ts +2 -2
  170. package/src/suppress.ts +39 -55
  171. package/src/symbol-keys.ts +2 -5
  172. package/src/template-field.ts +5 -18
  173. package/src/test-globals.ts +9 -27
  174. package/src/test-joins.ts +6 -8
  175. package/src/text/compare.ts +27 -0
  176. package/src/text/glob.ts +210 -0
  177. package/src/text/shell.ts +161 -0
  178. package/src/{yaml-document.ts → text/yaml.ts} +46 -0
  179. package/src/type-errors.ts +25 -36
  180. package/src/unseen-loads.ts +1 -12
  181. package/src/unwrap.ts +34 -0
  182. package/src/verbs/analyze.ts +38 -25
  183. package/src/verbs/describe.ts +13 -7
  184. package/src/verbs/explain.ts +7 -4
  185. package/src/verbs/print-config.ts +2 -1
  186. package/src/verbs/print-projects.ts +4 -2
  187. package/src/verbs/print-retained.ts +4 -2
  188. package/src/verbs/print-roots.ts +4 -2
  189. package/src/verbs/verb.ts +0 -6
  190. package/src/verbs/version.ts +4 -3
  191. package/src/workflow-steps.ts +9 -44
  192. package/src/workspace-manifests.ts +2 -2
  193. package/src/workspace-programs.ts +5 -3
  194. package/src/workspace-resolution.ts +21 -17
  195. package/src/workspace.ts +35 -121
  196. package/dist/src/glob.js +0 -65
  197. package/dist/src/pnpm-workspace.js +0 -120
  198. package/dist/src/version.js +0 -7
  199. package/src/glob.ts +0 -67
  200. package/src/pnpm-workspace.ts +0 -135
  201. package/src/version.ts +0 -7
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { componentModule } from "../src/component-files.js";
9
9
  import { extensionOf } from "../src/paths.js";
10
+ import { PRODUCT } from "../src/product.js";
10
11
  /** The JSON-RPC code of a method this mapper does not serve. */
11
12
  const METHOD_NOT_FOUND = -32601;
12
13
  /** The JSON-RPC code of a request whose parameters are not the protocol's. */
@@ -37,7 +38,7 @@ function answer(message) {
37
38
  });
38
39
  switch (message.method) {
39
40
  case "initialize":
40
- return reply({ positionEncoding: "utf-16", diagnosticSource: "deadset-ts" });
41
+ return reply({ positionEncoding: "utf-16", diagnosticSource: PRODUCT });
41
42
  case "openProject":
42
43
  return reply({});
43
44
  case "closeProject":
@@ -3,8 +3,9 @@ import { closeSync, fchmodSync, fsyncSync, mkdtempSync, openSync, readdirSync, r
3
3
  import { tmpdir } from "node:os";
4
4
  import { basename, dirname, extname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { PRODUCT } from "../src/product.js";
6
7
  /** The name the manifest of this package declares. */
7
- const PACKAGE_NAME = "@cplieger/deadset-ts";
8
+ const PACKAGE_NAME = `@cplieger/${PRODUCT}`;
8
9
  /** The version the walk found, read once per process. */
9
10
  let found;
10
11
  /**
@@ -78,7 +79,7 @@ function writeAtomically(path, pieces) {
78
79
  }
79
80
  /** A new directory under the platform's temporary directory. */
80
81
  function temporaryDirectory() {
81
- const path = mkdtempSync(join(tmpdir(), "deadset-ts-mapper-"));
82
+ const path = mkdtempSync(join(tmpdir(), `${PRODUCT}-mapper-`));
82
83
  return {
83
84
  path,
84
85
  remove: () => {
@@ -22,7 +22,6 @@ import { inOperandNames } from "./in-operands.js";
22
22
  import { sourceFilesOf } from "./source-files.js";
23
23
  import { evidenceRecords, heldRecords, disabledClasses, exemptionsOf, holdingWhile, isUnansweredRecord, retainedIn, writtenRecords, } from "./exempt.js";
24
24
  import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.js";
25
- import { globExpression } from "./glob.js";
26
25
  import { findingsPass, recordedFindings, rowKey } from "./findings-pass.js";
27
26
  import { unmatchedRootFindings } from "./findings/self-check.js";
28
27
  import { frameworkLifecycle } from "./framework-lifecycle.js";
@@ -33,9 +32,8 @@ import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
33
32
  import { inventory } from "./inventory.js";
34
33
  import { packageEntries, readManifest } from "./manifest.js";
35
34
  import { liveFilesAt, matrixOf, referenceKey, sweepMatrix, } from "./matrix.js";
36
- import { dirnamePath, extensionOf, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
35
+ import { ancestors, dirnamePath, extensionOf, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
37
36
  import { byPosition, isComponentFile } from "./position.js";
38
- import { LANGUAGE } from "./report.js";
39
37
  import { SetupError, setupLine } from "./setup-failure.js";
40
38
  import { pathsOf, readErrors, skippedRoots, skippedUnits, } from "./type-errors.js";
41
39
  import { reflectiveLookup } from "./reflective-lookup.js";
@@ -55,6 +53,10 @@ import { bindRows, readBaseline, readIgnoreFile } from "./suppress-file.js";
55
53
  import { inlineDirectives, inlineSuppressions } from "./suppress-inline.js";
56
54
  import { readTemplates, templateField } from "./template-field.js";
57
55
  import { ownErrors, workspaceRun } from "./workspace-run.js";
56
+ import { bytewise } from "./text/compare.js";
57
+ import { holdsManifest, inInstalledPackages, MANIFEST, manifestAt } from "./fs/manifest.js";
58
+ import { globExpression } from "./text/glob.js";
59
+ import { LANGUAGE } from "./product.js";
58
60
  /** The setting whose source decides where a finding about a configured root sits. */
59
61
  const ROOTS_SETTING = "roots.patterns";
60
62
  /**
@@ -71,21 +73,14 @@ function documentOf(host, provenance, setting, targetRoot) {
71
73
  const document = resolvePath(host.workingDirectory(), origin.label);
72
74
  return relativePath(resolvePath(host.workingDirectory(), targetRoot), document) ?? "";
73
75
  }
74
- /** Two strings ordered bytewise. */
75
- function compare(a, b) {
76
- if (a === b) {
77
- return 0;
78
- }
79
- return a < b ? -1 : 1;
80
- }
81
76
  /**
82
77
  * The manifests the analysis reads, each once: the target's own, then every workspace
83
78
  * member's and every nested package's below the target root.
84
79
  */
85
80
  function conventionManifests(host, targetRoot, memberDirs, nestedDirs) {
86
81
  const found = new Map();
87
- if (host.kindOf(joinPath(targetRoot, "package.json")) === "file") {
88
- found.set(targetRoot, { dir: targetRoot, path: "package.json" });
82
+ if (holdsManifest(host, targetRoot)) {
83
+ found.set(targetRoot, { dir: targetRoot, path: MANIFEST });
89
84
  }
90
85
  for (const [dirs, nested] of [
91
86
  [memberDirs, false],
@@ -109,17 +104,18 @@ function nestedPackageDirs(host, targetRoot, files, known) {
109
104
  const seen = new Set();
110
105
  const found = [];
111
106
  for (const file of files) {
112
- for (let dir = dirnamePath(file); dir !== targetRoot && !seen.has(dir) && relativePath(targetRoot, dir) !== undefined; dir = dirnamePath(dir)) {
107
+ for (const dir of ancestors(dirnamePath(file), targetRoot)) {
108
+ if (seen.has(dir) || relativePath(targetRoot, dir) === undefined) {
109
+ break;
110
+ }
113
111
  seen.add(dir);
114
112
  const below = relativePath(targetRoot, dir) ?? "";
115
- if (!below.split("/").includes("node_modules") &&
116
- !known.has(dir) &&
117
- host.kindOf(joinPath(dir, "package.json")) === "file") {
113
+ if (!inInstalledPackages(below) && !known.has(dir) && holdsManifest(host, dir)) {
118
114
  found.push(dir);
119
115
  }
120
116
  }
121
117
  }
122
- return found.sort(compare);
118
+ return found.sort(bytewise);
123
119
  }
124
120
  /**
125
121
  * Reads every project the scope discovers, and each declared consumer's, in one snapshot,
@@ -400,7 +396,9 @@ export function runRoots(engine, host, scope, config, provenance) {
400
396
  }
401
397
  }
402
398
  }
403
- const ordered = [...merged.values()].sort((a, b) => byPosition(a.position, b.position) || compare(a.kind, b.kind) || compare(a.source, b.source));
399
+ const ordered = [...merged.values()].sort((a, b) => byPosition(a.position, b.position) ||
400
+ bytewise(a.kind, b.kind) ||
401
+ bytewise(a.source, b.source));
404
402
  const unmatched = unmatchedEverywhere(config.rootPatterns, projects.map((answer) => answer.rooted));
405
403
  return {
406
404
  configurations,
@@ -438,18 +436,9 @@ function testEvidence(host, targetRoot, projects) {
438
436
  }
439
437
  }
440
438
  const manifests = new Map();
441
- const manifestAt = (dir) => {
439
+ const manifestIn = (dir) => {
442
440
  if (!manifests.has(dir)) {
443
- let value;
444
- try {
445
- value = JSON.parse(host.readFile(joinPath(dir, "package.json")));
446
- }
447
- catch {
448
- value = undefined;
449
- }
450
- manifests.set(dir, typeof value === "object" && value !== null && !Array.isArray(value)
451
- ? value
452
- : undefined);
441
+ manifests.set(dir, manifestAt(host, dir));
453
442
  }
454
443
  return manifests.get(dir);
455
444
  };
@@ -458,16 +447,14 @@ function testEvidence(host, targetRoot, projects) {
458
447
  return {
459
448
  imports,
460
449
  devDependency: (path, name) => {
461
- for (let dir = dirnamePath(joinPath(root, path));; dir = dirnamePath(dir)) {
462
- const manifest = manifestAt(dir);
450
+ for (const dir of ancestors(dirnamePath(joinPath(root, path)), root)) {
451
+ const manifest = manifestIn(dir);
463
452
  const other = OTHER_SECTIONS.some((one) => declares(manifest?.[one], name));
464
453
  if (declares(manifest?.[DEV_SECTION], name) || other) {
465
454
  return !other;
466
455
  }
467
- if (normalizePath(dir) === normalizePath(root) || dirnamePath(dir) === dir) {
468
- return false;
469
- }
470
456
  }
457
+ return false;
471
458
  },
472
459
  };
473
460
  }
@@ -574,8 +561,8 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
574
561
  const exempt = detected.records;
575
562
  const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
576
563
  const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
577
- const supportFiles = [...support].filter((path) => held.has(path)).sort();
578
- const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort();
564
+ const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
565
+ const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
579
566
  const configured = {
580
567
  configuration: projectRead.configuration,
581
568
  symbols: projectRead.held.symbols,
@@ -774,7 +761,7 @@ function sweptOf(read, input) {
774
761
  unanswered: read.unanswered,
775
762
  heldByUnanswered: [...held],
776
763
  skipped: read.projects.flatMap((one) => one.skipped),
777
- componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(compare),
764
+ componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(bytewise),
778
765
  };
779
766
  }
780
767
  /**
@@ -853,16 +840,11 @@ function judgedMembers(host, targetRoot, read) {
853
840
  }
854
841
  /** The directory of the nearest `package.json` at or above a file, inside `root`, else `root`. */
855
842
  function nearestManifestDir(host, root, file) {
856
- for (let dir = dirnamePath(file); relativePath(root, dir) !== undefined; dir = dirnamePath(dir)) {
857
- if (host.kindOf(joinPath(dir, "package.json")) === "file") {
858
- return dir;
859
- }
860
- }
861
- return root;
843
+ return ancestors(dirnamePath(file), root).find((dir) => holdsManifest(host, dir)) ?? root;
862
844
  }
863
845
  /**
864
846
  * The input every emitter reads over one sweep of a read run: the facts beside the sweep
865
- * each kind family reads, every per-project one read in the same session as the sweep.
847
+ * each emitter reads, every per-project one read in the same session as the sweep.
866
848
  */
867
849
  export function emitterInputOver(host, scope, config, read, input, selfCheck) {
868
850
  const targetRoot = scope.target.path;
@@ -904,7 +886,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
904
886
  * directives, the ignore file's entries and the baseline's rows are bound before any
905
887
  * sweep, and the run is swept once under every bound record's mark and once under none,
906
888
  * so a record is decided against the finding its code would have produced. The
907
- * self-check family reports the refused suppressions and the roots that named nothing.
889
+ * configuration family reports the refused suppressions and the roots that named nothing.
908
890
  * Beside the inputs it answers the projects and test-file rules a report names.
909
891
  */
910
892
  function readAnalysis(engine, host, scope, config, provenance, mode, detectors) {
@@ -988,7 +970,7 @@ function unmappedEverywhere(projects) {
988
970
  }
989
971
  /**
990
972
  * The analysis of the run the scope and the configuration describe: the run read with its
991
- * suppressions bound, every family's findings with the suppressions applied and the
973
+ * suppressions bound, every emitter's findings with the suppressions applied and the
992
974
  * declared edges evaluated, the projects and test-file rules the report names, and the sweep
993
975
  * an explanation reads.
994
976
  */
@@ -5,7 +5,9 @@
5
5
  * declarations, and a use of one resolves to nothing; each such use is a use of the package.
6
6
  */
7
7
  import { isClassDeclaration, isEnumDeclaration, isExportAssignment, isExportDeclaration, isFunctionDeclaration, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isInterfaceDeclaration, isModuleBlock, isModuleDeclaration, isStringLiteral, isTypeAliasDeclaration, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
8
- import { dirnamePath, joinPath, resolvePath } from "./paths.js";
8
+ import { ancestors, dirnamePath, joinPath, resolvePath } from "./paths.js";
9
+ import { entriesOf } from "./fs/tree.js";
10
+ import { manifestAt } from "./fs/manifest.js";
9
11
  const TYPE_ROOT = "node_modules/@types";
10
12
  const NONE = { globals: new Map(), modules: new Map() };
11
13
  /**
@@ -73,19 +75,11 @@ function fileDeclarations(file, globals, modules) {
73
75
  }
74
76
  /** The entry declaration file of one installed type package's directory. */
75
77
  function entryOf(host, dir) {
76
- try {
77
- const manifest = JSON.parse(host.readFile(joinPath(dir, "package.json")));
78
- const named = typeof manifest === "object" && manifest !== null
79
- ? (manifest["types"] ??
80
- manifest["typings"])
81
- : undefined;
82
- if (typeof named === "string" && named !== "") {
83
- const path = resolvePath(dir, named);
84
- return path.endsWith(".ts") ? path : `${path}.d.ts`;
85
- }
86
- }
87
- catch {
88
- // A package with no readable manifest is read from its index, as the compiler reads it.
78
+ const manifest = manifestAt(host, dir);
79
+ const named = manifest?.["types"] ?? manifest?.["typings"];
80
+ if (typeof named === "string" && named !== "") {
81
+ const path = resolvePath(dir, named);
82
+ return path.endsWith(".ts") ? path : `${path}.d.ts`;
89
83
  }
90
84
  return joinPath(dir, "index.d.ts");
91
85
  }
@@ -146,14 +140,7 @@ export function automaticTypes(host, configFile, options, parse) {
146
140
  };
147
141
  const read = new Set();
148
142
  for (const root of typeRoots(configFile, options)) {
149
- let entries;
150
- try {
151
- entries = host.readDirectory(root);
152
- }
153
- catch {
154
- entries = [];
155
- }
156
- for (const entry of entries) {
143
+ for (const entry of entriesOf(host, root)) {
157
144
  if (read.has(entry.name) || host.kindOf(joinPath(root, entry.name)) !== "directory") {
158
145
  continue;
159
146
  }
@@ -179,11 +166,5 @@ function typeRoots(configFile, options) {
179
166
  if (Array.isArray(listed)) {
180
167
  return listed.filter((root) => typeof root === "string" && root.endsWith(`/${TYPE_ROOT}`));
181
168
  }
182
- const roots = [];
183
- for (let dir = dirnamePath(configFile);; dir = dirnamePath(dir)) {
184
- roots.push(joinPath(dir, TYPE_ROOT));
185
- if (dirnamePath(dir) === dir) {
186
- return roots;
187
- }
188
- }
169
+ return ancestors(dirnamePath(configFile)).map((dir) => joinPath(dir, TYPE_ROOT));
189
170
  }
@@ -4,11 +4,15 @@
4
4
  * A script is read without running it, so a value that is not written out, a computed
5
5
  * path or an options object built at run time among them, names nothing.
6
6
  */
7
- import { isArrayBindingPattern, isArrayLiteralExpression, isArrowFunction, isAsExpression, isCallExpression, isConstructorDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isIdentifier, isImportDeclaration, isMetaProperty, isMethodDeclaration, isNamedImports, isNamespaceImport, isNewExpression, isNoSubstitutionTemplateLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isSetAccessorDeclaration, isStringLiteral, isVariableDeclaration, isVariableStatement, NodeFlags, } from "@typescript/native/ast";
7
+ import { isArrayBindingPattern, isArrayLiteralExpression, isArrowFunction, isCallExpression, isConstructorDeclaration, isFunctionDeclaration, isFunctionExpression, isGetAccessorDeclaration, isIdentifier, isImportDeclaration, isMetaProperty, isMethodDeclaration, isNamedImports, isNamespaceImport, isNewExpression, isNoSubstitutionTemplateLiteral, isObjectBindingPattern, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isSetAccessorDeclaration, isStringLiteral, isVariableDeclaration, isVariableStatement, NodeFlags, } from "@typescript/native/ast";
8
8
  import { filesNamedBy } from "./configuration-files.js";
9
- import { globExpression } from "./glob.js";
10
- import { scriptTokens } from "./manifest.js";
11
- import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
9
+ import { ancestors, dirnamePath, relativePath, resolvePath } from "./paths.js";
10
+ import { bytewise } from "./text/compare.js";
11
+ import { isRecord } from "./json-document.js";
12
+ import { unwrapped } from "./unwrap.js";
13
+ import { holdsManifest, inInstalledPackages, manifestAt } from "./fs/manifest.js";
14
+ import { globExpression } from "./text/glob.js";
15
+ import { scriptTokens } from "./text/shell.js";
12
16
  /**
13
17
  * The bundlers whose build call names its entries: esbuild resolves `entryPoints` against
14
18
  * `absWorkingDir` (https://esbuild.github.io/api/#working-directory), webpack `entry`
@@ -27,18 +31,6 @@ const BUNDLERS = [
27
31
  { module: "rollup", calls: ["rollup", "watch"], option: "input", base: "", paths: true },
28
32
  ];
29
33
  const MODULE_EXTENSION = /\.(?:js|mjs|cjs|ts|mts|cts)$/u;
30
- const MANIFEST = "package.json";
31
- function isRecord(value) {
32
- return typeof value === "object" && value !== null && !Array.isArray(value);
33
- }
34
- /** The expression a wrapper that changes no value holds. */
35
- function unwrapped(node) {
36
- let at = node;
37
- while (isParenthesizedExpression(at) || isAsExpression(at) || isSatisfiesExpression(at)) {
38
- at = at.expression;
39
- }
40
- return at;
41
- }
42
34
  function literalOf(node) {
43
35
  const at = unwrapped(node);
44
36
  return isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at) ? at.text : undefined;
@@ -372,14 +364,7 @@ function scriptEntries(file, dir, files) {
372
364
  }
373
365
  /** The modules one manifest's scripts run, by absolute path, each below the target root. */
374
366
  function scriptModules(host, root, dir) {
375
- let manifest;
376
- try {
377
- manifest = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
378
- }
379
- catch {
380
- return [];
381
- }
382
- const scripts = isRecord(manifest) ? manifest["scripts"] : undefined;
367
+ const scripts = manifestAt(host, dir)?.["scripts"];
383
368
  if (!isRecord(scripts)) {
384
369
  return [];
385
370
  }
@@ -392,13 +377,13 @@ function scriptModules(host, root, dir) {
392
377
  const path = resolvePath(dir, token);
393
378
  if (MODULE_EXTENSION.test(path) &&
394
379
  relativePath(root, path) !== undefined &&
395
- !path.split("/").includes("node_modules") &&
380
+ !inInstalledPackages(path) &&
396
381
  host.kindOf(path) === "file") {
397
382
  found.add(path);
398
383
  }
399
384
  }
400
385
  }
401
- return [...found].sort();
386
+ return [...found].sort(bytewise);
402
387
  }
403
388
  /**
404
389
  * Every own file of one project a build script names as a bundler's entry: a module a
@@ -409,13 +394,16 @@ export function buildScriptEntries(host, targetRoot, files, parse) {
409
394
  const root = resolvePath(host.workingDirectory(), targetRoot);
410
395
  const dirs = new Set([root]);
411
396
  for (const file of files.byName.values()) {
412
- for (let dir = dirnamePath(file.fileName); relativePath(root, dir) !== undefined && !dirs.has(dir); dir = dirnamePath(dir)) {
397
+ for (const dir of ancestors(dirnamePath(file.fileName), root)) {
398
+ if (dirs.has(dir)) {
399
+ break;
400
+ }
413
401
  dirs.add(dir);
414
402
  }
415
403
  }
416
404
  const found = [];
417
- for (const dir of [...dirs].sort()) {
418
- if (host.kindOf(joinPath(dir, MANIFEST)) !== "file") {
405
+ for (const dir of [...dirs].sort(bytewise)) {
406
+ if (!holdsManifest(host, dir)) {
419
407
  continue;
420
408
  }
421
409
  for (const path of scriptModules(host, root, dir)) {
@@ -5,9 +5,11 @@
5
5
  * member wins over one it extends. The mapper resolves as a package linked into the
6
6
  * `node_modules` beside each configuration, to a directory holding only its manifest.
7
7
  */
8
+ import { INSTALLED_PACKAGES } from "./fs/manifest.js";
8
9
  import { dirnamePath, joinPath } from "./paths.js";
10
+ import { PRODUCT } from "./product.js";
9
11
  /** The name the mapper's manifest declares and every configuration's entry names. */
10
- const MAPPER_PACKAGE = "deadset-ts-component-files";
12
+ const MAPPER_PACKAGE = `${PRODUCT}-component-files`;
11
13
  /** The manifest of the mapper's package, which runs `command`. */
12
14
  export function mapperManifest(command) {
13
15
  return `${JSON.stringify({
@@ -122,7 +124,7 @@ export function componentLayer(host, configFiles, mapper, written = new Map()) {
122
124
  for (const configFile of configFiles) {
123
125
  files[configFile] = withContentMappers(written.get(configFile) ?? host.readFile(configFile), mappers);
124
126
  if (mapper !== undefined) {
125
- symlinks[joinPath(dirnamePath(configFile), "node_modules", MAPPER_PACKAGE)] = {
127
+ symlinks[joinPath(dirnamePath(configFile), INSTALLED_PACKAGES, MAPPER_PACKAGE)] = {
126
128
  target: mapper.packageDirectory,
127
129
  host: true,
128
130
  };
@@ -4,13 +4,12 @@
4
4
  * and every dead declaration that falls with them, being dead only through them.
5
5
  */
6
6
  import { OUTSIDE } from "./graph.js";
7
- /** The name every component identifier this analyzer mints starts with. */
8
- const ANALYZER = "deadset-ts";
7
+ import { PRODUCT } from "./product.js";
9
8
  /** The fewest digits a component identifier's number is written with. */
10
9
  const ID_DIGITS = 4;
11
10
  /** The identifier of the component at one place of the run's order, counted from one. */
12
11
  export function componentId(place) {
13
- return `${ANALYZER}/c-${String(place).padStart(ID_DIGITS, "0")}`;
12
+ return `${PRODUCT}/c-${String(place).padStart(ID_DIGITS, "0")}`;
14
13
  }
15
14
  /** The index of a declaration the component walk has not reached. */
16
15
  const UNVISITED = -1;
@@ -1,4 +1,5 @@
1
- import { CONTRACT_VERSION } from "./version.js";
1
+ import { CONTRACT_VERSION, } from "./contract/contract.generated.js";
2
+ import { LANGUAGE, PRODUCT } from "./product.js";
2
3
  /**
3
4
  * The name of the repository configuration at the target root, which is also the
4
5
  * document a finding about the configuration names where no document of the
@@ -47,7 +48,7 @@ export function defaultConfig() {
47
48
  providers: {
48
49
  analyzers: [
49
50
  { shape: "installed", name: "deadset-go", languages: ["go"], command: "deadset-go" },
50
- { shape: "installed", name: "deadset-ts", languages: ["ts"], command: "deadset-ts" },
51
+ { shape: "installed", name: PRODUCT, languages: [LANGUAGE], command: PRODUCT },
51
52
  ],
52
53
  },
53
54
  ts: {