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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/bin/node-host.js +21 -3
  2. package/dist/src/analysis.js +13 -14
  3. package/dist/src/config.js +6 -83
  4. package/dist/src/configured-declarations.js +15 -20
  5. package/dist/src/consumers.js +2 -2
  6. package/dist/src/contract/config.generated.js +544 -0
  7. package/dist/src/contract/report.generated.js +3 -2
  8. package/dist/src/discover.js +1 -1
  9. package/dist/src/edges.js +36 -112
  10. package/dist/src/exempt-classes.js +0 -2
  11. package/dist/src/exempt.js +1 -1
  12. package/dist/src/findings/completion.js +5 -4
  13. package/dist/src/findings/emitters.js +1 -1
  14. package/dist/src/findings/intra-function.js +1 -1
  15. package/dist/src/findings/non-code-artifacts.js +2 -2
  16. package/dist/src/findings/unused-declarations.js +1 -1
  17. package/dist/src/findings/visibility-narrowing.js +2 -2
  18. package/dist/src/findings-pass.js +1 -1
  19. package/dist/src/framework-lifecycle.js +7 -7
  20. package/dist/src/fs/document.js +59 -0
  21. package/dist/src/injection-container.js +1 -1
  22. package/dist/src/json-document.js +194 -67
  23. package/dist/src/kinds.js +0 -7
  24. package/dist/src/print.js +10 -79
  25. package/dist/src/report-schema.js +3 -224
  26. package/dist/src/resolve.js +245 -715
  27. package/dist/src/run.js +48 -55
  28. package/dist/src/schema.js +320 -344
  29. package/dist/src/scope.js +33 -101
  30. package/dist/src/serialization-contract.js +1 -1
  31. package/dist/src/suppress-file.js +15 -17
  32. package/dist/src/suppress.js +3 -3
  33. package/dist/src/template-field.js +4 -4
  34. package/dist/src/usage.js +10 -0
  35. package/dist/src/verbs/analyze.js +12 -15
  36. package/dist/src/verbs/explain.js +3 -3
  37. package/dist/src/verbs/print-projects.js +2 -2
  38. package/jsr.json +1 -1
  39. package/package.json +1 -1
  40. package/src/analysis.ts +30 -26
  41. package/src/config.ts +31 -298
  42. package/src/configured-declarations.ts +18 -23
  43. package/src/consumers.ts +4 -4
  44. package/src/contract/config.generated.ts +798 -0
  45. package/src/contract/report.generated.ts +3 -2
  46. package/src/discover.ts +1 -1
  47. package/src/edges.ts +39 -124
  48. package/src/exempt-classes.ts +0 -5
  49. package/src/exempt.ts +4 -4
  50. package/src/findings/completion.ts +5 -6
  51. package/src/findings/emitter.ts +2 -2
  52. package/src/findings/emitters.ts +1 -1
  53. package/src/findings/intra-function.ts +1 -1
  54. package/src/findings/non-code-artifacts.ts +4 -4
  55. package/src/findings/unused-declarations.ts +1 -1
  56. package/src/findings/visibility-narrowing.ts +2 -2
  57. package/src/findings-pass.ts +3 -3
  58. package/src/framework-lifecycle.ts +7 -7
  59. package/src/fs/document.ts +74 -0
  60. package/src/host.ts +12 -5
  61. package/src/injection-container.ts +1 -1
  62. package/src/json-document.ts +236 -76
  63. package/src/kinds.ts +0 -8
  64. package/src/print.ts +11 -92
  65. package/src/report-schema.ts +3 -299
  66. package/src/resolve.ts +281 -1105
  67. package/src/run.ts +50 -63
  68. package/src/schema.ts +391 -389
  69. package/src/scope.ts +39 -119
  70. package/src/serialization-contract.ts +1 -1
  71. package/src/suppress-file.ts +15 -20
  72. package/src/suppress.ts +3 -3
  73. package/src/template-field.ts +10 -7
  74. package/src/usage.ts +10 -0
  75. package/src/verbs/analyze.ts +12 -23
  76. package/src/verbs/explain.ts +3 -7
  77. package/src/verbs/print-projects.ts +2 -2
  78. package/src/verbs/verb.ts +2 -2
package/dist/src/run.js CHANGED
@@ -1,9 +1,12 @@
1
+ import { CONFIG_MAX_BYTES, SETTINGS } from "./contract/config.generated.js";
1
2
  import { EXIT_FAILURE, EXIT_USAGE } from "./contract/contract.generated.js";
2
- import { ConfigError, REPOSITORY_DOCUMENT } from "./config.js";
3
+ import { REPOSITORY_DOCUMENT } from "./config.js";
3
4
  import { DiscoveryError, renderDiagnostic } from "./discover.js";
5
+ import { readTargetDocument, TargetDocumentError } from "./fs/document.js";
4
6
  import { joinPath, resolvePath } from "./paths.js";
