@cplieger/deadset-ts 8.0.0-dev.1 → 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 (276) 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 +181 -341
  5. package/dist/src/augmentations.js +106 -13
  6. package/dist/src/automatic-types.js +10 -29
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +2 -3
  10. package/dist/src/config.js +6 -82
  11. package/dist/src/configuration-files.js +28 -176
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +1 -1
  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 +73 -3
  20. package/dist/src/conventions.js +36 -66
  21. package/dist/src/dependencies.js +103 -40
  22. package/dist/src/edges.js +38 -122
  23. package/dist/src/element-access.js +4 -6
  24. package/dist/src/entry-point-gaps.js +2 -8
  25. package/dist/src/entry-points.js +11 -27
  26. package/dist/src/enum-group.js +3 -10
  27. package/dist/src/erased-stores.js +4 -6
  28. package/dist/src/exempt-classes.js +1 -63
  29. package/dist/src/exempt.js +21 -40
  30. package/dist/src/failure.js +36 -0
  31. package/dist/src/file-facts.js +2 -25
  32. package/dist/src/findings/completion.js +139 -72
  33. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  34. package/dist/src/findings/emitters.js +5 -5
  35. package/dist/src/findings/interfaces.js +4 -5
  36. package/dist/src/findings/intra-function.js +13 -10
  37. package/dist/src/findings/non-code-artifacts.js +7 -8
  38. package/dist/src/findings/reads-and-writes.js +16 -13
  39. package/dist/src/findings/self-check.js +10 -12
  40. package/dist/src/findings/unused-declarations.js +41 -32
  41. package/dist/src/findings/visibility-narrowing.js +19 -16
  42. package/dist/src/findings-pass.js +8 -15
  43. package/dist/src/framework-lifecycle.js +7 -7
  44. package/dist/src/fs/document.js +52 -0
  45. package/dist/src/fs/manifest.js +72 -0
  46. package/dist/src/fs/tree.js +88 -0
  47. package/dist/src/generated-file.js +7 -4
  48. package/dist/src/git-ignore.js +39 -26
  49. package/dist/src/graph.js +5 -3
  50. package/dist/src/html-entries.js +6 -33
  51. package/dist/src/in-operands.js +2 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/injection-container.js +1 -1
  54. package/dist/src/intra-function-parts.js +63 -43
  55. package/dist/src/inventory.js +2 -21
  56. package/dist/src/javascript-file.js +33 -0
  57. package/dist/src/json-document.js +198 -67
  58. package/dist/src/keyof-comparisons.js +4 -6
  59. package/dist/src/kinds.js +3 -366
  60. package/dist/src/load/classify.js +270 -0
  61. package/dist/src/load/diagnostics.js +80 -0
  62. package/dist/src/load/discover.js +277 -0
  63. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  64. package/dist/src/load/expected-module.js +136 -0
  65. package/dist/src/load/load.js +27 -0
  66. package/dist/src/load/module-lookup.js +37 -0
  67. package/dist/src/load/plan.js +313 -0
  68. package/dist/src/load/specifiers.js +115 -0
  69. package/dist/src/load/synthesize.js +140 -0
  70. package/dist/src/load/test-globals.js +207 -0
  71. package/dist/src/load/test-joins.js +82 -0
  72. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  73. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  74. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
  75. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  76. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  77. package/dist/src/manifest.js +49 -54
  78. package/dist/src/matrix.js +76 -4
  79. package/dist/src/mdx-entries.js +3 -26
  80. package/dist/src/outside-tests.js +1 -1
  81. package/dist/src/partial.js +2 -1
  82. package/dist/src/paths.js +26 -15
  83. package/dist/src/position.js +2 -1
  84. package/dist/src/print.js +11 -79
  85. package/dist/src/product.js +13 -0
  86. package/dist/src/query.js +1 -0
  87. package/dist/src/ref.js +1 -0
  88. package/dist/src/references.js +48 -30
  89. package/dist/src/report-schema.js +51 -0
  90. package/dist/src/report.js +57 -41
  91. package/dist/src/reporters/annotations.js +15 -8
  92. package/dist/src/reporters/sarif.js +16 -10
  93. package/dist/src/reporters/template.js +4 -19
  94. package/dist/src/resolve.js +245 -729
  95. package/dist/src/roots.js +273 -87
  96. package/dist/src/run.js +66 -77
  97. package/dist/src/schema.js +320 -343
  98. package/dist/src/scope.js +38 -115
  99. package/dist/src/serialization-contract.js +595 -21
  100. package/dist/src/session.js +34 -29
  101. package/dist/src/source-files.js +1 -1
  102. package/dist/src/suppress-file.js +25 -28
  103. package/dist/src/suppress-inline.js +3 -2
  104. package/dist/src/suppress.js +33 -51
  105. package/dist/src/sweep.js +7 -9
  106. package/dist/src/symbol-keys.js +3 -5
  107. package/dist/src/template-field.js +9 -19
  108. package/dist/src/test-support.js +8 -11
  109. package/dist/src/text/compare.js +26 -0
  110. package/dist/src/text/glob.js +194 -0
  111. package/dist/src/text/named-files.js +54 -0
  112. package/dist/src/text/shell.js +159 -0
  113. package/dist/src/text/yaml.js +393 -0
  114. package/dist/src/type-errors.js +11 -232
  115. package/dist/src/unseen-loads.js +100 -0
  116. package/dist/src/unwrap.js +23 -0
  117. package/dist/src/usage.js +10 -0
  118. package/dist/src/verbs/analyze.js +166 -126
  119. package/dist/src/verbs/describe.js +9 -16
  120. package/dist/src/verbs/explain.js +10 -7
  121. package/dist/src/verbs/print-config.js +2 -1
  122. package/dist/src/verbs/print-projects.js +6 -4
  123. package/dist/src/verbs/print-retained.js +4 -2
  124. package/dist/src/verbs/print-roots.js +4 -2
  125. package/dist/src/verbs/verb.js +1 -5
  126. package/dist/src/verbs/version.js +14 -3
  127. package/dist/src/workflow-steps.js +62 -64
  128. package/jsr.json +1 -1
  129. package/package.json +4 -3
  130. package/src/analysis.ts +245 -502
  131. package/src/augmentations.ts +135 -17
  132. package/src/automatic-types.ts +11 -29
  133. package/src/build-scripts.ts +543 -0
  134. package/src/component-layer.ts +4 -2
  135. package/src/components.ts +2 -4
  136. package/src/config.ts +31 -302
  137. package/src/configuration-files.ts +34 -179
  138. package/src/configured-declarations.ts +18 -23
  139. package/src/conformance-record.ts +1 -1
  140. package/src/consumers.ts +6 -57
  141. package/src/contextual-uses.ts +64 -12
  142. package/src/contract/config.generated.ts +818 -0
  143. package/src/contract/contract.generated.ts +1308 -0
  144. package/src/contract/report.generated.ts +1237 -0
  145. package/src/convention-rows.ts +85 -3
  146. package/src/conventions.ts +46 -84
  147. package/src/dependencies.ts +118 -46
  148. package/src/edges.ts +41 -140
  149. package/src/element-access.ts +4 -7
  150. package/src/entry-point-gaps.ts +3 -9
  151. package/src/entry-points.ts +12 -38
  152. package/src/enum-group.ts +2 -11
  153. package/src/erased-stores.ts +3 -7
  154. package/src/exempt-classes.ts +1 -75
  155. package/src/exempt.ts +36 -50
  156. package/src/failure.ts +63 -0
  157. package/src/file-facts.ts +9 -24
  158. package/src/finding.ts +14 -9
  159. package/src/findings/boundary.ts +2 -0
  160. package/src/findings/completion.ts +181 -84
  161. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  162. package/src/findings/emitter.ts +8 -9
  163. package/src/findings/emitters.ts +7 -7
  164. package/src/findings/interfaces.ts +4 -6
  165. package/src/findings/intra-function.ts +13 -11
  166. package/src/findings/non-code-artifacts.ts +9 -11
  167. package/src/findings/reads-and-writes.ts +20 -16
  168. package/src/findings/self-check.ts +11 -17
  169. package/src/findings/unused-declarations.ts +45 -32
  170. package/src/findings/visibility-narrowing.ts +20 -17
  171. package/src/findings-pass.ts +10 -19
  172. package/src/framework-lifecycle.ts +7 -7
  173. package/src/fs/document.ts +70 -0
  174. package/src/fs/manifest.ts +92 -0
  175. package/src/fs/tree.ts +110 -0
  176. package/src/generated-file.ts +7 -4
  177. package/src/git-ignore.ts +50 -26
  178. package/src/graph.ts +5 -3
  179. package/src/host.ts +12 -5
  180. package/src/html-entries.ts +6 -33
  181. package/src/in-operands.ts +2 -1
  182. package/src/index.ts +1 -1
  183. package/src/injection-container.ts +1 -1
  184. package/src/intra-function-parts.ts +73 -44
  185. package/src/inventory.ts +2 -20
  186. package/src/javascript-file.ts +37 -0
  187. package/src/json-document.ts +241 -76
  188. package/src/keyof-comparisons.ts +3 -7
  189. package/src/kinds.ts +5 -413
  190. package/src/load/classify.ts +397 -0
  191. package/src/load/diagnostics.ts +144 -0
  192. package/src/load/discover.ts +455 -0
  193. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  194. package/src/load/expected-module.ts +188 -0
  195. package/src/load/load.ts +73 -0
  196. package/src/load/module-lookup.ts +50 -0
  197. package/src/load/plan.ts +504 -0
  198. package/src/load/specifiers.ts +168 -0
  199. package/src/load/synthesize.ts +211 -0
  200. package/src/load/test-globals.ts +251 -0
  201. package/src/load/test-joins.ts +98 -0
  202. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  203. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  204. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
  205. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  206. package/src/{workspace.ts → load/workspace.ts} +90 -134
  207. package/src/manifest.ts +81 -75
  208. package/src/matrix.ts +122 -4
  209. package/src/mdx-entries.ts +3 -26
  210. package/src/outside-tests.ts +1 -1
  211. package/src/partial.ts +3 -2
  212. package/src/paths.ts +27 -15
  213. package/src/position.ts +2 -1
  214. package/src/print.ts +12 -92
  215. package/src/product.ts +18 -0
  216. package/src/query.ts +11 -0
  217. package/src/ref.ts +1 -0
  218. package/src/references.ts +52 -31
  219. package/src/report-schema.ts +68 -0
  220. package/src/report.ts +101 -224
  221. package/src/reporters/annotations.ts +22 -11
  222. package/src/reporters/json.ts +1 -1
  223. package/src/reporters/reporter.ts +2 -4
  224. package/src/reporters/reporters.ts +1 -1
  225. package/src/reporters/sarif.ts +29 -16
  226. package/src/reporters/template.ts +4 -20
  227. package/src/reporters/text.ts +3 -3
  228. package/src/resolve.ts +283 -1114
  229. package/src/roots.ts +339 -104
  230. package/src/run.ts +75 -91
  231. package/src/schema.ts +391 -388
  232. package/src/scope.ts +46 -138
  233. package/src/serialization-contract.ts +763 -22
  234. package/src/session.ts +70 -54
  235. package/src/source-files.ts +1 -1
  236. package/src/suppress-file.ts +24 -33
  237. package/src/suppress-inline.ts +2 -2
  238. package/src/suppress.ts +43 -58
  239. package/src/sweep.ts +23 -9
  240. package/src/symbol-keys.ts +2 -5
  241. package/src/template-field.ts +15 -25
  242. package/src/test-support.ts +17 -13
  243. package/src/text/compare.ts +27 -0
  244. package/src/text/glob.ts +210 -0
  245. package/src/text/named-files.inputs.json +1522 -0
  246. package/src/text/named-files.ts +68 -0
  247. package/src/text/shell.ts +161 -0
  248. package/src/text/yaml.ts +423 -0
  249. package/src/type-errors.ts +18 -288
  250. package/src/unseen-loads.ts +134 -0
  251. package/src/unwrap.ts +34 -0
  252. package/src/usage.ts +10 -0
  253. package/src/verbs/analyze.ts +224 -162
  254. package/src/verbs/describe.ts +14 -15
  255. package/src/verbs/explain.ts +10 -11
  256. package/src/verbs/print-config.ts +2 -1
  257. package/src/verbs/print-projects.ts +6 -4
  258. package/src/verbs/print-retained.ts +4 -2
  259. package/src/verbs/print-roots.ts +4 -2
  260. package/src/verbs/verb.ts +2 -8
  261. package/src/verbs/version.ts +15 -3
  262. package/src/workflow-steps.ts +74 -64
  263. package/dist/src/base-url.js +0 -18
  264. package/dist/src/discover.js +0 -468
  265. package/dist/src/glob.js +0 -65
  266. package/dist/src/pnpm-workspace.js +0 -120
  267. package/dist/src/setup-failure.js +0 -23
  268. package/dist/src/test-joins.js +0 -101
  269. package/dist/src/version.js +0 -7
  270. package/src/base-url.ts +0 -24
  271. package/src/discover.ts +0 -653
  272. package/src/glob.ts +0 -67
  273. package/src/pnpm-workspace.ts +0 -135
  274. package/src/setup-failure.ts +0 -39
  275. package/src/test-joins.ts +0 -120
  276. package/src/version.ts +0 -7
