@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
package/src/scope.ts CHANGED
@@ -1,11 +1,12 @@
1
- import { ConfigError } from "./config.ts";
1
+ import { SCOPE_SCHEMA } from "./contract/config.generated.ts";
2
2
  import type { Host } from "./host.ts";
3
+ import { dotted, locatedFault, placeIn, readStrict, StrictJSONError } from "./json-document.ts";
3
4
  import { dirnamePath, isAbsolutePath, joinPath, resolvePath } from "./paths.ts";
4
- import { checkDocument, type KeyNode } from "./schema.ts";
5
-
6
- /** The roles a scope document declares for a module. */
7
- const ROLE_TARGET = "target";
8
- const ROLE_CONSUMER = "consumer";
5
+ import { MARKERS } from "./load/discover.ts";
6
+ import { failureExit } from "./failure.ts";
7
+ import { message } from "./product.ts";
8
+ import { firstRefusal } from "./schema.ts";
9
+ import { UsageError } from "./usage.ts";
9
10
 
10
11
  /**
11
12
  * A scope document above this length is refused rather than decoded. It names one
@@ -14,23 +15,14 @@ const ROLE_CONSUMER = "consumer";
14
15
  const MAX_DOCUMENT_LENGTH = 1 << 20;
15
16
 
16
17
  /**
17
- * A scope document that cannot be read as one. It ends the run with the failure
18
- * code: the run could not learn what to analyze, so it produced no answer.
18
+ * The bytes read of a scope document. A UTF-16 unit decodes from at most three bytes,
19
+ * so a document past the bound is past it within these.
19
20
  */
20
- export class ScopeError extends Error {
21
- constructor(message: string) {
22
- super(message);
23
- this.name = "ScopeError";
24
- }
25
- }
21
+ const MAX_DOCUMENT_BYTES = 3 * (MAX_DOCUMENT_LENGTH + 1);
26
22
 
27
23
  /**
28
- * One module the run reads: the target or a declared consumer.
29
- *
30
- * The role a document declares is not carried here, because the resolved scope
31
- * holds exactly one target and a list of consumers, so a module's role is where it
32
- * sits. What a document declares is read and refused where it contradicts that
33
- * position, which is the only place the declaration can be wrong.
24
+ * One module the run reads: the target or a declared consumer. The role a document
25
+ * declares is not carried, because a module's role is where the scope holds it.
34
26
  */
