@cplieger/deadset-ts 8.0.0-dev.6 → 8.0.0-dev.8

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 (193) hide show
  1. package/dist/bin/mapper-connection.js +2 -1
  2. package/dist/bin/node-host.js +24 -5
  3. package/dist/src/analysis.js +37 -56
  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 +6 -82
  9. package/dist/src/configuration-files.js +27 -168
  10. package/dist/src/configured-declarations.js +15 -20
  11. package/dist/src/consumers.js +2 -2
  12. package/dist/src/contract/config.generated.js +544 -0
  13. package/dist/src/contract/contract.generated.js +13 -0
  14. package/dist/src/contract/report.generated.js +3 -2
  15. package/dist/src/conventions.js +20 -60
  16. package/dist/src/dependencies.js +25 -43
  17. package/dist/src/discover.js +14 -40
  18. package/dist/src/edges.js +38 -122
  19. package/dist/src/element-access.js +4 -6
  20. package/dist/src/entry-point-gaps.js +2 -8
  21. package/dist/src/entry-points.js +3 -10
  22. package/dist/src/enum-group.js +3 -10
  23. package/dist/src/erased-stores.js +4 -6
  24. package/dist/src/exempt-classes.js +0 -4
  25. package/dist/src/exempt.js +6 -22
  26. package/dist/src/file-facts.js +2 -25
  27. package/dist/src/findings/completion.js +5 -4
  28. package/dist/src/findings/emitters.js +1 -1
  29. package/dist/src/findings/intra-function.js +1 -1
  30. package/dist/src/findings/non-code-artifacts.js +2 -2
  31. package/dist/src/findings/reads-and-writes.js +2 -1
  32. package/dist/src/findings/self-check.js +3 -2
  33. package/dist/src/findings/unused-declarations.js +1 -1
  34. package/dist/src/findings/visibility-narrowing.js +2 -2
  35. package/dist/src/findings-pass.js +7 -12
  36. package/dist/src/framework-lifecycle.js +7 -7
  37. package/dist/src/fs/document.js +59 -0
  38. package/dist/src/fs/manifest.js +43 -0
  39. package/dist/src/fs/tree.js +88 -0
  40. package/dist/src/git-ignore.js +34 -25
  41. package/dist/src/html-entries.js +6 -33
  42. package/dist/src/in-operands.js +2 -1
  43. package/dist/src/injection-container.js +1 -1
  44. package/dist/src/intra-function-parts.js +10 -13
  45. package/dist/src/inventory.js +2 -21
  46. package/dist/src/json-document.js +198 -67
  47. package/dist/src/keyof-comparisons.js +4 -6
  48. package/dist/src/kinds.js +0 -7
  49. package/dist/src/manifest.js +5 -43
  50. package/dist/src/mdx-entries.js +3 -26
  51. package/dist/src/partial.js +2 -1
  52. package/dist/src/paths.js +26 -15
  53. package/dist/src/position.js +2 -1
  54. package/dist/src/print.js +11 -79
  55. package/dist/src/product.js +13 -0
  56. package/dist/src/references.js +14 -27
  57. package/dist/src/report-schema.js +3 -225
  58. package/dist/src/report.js +22 -31
  59. package/dist/src/reporters/sarif.js +4 -2
  60. package/dist/src/reporters/template.js +4 -19
  61. package/dist/src/resolve.js +245 -724
  62. package/dist/src/roots.js +7 -17
  63. package/dist/src/run.js +55 -61
  64. package/dist/src/schema.js +320 -343
  65. package/dist/src/scope.js +34 -103
  66. package/dist/src/serialization-contract.js +5 -9
  67. package/dist/src/session.js +2 -1
  68. package/dist/src/suppress-file.js +21 -25
  69. package/dist/src/suppress.js +3 -3
  70. package/dist/src/symbol-keys.js +3 -5
  71. package/dist/src/template-field.js +9 -19
  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/usage.js +10 -0
  82. package/dist/src/verbs/analyze.js +25 -26
  83. package/dist/src/verbs/describe.js +4 -4
  84. package/dist/src/verbs/explain.js +8 -6
  85. package/dist/src/verbs/print-projects.js +4 -3
  86. package/dist/src/verbs/print-retained.js +2 -1
  87. package/dist/src/verbs/print-roots.js +2 -1
  88. package/dist/src/verbs/version.js +2 -1
  89. package/dist/src/workflow-steps.js +9 -46
  90. package/dist/src/workspace-manifests.js +2 -2
  91. package/dist/src/workspace-programs.js +5 -3
  92. package/dist/src/workspace-resolution.js +13 -17
  93. package/dist/src/workspace.js +28 -116
  94. package/jsr.json +1 -1
  95. package/package.json +1 -1
  96. package/src/analysis.ts +55 -76
  97. package/src/automatic-types.ts +11 -29
  98. package/src/build-scripts.ts +17 -38
  99. package/src/component-layer.ts +4 -2
  100. package/src/components.ts +2 -4
  101. package/src/config.ts +31 -296
  102. package/src/configuration-files.ts +27 -170
  103. package/src/configured-declarations.ts +18 -23
  104. package/src/consumers.ts +4 -4
  105. package/src/contract/config.generated.ts +798 -0
  106. package/src/contract/contract.generated.ts +25 -0
  107. package/src/contract/report.generated.ts +3 -2
  108. package/src/conventions.ts +26 -74
  109. package/src/dependencies.ts +32 -50
  110. package/src/discover.ts +15 -40
  111. package/src/edges.ts +41 -140
  112. package/src/element-access.ts +4 -7
  113. package/src/entry-point-gaps.ts +3 -9
  114. package/src/entry-points.ts +2 -13
  115. package/src/enum-group.ts +2 -11
  116. package/src/erased-stores.ts +3 -7
  117. package/src/exempt-classes.ts +0 -5
  118. package/src/exempt.ts +8 -30
  119. package/src/file-facts.ts +6 -24
  120. package/src/findings/completion.ts +5 -6
  121. package/src/findings/emitter.ts +2 -2
  122. package/src/findings/emitters.ts +1 -1
  123. package/src/findings/intra-function.ts +1 -1
  124. package/src/findings/non-code-artifacts.ts +4 -4
  125. package/src/findings/reads-and-writes.ts +2 -1
  126. package/src/findings/self-check.ts +3 -2
  127. package/src/findings/unused-declarations.ts +1 -1
  128. package/src/findings/visibility-narrowing.ts +2 -2
  129. package/src/findings-pass.ts +9 -15
  130. package/src/framework-lifecycle.ts +7 -7
  131. package/src/fs/document.ts +74 -0
  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/host.ts +12 -5
  136. package/src/html-entries.ts +6 -33
  137. package/src/in-operands.ts +2 -1
  138. package/src/injection-container.ts +1 -1
  139. package/src/intra-function-parts.ts +10 -14
  140. package/src/inventory.ts +2 -20
  141. package/src/json-document.ts +241 -76
  142. package/src/keyof-comparisons.ts +3 -7
  143. package/src/kinds.ts +0 -8
  144. package/src/manifest.ts +5 -46
  145. package/src/mdx-entries.ts +3 -26
  146. package/src/partial.ts +2 -1
  147. package/src/paths.ts +27 -15
  148. package/src/position.ts +2 -1
  149. package/src/print.ts +12 -92
  150. package/src/product.ts +18 -0
  151. package/src/references.ts +14 -29
  152. package/src/report-schema.ts +3 -301
  153. package/src/report.ts +24 -34
  154. package/src/reporters/sarif.ts +4 -4
  155. package/src/reporters/template.ts +4 -20
  156. package/src/resolve.ts +283 -1114
  157. package/src/roots.ts +7 -20
  158. package/src/run.ts +57 -75
  159. package/src/schema.ts +391 -388
  160. package/src/scope.ts +40 -126
  161. package/src/serialization-contract.ts +5 -10
  162. package/src/session.ts +2 -1
  163. package/src/suppress-file.ts +21 -29
  164. package/src/suppress.ts +3 -3
  165. package/src/symbol-keys.ts +2 -5
  166. package/src/template-field.ts +15 -25
  167. package/src/test-globals.ts +9 -27
  168. package/src/test-joins.ts +6 -8
  169. package/src/text/compare.ts +27 -0
  170. package/src/text/glob.ts +210 -0
  171. package/src/text/shell.ts +161 -0
  172. package/src/{yaml-document.ts → text/yaml.ts} +46 -0
  173. package/src/type-errors.ts +25 -36
  174. package/src/unseen-loads.ts +1 -12
  175. package/src/unwrap.ts +34 -0
  176. package/src/usage.ts +10 -0
  177. package/src/verbs/analyze.ts +32 -42
  178. package/src/verbs/describe.ts +4 -4
  179. package/src/verbs/explain.ts +8 -10
  180. package/src/verbs/print-projects.ts +4 -3
  181. package/src/verbs/print-retained.ts +2 -1
  182. package/src/verbs/print-roots.ts +2 -1
  183. package/src/verbs/verb.ts +2 -2
  184. package/src/verbs/version.ts +2 -1
  185. package/src/workflow-steps.ts +9 -44
  186. package/src/workspace-manifests.ts +2 -2
  187. package/src/workspace-programs.ts +5 -3
  188. package/src/workspace-resolution.ts +21 -17
  189. package/src/workspace.ts +35 -121
  190. package/dist/src/glob.js +0 -65
  191. package/dist/src/pnpm-workspace.js +0 -120
  192. package/src/glob.ts +0 -67
  193. package/src/pnpm-workspace.ts +0 -135