@@ -1,468 +0,0 @@
1
- import { DiagnosticCategory } from "@typescript/native/sync";
2
- import { baseUrlPaths } from "./base-url.js";
3
- import { dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
4
- import { SetupError } from "./setup-failure.js";
5
- import { writtenPath } from "./workspace-programs.js";
6
- /** Directory names discovery does not descend into. */
7
- export const IGNORED_DIRECTORIES = new Set(["node_modules", ".git"]);
8
- /** A compiler configuration file discovery recognises under a root. */
9
- const CONFIG_FILE = /^tsconfig.*\.json$/u;
10
- /**
11
- * A run that cannot read what it was asked to analyze. It ends the run with the
12
- * failure code and no finding list: a configuration file the compiler cannot read,
13
- * or a project carrying an error, leaves the analysis without the type information
14
- * every answer rests on, and a partial answer is never printed as a complete one.
15
- */
16
- export class DiscoveryError extends Error {
17
- /** The diagnostics the compiler reported, in the order it reported them. */
18
- diagnostics;
19
- constructor(message, diagnostics) {
20
- super(message);
21
- this.name = "DiscoveryError";
22
- this.diagnostics = diagnostics;
23
- }
24
- }
25
- /** The category an error diagnostic carries, which the protocol sends as a number. */
26
- const ERROR_CATEGORY = DiagnosticCategory.Error;
27
- /** Whether one diagnostic is an error, which is what fails a run closed. */
28
- function isError(diagnostic) {
29
- return diagnostic.category === ERROR_CATEGORY;
30
- }
31
- /**
32
- * One diagnostic as a line naming its file, its line and column, its code and its
33
- * message: `path:line:column: TScode: message`, the position left out where the
34
- * diagnostic names none and the file where it names none. `display` spells the
35
- * file's path; it answers the path itself where it is not given.
36
- */
37
- export function renderDiagnostic(located, display = (path) => path) {
38
- const { diagnostic, at } = located;
39
- const message = `TS${String(diagnostic.code)}: ${diagnostic.text}`;
40
- if (diagnostic.fileName === undefined) {
41
- return message;
42
- }
43
- const where = display(diagnostic.fileName);
44
- return at === undefined
45
- ? `${where}: ${message}`
46
- : `${where}:${String(at.line)}:${String(at.column)}: ${message}`;
47
- }
48
- /** Each diagnostic with the line and column its offset falls on. */
49
- function locatedIn(diagnostics, locate) {
50
- return diagnostics.map((diagnostic) => ({
51
- diagnostic,
52
- at: diagnostic.fileName === undefined ? undefined : locate(diagnostic.fileName, diagnostic.pos),
53
- }));
54
- }
55
- /**
56
- * Every error a project's three diagnostic sets carry, in the order the compiler
57
- * reported them: a configuration whose options do not parse, a file whose syntax
58
- * does not, and a program that does not type-check. A resolved configuration
59
- * carries no diagnostics of its own, so a configuration written with an unreadable
60
- * option resolves and is refused here, once its project is open.
61
- */
62
- export function diagnosticErrors(sets) {
63
- return [...sets.configParsing, ...sets.syntactic, ...sets.semantic].filter(isError);
64
- }
65
- /**
66
- * The codes of a type library and a lib the configuration names that the compiler
67
- * cannot find, which it reports while it gathers the program's files,
68
- * https://github.com/microsoft/typescript-go/blob/89d5d5b2849a0db0957065889ca58536fa6d2e4a/internal/compiler/processingDiagnostic.go,
69
- * and {@link MISSING_GLOBAL_TYPE}, which the checker reports.
70
- */
71
- const UNFOUND_LIBRARY = new Set([2318, 2688, 2726, 2727]);
72
- /**
73
- * The code of a global type the checker finds in no library the program holds. The checker
74
- * types every use of one against nothing and places no error in the file, so the analysis
75
- * skips each file of such a project whole.
76
- */
77
- export const MISSING_GLOBAL_TYPE = 2318;
78
- /** The errors one open project carries, each located in the file it names. */
79
- export function projectErrors(sets) {
80
- // The compiler numbers its semantic messages from 2000 and its option messages from
81
- // 5000. A file-less option error, a removed option or an output layout, leaves the
82
- // program whole, and the compiler checks it all the same:
83
- // https://github.com/microsoft/TypeScript/wiki/Coding-guidelines#diagnostic-message-codes
84
- const semantic = sets.unplaced.filter((diagnostic) => isError(diagnostic) && diagnostic.code >= 2000 && diagnostic.code < 3000);
85
- const unfound = semantic.filter(({ code }) => UNFOUND_LIBRARY.has(code));
86
- const load = [
87
- ...sets.configParsing.filter(isError),
88
- ...semantic.filter(({ code }) => !UNFOUND_LIBRARY.has(code)),
89
- ];
90
- return {
91
- load: locatedIn(load, sets.locate),
92
- check: load.length > 0 ? [] : locatedIn(diagnosticErrors(sets), sets.locate),
93
- unfound: load.length > 0 ? [] : locatedIn(unfound, sets.locate),
94
- };
95
- }
96
- /**
97
- * The first line of one error about the target, every mention of the target root
98
- * spelled relative to it: a path below the root loses the root and its separator, and
99
- * the root itself is `.`.
100
- */
101
- export function targetRelative(text, targetRoot) {
102
- const root = targetRoot.endsWith("/") ? targetRoot.slice(0, -1) : targetRoot;
103
- const [first = ""] = text.split(/\r?\n/u);
104
- const spelled = first.split(`${root}/`).join("").split(root).join(".").trim();
105
- return spelled === "" ? "the configuration could not be built" : spelled;
106
- }
107
- /**
108
- * Whether one configuration is the analyzer's own guess: discovery derived it and the
109
- * scope did not name it. A guess that does not load is dropped; any other ends the run.
110
- */
111
- export function isGuess(discovery, configFile) {
112
- return discovery.derived && !discovery.fromScope.includes(configFile);
113
- }
114
- /**
115
- * The configuration files below `root`, in ascending path order, skipping an
116
- * ignored directory. A directory that cannot be read is skipped: a tree the
117
- * analysis may not enter names no project.
118
- */
119
- function configFilesUnder(host, root) {
120
- const found = [];
121
- const pending = [root];
122
- while (pending.length > 0) {
123
- const dir = pending.pop();
124
- if (dir === undefined) {
125
- break;
126
- }
127
- let entries;
128
- try {
129
- entries = host.readDirectory(dir);
130
- }
131
- catch {
132
- continue;
133
- }
134
- for (const entry of [...entries].sort((a, b) => (a.name < b.name ? -1 : 1))) {
135
- const path = joinPath(dir, entry.name);
136
- if (entry.directory) {
137
- if (!IGNORED_DIRECTORIES.has(entry.name)) {
138
- pending.push(path);
139
- }
140
- continue;
141
- }
142
- if (CONFIG_FILE.test(entry.name)) {
143
- found.push(path);
144
- }
145
- }
146
- }
147
- return found.sort();
148
- }
149
- /**
150
- * The configuration file the scope names for the target directly, where its path
151
- * names one rather than a directory. A target naming a directory is reached by the
152
- * walk over that directory instead. A consumer's projects are a consumer's, never the
153
- * target's, so no consumer path is read here.
154
- */
155
- function scopeConfigFiles(host, scope) {
156
- return [scope.target.path]
157
- .filter((path) => path.endsWith(".json"))
158
- .map((path) => resolvePath(host.workingDirectory(), path));
159
- }
160
- /**
161
- * Every configuration file reached from `pending`, in the order discovery reads them:
162
- * each once, each followed by the configurations it references that `follows` admits,
163
- * transitively. A configuration the compiler cannot read ends the run naming it, unless
164
- * `unreadable` is given, which is then told the configuration and why, and the walk
165
- * goes on without it.
166
- */
167
- function derivedFrom(engine, host, pending, follows, unreadable) {
168
- const seen = new Set();
169
- const found = [];
170
- while (pending.length > 0) {
171
- const configFile = pending.shift();
172
- if (configFile === undefined) {
173
- break;
174
- }
175
- const path = resolvePath(host.workingDirectory(), configFile);
176
- if (seen.has(path)) {
177
- continue;
178
- }
179
- seen.add(path);
180
- const read = readConfiguration(engine, path);
181
- if ("reason" in read) {
182
- if (unreadable === undefined) {
183
- throw new DiscoveryError(`${path} cannot be read as a compiler configuration: ${read.reason}`, []);
184
- }
185
- unreadable(path, read.reason);
186
- continue;
187
- }
188
- found.push(path);
189
- pending.push(...read.references.filter(follows));
190
- }
191
- return found;
192
- }
193
- /**
194
- * The compiler configurations one consumer is loaded through: every one under its
195
- * root that is not inside an ignored directory, and the configurations each of those
196
- * references, transitively, in that order. A root that is absent, that is no
197
- * directory, or that holds no configuration ends the run naming it, because a
198
- * finding computed without a declared consumer would claim a reference set the run
199
- * never read.
200
- */
201
- export function consumerProjects(engine, host, root) {
202
- const kind = host.kindOf(root);
203
- if (kind === "absent") {
204
- throw new SetupError([
205
- {
206
- setupClass: "missing-consumer",
207
- detail: `the scope declares the consumer ${root}, and nothing is at that path: check the consumer out at ${root} and install its dependencies`,
208
- },
209
- ]);
210
- }
211
- if (kind !== "directory") {
212
- throw new DiscoveryError(`the consumer ${root} is not a directory`, []);
213
- }
214
- const found = derivedFrom(engine, host, configFilesUnder(host, root), () => true);
215
- if (found.length === 0) {
216
- throw new DiscoveryError(`the consumer ${root} holds no compiler configuration, so none of its references can be read`, []);
217
- }
218
- return found;
219
- }
220
- /**
221
- * The name a derived project carries: its configuration file's path below the target
222
- * root, or the absolute path of a file outside it.
223
- */
224
- function derivedId(targetRoot, configFile) {
225
- return relativePath(targetRoot, configFile) ?? configFile;
226
- }
227
- /**
228
- * The code of a configuration whose `extends` chain returns to a configuration it already
229
- * passed. The parse reports it and returns, and a snapshot opened from it never answers:
230
- * https://github.com/microsoft/TypeScript/issues/64754
231
- */
232
- const CIRCULAR_EXTENDS = 18000;
233
- /** The configuration files one parsed configuration's own `extends` names by path. */
234
- function extendedPaths(parsed, configFile) {
235
- const { raw } = parsed;
236
- const named = typeof raw === "object" && raw !== null ? Reflect.get(raw, "extends") : [];
237
- return (Array.isArray(named) ? named : [named])
238
- .filter((one) => typeof one === "string")
239
- .filter((one) => one.startsWith("./") || one.startsWith("../") || isAbsolutePath(one))
240
- .map((one) => resolvePath(dirnamePath(configFile), one));
241
- }
242
- /**
243
- * The `extends` chain from `configFile` to the first configuration it reaches twice, each
244
- * link by path, or undefined where no chain written by path returns.
245
- */
246
- function extendsCycle(engine, configFile, parsed) {
247
- const walk = (chain, at) => {
248
- for (const next of extendedPaths(at, chain.at(-1) ?? configFile)) {
249
- if (chain.includes(next)) {
250
- return [...chain, next];
251
- }
252
- let read;
253
- try {
254
- read = engine.parseConfigFile(next);
255
- }
256
- catch {
257
- continue;
258
- }
259
- const cycle = walk([...chain, next], read);
260
- if (cycle !== undefined) {
261
- return cycle;
262
- }
263
- }
264
- return undefined;
265
- };
266
- return walk([configFile], parsed);
267
- }
268
- /** The configuration files one parsed configuration's `references` name. */
269
- function referencesOf(parsed) {
270
- // The parse answers a directory reference as the directory; the compiler reads a
271
- // path not ending `.json` as its `tsconfig.json`:
272
- // https://github.com/microsoft/typescript-go/blob/89d5d5b2849a0db0957065889ca58536fa6d2e4a/internal/core/projectreference.go#L18
273
- return (parsed.projectReferences ?? []).map(({ path }) => path.endsWith(".json") ? path : joinPath(path, "tsconfig.json"));
274
- }
275
- /** Why one parsed configuration's own `extends` chain cannot be opened, where it is circular. */
276
- function circularity(engine, configFile, parsed) {
277
- const chain = extendsCycle(engine, configFile, parsed);
278
- if (chain === undefined && !parsed.errors.some(({ code }) => code === CIRCULAR_EXTENDS)) {
279
- return undefined;
280
- }
281
- return `TS${String(CIRCULAR_EXTENDS)}: Circularity detected while resolving configuration: ${(chain ?? [configFile]).join(" -> ")}`;
282
- }
283
- /**
284
- * Why a configuration the `references` reach, transitively, cannot be opened, where one's
285
- * `extends` chain is circular: the compiler opens every referenced project with the one
286
- * that references it.
287
- */
288
- function referencedCircularity(engine, references, visited) {
289
- for (const reference of references) {
290
- if (visited.has(reference)) {
291
- continue;
292
- }
293
- visited.add(reference);
294
- let parsed;
295
- try {
296
- parsed = engine.parseConfigFile(reference);
297
- }
298
- catch {
299
- continue;
300
- }
301
- const reason = circularity(engine, reference, parsed) ??
302
- referencedCircularity(engine, referencesOf(parsed), visited);
303
- if (reason !== undefined) {
304
- return reason;
305
- }
306
- }
307
- return undefined;
308
- }
309
- /**
310
- * The configuration files one configuration's `references` name, or why the compiler
311
- * cannot read the configuration: it throws, or its `extends` chain or that of a
312
- * configuration it references is circular, which the analysis refuses before any
313
- * snapshot is asked to open it.
314
- */
315
- function readConfiguration(engine, configFile) {
316
- try {
317
- const parsed = engine.parseConfigFile(configFile);
318
- const references = referencesOf(parsed);
319
- const reason = circularity(engine, configFile, parsed) ??
320
- referencedCircularity(engine, references, new Set([configFile]));
321
- return reason === undefined ? { references } : { reason };
322
- }
323
- catch (error) {
324
- return { reason: error instanceof Error ? error.message : String(error) };
325
- }
326
- }
327
- /**
328
- * The references of one compiler configuration file, or ends the run naming it: a
329
- * project opened from a configuration the compiler cannot read would be analyzed with
330
- * no type information.
331
- */
332
- function parseOrRefuse(engine, configFile, named) {
333
- const read = readConfiguration(engine, configFile);
334
- if ("reason" in read) {
335
- throw new DiscoveryError(`${named} cannot be read as a compiler configuration: ${read.reason}`, []);
336
- }
337
- return read.references;
338
- }
339
- /**
340
- * The projects a build matrix declares, in its order, each entry a file below the target
341
- * root: an entry naming an absent file, a directory or a file the compiler cannot read
342
- * ends the run naming it, and one naming an earlier entry's file adds nothing. A
343
- * reference below the root the matrix does not name ends the run naming both, because the
344
- * compiler builds a referenced project's sources into the referencing program without
345
- * reporting their diagnostics. A reference outside the root is an outside project.
346
- */
347
- function declaredProjects(engine, host, targetRoot, entries) {
348
- const seen = new Set();
349
- const projects = [];
350
- const references = new Map();
351
- for (const entry of entries) {
352
- const configFile = joinPath(targetRoot, entry.project);
353
- const named = `the project ${JSON.stringify(entry.id)} (${configFile})`;
354
- const kind = host.kindOf(configFile);
355
- if (kind !== "file") {
356
- throw new DiscoveryError(kind === "absent"
357
- ? `${named} does not exist`
358
- : `${named} is a directory, and a project names its compiler configuration file`, []);
359
- }
360
- if (seen.has(configFile)) {
361
- continue;
362
- }
363
- seen.add(configFile);
364
- references.set(configFile, parseOrRefuse(engine, configFile, named));
365
- projects.push({ id: entry.id, configFile });
366
- }
367
- for (const project of projects) {
368
- const unnamed = references
369
- .get(project.configFile)
370
- ?.find((path) => !seen.has(path) && relativePath(targetRoot, path) !== undefined);
371
- if (unnamed !== undefined) {
372
- throw new DiscoveryError(`the project ${JSON.stringify(project.id)} (${project.configFile}) references ` +
373
- `${unnamed}, which the build matrix does not name. A referenced project is built ` +
374
- "into the program that references it, so the matrix names it too", []);
375
- }
376
- }
377
- return {
378
- projects,
379
- derived: false,
380
- notBuilt: [],
381
- configFiles: projects.map((project) => project.configFile),
382
- fromScope: [],
383
- };
384
- }
385
- /**
386
- * The projects a run derives where the matrix declares none, in discovery order: the
387
- * paths the scope names, every compiler configuration under the target root outside an
388
- * ignored directory, then each configuration below the root those reference,
389
- * transitively, each once. A reference outside the root is an outside project, whose
390
- * sources the compiler builds into the referencing program. A configuration the scope
391
- * names ends the run where it cannot be read; one the walk found is dropped and named.
392
- */
393
- function derivedProjects(engine, host, scope) {
394
- const targetRoot = scope.target.path;
395
- const fromScope = scopeConfigFiles(host, scope);
396
- const notBuilt = [];
397
- const rootDir = resolvePath(host.workingDirectory(), fromScope.length > 0 ? dirnamePath(targetRoot) : targetRoot);
398
- const configFiles = derivedFrom(engine, host, [...fromScope, ...configFilesUnder(host, targetRoot)], (reference) => relativePath(rootDir, reference) !== undefined, (configFile, reason) => {
399
- if (fromScope.includes(configFile)) {
400
- throw new DiscoveryError(`${configFile} cannot be read as a compiler configuration: ${reason}`, []);
401
- }
402
- notBuilt.push({
403
- id: derivedId(targetRoot, configFile),
404
- configFile,
405
- error: targetRelative(reason, resolvePath(host.workingDirectory(), targetRoot)),
406
- });
407
- });
408
- const projects = configFiles.map((configFile) => ({
409
- id: derivedId(targetRoot, configFile),
410
- configFile,
411
- }));
412
- return { projects, derived: true, notBuilt, configFiles, fromScope };
413
- }
414
- /**
415
- * Every project one run analyzes.
416
- *
417
- * The project entries of the build matrix, where it holds any, are the projects:
418
- * exactly those, in the order the matrix lists them, each named by its declared
419
- * identifier, as {@link declaredProjects} reads them. A matrix holding no project
420
- * entry, the empty one included, leaves discovery to derive the projects from the
421
- * scope and the target tree. A platform entry names a configuration of another
422
- * language and plays no part here.
423
- *
424
- * A configuration file the compiler cannot read is never analyzed. One the matrix or
425
- * the scope names ends the run with the failure code; a guess is dropped and named in
426
- * {@link Discovery.notBuilt}. What a configuration's own contents say is read once its
427
- * project is open, by {@link diagnosticErrors}, because a resolution carries none.
428
- *
429
- * Nothing reads a build output: a project is the files its configuration names, so a
430
- * package whose sources ship as TypeScript is analyzed as it stands.
431
- */
432
- export function discoverProjects(engine, host, scope, configurations = []) {
433
- const declared = configurations.filter((entry) => entry.shape === "project");
434
- if (declared.length > 0) {
435
- return declaredProjects(engine, host, scope.target.path, declared);
436
- }
437
- return derivedProjects(engine, host, scope);
438
- }
439
- /**
440
- * How the snapshot reads each configuration of `configFiles` that sets `baseUrl` and
441
- * `programs` does not already describe: a configuration only the snapshot holds, which
442
- * extends it and states the `paths` {@link baseUrlPaths} gives, so its imports resolve as
443
- * the compilers before version 7 resolve them. A configuration the compiler cannot read is
444
- * left for its project to refuse.
445
- */
446
- export function withBaseUrlPaths(engine, host, configFiles, programs) {
447
- const found = new Map(programs);
448
- for (const configFile of configFiles) {
449
- if (found.has(configFile)) {
450
- continue;
451
- }
452
- let paths;
453
- try {
454
- paths = baseUrlPaths(engine.parseConfigFile(configFile).options);
455
- }
456
- catch {
457
- continue;
458
- }
459
- if (paths !== undefined) {
460
- found.set(configFile, {
461
- kind: "configuration",
462
- file: writtenPath(host, configFile),
463
- text: `${JSON.stringify({ extends: configFile, compilerOptions: { paths } }, null, 2)}\n`,
464
- });
465
- }
466
- }
467
- return found;
468
- }
package/dist/src/glob.js DELETED
@@ -1,65 +0,0 @@
1
- /**
2
- * Glob patterns over the paths of the target's own files, as the configuration
3
- * writes them. Both `ts.test_files` and `ts.entry_files` name files this way, and
4
- * one grammar answers for both.
5
- *
6
- * A configured root is not written in this grammar. It names a symbol reference
7
- * rather than a path, `*` there spans the solidus and a brace list means nothing,
8
- * so that rule is written where it is read.
9
- */
10
- /**
11
- * One literal run of a pattern, with every character the expression syntax claims
12
- * escaped.
13
- *
14
- * The set is the syntax characters and the solidus, and it is closed: an escape of any
15
- * other character is refused outright by the expression syntax under the unicode flag,
16
- * so escaping a hyphen, which needs none outside a character class, would refuse every
17
- * pattern that names a hyphenated path.
18
- */
19
- function quoted(text) {
20
- return text.replaceAll(/[.*+?^${}()|[\]\\/]/gu, (character) => `\\${character}`);
21
- }
22
- /**
23
- * The expression one glob pattern denotes. `**` spans path separators while `*` and `?`
24
- * do not, a brace list is an alternation of its members, and every other character
25
- * stands for itself.
26
- */
27
- export function globExpression(pattern) {
28
- let source = "^";
29
- let at = 0;
30
- while (at < pattern.length) {
31
- const rest = pattern.slice(at);
32
- if (rest.startsWith("**/")) {
33
- source += "(?:[^/]*/)*";
34
- at += 3;
35
- continue;
36
- }
37
- if (rest.startsWith("**")) {
38
- source += ".*";
39
- at += 2;
40
- continue;
41
- }
42
- const character = pattern[at] ?? "";
43
- at += 1;
44
- if (character === "*") {
45
- source += "[^/]*";
46
- continue;
47
- }
48
- if (character === "?") {
49
- source += "[^/]";
50
- continue;
51
- }
52
- if (character === "{") {
53
- const close = pattern.indexOf("}", at);
54
- if (close < 0) {
55
- source += "\\{";
56
- continue;
57
- }
58
- source += `(?:${pattern.slice(at, close).split(",").map(quoted).join("|")})`;
59
- at = close + 1;
60
- continue;
61
- }
62
- source += quoted(character);
63
- }
64
- return new RegExp(`${source}$`, "u");
65
- }
@@ -1,120 +0,0 @@
1
- /**
2
- * The `packages` list of a `pnpm-workspace.yaml`. The document is read as far as that
3
- * one key needs and no further: a top-level `packages` key holding a block sequence or
4
- * a one-line flow sequence of plain or quoted strings. Any other value of the key is
5
- * refused rather than guessed at, because a list read wrong names the wrong packages.
6
- */
7
- /** The characters a plain scalar may not start with. */
8
- const INDICATORS = new Set(["[", "]", "{", "}", ",", "&", "*", "!", "|", ">", "%", "@", "`", "#"]);
9
- /** One line with its comment removed, a `#` inside quotes kept. */
10
- function uncommented(line) {
11
- let quote;
12
- for (let at = 0; at < line.length; at += 1) {
13
- const character = line[at];
14
- if (quote !== undefined) {
15
- if (character === quote) {
16
- quote = undefined;
17
- }
18
- continue;
19
- }
20
- if (character === "'" || character === '"') {
21
- quote = character;
22
- }
23
- else if (character === "#" && (at === 0 || /\s/u.test(line[at - 1] ?? ""))) {
24
- return line.slice(0, at).trimEnd();
25
- }
26
- }
27
- return line.trimEnd();
28
- }
29
- /** One scalar as written, or `undefined` where it is not a string this reader reads. */
30
- function scalarOf(text) {
31
- const value = text.trim();
32
- if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) {
33
- const inner = value.slice(1, -1);
34
- return /'(?!')/u.test(inner.replaceAll("''", "")) ? undefined : inner.replaceAll("''", "'");
35
- }
36
- if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
37
- const inner = value.slice(1, -1);
38
- return inner.includes("\\") || inner.includes('"') ? undefined : inner;
39
- }
40
- if (value === "" ||
41
- INDICATORS.has(value[0] ?? "") ||
42
- value.startsWith("'") ||
43
- value.startsWith('"')) {
44
- return undefined;
45
- }
46
- if (value.startsWith("- ") || value.startsWith("? ") || /:(?:\s|$)/u.test(value)) {
47
- return undefined;
48
- }
49
- return value;
50
- }
51
- /** The entries of a one-line flow sequence, or `undefined` where one does not read. */
52
- function flowOf(text) {
53
- const inner = text.slice(1, -1).trim();
54
- if (inner === "") {
55
- return [];
56
- }
57
- const entries = inner.split(",");
58
- if (entries.length > 1 && entries.at(-1)?.trim() === "") {
59
- entries.pop();
60
- }
61
- const found = [];
62
- for (const entry of entries) {
63
- const value = scalarOf(entry);
64
- if (value === undefined) {
65
- return undefined;
66
- }
67
- found.push(value);
68
- }
69
- return found;
70
- }
71
- const KEY = /^(?:packages|'packages'|"packages")\s*:(?:\s(.*))?$/u;
72
- /** The `packages` list one `pnpm-workspace.yaml` text declares. */
73
- export function pnpmPackages(text) {
74
- const lines = text.split(/\r?\n/u).map(uncommented);
75
- const keys = lines.flatMap((line, at) => (KEY.test(line) ? [at] : []));
76
- const [at] = keys;
77
- if (at === undefined) {
78
- return { kind: "absent" };
79
- }
80
- if (keys.length > 1) {
81
- return { kind: "refused", reason: "the packages key is declared more than once" };
82
- }
83
- const rest = (KEY.exec(lines[at] ?? "")?.[1] ?? "").trim();
84
- if (rest !== "") {
85
- const listed = rest.startsWith("[") && rest.endsWith("]") ? flowOf(rest) : undefined;
86
- return listed === undefined
87
- ? {
88
- kind: "refused",
89
- reason: `packages holds ${JSON.stringify(rest)}, not a sequence of strings`,
90
- }
91
- : { kind: "listed", patterns: listed };
92
- }
93
- const patterns = [];
94
- for (const line of lines.slice(at + 1)) {
95
- if (line.trim() === "") {
96
- continue;
97
- }
98
- const item = /^(\s*)-(?:\s+(.*))?$/u.exec(line);
99
- if (item === null) {
100
- if (/^\s/u.test(line)) {
101
- return {
102
- kind: "refused",
103
- reason: `packages holds ${JSON.stringify(line.trim())}, not a sequence item`,
104
- };
105
- }
106
- break;
107
- }
108
- const value = scalarOf(item[2] ?? "");
109
- if (value === undefined) {
110
- return {
111
- kind: "refused",
112
- reason: `the packages item ${JSON.stringify(line.trim())} is not a plain or quoted string`,
113
- };
114
- }
115
- patterns.push(value);
116
- }
117
- return patterns.length === 0
118
- ? { kind: "refused", reason: "packages holds no sequence" }
119
- : { kind: "listed", patterns };
120
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * A setup failure: a file or a component the analysis needs and the project does not
3
- * provide. Each one names what is missing and the fix, on one line of the error stream
4
- * that starts with its class.
5
- */
6
- /** The failure as the one line of the error stream that names it. */
7
- export function setupLine(failure) {
8
- return `setup failure: ${failure.setupClass}: ${failure.detail}`;
9
- }
10
- /**
11
- * A run that met a setup failure where none may be dropped: in a configuration the
12
- * configuration document or the scope declares, in a declared consumer, or in every
13
- * configuration discovery derived. It ends the run with the failure code and no finding
14
- * list.
15
- */
16
- export class SetupError extends Error {
17
- failures;
18
- constructor(failures) {
19
- super(failures.map(setupLine).join("\n"));
20
- this.name = "SetupError";
21
- this.failures = failures;
22
- }
23
- }