35
27
  export interface Module {
36
28
  /** The package name. A document may state it; otherwise it is empty. */
@@ -45,150 +37,66 @@ export interface Scope {
45
37
  readonly consumers: readonly Module[];
46
38
  }
47
39
 
48
- const MODULE: KeyNode = {
49
- kind: "section",
50
- members: { id: { kind: "leaf" }, role: { kind: "leaf" }, path: { kind: "leaf" } },
51
- };
52
-
53
- /** The closed key list of the scope document, compared as bytes. */
54
- const SCOPE_ROOT: KeyNode = {
55
- kind: "section",
56
- members: {
57
- target: MODULE,
58
- workspace: { kind: "leaf" },
59
- consumers: { kind: "list", members: MODULE.members ?? {} },
60
- },
61
- };
62
-
63
- function isRecord(value: unknown): value is Record<string, unknown> {
64
- return typeof value === "object" && value !== null && !Array.isArray(value);
65
- }
66
-
67
- /**
68
- * One string member, or undefined where the document omits it. A member the
69
- * document writes is a string holding at least one character, so `null` and `""`
70
- * are refused rather than read as absent.
71
- */
72
- function stringMember(
73
- parent: Record<string, unknown>,
74
- name: string,
75
- at: string,
76
- ): string | undefined {
77
- if (!Object.hasOwn(parent, name)) {
78
- return undefined;
79
- }
80
- const value = parent[name];
81
- if (typeof value !== "string") {
82
- throw new ScopeError(`scope: ${at === "" ? name : `${at}.${name}`} is not a string`);
83
- }
84
- if (value === "") {
85
- throw new ScopeError(`scope: ${at === "" ? name : `${at}.${name}`} names nothing`);
86
- }
87
- return value;
88
- }
89
-
90
- function readModule(value: unknown, at: string, role: string, documentDir: string): Module {
91
- if (!isRecord(value)) {
92
- throw new ScopeError(`scope: ${at} is not an object`);
93
- }
94
- const declared = stringMember(value, "role", at);
95
- if (declared !== undefined && declared !== role) {
96
- throw new ScopeError(
97
- `scope: ${at}.role is ${JSON.stringify(declared)}, want ${JSON.stringify(role)}`,
98
- );
99
- }
100
- const path = stringMember(value, "path", at);
101
- if (path === undefined) {
102
- throw new ScopeError(`scope: ${at}.path names nothing`);
103
- }
104
- return {
105
- id: stringMember(value, "id", at) ?? "",
106
- path: isAbsolutePath(path) ? path : joinPath(documentDir, path),
107
- };
40
+ interface DeclaredModule {
41
+ readonly id?: string;
42
+ readonly path: string;
108
43
  }
109
44
 
110
- /**
111
- * Walks the document's text against the closed key list, refusing a key the list
112
- * does not declare, compared as bytes, and a key one object writes twice, which a
113
- * parse cannot report because it keeps the last value.
114
- */
115
- function checkKeys(text: string, file: string): void {
116
- try {
117
- checkDocument(text, SCOPE_ROOT, `scope: ${file}`);
118
- } catch (error: unknown) {
119
- if (error instanceof ConfigError) {
120
- // The configuration's refusal names the nearest configuration key, which a
121
- // scope document does not have.
122
- throw new ScopeError(
123
- error.kind === "unimplemented-key"
124
- ? `scope: ${file}: ${error.key} is not a declared key`
125
- : error.message,
126
- );
127
- }
128
- throw error;
129
- }
45
+ function refusal(file: string, place: string, reason: string): UsageError {
46
+ return new UsageError(`scope: ${file}: ${place === "" ? "" : `${place}: `}${reason}`);
130
47
  }
131
48
 
132
49
  /**
133
- * Decodes the scope document at `file`. Decoding is strict: an undeclared key, a
134
- * key written twice in one object, and a value of a type the document does not
135
- * admit, `null` included, are errors, and a relative path inside the document
136
- * resolves against the document's own directory.
137
- *
138
- * The `workspace` key the format declares is checked and carries nothing here: it
139
- * names the file a Go consumer resolves the target through, and a TypeScript
140
- * project resolves one through its own compiler configuration.
50
+ * Decodes the scope document at `file`, held to the Contract's scope schema, a relative
51
+ * path resolved against the document's own directory. A document that cannot be read or is
52
+ * refused is a usage error, as any document the invocation names. `workspace` is read by Go consumers
53
+ * alone: a TypeScript project resolves the target through its own compiler configuration.
141
54
  */
142
55
  export function readScope(host: Host, file: string): Scope {
143
56
  const absolute = resolvePath(host.workingDirectory(), file);
144
57
  let text: string;
145
58
  try {
146
- text = host.readFile(absolute);
59
+ text = host.readFile(absolute, MAX_DOCUMENT_BYTES);
147
60
  } catch (error: unknown) {
148
- throw new ScopeError(
149
- `scope: ${file}: ${error instanceof Error ? error.message : String(error)}`,
150
- );
61
+ throw new UsageError(`scope: ${file}: ${message(error)}`);
151
62
  }
152
63
  if (text.length > MAX_DOCUMENT_LENGTH) {
153
- throw new ScopeError(`scope: ${file} is longer than ${String(MAX_DOCUMENT_LENGTH)} characters`);
64
+ throw new UsageError(`scope: ${file} is longer than ${String(MAX_DOCUMENT_LENGTH)} characters`);
154
65
  }
155
66
  let value: unknown;
156
67
  try {
157
- value = JSON.parse(text);
68
+ value = readStrict(text).value;
158
69
  } catch (error: unknown) {
159
- throw new ScopeError(
160
- `scope: ${file}: ${error instanceof Error ? error.message : String(error)}`,
161
- );
70
+ if (!(error instanceof StrictJSONError)) {
71
+ throw error;
72
+ }
73
+ throw refusal(file, dotted(error.place), locatedFault(text, error));
162
74
  }
163
- if (!isRecord(value)) {
164
- throw new ScopeError(`scope: ${file} is not one JSON object`);
75
+ const refused = firstRefusal(SCOPE_SCHEMA, value);
76
+ if (refused !== undefined) {
77
+ throw refusal(file, dotted(placeIn(value, refused.pointer, refused.member)), refused.reason);
165
78
  }
166
- checkKeys(text, file);
167
- stringMember(value, "workspace", "");
79
+ const declared = value as { target: DeclaredModule; consumers?: readonly DeclaredModule[] };
168
80
  const documentDir = dirnamePath(absolute);
169
- if (!Object.hasOwn(value, "target")) {
170
- throw new ScopeError(`scope: ${file} names no target`);
171
- }
172
- const target = readModule(value["target"], "target", ROLE_TARGET, documentDir);
173
- const listed = Object.hasOwn(value, "consumers") ? value["consumers"] : [];
174
- if (!Array.isArray(listed)) {
175
- throw new ScopeError(`scope: ${file}: consumers is not an array`);
176
- }
177
- const consumers = (listed as unknown[]).map((entry, index) =>
178
- readModule(entry, `consumers[${String(index)}]`, ROLE_CONSUMER, documentDir),
179
- );
180
- return { target, consumers };
81
+ const moduleOf = (module: DeclaredModule): Module => ({
82
+ id: module.id ?? "",
83
+ path: isAbsolutePath(module.path) ? module.path : joinPath(documentDir, module.path),
84
+ });
85
+ return { target: moduleOf(declared.target), consumers: (declared.consumers ?? []).map(moduleOf) };
181
86
  }
182
87
 
183
- /** The single-package scope one directory is, when no scope document is given. */
88
+ /**
89
+ * The single-package scope one directory is, when no scope document is given. A target that is
90
+ * no directory holds no program.
91
+ */
184
92
  export function scopeForDir(host: Host, dir: string): Scope {
185
93
  const path = resolvePath(host.workingDirectory(), dir);
186
94
  const kind = host.kindOf(path);
187
- if (kind === "absent") {
188
- throw new ScopeError(`scope: ${path} does not exist`);
189
- }
190
95
  if (kind !== "directory") {
191
- throw new ScopeError(`scope: ${path} is not a directory`);
96
+ throw failureExit(
97
+ "no-program",
98
+ `the target ${path} ${kind === "absent" ? "does not exist" : "is not a directory"}, so it holds no compiler configuration, no file named ${MARKERS.join(", ")}: name the directory that holds one`,
99
+ );
192
100
  }
193
101
  return { target: { id: "", path }, consumers: [] };
194
102
  }