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

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 (201) hide show
  1. package/dist/bin/mapper-connection.js +2 -1
  2. package/dist/bin/node-host.js +3 -2
  3. package/dist/src/analysis.js +28 -46
  4. package/dist/src/automatic-types.js +10 -29
  5. package/dist/src/build-scripts.js +17 -29
  6. package/dist/src/component-layer.js +4 -2
  7. package/dist/src/components.js +2 -3
  8. package/dist/src/config.js +3 -2
  9. package/dist/src/configuration-files.js +27 -168
  10. package/dist/src/conformance-record.js +1 -1
  11. package/dist/src/contract/contract.generated.js +1084 -0
  12. package/dist/src/contract/report.generated.js +796 -0
  13. package/dist/src/conventions.js +20 -60
  14. package/dist/src/dependencies.js +25 -43
  15. package/dist/src/discover.js +13 -39
  16. package/dist/src/edges.js +7 -15
  17. package/dist/src/element-access.js +4 -6
  18. package/dist/src/entry-point-gaps.js +2 -8
  19. package/dist/src/entry-points.js +3 -10
  20. package/dist/src/enum-group.js +3 -10
  21. package/dist/src/erased-stores.js +4 -6
  22. package/dist/src/exempt-classes.js +3 -63
  23. package/dist/src/exempt.js +13 -40
  24. package/dist/src/file-facts.js +2 -25
  25. package/dist/src/findings/completion.js +11 -20
  26. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  27. package/dist/src/findings/emitters.js +4 -4
  28. package/dist/src/findings/interfaces.js +4 -5
  29. package/dist/src/findings/intra-function.js +8 -7
  30. package/dist/src/findings/non-code-artifacts.js +5 -6
  31. package/dist/src/findings/reads-and-writes.js +11 -9
  32. package/dist/src/findings/self-check.js +10 -12
  33. package/dist/src/findings/unused-declarations.js +28 -27
  34. package/dist/src/findings/visibility-narrowing.js +9 -11
  35. package/dist/src/findings-pass.js +7 -14
  36. package/dist/src/fs/manifest.js +43 -0
  37. package/dist/src/fs/tree.js +88 -0
  38. package/dist/src/git-ignore.js +34 -25
  39. package/dist/src/html-entries.js +6 -33
  40. package/dist/src/in-operands.js +2 -1
  41. package/dist/src/index.js +1 -1
  42. package/dist/src/intra-function-parts.js +18 -26
  43. package/dist/src/inventory.js +2 -21
  44. package/dist/src/json-document.js +4 -0
  45. package/dist/src/keyof-comparisons.js +4 -6
  46. package/dist/src/kinds.js +4 -360
  47. package/dist/src/manifest.js +5 -43
  48. package/dist/src/mdx-entries.js +3 -26
  49. package/dist/src/partial.js +2 -1
  50. package/dist/src/paths.js +26 -15
  51. package/dist/src/position.js +2 -1
  52. package/dist/src/print.js +3 -2
  53. package/dist/src/product.js +13 -0
  54. package/dist/src/references.js +14 -27
  55. package/dist/src/report-schema.js +272 -0
  56. package/dist/src/report.js +39 -42
  57. package/dist/src/reporters/sarif.js +4 -2
  58. package/dist/src/reporters/template.js +4 -19
  59. package/dist/src/resolve.js +12 -26
  60. package/dist/src/roots.js +7 -17
  61. package/dist/src/run.js +10 -8
  62. package/dist/src/schema.js +4 -3
  63. package/dist/src/scope.js +4 -5
  64. package/dist/src/serialization-contract.js +4 -8
  65. package/dist/src/session.js +2 -1
  66. package/dist/src/setup-failure.js +2 -6
  67. package/dist/src/suppress-file.js +12 -13
  68. package/dist/src/suppress-inline.js +3 -2
  69. package/dist/src/suppress.js +29 -48
  70. package/dist/src/symbol-keys.js +3 -5
  71. package/dist/src/template-field.js +5 -15
  72. package/dist/src/test-globals.js +6 -28
  73. package/dist/src/test-joins.js +6 -6
  74. package/dist/src/text/compare.js +26 -0
  75. package/dist/src/text/glob.js +194 -0
  76. package/dist/src/text/shell.js +159 -0
  77. package/dist/src/{yaml-document.js → text/yaml.js} +38 -0
  78. package/dist/src/type-errors.js +14 -38
  79. package/dist/src/unseen-loads.js +2 -9
  80. package/dist/src/unwrap.js +23 -0
  81. package/dist/src/verbs/analyze.js +22 -15
  82. package/dist/src/verbs/describe.js +7 -7
  83. package/dist/src/verbs/explain.js +7 -4
  84. package/dist/src/verbs/print-config.js +2 -1
  85. package/dist/src/verbs/print-projects.js +4 -2
  86. package/dist/src/verbs/print-retained.js +4 -2
  87. package/dist/src/verbs/print-roots.js +4 -2
  88. package/dist/src/verbs/verb.js +1 -5
  89. package/dist/src/verbs/version.js +4 -3
  90. package/dist/src/workflow-steps.js +9 -46
  91. package/dist/src/workspace-manifests.js +2 -2
  92. package/dist/src/workspace-programs.js +5 -3
  93. package/dist/src/workspace-resolution.js +13 -17
  94. package/dist/src/workspace.js +28 -116
  95. package/jsr.json +1 -1
  96. package/package.json +2 -1
  97. package/src/analysis.ts +29 -54
  98. package/src/automatic-types.ts +11 -29
  99. package/src/build-scripts.ts +17 -38
  100. package/src/component-layer.ts +4 -2
  101. package/src/components.ts +2 -4
  102. package/src/config.ts +11 -15
  103. package/src/configuration-files.ts +27 -170
  104. package/src/conformance-record.ts +1 -1
  105. package/src/contract/contract.generated.ts +1148 -0
  106. package/src/contract/report.generated.ts +1157 -0
  107. package/src/conventions.ts +26 -74
  108. package/src/dependencies.ts +32 -50
  109. package/src/discover.ts +14 -39
  110. package/src/edges.ts +7 -21
  111. package/src/element-access.ts +4 -7
  112. package/src/entry-point-gaps.ts +3 -9
  113. package/src/entry-points.ts +2 -13
  114. package/src/enum-group.ts +2 -11
  115. package/src/erased-stores.ts +3 -7
  116. package/src/exempt-classes.ts +5 -74
  117. package/src/exempt.ts +17 -47
  118. package/src/file-facts.ts +6 -24
  119. package/src/finding.ts +9 -9
  120. package/src/findings/completion.ts +22 -23
  121. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  122. package/src/findings/emitter.ts +6 -7
  123. package/src/findings/emitters.ts +6 -6
  124. package/src/findings/interfaces.ts +4 -6
  125. package/src/findings/intra-function.ts +8 -8
  126. package/src/findings/non-code-artifacts.ts +5 -7
  127. package/src/findings/reads-and-writes.ts +15 -12
  128. package/src/findings/self-check.ts +11 -17
  129. package/src/findings/unused-declarations.ts +28 -27
  130. package/src/findings/visibility-narrowing.ts +9 -12
  131. package/src/findings-pass.ts +7 -16
  132. package/src/fs/manifest.ts +52 -0
  133. package/src/fs/tree.ts +110 -0
  134. package/src/git-ignore.ts +38 -25
  135. package/src/html-entries.ts +6 -33
  136. package/src/in-operands.ts +2 -1
  137. package/src/index.ts +1 -1
  138. package/src/intra-function-parts.ts +18 -28
  139. package/src/inventory.ts +2 -20
  140. package/src/json-document.ts +5 -0
  141. package/src/keyof-comparisons.ts +3 -7
  142. package/src/kinds.ts +6 -406
  143. package/src/manifest.ts +5 -46
  144. package/src/mdx-entries.ts +3 -26
  145. package/src/partial.ts +2 -1
  146. package/src/paths.ts +27 -15
  147. package/src/position.ts +2 -1
  148. package/src/print.ts +3 -2
  149. package/src/product.ts +18 -0
  150. package/src/references.ts +14 -29
  151. package/src/report-schema.ts +364 -0
  152. package/src/report.ts +66 -229
  153. package/src/reporters/annotations.ts +2 -2
  154. package/src/reporters/json.ts +1 -1
  155. package/src/reporters/reporter.ts +2 -2
  156. package/src/reporters/reporters.ts +1 -1
  157. package/src/reporters/sarif.ts +17 -12
  158. package/src/reporters/template.ts +4 -20
  159. package/src/reporters/text.ts +3 -3
  160. package/src/resolve.ts +31 -38
  161. package/src/roots.ts +7 -20
  162. package/src/run.ts +10 -14
  163. package/src/schema.ts +4 -3
  164. package/src/scope.ts +4 -10
  165. package/src/serialization-contract.ts +4 -9
  166. package/src/session.ts +2 -1
  167. package/src/setup-failure.ts +5 -7
  168. package/src/suppress-file.ts +11 -15
  169. package/src/suppress-inline.ts +2 -2
  170. package/src/suppress.ts +39 -55
  171. package/src/symbol-keys.ts +2 -5
  172. package/src/template-field.ts +5 -18
  173. package/src/test-globals.ts +9 -27
  174. package/src/test-joins.ts +6 -8
  175. package/src/text/compare.ts +27 -0
  176. package/src/text/glob.ts +210 -0
  177. package/src/text/shell.ts +161 -0
  178. package/src/{yaml-document.ts → text/yaml.ts} +46 -0
  179. package/src/type-errors.ts +25 -36
  180. package/src/unseen-loads.ts +1 -12
  181. package/src/unwrap.ts +34 -0
  182. package/src/verbs/analyze.ts +38 -25
  183. package/src/verbs/describe.ts +13 -7
  184. package/src/verbs/explain.ts +7 -4
  185. package/src/verbs/print-config.ts +2 -1
  186. package/src/verbs/print-projects.ts +4 -2
  187. package/src/verbs/print-retained.ts +4 -2
  188. package/src/verbs/print-roots.ts +4 -2
  189. package/src/verbs/verb.ts +0 -6
  190. package/src/verbs/version.ts +4 -3
  191. package/src/workflow-steps.ts +9 -44
  192. package/src/workspace-manifests.ts +2 -2
  193. package/src/workspace-programs.ts +5 -3
  194. package/src/workspace-resolution.ts +21 -17
  195. package/src/workspace.ts +35 -121
  196. package/dist/src/glob.js +0 -65
  197. package/dist/src/pnpm-workspace.js +0 -120
  198. package/dist/src/version.js +0 -7
  199. package/src/glob.ts +0 -67
  200. package/src/pnpm-workspace.ts +0 -135
  201. package/src/version.ts +0 -7
