@cplieger/deadset-ts 7.2.0-dev.4 → 8.0.0-dev.10

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 (288) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/mapper-connection.js +2 -1
  3. package/dist/bin/node-host.js +24 -5
  4. package/dist/src/analysis.js +245 -309
  5. package/dist/src/augmentations.js +124 -18
  6. package/dist/src/automatic-types.js +170 -0
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +9 -9
  10. package/dist/src/config.js +6 -81
  11. package/dist/src/configuration-files.js +78 -188
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +2 -2
  14. package/dist/src/consumers.js +3 -30
  15. package/dist/src/contextual-uses.js +56 -9
  16. package/dist/src/contract/config.generated.js +558 -0
  17. package/dist/src/contract/contract.generated.js +1244 -0
  18. package/dist/src/contract/report.generated.js +862 -0
  19. package/dist/src/convention-rows.js +146 -1
  20. package/dist/src/conventions.js +136 -70
  21. package/dist/src/decorator.js +21 -18
  22. package/dist/src/dependencies.js +280 -62
  23. package/dist/src/edges.js +38 -122
  24. package/dist/src/element-access.js +4 -6
  25. package/dist/src/entry-point-gaps.js +9 -18
  26. package/dist/src/entry-points.js +106 -21
  27. package/dist/src/enum-group.js +3 -10
  28. package/dist/src/erased-stores.js +4 -6
  29. package/dist/src/exempt-classes.js +1 -63
  30. package/dist/src/exempt.js +21 -40
  31. package/dist/src/failure.js +36 -0
  32. package/dist/src/file-facts.js +2 -25
  33. package/dist/src/findings/completion.js +225 -63
  34. package/dist/src/findings/dependencies-and-module-machinery.js +72 -27
  35. package/dist/src/findings/emitters.js +6 -6
  36. package/dist/src/findings/interfaces.js +4 -5
  37. package/dist/src/findings/intra-function.js +53 -19
  38. package/dist/src/findings/non-code-artifacts.js +71 -39
  39. package/dist/src/findings/reads-and-writes.js +16 -13
  40. package/dist/src/findings/self-check.js +10 -12
  41. package/dist/src/findings/unused-declarations.js +57 -28
  42. package/dist/src/findings/visibility-narrowing.js +40 -18
  43. package/dist/src/findings-pass.js +8 -15
  44. package/dist/src/framework-lifecycle.js +7 -7
  45. package/dist/src/fs/document.js +52 -0
  46. package/dist/src/fs/manifest.js +72 -0
  47. package/dist/src/fs/tree.js +88 -0
  48. package/dist/src/generated-file.js +18 -4
  49. package/dist/src/git-ignore.js +99 -0
  50. package/dist/src/graph.js +9 -4
  51. package/dist/src/html-entries.js +6 -33
  52. package/dist/src/import-bindings.js +97 -0
  53. package/dist/src/in-operands.js +2 -1
  54. package/dist/src/index.js +1 -1
  55. package/dist/src/indexed-access.js +130 -28
  56. package/dist/src/injection-container.js +1 -1
  57. package/dist/src/interface-satisfaction.js +30 -12
  58. package/dist/src/intra-function-parts.js +341 -69
  59. package/dist/src/inventory.js +54 -29
  60. package/dist/src/javascript-file.js +33 -0
  61. package/dist/src/json-document.js +198 -67
  62. package/dist/src/keyof-comparisons.js +4 -6
  63. package/dist/src/kinds.js +3 -366
  64. package/dist/src/load/classify.js +270 -0
  65. package/dist/src/load/diagnostics.js +80 -0
  66. package/dist/src/load/discover.js +277 -0
  67. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  68. package/dist/src/load/expected-module.js +136 -0
  69. package/dist/src/load/load.js +27 -0
  70. package/dist/src/load/module-lookup.js +37 -0
  71. package/dist/src/load/plan.js +313 -0
  72. package/dist/src/load/specifiers.js +115 -0
  73. package/dist/src/load/synthesize.js +140 -0
  74. package/dist/src/load/test-globals.js +207 -0
  75. package/dist/src/load/test-joins.js +82 -0
  76. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  77. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +88 -61
  78. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +60 -59
  79. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  80. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  81. package/dist/src/manifest.js +49 -54
  82. package/dist/src/matrix.js +94 -13
  83. package/dist/src/mdx-entries.js +174 -0
  84. package/dist/src/module-declarations.js +9 -13
  85. package/dist/src/outside-tests.js +1 -1
  86. package/dist/src/overrides.js +41 -10
  87. package/dist/src/partial.js +2 -1
  88. package/dist/src/paths.js +26 -15
  89. package/dist/src/position.js +2 -1
  90. package/dist/src/print.js +11 -78
  91. package/dist/src/product.js +13 -0
  92. package/dist/src/query.js +1 -0
  93. package/dist/src/ref.js +11 -0
  94. package/dist/src/references.js +52 -31
  95. package/dist/src/report-schema.js +51 -0
  96. package/dist/src/report.js +59 -41
  97. package/dist/src/reporters/annotations.js +15 -8
  98. package/dist/src/reporters/sarif.js +16 -10
  99. package/dist/src/reporters/template.js +4 -19
  100. package/dist/src/resolve.js +245 -727
  101. package/dist/src/roots.js +374 -116
  102. package/dist/src/run.js +66 -77
  103. package/dist/src/schema.js +320 -342
  104. package/dist/src/scope.js +38 -115
  105. package/dist/src/serialization-contract.js +649 -29
  106. package/dist/src/session.js +41 -29
  107. package/dist/src/source-files.js +40 -15
  108. package/dist/src/suppress-file.js +34 -29
  109. package/dist/src/suppress-inline.js +21 -4
  110. package/dist/src/suppress.js +40 -56
  111. package/dist/src/sweep.js +32 -17
  112. package/dist/src/symbol-keys.js +105 -6
  113. package/dist/src/template-field.js +9 -19
  114. package/dist/src/test-support.js +119 -18
  115. package/dist/src/text/compare.js +26 -0
  116. package/dist/src/text/glob.js +194 -0
  117. package/dist/src/text/named-files.js +54 -0
  118. package/dist/src/text/shell.js +159 -0
  119. package/dist/src/text/yaml.js +393 -0
  120. package/dist/src/type-errors.js +27 -221
  121. package/dist/src/type-parameter-reads.js +172 -0
  122. package/dist/src/unseen-loads.js +100 -0
  123. package/dist/src/unwrap.js +23 -0
  124. package/dist/src/usage.js +10 -0
  125. package/dist/src/verbs/analyze.js +181 -125
  126. package/dist/src/verbs/describe.js +9 -16
  127. package/dist/src/verbs/explain.js +14 -9
  128. package/dist/src/verbs/print-config.js +2 -1
  129. package/dist/src/verbs/print-projects.js +6 -4
  130. package/dist/src/verbs/print-retained.js +4 -2
  131. package/dist/src/verbs/print-roots.js +4 -2
  132. package/dist/src/verbs/verb.js +1 -5
  133. package/dist/src/verbs/version.js +14 -3
  134. package/dist/src/workflow-steps.js +128 -33
  135. package/jsr.json +1 -1
  136. package/package.json +5 -4
  137. package/src/analysis.ts +333 -457
  138. package/src/augmentations.ts +152 -23
  139. package/src/automatic-types.ts +228 -0
  140. package/src/build-scripts.ts +543 -0
  141. package/src/component-layer.ts +4 -2
  142. package/src/components.ts +9 -10
  143. package/src/config.ts +31 -299
  144. package/src/configuration-files.ts +100 -191
  145. package/src/configured-declarations.ts +18 -23
  146. package/src/conformance-record.ts +2 -2
  147. package/src/consumers.ts +6 -57
  148. package/src/contextual-uses.ts +64 -12
  149. package/src/contract/config.generated.ts +818 -0
  150. package/src/contract/contract.generated.ts +1308 -0
  151. package/src/contract/report.generated.ts +1237 -0
  152. package/src/convention-rows.ts +186 -1
  153. package/src/conventions.ts +166 -90
  154. package/src/decorator.ts +28 -18
  155. package/src/dependencies.ts +356 -78
  156. package/src/edges.ts +41 -140
  157. package/src/element-access.ts +4 -7
  158. package/src/entry-point-gaps.ts +11 -20
  159. package/src/entry-points.ts +124 -28
  160. package/src/enum-group.ts +2 -11
  161. package/src/erased-stores.ts +3 -7
  162. package/src/exempt-classes.ts +1 -75
  163. package/src/exempt.ts +36 -50
  164. package/src/failure.ts +63 -0
  165. package/src/file-facts.ts +9 -24
  166. package/src/finding.ts +24 -9
  167. package/src/findings/boundary.ts +2 -0
  168. package/src/findings/completion.ts +297 -77
  169. package/src/findings/dependencies-and-module-machinery.ts +90 -31
  170. package/src/findings/emitter.ts +8 -9
  171. package/src/findings/emitters.ts +8 -8
  172. package/src/findings/interfaces.ts +4 -6
  173. package/src/findings/intra-function.ts +64 -20
  174. package/src/findings/non-code-artifacts.ts +88 -50
  175. package/src/findings/reads-and-writes.ts +20 -16
  176. package/src/findings/self-check.ts +11 -17
  177. package/src/findings/unused-declarations.ts +65 -28
  178. package/src/findings/visibility-narrowing.ts +51 -19
  179. package/src/findings-pass.ts +10 -19
  180. package/src/framework-lifecycle.ts +7 -7
  181. package/src/fs/document.ts +70 -0
  182. package/src/fs/manifest.ts +92 -0
  183. package/src/fs/tree.ts +110 -0
  184. package/src/generated-file.ts +23 -4
  185. package/src/git-ignore.ts +122 -0
  186. package/src/graph.ts +11 -3
  187. package/src/host.ts +17 -14
  188. package/src/html-entries.ts +6 -33
  189. package/src/import-bindings.ts +128 -0
  190. package/src/in-operands.ts +2 -1
  191. package/src/index.ts +1 -1
  192. package/src/indexed-access.ts +152 -30
  193. package/src/injection-container.ts +1 -1
  194. package/src/interface-satisfaction.ts +33 -13
  195. package/src/intra-function-parts.ts +449 -85
  196. package/src/inventory.ts +73 -27
  197. package/src/javascript-file.ts +37 -0
  198. package/src/json-document.ts +241 -76
  199. package/src/keyof-comparisons.ts +3 -7
  200. package/src/kinds.ts +5 -413
  201. package/src/load/classify.ts +397 -0
  202. package/src/load/diagnostics.ts +144 -0
  203. package/src/load/discover.ts +455 -0
  204. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  205. package/src/load/expected-module.ts +188 -0
  206. package/src/load/load.ts +73 -0
  207. package/src/load/module-lookup.ts +50 -0
  208. package/src/load/plan.ts +504 -0
  209. package/src/load/specifiers.ts +168 -0
  210. package/src/load/synthesize.ts +211 -0
  211. package/src/load/test-globals.ts +251 -0
  212. package/src/load/test-joins.ts +98 -0
  213. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  214. package/src/{workspace-programs.ts → load/workspace-programs.ts} +127 -80
  215. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +73 -64
  216. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  217. package/src/{workspace.ts → load/workspace.ts} +90 -134
  218. package/src/manifest.ts +81 -75
  219. package/src/matrix.ts +154 -18
  220. package/src/mdx-entries.ts +218 -0
  221. package/src/module-declarations.ts +11 -13
  222. package/src/outside-tests.ts +1 -1
  223. package/src/overrides.ts +51 -12
  224. package/src/partial.ts +3 -2
  225. package/src/paths.ts +27 -15
  226. package/src/position.ts +2 -1
  227. package/src/print.ts +12 -91
  228. package/src/product.ts +18 -0
  229. package/src/query.ts +11 -0
  230. package/src/ref.ts +13 -0
  231. package/src/references.ts +62 -32
  232. package/src/report-schema.ts +68 -0
  233. package/src/report.ts +105 -215
  234. package/src/reporters/annotations.ts +22 -11
  235. package/src/reporters/json.ts +1 -1
  236. package/src/reporters/reporter.ts +2 -4
  237. package/src/reporters/reporters.ts +1 -1
  238. package/src/reporters/sarif.ts +29 -16
  239. package/src/reporters/template.ts +4 -20
  240. package/src/reporters/text.ts +3 -3
  241. package/src/resolve.ts +283 -1111
  242. package/src/roots.ts +490 -137
  243. package/src/run.ts +75 -91
  244. package/src/schema.ts +391 -387
  245. package/src/scope.ts +46 -138
  246. package/src/serialization-contract.ts +818 -26
  247. package/src/session.ts +77 -54
  248. package/src/source-files.ts +67 -17
  249. package/src/suppress-file.ts +36 -34
  250. package/src/suppress-inline.ts +20 -3
  251. package/src/suppress.ts +52 -63
  252. package/src/sweep.ts +53 -18
  253. package/src/symbol-keys.ts +131 -7
  254. package/src/template-field.ts +15 -25
  255. package/src/test-support.ts +155 -18
  256. package/src/text/compare.ts +27 -0
  257. package/src/text/glob.ts +210 -0
  258. package/src/text/named-files.inputs.json +1522 -0
  259. package/src/text/named-files.ts +68 -0
  260. package/src/text/shell.ts +161 -0
  261. package/src/text/yaml.ts +423 -0
  262. package/src/type-errors.ts +35 -273
  263. package/src/type-parameter-reads.ts +227 -0
  264. package/src/unseen-loads.ts +134 -0
  265. package/src/unwrap.ts +34 -0
  266. package/src/usage.ts +10 -0
  267. package/src/verbs/analyze.ts +245 -161
  268. package/src/verbs/describe.ts +14 -15
  269. package/src/verbs/explain.ts +15 -13
  270. package/src/verbs/print-config.ts +2 -1
  271. package/src/verbs/print-projects.ts +6 -4
  272. package/src/verbs/print-retained.ts +4 -2
  273. package/src/verbs/print-roots.ts +4 -2
  274. package/src/verbs/verb.ts +2 -8
  275. package/src/verbs/version.ts +15 -3
  276. package/src/workflow-steps.ts +149 -34
  277. package/dist/src/discover.js +0 -347
  278. package/dist/src/glob.js +0 -65
  279. package/dist/src/pnpm-workspace.js +0 -120
  280. package/dist/src/setup-failure.js +0 -23
  281. package/dist/src/test-joins.js +0 -101
  282. package/dist/src/version.js +0 -7
  283. package/src/discover.ts +0 -510
  284. package/src/glob.ts +0 -67
  285. package/src/pnpm-workspace.ts +0 -135
  286. package/src/setup-failure.ts +0 -39
  287. package/src/test-joins.ts +0 -120
  288. package/src/version.ts +0 -7