5
7
  import { readScope, ScopeError, scopeForDir } from "./scope.js";
6
8
  import { SetupError, setupLine } from "./setup-failure.js";
9
+ import { UsageError } from "./usage.js";
7
10
  import { openEngine } from "./session.js";
8
11
  import { printConfigVerb } from "./verbs/print-config.js";
9
12
  import { printProjectsVerb } from "./verbs/print-projects.js";
@@ -34,29 +37,12 @@ const USAGE = `usage: ${PRODUCT} <verb> [options]\nverbs: ${VERBS.map((verb) =>
34
37
  */
35
38
  const SOURCE_EDIT_TOKENS = ["fix", "edit", "delete", "rewrite"];
36
39
  /**
37
- * Maps an option name to the setting of the Contract's configuration schema it supplies,
38
- * so one entry registers the option, supplies the document resolution reads, and gives
39
- * the spelling the setting's provenance names. The name is this command's vocabulary and
40
- * is never derived from the path: a setting reaches the command line only by an entry,
41
- * and a path names a key the schema declares.
40
+ * Maps an option name to the setting of the Contract's configuration schema it supplies:
41
+ * the options contract/settings.json names for a setting this analyzer reads.
42
42
  */
43
- export const SETTING_OPTIONS = new Map([
44
- ["min-confidence", "analysis.min_confidence"],
45
- ["sort", "reporters.sort"],
46
- ["cascade", "reporters.cascade"],
47
- ["max-findings", "reporters.max_findings"],
48
- ["fail-on", "reporters.fail_on"],
49
- ]);
43
+ export const SETTING_OPTIONS = new Map(SETTINGS.flatMap((row) => (row.option === undefined ? [] : [[row.option, row.key]])));
50
44
  /** The options that take a value and are not settings. */
51
45
  const PLAIN_OPTIONS = new Set(["target", "config", "central", "scope"]);
52
- /**
53
- * The setting options whose value is an integer rather than a string. A value
54
- * written other than as digits is passed on as the string it is, so resolution
55
- * refuses it by its type rather than reading `1e2` as 100.
56
- */
57
- const INTEGER_OPTIONS = new Set(["max-findings"]);
58
- /** An integer as an option writes it: an optional minus sign and digits alone. */
59
- const INTEGER_TEXT = /^-?[0-9]+$/u;
60
46
  /** No option beyond the ones every verb takes. */
61
47
  const NO_OPTIONS = { plain: [], repeatable: [] };
62
48
  /**
@@ -83,7 +69,7 @@ function readOptions(args, own) {
83
69
  const repeated = new Map();
84
70
  for (const arg of args) {
85
71
  if (!arg.startsWith("-")) {
86
- throw new ConfigError("malformed", "", `unexpected argument ${JSON.stringify(arg)}`);
72
+ throw new UsageError(`unexpected argument ${JSON.stringify(arg)}`);
87
73
  }
88
74
  const [spelled, ...rest] = arg.split("=");
89
75
  const name = (spelled ?? "").replace(/^-+/u, "");
@@ -91,10 +77,10 @@ function readOptions(args, own) {
91
77
  !SETTING_OPTIONS.has(name) &&
92
78
  !own.plain.includes(name) &&
93
79
  !own.repeatable.includes(name)) {
94
- throw new ConfigError("malformed", "", `unknown option ${JSON.stringify(spelled ?? arg)}`);
80
+ throw new UsageError(`unknown option ${JSON.stringify(spelled ?? arg)}`);
95
81
  }
96
82
  if (rest.length === 0) {
97
- throw new ConfigError("malformed", "", `option ${JSON.stringify(spelled ?? arg)} takes a value`);
83
+ throw new UsageError(`option ${JSON.stringify(spelled ?? arg)} takes a value`);
98
84
  }
99
85
  const value = rest.join("=");
100
86
  named.set(name, value);
@@ -102,45 +88,54 @@ function readOptions(args, own) {
102
88
  }
103
89
  return { named, repeated };
104
90
  }
105
- function readFileOr(host, path, orUndefined) {
91
+ /** The document an option names. */
92
+ function documentAt(host, label) {
106
93
  try {
107
- return host.readFile(resolvePath(host.workingDirectory(), path));
94
+ const path = resolvePath(host.workingDirectory(), label);
95
+ // A file past the bound reads as one byte more than it, which resolution refuses.
96
+ return { text: host.readFile(path, CONFIG_MAX_BYTES + 1), label };
108
97
  }
109
98
  catch (error) {
110
- if (orUndefined) {
111
- return undefined;
112
- }
113
- throw new ConfigError("malformed", "", `${path}: ${message(error)}`);
99
+ throw new UsageError(`${label}: ${message(error)}`);
114
100
  }
115
101
  }
116
102
  /**
117
- * The configuration documents one invocation reads: the repository configuration
118
- * at the target root or the path an option named, the central configuration, and
119
- * the settings the options supply as one flag document.
103
+ * The repository configuration at the target root, none where it is absent. One that
104
+ * cannot be read is a configuration document that cannot be, refused with the usage code.
105
+ */
106
+ function repositoryAt(host, target) {
107
+ const label = joinPath(target, REPOSITORY_DOCUMENT);
108
+ const root = resolvePath(host.workingDirectory(), target);
109
+ try {
110
+ const text = readTargetDocument(host, root, REPOSITORY_DOCUMENT, label);
111
+ return text === undefined ? undefined : { text, label };
112
+ }
113
+ catch (error) {
114
+ throw error instanceof TargetDocumentError ? new UsageError(error.message) : error;
115
+ }
116
+ }
117
+ /**
118
+ * The configuration sources one invocation carries: the repository configuration at
119
+ * the target root or the path an option named, the central configuration, and the
120
+ * text each setting option was given.
120
121
  */
121
122
  function inputsOf(host, options) {
122
- const target = options.named.get("target") ?? ".";
123
123
  const named = options.named.get("config");
124
- const repositoryLabel = named ?? joinPath(target, REPOSITORY_DOCUMENT);
125
- const repository = readFileOr(host, repositoryLabel, named === undefined);
124
+ const target = options.named.get("target") ?? ".";
125
+ const repository = named === undefined ? repositoryAt(host, target) : documentAt(host, named);
126
126
  const centralLabel = options.named.get("central");
127
- const central = centralLabel === undefined ? undefined : readFileOr(host, centralLabel, false);
128
- const flat = {};
129
- const flagLabels = new Map();
130
- for (const [name, path] of SETTING_OPTIONS) {
127
+ const central = centralLabel === undefined ? undefined : documentAt(host, centralLabel);
128
+ const flags = new Map();
129
+ for (const [name, key] of SETTING_OPTIONS) {
131
130
  const value = options.named.get(name);
132
- if (value === undefined) {
133
- continue;
131
+ if (value !== undefined) {
132
+ flags.set(key, value);
134
133
  }
135
- flat[path] = INTEGER_OPTIONS.has(name) && INTEGER_TEXT.test(value) ? Number(value) : value;
136
- flagLabels.set(path, `--${name}`);
137
134
  }
138
- const flags = Object.keys(flat).length === 0 ? undefined : JSON.stringify(flat);
139
135
  return {
140
- ...(flags === undefined ? {} : { flags }),
141
- ...(repository === undefined ? {} : { repository, repositoryLabel }),
142
- ...(central === undefined || centralLabel === undefined ? {} : { central, centralLabel }),
143
- flagLabels,
136
+ flags,
137
+ ...(repository === undefined ? {} : { repository }),
138
+ ...(central === undefined ? {} : { central }),
144
139
  };
145
140
  }
146
141
  /** The scope one invocation analyzes: the document an option named, or the target. */
@@ -156,9 +151,7 @@ function scopeOf(host, options) {
156
151
  * the exit code: 0 for a completed verb, 1 for a finding that fails the run, 2 for a
157
152
  * usage error, a requested source edit or a refused configuration, 3 for a failure that
158
153
  * produced no answer. It writes nothing outside `out` and `err` and never exits the
159
- * process. `host` is the platform the run reads, the version it reports included, and
160
- * `openClient` opens the compiler client; a caller that watches what a run reads
161
- * supplies its own of either.
154
+ * process. A caller that watches what a run reads supplies its own `host` or `openClient`.
162
155
  */
163
156
  export function run(args, out, err, host, openClient = openEngine) {
164
157
  const editing = sourceEditOption(args);
@@ -198,7 +191,7 @@ function invoke(verb, own, args, streams, openClient) {
198
191
  openClient: (config) => {
199
192
  opened = openClient({
200
193
  collectTiming: false,
201
- components: { extensions: config.ts.componentExtensions, host: streams.host },
194
+ components: { extensions: config.ts.component_extensions, host: streams.host },
202
195
  });
203
196
  return opened;
204
197
  },
@@ -211,7 +204,7 @@ function invoke(verb, own, args, streams, openClient) {
211
204
  }
212
205
  /** Turns one refusal into the exit code the Contract's table gives it. */
213
206
  function refuse(error, err) {
214
- if (error instanceof ConfigError) {
207
+ if (error instanceof UsageError) {
215
208
  diagnose(err, error.message);
216
209
  err.write(USAGE);
217
210
  return EXIT_USAGE;
@@ -229,7 +222,7 @@ function refuse(error, err) {
229
222
  }
230
223
  return EXIT_FAILURE;
231
224
  }
232
- if (error instanceof ScopeError) {
225
+ if (error instanceof ScopeError || error instanceof TargetDocumentError) {
233
226
  diagnose(err, error.message);
234
227
  return EXIT_FAILURE;
235
228
  }