@@ -9,6 +9,7 @@
9
9
  import { CHUNK_LENGTH } from "../json-chunks.js";
10
10
  import { RenderError } from "./reporter.js";
11
11
  import { utf8Bytes } from "./sha256.js";
12
+ import { bytewise } from "../text/compare.js";
12
13
  /** A template that does not parse, which refuses the invocation before any analysis. */
13
14
  export class TemplateError extends Error {
14
15
  constructor(message) {
@@ -513,7 +514,7 @@ function formatted(value, nested) {
513
514
  }
514
515
  const object = value;
515
516
  const entries = Object.keys(object)
516
- .sort()
517
+ .sort(bytewise)
517
518
  .map((key) => `${key}:${formatted(object[key] ?? null, true)}`);
518
519
  return `map[${entries.join(" ")}]`;
519
520
  }
@@ -538,26 +539,10 @@ function compareBasic(name, a, b) {
538
539
  return Number.NaN;
539
540
  }
540
541
  if (kind === "string") {
541
- return byCodePoints(a, b);
542
+ return bytewise(a, b);
542
543
  }
543
544
  return a < b ? -1 : 1;
544
545
  }
545
- /**
546
- * Two strings ordered by the bytes of their UTF-8 encodings, which is the order of their
547
- * code points: the order of their UTF-16 code units differs above U+FFFF.
548
- */
549
- function byCodePoints(a, b) {
550
- let at = 0;
551
- while (at < a.length && at < b.length) {
552
- const x = a.codePointAt(at) ?? 0;
553
- const y = b.codePointAt(at) ?? 0;
554
- if (x !== y) {
555
- return x < y ? -1 : 1;
556
- }
557
- at += x > 0xffff ? 2 : 1;
558
- }
559
- return a.length - b.length;
560
- }
561
546
  /** The escapes `%q` writes for the control characters that have one of their own. */