@@ -8,7 +8,6 @@
8
8
 
9
9
  import {
10
10
  isArrayLiteralExpression,
11
- isAsExpression,
12
11
  isBinaryExpression,
13
12
  isCallExpression,
14
13
  isClassDeclaration,
@@ -22,27 +21,20 @@ import {
22
21
  isNamedExports,
23
22
  isNamespaceImport,
24
23
  isNoSubstitutionTemplateLiteral,
25
- isNonNullExpression,
26
24
  isNumericLiteral,
27
25
  isObjectBindingPattern,
28
26
  isObjectLiteralExpression,
29
- isParenthesizedExpression,
30
27
  isPropertyAccessExpression,
31
28
  isPropertyAssignment,
32
- isSatisfiesExpression,
33
29
  isShorthandPropertyAssignment,
34
30
  isSpreadAssignment,
35
31
  isStringLiteral,
36
32
  isVariableStatement,
37
33
  SyntaxKind,
38
- type AsExpression,
39
34
  type Identifier,
40
35
  type Node,
41
36
  type ObjectBindingPattern,
42
- type NonNullExpression,
43
37
  type ObjectLiteralExpression,
44
- type ParenthesizedExpression,
45
- type SatisfiesExpression,
46
38
  type SourceFile,
47
39
  } from "@typescript/native/ast";
48
40
  import { lineOf } from "./component-files.ts";
@@ -51,19 +43,34 @@ import {
51
43
  type ConventionRow,
52
44
  type DirectoryMove,
53
45
  type HelperReading,
46
+ type ManifestEntryKey,
54
47
  type MoveReading,
55
48
  type OptionsCall,
56
49
  type PackageKey,
50
+ type PrefixedNameReading,
57
51
  type ShortNameReading,
58
52
  type TestFileReading,
59
53
  } from "./convention-rows.ts";
60
54
  import { documentStrings } from "./configuration-files.ts";
61
- import { globExpression } from "./glob.ts";
62
55
  import type { Host } from "./host.ts";
63
- import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "./paths.ts";
64
- import type { SetupFailure } from "./setup-failure.ts";
56
+ import {
57
+ ancestors,
58
+ dirnamePath,
59
+ joinPath,
60
+ normalizePath,
61
+ relativePath,
62
+ resolvePath,
63
+ } from "./paths.ts";
64
+ import type { Failure } from "./failure.ts";
65
65
  import type { SourceFiles } from "./source-files.ts";
66
66
  import { satisfies } from "./version-range.ts";
67
+ import { bytewise } from "./text/compare.ts";
68
+ import { isRecord } from "./json-document.ts";
69
+ import { unwrapped } from "./unwrap.ts";
70
+ import { filesIn } from "./fs/tree.ts";
71
+ import { DEPENDENCY_SECTIONS, INSTALLED_PACKAGES, MANIFEST, readJSON } from "./fs/manifest.ts";
72
+ import { globExpression } from "./text/glob.ts";
73
+ import { yamlDocument } from "./text/yaml.ts";
67
74
 
68
75
  /** One manifest the analysis reads. */
69
76
  export interface ConventionManifest {
@@ -108,7 +115,7 @@ interface GeneratedDirectory {
108
115
  /** A setup failure a row met, at the directory of the manifest that declared it. */
109
116
  interface ConventionFailure {
110
117
  readonly dir: string;
111
- readonly failure: SetupFailure;
118
+ readonly failure: Failure;
112
119
  }
113
120
 
114
121
  /** What the rows decided for one run. */
@@ -149,30 +156,19 @@ type ParseSource = (fileName: string, text: string) => SourceFile;
149
156
 
150
157
  const JSON_EXTENSION = ".json";
151
158
 
159
+ /**
160
+ * A configuration file its tool reads as a YAML document, read as the JSON document it
161
+ * denotes. Its nodes' offsets are that JSON text's, so no move may read one: a failure's
162
+ * line would name the wrong line.
163
+ */
164
+ const YAML_NAME = /\.ya?ml$/u;
165
+
152
166
  /** A configuration file with no extension that its tool reads as a JSON document. */
153
167
  const JSON_RC = /^\.[\w-]+rc$/u;
154
168
 
155
169
  /** The sections an installed package is required by, so its absence fails the run. */
156
170
  const REQUIRED_SECTIONS = ["dependencies", "devDependencies"] as const;
157
171
 
158
- const DEPENDENCY_SECTIONS = [
159
- ...REQUIRED_SECTIONS,
160
- "peerDependencies",
161
- "optionalDependencies",
162
- ] as const;
163
-
164
- function isRecord(value: unknown): value is Record<string, unknown> {
165
- return typeof value === "object" && value !== null && !Array.isArray(value);
166
- }
167
-
168
- function readJSON(host: Host, path: string): unknown {
169
- try {
170
- return JSON.parse(host.readFile(path));
171
- } catch {
172
- return undefined;
173
- }
174
- }
175
-
176
172
  function declares(
177
173
  manifest: unknown,
178
174
  name: string,
@@ -193,38 +189,15 @@ function declares(
193
189
  * none, or `undefined` where no `node_modules` holds it.
194
190
  */
195
191
  function installedVersion(host: Host, dir: string, name: string): string | undefined {
196
- for (let at = normalizePath(dir); ; at = dirnamePath(at)) {
197
- const path = joinPath(at, "node_modules", name, "package.json");
192
+ for (const at of ancestors(dir)) {
193
+ const path = joinPath(at, INSTALLED_PACKAGES, name, MANIFEST);
198
194
  if (host.kindOf(path) === "file") {
199
195
  const manifest = readJSON(host, path);
200
196
  const version = isRecord(manifest) ? manifest["version"] : undefined;
201
197
  return typeof version === "string" ? version : "";
202
198
  }
203
- if (dirnamePath(at) === at) {
204
- return undefined;
205
- }
206
- }
207
- }
208
-
209
- /** Whether one node wraps an expression without changing its value. */
210
- function isWrapper(
211
- node: Node,
212
- ): node is ParenthesizedExpression | AsExpression | SatisfiesExpression | NonNullExpression {
213
- return (
214
- isParenthesizedExpression(node) ||
215
- isAsExpression(node) ||
216
- isSatisfiesExpression(node) ||
217
- isNonNullExpression(node)
218
- );
219
- }
220
-
221
- /** The expression a wrapper that changes no value holds. */
222
- function unwrapped(node: Node): Node {
223
- let at = node;
224
- while (isWrapper(at)) {
225
- at = at.expression;
226
199
  }
227
- return at;
200
+ return undefined;
228
201
  }
229
202
 
230
203
  /** The key one property is written with, where it is written as a name or as literal text. */
@@ -692,6 +665,47 @@ function manifestKeyUses(manifest: unknown, keys: readonly string[]): readonly s
692
665
  );
693
666
  }
694
667
 
668
+ /** The extensions an entry a manifest entry key names without one may carry. */
669
+ const ENTRY_EXTENSIONS = "{js,jsx,mjs,cjs,ts,tsx,mts,cts}";
670
+
671
+ /** The characters that make a manifest string a pattern rather than a directory's name. */
672
+ const PATTERN = /[*?{}[\]]/u;
673
+
674
+ /**
675
+ * The entry globs one applied row's manifest entry keys write, below the manifest's
676
+ * directory: a directory's every module, or a file with or without an extension. A string
677
+ * that leaves the directory names nothing.
678
+ */
679
+ function manifestEntryGlobs(manifest: unknown, keys: readonly ManifestEntryKey[]): string[] {
680
+ const at = (value: unknown, path: readonly string[]): unknown[] => {
681
+ const [key, ...rest] = path;
682
+ if (key === undefined) {
683
+ return [value];
684
+ }
685
+ if (!isRecord(value)) {
686
+ return [];
687
+ }
688
+ const next = key === "*" ? Object.values(value) : Object.hasOwn(value, key) ? [value[key]] : [];
689
+ return next.flatMap((one) => at(one, rest));
690
+ };
691
+ return keys.flatMap(({ key, directory }) =>
692
+ at(manifest, key.split(".")).flatMap((value) =>
693
+ documentStrings(value).flatMap((text) => {
694
+ const path = normalizePath(text)
695
+ .replace(/^(?:\.\/)+/u, "")
696
+ .replace(/\/+$/u, "");
697
+ if (path === "" || path === ".." || path.startsWith("../") || path.startsWith("/")) {
698
+ return [];
699
+ }
700
+ if (!directory) {
701
+ return [path, `${path}.${ENTRY_EXTENSIONS}`];
702
+ }
703
+ return PATTERN.test(path) ? [] : [`${path}/**/*.${ENTRY_EXTENSIONS}`];
704
+ }),
705
+ ),
706
+ );
707
+ }
708
+
695
709
  /** What one configuration file states about one property. */
696
710
  interface PropertyReading {
697
711
  /** The literal values the file sets the property to. */
@@ -772,16 +786,7 @@ function expand(
772
786
  /** The configuration files in one directory that one glob names, by name. */
773
787
  function configurationFiles(host: Host, dir: string, glob: string): readonly string[] {
774
788
  const expression = globExpression(glob);
775
- let entries;
776
- try {
777
- entries = host.readDirectory(dir);
778
- } catch {
779
- return [];
780
- }
781
- return entries
782
- .filter((entry) => !entry.directory && expression.test(entry.name))
783
- .map((entry) => entry.name)
784
- .sort();
789
+ return filesIn(host, dir, (name) => expression.test(name));
785
790
  }
786
791
 
787
792
  /** What one move resolved to: its directories, or the failure its property met. */
@@ -840,6 +845,14 @@ function readingFiles(
840
845
  } catch {
841
846
  continue;
842
847
  }
848
+ if (YAML_NAME.test(name)) {
849
+ const value = yamlDocument(text);
850
+ if (value !== undefined) {
851
+ const json = JSON.stringify(value);
852
+ found.push({ name, text: json, file: parse(`${path}${JSON_EXTENSION}`, json) });
853
+ }
854
+ continue;
855
+ }
843
856
  found.push({
844
857
  name,
845
858
  text,
@@ -889,7 +902,67 @@ function shortNameUses(
889
902
  }
890
903
  }
891
904
  }
892
- return [...used].filter((name) => declared.has(name)).sort(compare);
905
+ return [...used].filter((name) => declared.has(name)).sort(bytewise);
906
+ }
907
+
908
+ /**
909
+ * The package one value of a prefixed-name reading names, or none: ESLint's own naming,
910
+ * https://github.com/eslint/eslintrc/blob/main/lib/shared/naming.js
911
+ */
912
+ function prefixedPackage(value: string, reading: PrefixedNameReading): string | undefined {
913
+ const { prefix, marker } = reading;
914
+ let name: string;
915
+ if (marker === undefined) {
916
+ if (value.includes(":") || value.startsWith(".") || value.startsWith("/")) {
917
+ return undefined;
918
+ }
919
+ const parts = value.split("/");
920
+ name = (value.startsWith("@") ? parts.slice(0, 2) : parts.slice(0, 1)).join("/");
921
+ } else {
922
+ if (!value.startsWith(marker) || !value.includes("/", marker.length)) {
923
+ return undefined;
924
+ }
925
+ name = value.slice(marker.length, value.lastIndexOf("/"));
926
+ }
927
+ if (name === "") {
928
+ return undefined;
929
+ }
930
+ if (!name.startsWith("@")) {
931
+ return name.startsWith(`${prefix}-`) ? name : `${prefix}-${name}`;
932
+ }
933
+ const [scope, rest] = name.split("/");
934
+ if (rest === undefined || rest === "" || rest === prefix) {
935
+ return `${scope ?? name}/${prefix}`;
936
+ }
937
+ return rest.startsWith(`${prefix}-`) ? name : `${scope ?? name}/${prefix}-${rest}`;
938
+ }
939
+
940
+ /** The declared dependencies an applied row's prefixed names use. */
941
+ function prefixedNameUses(
942
+ host: Host,
943
+ parse: ParseSource,
944
+ dir: string,
945
+ manifest: unknown,
946
+ readings: readonly PrefixedNameReading[],
947
+ ): readonly string[] {
948
+ const declared = new Set(
949
+ DEPENDENCY_SECTIONS.flatMap((section) => {
950
+ const held = isRecord(manifest) ? manifest[section] : undefined;
951
+ return isRecord(held) ? Object.keys(held) : [];
952
+ }),
953
+ );
954
+ const used = new Set<string>();
955
+ for (const reading of readings) {
956
+ for (const { file } of readingFiles(host, parse, dir, reading.files)) {
957
+ for (const value of readProperty(file, reading.property, reading.call, true).values) {
958
+ const named = prefixedPackage(value, reading);
959
+ if (named !== undefined && declared.has(named)) {
960
+ used.add(named);
961
+ }
962
+ }
963
+ }
964
+ }
965
+ return [...used].sort(bytewise);
893
966
  }
894
967
 
895
968
  /** The declared dependencies an applied row's helper settings use. */
@@ -973,14 +1046,6 @@ function packageKeyUses(
973
1046
  );
974
1047
  }
975
1048
 
976
- /** Two strings ordered bytewise. */
977
- function compare(a: string, b: string): number {
978
- if (a === b) {
979
- return 0;
980
- }
981
- return a < b ? -1 : 1;
982
- }
983
-
984
1049
  /**
985
1050
  * What the rows decide over the manifests the analysis reads. A row `disabled` names
986
1051
  * is skipped before anything is read for it.
@@ -1000,7 +1065,7 @@ export function readConventions(
1000
1065
  const selected = new Map<string, { starts: Set<number>; texts: string[] }>();
1001
1066
  const testFiles = new Set<string>();
1002
1067
  for (const manifest of manifests) {
1003
- const declared = readJSON(host, joinPath(manifest.dir, "package.json"));
1068
+ const declared = readJSON(host, joinPath(manifest.dir, MANIFEST));
1004
1069
  const versions = new Map<string, string | undefined>();
1005
1070
  const missing = new Set<string>();
1006
1071
  for (const row of rows) {
@@ -1023,7 +1088,7 @@ export function readConventions(
1023
1088
  failures.push({
1024
1089
  dir: manifest.dir,
1025
1090
  failure: {
1026
- setupClass: "missing-module",
1091
+ failureClass: "missing-module",
1027
1092
  detail:
1028
1093
  `${manifest.path} declares ${row.package}, which no node_modules at or ` +
1029
1094
  `above its directory holds: run the package manager's install`,
@@ -1049,7 +1114,7 @@ export function readConventions(
1049
1114
  failures.push({
1050
1115
  dir: manifest.dir,
1051
1116
  failure: {
1052
- setupClass: "convention-not-literal",
1117
+ failureClass: "convention-not-literal",
1053
1118
  detail: where === "." ? failed : `${where}/${failed}`,
1054
1119
  },
1055
1120
  });
@@ -1064,6 +1129,10 @@ export function readConventions(
1064
1129
  for (const name of shortNameUses(host, parse, manifest.dir, declared, row.shortNames ?? [])) {
1065
1130
  uses.add(name);
1066
1131
  }
1132
+ const prefixed = row.prefixedNames ?? [];
1133
+ for (const name of prefixedNameUses(host, parse, manifest.dir, declared, prefixed)) {
1134
+ uses.add(name);
1135
+ }
1067
1136
  const keys = row.packageKeys ?? [];
1068
1137
  for (const name of packageKeyUses(host, parse, manifest.dir, declared, keys)) {
1069
1138
  uses.add(name);
@@ -1082,7 +1151,11 @@ export function readConventions(
1082
1151
  for (const below of new Set((row.generated ?? []).flatMap((one) => expand(one, resolved)))) {
1083
1152
  generated.push({ dir: manifest.dir, row: row.name, below });
1084
1153
  }
1085
- for (const glob of new Set(row.entries.flatMap((entry) => expand(entry, resolved)))) {
1154
+ const written = [
1155
+ ...row.entries.flatMap((entry) => expand(entry, resolved)),
1156
+ ...manifestEntryGlobs(declared, row.manifestEntries ?? []),
1157
+ ];
1158
+ for (const glob of new Set(written)) {
1086
1159
  globs.push({
1087
1160
  dir: manifest.dir,
1088
1161
  row: row.name,
@@ -1095,16 +1168,16 @@ export function readConventions(
1095
1168
  const unique = [...new Map(applied.map((one) => [JSON.stringify(one), one])).values()];
1096
1169
  unique.sort(
1097
1170
  (a, b) =>
1098
- compare(a.name, b.name) ||
1099
- compare(a.manifest, b.manifest) ||
1100
- compare(JSON.stringify(a), JSON.stringify(b)),
1171
+ bytewise(a.name, b.name) ||
1172
+ bytewise(a.manifest, b.manifest) ||
1173
+ bytewise(JSON.stringify(a), JSON.stringify(b)),
1101
1174
  );
1102
1175
  return {
1103
1176
  applied: unique,
1104
1177
  globs,
1105
1178
  generated,
1106
1179
  failures,
1107
- uses: [...uses].sort(compare),
1180
+ uses: [...uses].sort(bytewise),
1108
1181
  selected,
1109
1182
  testFiles,
1110
1183
  };
@@ -1138,12 +1211,15 @@ export function conventionEntries(
1138
1211
  const found = new Map<string, ConventionEntry>();
1139
1212
  for (const glob of conventions.globs) {
1140
1213
  for (const file of files.byName.values()) {
1141
- const path = relativePath(glob.dir, file.fileName);
1142
- if (
1143
- path !== undefined &&
1144
- glob.expression.test(path) &&
1145
- !glob.excludes.some((one) => one.test(path))
1146
- ) {
1214
+ const matched = [file.fileName, ...files.writtenAs(file)].some((name) => {
1215
+ const path = relativePath(glob.dir, name);
1216
+ return (
1217
+ path !== undefined &&
1218
+ glob.expression.test(path) &&
1219
+ !glob.excludes.some((one) => one.test(path))
1220
+ );
1221
+ });
1222
+ if (matched) {
1147
1223
  found.set(`${file.fileName}\u0000${glob.row}`, { file, row: glob.row });
1148
1224
  }
1149
1225
  }
@@ -1159,7 +1235,7 @@ export function conventionFailuresFor(
1159
1235
  conventions: Conventions,
1160
1236
  configFile: string,
1161
1237
  ownFiles: readonly string[],
1162
- ): readonly SetupFailure[] {
1238
+ ): readonly Failure[] {
1163
1239
  return conventions.failures
1164
1240
  .filter(
1165
1241
  ({ dir }) =>
package/src/decorator.ts CHANGED
@@ -1,14 +1,10 @@
1
1
  /**
2
- * The decorator class: a member a decorator expression is attached to, and every
3
- * member of a class a decorator expression is attached to, is held back, because the
4
- * decorator receives the member or the class when the class is defined and may reach
5
- * the member by its name.
6
- *
7
- * The rule is read from the tree alone: a decorator is attached where it is written.
8
- * The use the decorator itself makes of what it decorates is the reference pass's,
9
- * which records it as a `decorator` reference; this class records only that the
10
- * declaration is held back, and the member set of a decorated class is every member
11
- * the inventory holds for the class, static members included.
2
+ * The decorator class: a member a decorator expression is attached to, and every member
3
+ * of a class one is attached to but the member a parameter property declares, is held
4
+ * back, because the decorator may reach the member by its name. The rule is read from
5
+ * the tree alone. The decorator's own use of what it decorates is the reference pass's
6
+ * `decorator` reference; this class records only that the declaration is held back,
7
+ * static members of a decorated class included.
12
8
  */
13
9
 
14
10
  import type { Node } from "@typescript/native/ast";
@@ -44,25 +40,39 @@ export function decorator<Brand>(input: DetectorInput<Brand>): readonly Evidence
44
40
  }
45
41
  }
46
42
 
47
- const found: Evidence[] = [];
43
+ const decorated: {
44
+ readonly symbol: InventorySymbol;
45
+ readonly detail: string;
46
+ readonly site: Evidence["site"];
47
+ }[] = [];
48
+ // A decorated class's container passes each constructor argument, which keeps the
49
+ // parameter, not the member a parameter property stores it in.
50
+ const parameterMembers = new Set<string>();
48
51
  for (const file of project.ownSourceFiles()) {
49
52
  const visit = (node: Node): void => {
50
53
  const id = held.declarations.get(nodeKey(file, node));
51
54
  const symbol = id === undefined ? undefined : byId.get(id);
55
+ if (id !== undefined && isParameterProperty(node)) {
56
+ parameterMembers.add(id);
57
+ }
52
58
  // A parameter property's decorator is attached to its parameter, and to no member.
53
59
  if (symbol !== undefined && DECORATED.has(symbol.kind) && !isParameterProperty(node)) {
54
60
  for (const attached of decoratorsOf(node)) {
55
- const detail = `decorated by ${spelledDecorator(attached)}`;
56
- const site = renderPosition(file, targetRoot, attached.getStart());
57
- const reached = symbol.kind === "class" ? (membersOf.get(symbol.id) ?? []) : [symbol];
58
- for (const member of reached) {
59
- found.push({ id: member.id, detail, site });
60
- }
61
+ decorated.push({
62
+ symbol,
63
+ detail: `decorated by ${spelledDecorator(attached)}`,
64
+ site: renderPosition(file, targetRoot, attached.getStart()),
65
+ });
61
66
  }
62
67
  }
63
68
  node.forEachChild(visit);
64
69
  };
65
70
  file.forEachChild(visit);
66
71
  }
67
- return found;
72
+ return decorated.flatMap(({ symbol, detail, site }) =>
73
+ (symbol.kind === "class"
74
+ ? (membersOf.get(symbol.id) ?? []).filter((member) => !parameterMembers.has(member.id))
75
+ : [symbol]
76
+ ).map((member) => ({ id: member.id, detail, site })),
77
+ );
68
78
  }