@@ -9,6 +9,7 @@ import { resolveRelativeSpecifier } from "./configuration-files.ts";
9
9
  import type { Host } from "./host.ts";
10
10
  import { dirnamePath, joinPath, resolvePath } from "./paths.ts";
11
11
  import type { SourceFiles } from "./source-files.ts";
12
+ import { filesBelow } from "./fs/tree.ts";
12
13
 
13
14
  /** One file a document imports, the specifier that named it, and the export names it reads. */
14
15
  interface DocumentEntry {
@@ -18,9 +19,6 @@ interface DocumentEntry {
18
19
  readonly names: readonly string[] | undefined;
19
20
  }
20
21
 
21
- /** The directories no document is read below. */
22
- const SKIPPED: ReadonlySet<string> = new Set(["node_modules", ".git"]);
23
-
24
22
  /** The extensions of a document whose imports an MDX compiler reads. */
25
23
  const DOCUMENT = /\.mdx?$/u;
26
24
 
@@ -129,28 +127,6 @@ function clauseNames(clause: string): readonly string[] | undefined {
129
127
  return names;
130
128
  }
131
129
 
132
- /** Every document below `dir`, outside every skipped directory, by absolute path. */
133
- function documents(host: Host, dir: string): readonly string[] {
134
- let entries;
135
- try {
136
- entries = host.readDirectory(dir);
137
- } catch {
138
- return [];
139
- }
140
- const found: string[] = [];
141
- for (const entry of entries) {
142
- const path = joinPath(dir, entry.name);
143
- if (entry.directory) {
144
- if (!SKIPPED.has(entry.name)) {
145
- found.push(...documents(host, path));
146
- }
147
- } else if (DOCUMENT.test(entry.name)) {
148
- found.push(path);
149
- }
150
- }
151
- return found.sort();
152
- }
153
-
154
130
  /** The relative specifiers one document's import lines name, its fenced code blocks skipped. */
155
131
  function importedBy(
156
132
  text: string,
@@ -205,7 +181,8 @@ function documentImports(host: Host, root: string): readonly DocumentImports[] {
205
181
  if (known !== undefined) {
206
182
  return known;
207
183
  }
208
- const found = documents(host, root).flatMap((path) => {
184
+ const found = filesBelow(host, root, (name) => DOCUMENT.test(name)).flatMap((below) => {
185
+ const path = joinPath(root, below);
209
186
  try {
210
187
  return [{ path, imports: importedBy(host.readFile(path)) }];
211
188
  } catch {
package/src/partial.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { NotBuilt } from "./discover.ts";
2
2
  import { relativePath } from "./paths.ts";
3
3
  import type { UnansweredQuestion } from "./query.ts";
4
+ import { bytewise } from "./text/compare.ts";
4
5
 
5
6
  /** What a run read only in part. */
6
7
  interface Partial {
@@ -24,7 +25,7 @@ function counted(n: number, one: string, many: string): string {
24
25
  */
25
26
  export function partialNotes(partial: Partial): readonly string[] {
26
27
  const notes = [...partial.notBuilt]
27
- .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
28
+ .sort((a, b) => bytewise(a.id, b.id))
28
29
  .map(
29
30
  (one) =>
30
31
  `the derived configuration ${one.id} was not built and is not analyzed: ${one.error}`,
package/src/paths.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  /**
2
- * Filesystem paths, as the supported platform spells them: a solidus separates
3
- * segments and a leading solidus makes a path absolute.
4
- *
5
- * They are written here rather than taken from the platform's own library because
6
- * every module below the command line stays free of the platform, and because the
7
- * supported platform set is one, so a second spelling would be a rule nothing
8
- * exercises.
2
+ * Filesystem paths as the supported platform spells them: a solidus between segments, a
3
+ * leading one for an absolute path. They are written here rather than taken from the
4
+ * platform's library so every module below the command line stays free of the platform.
9
5
  */
10
6
 
11
7
  const SEPARATOR = "/";
@@ -67,6 +63,25 @@ export function dirnamePath(path: string): string {
67
63
  return cut === 0 ? SEPARATOR : normalized.slice(0, cut);
68
64
  }
69
65
 
66
+ /**
67
+ * `dir` and every directory above it, nearest first, normalized. With `top`, the list ends
68
+ * at `top` and is empty where `dir` is neither `top` nor below it; without, it ends at the
69
+ * root of the path.
70
+ */
71
+ export function ancestors(dir: string, top?: string): readonly string[] {
72
+ const end = top === undefined ? undefined : normalizePath(top);
73
+ const found: string[] = [];
74
+ for (let at = normalizePath(dir); ; at = dirnamePath(at)) {
75
+ if (end !== undefined && at !== end && relativePath(end, at) === undefined) {
76
+ return [];
77
+ }
78
+ found.push(at);
79
+ if (at === end || dirnamePath(at) === at) {
80
+ return found;
81
+ }
82
+ }
83
+ }
84
+
70
85
  /**
71
86
  * The extension of one path's last segment, from its last full stop, or the empty string
72
87
  * where it has none. A segment that only starts with a full stop has none.
@@ -101,14 +116,11 @@ export function queriedModulePath(specifier: string): string | undefined {
101
116
  }
102
117
 
103
118
  /**
104
- * One path as it reads below a root, or undefined when it is not below the root.
105
- * Both are normalized first, so a root written with a trailing separator or a `.`
106
- * segment reaches the same answer, and the comparison is then lexical, so a root
107
- * and a path spelled through different symbolic links name nothing in common. The
108
- * root itself is not below itself.
109
- *
110
- * The caller resolves both against the same directory before calling: a relative
111
- * root and an absolute path are two spellings this cannot reconcile.
119
+ * One path as it reads below a root, or undefined when it is not strictly below the root:
120
+ * the root itself is not below itself. Both are normalized, then compared lexically, so a
121
+ * root and a path spelled through different symbolic links name nothing in common. The
122
+ * caller resolves both against the same directory first: a relative root and an absolute
123
+ * path cannot be reconciled.
112
124
  */
113
125
  export function relativePath(root: string, path: string): string | undefined {
114
126
  const at = normalizePath(root);
package/src/position.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { SourceFile } from "@typescript/native/ast";
2
2
  import { relativePath } from "./paths.ts";
3
+ import { bytewise } from "./text/compare.ts";
3
4
 
4
5
  /**
5
6
  * Where one declaration is written, as every report renders it.
@@ -87,7 +88,7 @@ export function positionKey(position: Position): string {
87
88
  */
88
89
  export function byPosition(a: Position, b: Position): number {
89
90
  if (a.path !== b.path) {
90
- return a.path < b.path ? -1 : 1;
91
+ return bytewise(a.path, b.path);
91
92
  }
92
93
  if (a.line !== b.line) {
93
94
  return a.line - b.line;
package/src/print.ts CHANGED
@@ -1,96 +1,16 @@
1
- import {
2
- renderOrigin,
3
- type Config,
4
- type DeclarationEntry,
5
- type Provenance,
6
- type Provider,
7
- } from "./config.ts";
8
-
9
- /** One declaration entry as a document writes it: the members of its shape alone. */
10
- function declarationOf(entry: DeclarationEntry): Record<string, string> {
11
- switch (entry.shape) {
12
- case "symbol":
13
- return { symbol: entry.symbol };
14
- case "module":
15
- return { module: entry.module, name: entry.name };
16
- case "global":
17
- return { global: entry.global };
18
- }
19
- }
20
-
21
- /** One provider entry as a document writes it: the members of its shape alone. */
22
- function providerOf(entry: Provider): Record<string, unknown> {
23
- const installed = { name: entry.name, languages: entry.languages, command: entry.command };
24
- if (entry.shape === "installed") {
25
- return installed;
26
- }
27
- return { ...installed, source: entry.source, version: entry.version, digest: entry.digest };
28
- }
1
+ import { renderOrigin, type Provenance, type ResolvedConfig } from "./config.ts";
2
+ import { bytewise } from "./text/compare.ts";
29
3
 
30
4
  /**
31
- * The resolved configuration and its provenance as one JSON object, indented,
32
- * ending in a newline.
33
- *
34
- * The output is an instance of the closed key list, so reading it back as a
35
- * repository configuration resolves to the same configuration: the provenance
36
- * object is a declared key resolution ignores. Keys are written in the schema's
37
- * order and the severity and provenance objects in ascending key order, so one
38
- * configuration renders to one string whatever order a source named its settings
39
- * in.
5
+ * The resolved configuration and its provenance as one JSON object, indented, ending
6
+ * in a newline: the configuration in the order resolution gives it, then the provenance
7
+ * object in ascending key order. Read back as a repository configuration it resolves to
8
+ * the same configuration, because resolution checks the provenance object and then
9
+ * ignores it.
40
10
  */
41
- export function printConfig(config: Config, provenance: Provenance): string {
42
- const document = {
43
- contract_version: config.contractVersion,
44
- target: { kind: config.targetKind },
45
- analysis: {
46
- languages: config.analysis.languages,
47
- min_confidence: config.analysis.minConfidence,
48
- generated_files: config.analysis.generatedFiles,
49
- consumer_tests: config.analysis.consumerTests,
50
- configurations: config.analysis.configurations.map((entry) =>
51
- entry.shape === "project"
52
- ? { id: entry.id, project: entry.project }
53
- : { id: entry.id, os: entry.os, arch: entry.arch, tags: entry.tags },
54
- ),
55
- matrix: { complete: config.analysis.matrixComplete },
56
- template_dirs: config.analysis.templateDirs,
57
- template_delimiters: {
58
- left: config.analysis.templateDelimiters.left,
59
- right: config.analysis.templateDelimiters.right,
60
- },
61
- },
62
- consumers: { complete: config.consumersComplete },
63
- roots: { patterns: config.rootPatterns },
64
- severity: Object.fromEntries([...config.severity].sort(([a], [b]) => (a < b ? -1 : 1))),
65
- exemptions: { disabled: config.exemptionsDisabled },
66
- reporters: {
67
- formats: config.reporters.formats,
68
- sort: config.reporters.sort,
69
- cascade: config.reporters.cascade,
70
- max_findings: config.reporters.maxFindings,
71
- fail_on: config.reporters.failOn,
72
- },
73
- providers: { analyzers: config.providers.analyzers.map(providerOf) },
74
- go: {},
75
- ts: {
76
- test_files: config.ts.testFiles,
77
- entry_files: config.ts.entryFiles,
78
- component_extensions: config.ts.componentExtensions,
79
- disabled_conventions: config.ts.disabledConventions,
80
- injection_registrations: config.ts.injectionRegistrations.map(declarationOf),
81
- lifecycle_contracts: config.ts.lifecycleContracts.map((entry) => ({
82
- components: entry.components.map(declarationOf),
83
- bases: entry.bases.map(declarationOf),
84
- members: entry.members,
85
- })),
86
- serializers: config.ts.serializers.map(declarationOf),
87
- roots_complete: config.ts.rootsComplete,
88
- },
89
- provenance: Object.fromEntries(
90
- [...provenance]
91
- .sort(([a], [b]) => (a < b ? -1 : 1))
92
- .map(([path, origin]) => [path, renderOrigin(origin)]),
93
- ),
94
- };
95
- return `${JSON.stringify(document, undefined, 2)}\n`;
11
+ export function printConfig(config: ResolvedConfig, provenance: Provenance): string {
12
+ const origins = [...provenance]
13
+ .sort(([a], [b]) => bytewise(a, b))
14
+ .map(([path, origin]): [string, string] => [path, renderOrigin(origin)]);
15
+ return `${JSON.stringify({ ...config, provenance: Object.fromEntries(origins) }, undefined, 2)}\n`;
96
16
  }
package/src/product.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { LANGUAGE_ROWS } from "./contract/contract.generated.ts";
2
+ import type { Writer } from "./run.ts";
3
+
4
+ /** The language this analyzer reads. */
5
+ export const LANGUAGE = "ts";
6
+
7
+ /** The analyzer's name: the one its language's row names, which every output spells it with. */
8
+ export const PRODUCT = LANGUAGE_ROWS[LANGUAGE].analyzer;
9
+
10
+ /** Writes one diagnostic line to the error stream, named for the analyzer. */
11
+ export function diagnose(err: Writer, text: string): void {
12
+ err.write(`${PRODUCT}: ${text}\n`);
13
+ }
14
+
15
+ /** The text one thrown value carries. */
16
+ export function message(error: unknown): string {
17
+ return error instanceof Error ? error.message : String(error);
18
+ }
package/src/references.ts CHANGED
@@ -38,13 +38,13 @@ import {
38
38
  type ParameterDeclaration,
39
39
  type SourceFile,
40
40
  } from "@typescript/native/ast";
41
+ import { parenthesesRemoved } from "./unwrap.ts";
41
42
  import type { Symbol as TSSymbol } from "@typescript/native/sync";
42
43
  import { aliasChains, type ChainTarget } from "./alias-chain.ts";
43
44
  import { contextualUses, type FlowAt, type LiteralAt } from "./contextual-uses.ts";
44
45
  import { destructuring, propertyReadsOf, type PropertyRead } from "./destructuring.ts";
45
46
  import { specifierCandidates } from "./configuration-files.ts";
46
47
  import { namespaceUses } from "./namespace-objects.ts";
47
- import { globExpression } from "./glob.ts";
48
48
  import {
49
49
  declarationsByName,
50
50
  isParameterProperty,
@@ -73,6 +73,8 @@ import {
73
73
  type KeyedAccess,
74
74
  } from "./symbol-keys.ts";
75
75
  import { handedOn, valuesOf } from "./value-flow.ts";
76
+ import { bytewise } from "./text/compare.ts";
77
+ import { globExpression } from "./text/glob.ts";
76
78
 
77
79
  /**
78
80
  * Every use one project's own files make of the project's own declarations.
@@ -315,15 +317,6 @@ function isName(node: Node): boolean {
315
317
  return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
316
318
  }
317
319
 
318
- /** The expression one node is, through however many parentheses are written around it. */
319
- function unparenthesized(node: Node): Node {
320
- let held = node;
321
- while (isParenthesizedExpression(held)) {
322
- held = held.expression;
323
- }
324
- return held;
325
- }
326
-
327
320
  /**
328
321
  * Records the name one store writes into.
329
322
  *
@@ -333,7 +326,7 @@ function unparenthesized(node: Node): Node {
333
326
  * target writes each name it binds, through its spreads and nested patterns.
334
327
  */
335
328
  function markWrite(target: Node, writes: Set<number>, accesses: Set<Node>): void {
336
- const held = unparenthesized(target);
329
+ const held = parenthesesRemoved(target);
337
330
  if (isName(held)) {
338
331
  writes.add(held.pos);
339
332
  return;
@@ -348,7 +341,7 @@ function markWrite(target: Node, writes: Set<number>, accesses: Set<Node>): void
348
341
  accesses.add(held);
349
342
  // A store through a member's value lands in storage every holder of the value
350
343
  // reads, so it reads the member; a variable only ever stored into stays written.
351
- if (!isPropertyAccessExpression(unparenthesized(held.expression))) {
344
+ if (!isPropertyAccessExpression(parenthesesRemoved(held.expression))) {
352
345
  markWrite(held.expression, writes, accesses);
353
346
  }
354
347
  return;
@@ -524,7 +517,7 @@ interface FileSites {
524
517
 
525
518
  /** Whether one node is `import.meta.url`. */
526
519
  function isImportMetaURL(node: Node): boolean {
527
- const at = unparenthesized(node);
520
+ const at = parenthesesRemoved(node);
528
521
  return (
529
522
  isPropertyAccessExpression(at) &&
530
523
  isMetaProperty(at.expression) &&
@@ -536,7 +529,7 @@ function isImportMetaURL(node: Node): boolean {
536
529
  /** The module URL one node builds, where it builds one. */
537
530
  function moduleURLOf(node: Node): ModuleURL | undefined {
538
531
  const relative = (argument: Node | undefined): string | undefined => {
539
- const at = argument === undefined ? undefined : unparenthesized(argument);
532
+ const at = argument === undefined ? undefined : parenthesesRemoved(argument);
540
533
  return at !== undefined &&
541
534
  (isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at)) &&
542
535
  /^\.\.?\//u.test(at.text)
@@ -551,7 +544,7 @@ function moduleURLOf(node: Node): ModuleURL | undefined {
551
544
  : undefined;
552
545
  }
553
546
  if (isCallExpression(node)) {
554
- const callee = unparenthesized(node.expression);
547
+ const callee = parenthesesRemoved(node.expression);
555
548
  const specifier = relative(node.arguments[0]);
556
549
  if (
557
550
  specifier !== undefined &&
@@ -869,7 +862,7 @@ export function testFileRulesOf(
869
862
  };
870
863
  }),
871
864
  ...(support === 0 ? [] : [{ rule: TEST_SUPPORT_RULE, matched: support }]),
872
- ].sort((a, b) => compare(a.rule, b.rule));
865
+ ].sort((a, b) => bytewise(a.rule, b.rule));
873
866
  }
874
867
 
875
868
  const importedCache = new WeakMap<
@@ -1003,7 +996,7 @@ function aloneIn(
1003
996
  nodes.every((node) => sameTarget.some((one) => inside(node, one.value))),
1004
997
  )
1005
998
  .map(([name]) => name)
1006
- .sort(compare);
999
+ .sort(bytewise);
1007
1000
  if (names.length > 0) {
1008
1001
  result.push({ index: write.index, names });
1009
1002
  }
@@ -1011,14 +1004,6 @@ function aloneIn(
1011
1004
  return result;
1012
1005
  }
1013
1006
 
1014
- /** Two strings ordered bytewise, which is the order every set of a run is read in. */
1015
- function compare(a: string, b: string): number {
1016
- if (a === b) {
1017
- return 0;
1018
- }
1019
- return a < b ? -1 : 1;
1020
- }
1021
-
1022
1007
  /**
1023
1008
  * Every reference one project's own files make to the project's own declarations, in
1024
1009
  * position order, and the files the test-file rules classified.
@@ -1677,9 +1662,9 @@ export function references<Brand>(
1677
1662
  found.sort(
1678
1663
  (a, b) =>
1679
1664
  byPosition(a.position, b.position) ||
1680
- compare(a.to, b.to) ||
1681
- compare(a.from, b.from) ||
1682
- compare(a.use, b.use),
1665
+ bytewise(a.to, b.to) ||
1666
+ bytewise(a.from, b.from) ||
1667
+ bytewise(a.use, b.use),
1683
1668
  );
1684
1669
 
1685
1670
  return {
@@ -1687,7 +1672,7 @@ export function references<Brand>(
1687
1672
  consumer === undefined
1688
1673
  ? found
1689
1674
  : found.map((reference) => ({ ...reference, consumer: consumer.id })),
1690
- testFilePaths: tests.sort(compare),
1675
+ testFilePaths: tests.sort(bytewise),
1691
1676
  cost: {
1692
1677
  batched,
1693
1678
  fileBatches,