562
547
  const QUOTED_ESCAPES = {
563
548
  '"': '\\"',
@@ -903,7 +888,7 @@ class Execution {
903
888
  }
904
889
  else if (isObject(value)) {
905
890
  entries = Object.keys(value)
906
- .sort()
891
+ .sort(bytewise)
907
892
  .map((key) => [key, value[key] ?? null]);
908
893
  }
909
894
  else {
@@ -1,13 +1,15 @@
1
+ import { SEVERITIES, LANGUAGES, CONFIDENCES, FORMATS, FAMILY_KEY_LENGTH, } from "./contract/contract.generated.js";
1
2
  import { ConfigError, defaultConfig, } from "./config.js";
2
3
  import { CONVENTION_ROWS } from "./convention-rows.js";
4
+ import { EXEMPTION_CLASS_NAMES } from "./exempt-classes.js";
3
5
  import { FIXED_SEVERITY_CODES, LIVE_CODES } from "./kinds.js";
4
6
  import { checkDocument, malformed, nestFlags, SCHEMA_ROOT, SEVERITY_SECTION, } from "./schema.js";
7
+ import { bytewise } from "./text/compare.js";
8
+ import { isRecord } from "./json-document.js";
9
+ import { message } from "./product.js";
5
10
  /** Names the command-line flags in a refusal, where a document is named by its path. */
6
11
  const FLAGS_LABEL = "the command-line flags";
7
- /** The length of a severity key naming a whole family: the prefix and two digits. */
8
- export const FAMILY_KEY_LENGTH = 4;
9
12
  const SEVERITY_KEY = /^DS[0-9]{2}([0-9]{2})?$/u;
10
- const EXEMPTION_CLASS = /^[a-z][a-z0-9-]*$/u;
11
13
  const CONTRACT_VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+$/u;
12
14
  const ANALYZER_NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/u;
13
15
  const PROVIDER_SOURCE = /^(go|npm):[^ \t\r\n]+$/u;
@@ -30,12 +32,8 @@ const PROJECT_SEGMENT = String.raw `(?:[^/.\x00-\x1f\x7f][^/\x00-\x1f\x7f]*|\.[^
30
32
  */
31
33
  const PROJECT_PATH = new RegExp(`^${PROJECT_SEGMENT}(?:/${PROJECT_SEGMENT})*$`, "u");
32
34
  const TARGET_KINDS = ["application", "library"];
33
- const CONFIDENCES = ["certain", "probable", "possible"];
34
35
  const GENERATED_FILES = ["exclude", "include"];
35
36
  const CONSUMER_TESTS = ["test", "production"];
36
- const LANGUAGES = ["go", "ts"];
37
- const SEVERITIES = ["allow", "warn", "deny"];
38
- const FORMATS = ["text", "json", "github", "sarif", "template"];
39
37
  const SORTS = ["position", "size"];
40
38
  const CASCADES = ["roots", "full"];
41
39
  /**
@@ -48,9 +46,6 @@ function originOf(source, path) {
48
46
  }
49
47
  return { source: source.kind, label: source.label };
50
48
  }
51
- function isRecord(value) {
52
- return typeof value === "object" && value !== null && !Array.isArray(value);
53
- }
54
49
  function member(parent, name) {
55
50
  if (parent === undefined || !Object.hasOwn(parent, name)) {
56
51
  return undefined;
@@ -297,7 +292,7 @@ function unimplementedSeverityKey(label, path, reason) {
297
292
  * them all rather than the first one found.
298
293
  */
299
294
  function fixedByContract(code) {
300
- return FIXED_SEVERITY_CODES.filter((candidate) => code === candidate || (code.length === FAMILY_KEY_LENGTH && candidate.startsWith(code))).sort();
295
+ return FIXED_SEVERITY_CODES.filter((candidate) => code === candidate || (code.length === FAMILY_KEY_LENGTH && candidate.startsWith(code))).sort(bytewise);
301
296
  }
302
297
  /** The codes a refusal names: one on its own, and several with the last joined by and. */
303
298
  function spellCodes(codes) {
@@ -326,7 +321,7 @@ function readSeverity(document, label) {
326
321
  return undefined;
327
322
  }
328
323
  const severity = new Map();
329
- for (const code of Object.keys(object).sort()) {
324
+ for (const code of Object.keys(object).sort(bytewise)) {
330
325
  const path = `${SEVERITY_SECTION}.${code}`;
331
326
  if (!SEVERITY_KEY.test(code)) {
332
327
  throw unimplementedSeverityKey(label, path, "a severity key is one issue-kind code or one two-digit family prefix");
@@ -347,19 +342,10 @@ function readSeverity(document, label) {
347
342
  }
348
343
  return severity;
349
344
  }
350
- /** The exemption classes named for switching off. */
345
+ /** The exemption classes named for switching off, each one the vocabulary holds. */
351
346
  function readExemptions(document, label) {
352
347
  const exemptions = section(document, "exemptions", "exemptions", label);
353
- const disabled = readStrings(exemptions, "disabled", "exemptions.disabled", label, 0);
354
- if (disabled === undefined) {
355
- return undefined;
356
- }
357
- for (const entry of disabled) {
358
- if (!EXEMPTION_CLASS.test(entry)) {
359
- throw malformed(label, "exemptions.disabled", `${JSON.stringify(entry)} is not an exemption class name`);
360
- }
361
- }
362
- return disabled;
348
+ return readStrings(exemptions, "disabled", "exemptions.disabled", label, 0, EXEMPTION_CLASS_NAMES);
363
349
  }
364
350
  /** The members that name a declaration, each belonging to exactly one shape. */
365
351
  const SHAPE_MEMBERS = ["symbol", "module", "name", "global"];
@@ -577,7 +563,7 @@ function parseDocument(text, node, label) {
577
563
  value = JSON.parse(text);
578
564
  }
579
565
  catch (error) {
580
- throw malformed(label, "", error instanceof Error ? error.message : String(error));
566
+ throw malformed(label, "", message(error));
581
567
  }
582
568
  checkDocument(text, node, label);
583
569
  return value;
@@ -661,7 +647,7 @@ function settleSeverity(provenance, sources) {
661
647
  }
662
648
  }
663
649
  const severity = new Map();
664
- for (const code of [...codes].sort()) {
650
+ for (const code of [...codes].sort(bytewise)) {
665
651
  const path = `${SEVERITY_SECTION}.${code}`;
666
652
  for (const source of sources) {
667
653
  const value = source.doc.severity?.get(code);
@@ -697,7 +683,7 @@ function describeSource(named, text, label) {
697
683
  * print a provenance value the closed key list refuses to read back.
698
684
  */
699
685
  function checkLabels(provenance) {
700
- for (const path of [...provenance.keys()].sort()) {
686
+ for (const path of [...provenance.keys()].sort(bytewise)) {
701
687
  const origin = provenance.get(path);
702
688
  if (origin !== undefined && origin.source !== "default" && origin.label === "") {
703
689
  throw malformed(origin.source === "flag" ? FLAGS_LABEL : origin.source, path, `came from ${origin.source}, which names no file or flag`);
package/dist/src/roots.js CHANGED
@@ -13,13 +13,15 @@ import { isGlobalBlock } from "./augmentations.js";
13
13
  import { filesNamedBy, outsideChain, relativeSpecifiers, } from "./configuration-files.js";
14
14
  import { conventionEntries } from "./conventions.js";
15
15
  import { entryPoints } from "./entry-points.js";
16
- import { globExpression } from "./glob.js";
17
16
  import { nodeKey } from "./inventory.js";
18
- import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
17
+ import { ancestors, dirnamePath, relativePath, resolvePath } from "./paths.js";
19
18
  import { byPosition } from "./position.js";
20
19
  import { UNANSWERED } from "./query.js";
21
20
  import { sourceFilesOf } from "./source-files.js";
22
21
  import { typeQueryAliases } from "./type-query-alias.js";
22
+ import { bytewise } from "./text/compare.js";
23
+ import { holdsManifest } from "./fs/manifest.js";
24
+ import { globExpression } from "./text/glob.js";
23
25
  /** Whether one declaration is written below the directory of a published workspace member. */
24
26
  function inPublishedMember(held, id, root, members) {
25
27
  const path = held.symbols.find((symbol) => symbol.id === id)?.position.path;
@@ -47,13 +49,8 @@ const OUTPUT_EXTENSION = /\.(?:d\.ts|d\.mts|d\.cts|js|mjs|cjs|jsx)$/u;
47
49
  const SOURCE_EXTENSION = /\.(?:d\.)?[cm]?[jt]sx?$/u;
48
50
  /** Whether no `package.json` sits between one file and the manifest's directory, which holds it. */
49
51
  function ofPackage(host, dir, file) {
50
- for (let at = dirnamePath(file); at !== dir; at = dirnamePath(at)) {
51
- if (relativePath(dir, at) === undefined ||
52
- host.kindOf(joinPath(at, "package.json")) === "file") {
53
- return false;
54
- }
55
- }
56
- return true;
52
+ const between = ancestors(dirnamePath(file), dir);
53
+ return between.length > 0 && !between.slice(0, -1).some((at) => holdsManifest(host, at));
57
54
  }
58
55
  /**
59
56
  * The rooted files one manifest target reads back to by name: its path below the
@@ -163,13 +160,6 @@ export function matchRef(pattern, ref) {
163
160
  }
164
161
  return matchGlob(Array.from(pattern), Array.from(ref));
165
162
  }
166
- /** Two strings ordered bytewise, which is the order every set of a run is read in. */
167
- function compare(a, b) {
168
- if (a === b) {
169
- return 0;
170
- }
171
- return a < b ? -1 : 1;
172
- }
173
163
  /** The members of one declaration, indexed by the container that holds them. */
174
164
  function childrenOf(held) {
175
165
  const byParent = new Map();
@@ -344,7 +334,7 @@ export function roots(project, held, targetRoot, options) {
344
334
  const left = sites.get(a.id);
345
335
  const right = sites.get(b.id);
346
336
  const site = left === undefined || right === undefined ? 0 : byPosition(left, right);
347
- return site || compare(a.kind, b.kind) || compare(a.source, b.source);
337
+ return site || bytewise(a.kind, b.kind) || bytewise(a.source, b.source);
348
338
  });
349
339
  return {
350
340
  liveUnderReachability: ordered,
package/dist/src/run.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { EXIT_FAILURE, EXIT_USAGE } from "./contract/contract.generated.js";
1
2
  import { ConfigError, REPOSITORY_DOCUMENT } from "./config.js";
2
3
  import { DiscoveryError, renderDiagnostic } from "./discover.js";
3
4
  import { joinPath, resolvePath } from "./paths.js";
@@ -11,8 +12,9 @@ import { printRootsVerb } from "./verbs/print-roots.js";
11
12
  import { ANALYZE_OPTIONS, analyzeVerb } from "./verbs/analyze.js";
12
13
  import { describeVerb } from "./verbs/describe.js";
13
14
  import { EXPLAIN_OPTIONS, explainVerb } from "./verbs/explain.js";
14
- import { EXIT_FAILURE, EXIT_USAGE } from "./verbs/verb.js";
15
+ import {} from "./verbs/verb.js";
15
16
  import { versionVerb } from "./verbs/version.js";
17
+ import { diagnose, message, PRODUCT } from "./product.js";
16
18
  /** Every verb this command answers, in the order the usage text lists them. */
17
19
  const VERBS = [
18
20
  { name: "analyze", run: analyzeVerb, options: ANALYZE_OPTIONS },
@@ -24,7 +26,7 @@ const VERBS = [
24
26
  { name: "describe", run: describeVerb },
25
27
  { name: "version", run: versionVerb },
26
28
  ];
27
- const USAGE = `usage: deadset-ts <verb> [options]\nverbs: ${VERBS.map((verb) => verb.name).join(", ")}\n`;
29
+ const USAGE = `usage: ${PRODUCT} <verb> [options]\nverbs: ${VERBS.map((verb) => verb.name).join(", ")}\n`;
28
30
  /**
29
31
  * The tokens whose presence in an option's name makes that option a request to
30
32
  * edit a source file. The set is closed, and a token is matched in any position of
@@ -108,7 +110,7 @@ function readFileOr(host, path, orUndefined) {
108
110
  if (orUndefined) {
109
111
  return undefined;
110
112
  }
111
- throw new ConfigError("malformed", "", `${path}: ${error instanceof Error ? error.message : String(error)}`);
113
+ throw new ConfigError("malformed", "", `${path}: ${message(error)}`);
112
114
  }
113
115
  }
114
116
  /**
@@ -161,7 +163,7 @@ function scopeOf(host, options) {
161
163
  export function run(args, out, err, host, openClient = openEngine) {
162
164
  const editing = sourceEditOption(args);
163
165
  if (editing !== undefined) {
164
- err.write(`deadset-ts: ${editing} is not supported: deadset-ts reports and never edits a source file\n`);
166
+ diagnose(err, `${editing} is not supported: ${PRODUCT} reports and never edits a source file`);
165
167
  err.write(USAGE);
166
168
  return EXIT_USAGE;
167
169
  }
@@ -171,7 +173,7 @@ export function run(args, out, err, host, openClient = openEngine) {
171
173
  return invoke(verb.run, verb.options ?? NO_OPTIONS, args.slice(1), { out, err, host }, openClient);
172
174
  }
173
175
  if (name !== undefined) {
174
- err.write(`deadset-ts: unknown verb ${JSON.stringify(name)}\n`);
176
+ diagnose(err, `unknown verb ${JSON.stringify(name)}`);
175
177
  }
176
178
  err.write(USAGE);
177
179
  return EXIT_USAGE;
@@ -210,7 +212,7 @@ function invoke(verb, own, args, streams, openClient) {
210
212
  /** Turns one refusal into the exit code the Contract's table gives it. */
211
213
  function refuse(error, err) {
212
214
  if (error instanceof ConfigError) {
213
- err.write(`deadset-ts: ${error.message}\n`);
215
+ diagnose(err, error.message);
214
216
  err.write(USAGE);
215
217
  return EXIT_USAGE;
216
218
  }
@@ -218,7 +220,7 @@ function refuse(error, err) {
218
220
  for (const diagnostic of error.diagnostics) {
219
221
  err.write(`${renderDiagnostic(diagnostic)}\n`);
220
222
  }
221
- err.write(`deadset-ts: ${error.message}\n`);
223
+ diagnose(err, error.message);
222
224
  return EXIT_FAILURE;
223
225
  }
224
226
  if (error instanceof SetupError) {
@@ -228,7 +230,7 @@ function refuse(error, err) {
228
230
  return EXIT_FAILURE;
229
231
  }
230
232
  if (error instanceof ScopeError) {
231
- err.write(`deadset-ts: ${error.message}\n`);
233
+ diagnose(err, error.message);
232
234
  return EXIT_FAILURE;
233
235
  }
234
236
  throw error;
@@ -1,4 +1,5 @@
1
1
  import { ConfigError } from "./config.js";
2
+ import { bytewise } from "./text/compare.js";
2
3
  const leaf = { kind: "leaf" };
3
4
  const integer = { kind: "leaf", integer: true };
4
5
  /** A list of declarations, each entry in one of the three shapes the `ts` section states. */
@@ -128,7 +129,7 @@ function collect(node, at, keys, settingsOnly) {
128
129
  export function declaredKeys() {
129
130
  const keys = [];
130
131
  collect(SCHEMA_ROOT, "", keys, false);
131
- return keys.sort();
132
+ return keys.sort(bytewise);
132
133
  }
133
134
  /**
134
135
  * The dotted path of every setting that holds one value, in ascending order. A
@@ -139,7 +140,7 @@ export function declaredKeys() {
139
140
  export function settingPaths() {
140
141
  const paths = [];
141
142
  collect(SCHEMA_ROOT, "", paths, true);
142
- return paths.sort();
143
+ return paths.sort(bytewise);
143
144
  }
144
145
  /**
145
146
  * Whether one dotted path names a setting a source may supply: a setting of the
@@ -373,7 +374,7 @@ export function checkDocument(text, node, label) {
373
374
  */
374
375
  export function nestFlags(flat, label) {
375
376
  const nested = {};
376
- for (const path of Object.keys(flat).sort()) {
377
+ for (const path of Object.keys(flat).sort(bytewise)) {
377
378
  if (!declaresSetting(path)) {
378
379
  throw unimplementedKey(label, path);
379
380
  }
package/dist/src/scope.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { ConfigError } from "./config.js";
2
2
  import { dirnamePath, isAbsolutePath, joinPath, resolvePath } from "./paths.js";
3
3
  import { checkDocument } from "./schema.js";
4
+ import { isRecord } from "./json-document.js";
5
+ import { message } from "./product.js";
4
6
  /** The roles a scope document declares for a module. */
5
7
  const ROLE_TARGET = "target";
6
8
  const ROLE_CONSUMER = "consumer";
@@ -32,9 +34,6 @@ const SCOPE_ROOT = {
32
34
  consumers: { kind: "list", members: MODULE.members ?? {} },
33
35
  },
34
36
  };
35
- function isRecord(value) {
36
- return typeof value === "object" && value !== null && !Array.isArray(value);
37
- }
38
37
  /**
39
38
  * One string member, or undefined where the document omits it. A member the
40
39
  * document writes is a string holding at least one character, so `null` and `""`
@@ -107,7 +106,7 @@ export function readScope(host, file) {
107
106
  text = host.readFile(absolute);
108
107
  }
109
108
  catch (error) {
110
- throw new ScopeError(`scope: ${file}: ${error instanceof Error ? error.message : String(error)}`);
109
+ throw new ScopeError(`scope: ${file}: ${message(error)}`);
111
110
  }
112
111
  if (text.length > MAX_DOCUMENT_LENGTH) {
113
112
  throw new ScopeError(`scope: ${file} is longer than ${String(MAX_DOCUMENT_LENGTH)} characters`);
@@ -117,7 +116,7 @@ export function readScope(host, file) {
117
116
  value = JSON.parse(text);
118
117
  }
119
118
  catch (error) {
120
- throw new ScopeError(`scope: ${file}: ${error instanceof Error ? error.message : String(error)}`);
119
+ throw new ScopeError(`scope: ${file}: ${message(error)}`);
121
120
  }
122
121
  if (!isRecord(value)) {
123
122
  throw new ScopeError(`scope: ${file} is not one JSON object`);
@@ -7,6 +7,7 @@
7
7
  * function invoked through `call`, `apply` or `bind` is the callee.
8
8
  */
9
9
  import { isArrayLiteralExpression, isArrowFunction, isAsExpression, isAwaitExpression, isCallExpression, isClassDeclaration, isClassExpression, isClassStaticBlockDeclaration, isElementAccessExpression, isExpressionStatement, isFunctionDeclaration, isFunctionExpression, isFunctionLikeDeclaration, isGetAccessorDeclaration, isIdentifier, isInterfaceDeclaration, isMethodDeclaration, isNonNullExpression, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isParenthesizedExpression, isForInStatement, isPropertyAccessExpression, isPropertyDeclaration, isReturnStatement, isSatisfiesExpression, isSetAccessorDeclaration, isSourceFile, isSpreadAssignment, isSpreadElement, isStringLiteral, isTypeAssertion, isTypeLiteralNode, isVariableDeclaration, ModifierFlags, NodeFlags, SyntaxKind, } from "@typescript/native/ast";
10
+ import { parenthesesRemoved } from "./unwrap.js";
10
11
  import { SignatureKind, SymbolFlags, TypeFlags, } from "@typescript/native/sync";
11
12
  import { aliasChains } from "./alias-chain.js";
12
13
  import { calleeName, resolvedTargets, valuesPassed } from "./calls.js";
@@ -88,11 +89,6 @@ const FUNCTION_INTERFACES = new Set([
88
89
  "CallableFunction",
89
90
  "NewableFunction",
90
91
  ]);
91
- function unparenthesized(expression) {
92
- return isParenthesizedExpression(expression)
93
- ? unparenthesized(expression.expression)
94
- : expression;
95
- }
96
92
  /**
97
93
  * The invocation a call writes through a method of `Function.prototype`, read from
98
94
  * the syntax alone: `f.call(self, a)`, `f.apply(self, [a])`, `f.bind(self, a)`, which
@@ -101,12 +97,12 @@ function unparenthesized(expression) {
101
97
  * carries. Whether the method is the prototype's is resolution's to say.
102
98
  */
103
99
  function throughMethod(call) {
104
- const expression = unparenthesized(call.expression);
100
+ const expression = parenthesesRemoved(call.expression);
105
101
  if (isPropertyAccessExpression(expression) && FUNCTION_METHODS.has(expression.name.text)) {
106
102
  const [, ...rest] = call.arguments;
107
103
  let passed = rest;
108
104
  if (expression.name.text === "apply") {
109
- const list = rest[0] === undefined ? undefined : unparenthesized(rest[0]);
105
+ const list = rest[0] === undefined ? undefined : parenthesesRemoved(rest[0]);
110
106
  passed = list === undefined ? [] : isArrayLiteralExpression(list) ? list.elements : [list];
111
107
  }
112
108
  return {
@@ -115,7 +111,7 @@ function throughMethod(call) {
115
111
  };
116
112
  }
117
113
  if (isCallExpression(expression)) {
118
- const bound = unparenthesized(expression.expression);
114
+ const bound = parenthesesRemoved(expression.expression);
119
115
  if (isPropertyAccessExpression(bound) && bound.name.text === "bind") {
120
116
  return {
121
117
  method: bound.name,
@@ -3,6 +3,7 @@ import { componentLayer, mapperManifest } from "./component-layer.js";
3
3
  import { DiscoveryError } from "./discover.js";
4
4
  import { joinPath } from "./paths.js";
5
5
  import { queriesOf, UnansweredLog, } from "./query.js";
6
+ import { MANIFEST } from "./fs/manifest.js";
6
7
  /**
7
8
  * Opens the compiler client the analysis reads through.
8
9
  *
@@ -16,7 +17,7 @@ export function openEngine(options) {
16
17
  if (components !== undefined && components.extensions.length > 0) {
17
18
  const made = components.host.temporaryDirectory();
18
19
  try {
19
- components.host.writeDocument(joinPath(made.path, "package.json"), [
20
+ components.host.writeDocument(joinPath(made.path, MANIFEST), [
20
21
  mapperManifest(components.host.componentMapperCommand()),
21
22
  ]);
22
23
  }
@@ -1,11 +1,7 @@
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
- */
1
+ import { SETUP_FAILURE_PREFIX } from "./contract/contract.generated.js";
6
2
  /** The failure as the one line of the error stream that names it. */
7
3
  export function setupLine(failure) {
8
- return `setup failure: ${failure.setupClass}: ${failure.detail}`;
4
+ return `${SETUP_FAILURE_PREFIX}${failure.setupClass}: ${failure.detail}`;
9
5
  }
10
6
  /**
11
7
  * A run that met a setup failure where none may be dropped: in a configuration the
@@ -4,11 +4,13 @@
4
4
  * one record shape, so one decoder and one matcher serve both, and a row moves into the
5
5
  * ignore file by gaining a maintainer's reason.
6
6
  */
7
+ import { CODE } from "./contract/contract.generated.js";
7
8
  import { jsonChunks } from "./json-chunks.js";
8
9
  import { joinPath } from "./paths.js";
9
- import { positionAt, walkDocument } from "./json-document.js";
10
+ import { isRecord, positionAt, walkDocument } from "./json-document.js";
10
11
  import { declarationKey } from "./ref.js";
11
- import { CODE_FORM, SUPPRESSION_WITHOUT_REASON, SuppressionError, UNSCOPED_ENTRY, blankReason, isEntryPath, isPartKind, isSymbolRef, siteText, } from "./suppress.js";
12
+ import { CODE_FORM, SuppressionError, blankReason, isEntryPath, isPartKind, isSymbolRef, siteText, } from "./suppress.js";
13
+ import { message } from "./product.js";
12
14
  /** The name and the location the grammar fixes for the ignore file. */
13
15
  export const IGNORE_FILE = "deadset-ignore.json";
14
16
  /** The name and the location the grammar fixes for the baseline. */
@@ -42,9 +44,6 @@ const PATH_WANT = "a path relative to the target root, with the solidus as separ
42
44
  function documentSite(shape) {
43
45
  return { path: shape.file, line: 0, column: 0 };
44
46
  }
45
- function isObject(value) {
46
- return typeof value === "object" && value !== null && !Array.isArray(value);
47
- }
48
47
  /**
49
48
  * Reads one entry or row: the records it binds, the refusals it carries, or the
50
49
  * malformed value that ends the run.
@@ -53,7 +52,7 @@ function readRecord(value, site, byReference, shape) {
53
52
  const refuse = (text, want) => {
54
53
  throw new SuppressionError(shape.mechanism, siteText(site), text, want);
55
54
  };
56
- if (!isObject(value)) {
55
+ if (!isRecord(value)) {
57
56
  return refuse(JSON.stringify(value), shape.recordWant);
58
57
  }
59
58
  for (const [key, held] of Object.entries(value)) {
@@ -99,10 +98,10 @@ function readRecord(value, site, byReference, shape) {
99
98
  };
100
99
  const refusals = [];
101
100
  if (blankReason(reason)) {
102
- refusals.push({ ...written, reported: SUPPRESSION_WITHOUT_REASON });
101
+ refusals.push({ ...written, reported: CODE.suppressionWithoutReason });
103
102
  }
104
103
  if (written.path === "") {
105
- refusals.push({ ...written, reported: UNSCOPED_ENTRY });
104
+ refusals.push({ ...written, reported: CODE.unscopedIgnoreEntry });
106
105
  }
107
106
  if (refusals.length > 0) {
108
107
  return { records: [], refusals };
@@ -144,9 +143,9 @@ function readDocument(host, targetRoot, symbols, shape) {
144
143
  parsed = JSON.parse(text);
145
144
  }
146
145
  catch (error) {
147
- return malformed(`${shape.file}: ${error instanceof Error ? error.message : String(error)}`);
146
+ return malformed(`${shape.file}: ${message(error)}`);
148
147
  }
149
- if (!isObject(parsed)) {
148
+ if (!isRecord(parsed)) {
150
149
  return malformed(shape.file);
151
150
  }
152
151
  const walk = walkDocument(text, shape.array);
@@ -227,9 +226,9 @@ export function otherSchemeRows(text, own = OWN_SCHEME) {
227
226
  parsed = JSON.parse(text);
228
227
  }
229
228
  catch (error) {
230
- return refuse(error instanceof Error ? error.message : String(error));
229
+ return refuse(message(error));
231
230
  }
232
- const held = isObject(parsed) ? parsed[BASELINE_SHAPE.array] : undefined;
231
+ const held = isRecord(parsed) ? parsed[BASELINE_SHAPE.array] : undefined;
233
232
  if (!Array.isArray(held)) {
234
233
  return refuse(BASELINE_SHAPE.documentWant);
235
234
  }
@@ -238,7 +237,7 @@ export function otherSchemeRows(text, own = OWN_SCHEME) {
238
237
  readRecord(value, documentSite(BASELINE_SHAPE), new Map(), BASELINE_SHAPE);
239
238
  }
240
239
  catch (error) {
241
- return refuse(error instanceof Error ? error.message : String(error));
240
+ return refuse(message(error));
242
241
  }
243
242
  // readRecord has checked every member is a string and the code and symbol are present.
244
243
  const { code, symbol, path, reason } = value;
@@ -3,13 +3,14 @@
3
3
  * one or more codes and a reason, and binding to every declaration that begins on the line
4
4
  * below it, or on its own line where it trails a token there.
5
5
  */
6
+ import { CODE } from "./contract/contract.generated.js";
6
7
  import { isConstructorDeclaration, SyntaxKind, } from "@typescript/native/ast";
7
8
  import { importBindings } from "./import-bindings.js";
8
9
  import { isParameterProperty, nodeKey } from "./inventory.js";
9
10
  import { byPosition, positionKey, renderPosition } from "./position.js";
10
11
  import { importRef } from "./ref.js";
11
12
  import { signatureOf } from "./signatures.js";
12
- import { isPartKind, SUPPRESSION_WITHOUT_REASON, SuppressionError, siteText, } from "./suppress.js";
13
+ import { isPartKind, SuppressionError, siteText, } from "./suppress.js";
13
14
  /**
14
15
  * The three expressions the grammar applies to the text of each line comment, in this
15
16
  * order: a comment in the namespace, a well-formed directive, and a directive that lacks
@@ -274,7 +275,7 @@ export function inlineSuppressions(perProject) {
274
275
  case "no-reason":
275
276
  for (const code of directive.codes) {
276
277
  refusals.push({
277
- reported: SUPPRESSION_WITHOUT_REASON,
278
+ reported: CODE.suppressionWithoutReason,
278
279
  code,
279
280
  symbol: "",
280
281
  path: site.path,