@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.
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +3 -2
- package/dist/src/analysis.js +28 -46
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +17 -29
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +2 -3
- package/dist/src/config.js +3 -2
- package/dist/src/configuration-files.js +27 -168
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/contract/contract.generated.js +1084 -0
- package/dist/src/contract/report.generated.js +796 -0
- package/dist/src/conventions.js +20 -60
- package/dist/src/dependencies.js +25 -43
- package/dist/src/discover.js +13 -39
- package/dist/src/edges.js +7 -15
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +2 -8
- package/dist/src/entry-points.js +3 -10
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +3 -63
- package/dist/src/exempt.js +13 -40
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +11 -20
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +4 -4
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +8 -7
- package/dist/src/findings/non-code-artifacts.js +5 -6
- package/dist/src/findings/reads-and-writes.js +11 -9
- package/dist/src/findings/self-check.js +10 -12
- package/dist/src/findings/unused-declarations.js +28 -27
- package/dist/src/findings/visibility-narrowing.js +9 -11
- package/dist/src/findings-pass.js +7 -14
- package/dist/src/fs/manifest.js +43 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/git-ignore.js +34 -25
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/intra-function-parts.js +18 -26
- package/dist/src/inventory.js +2 -21
- package/dist/src/json-document.js +4 -0
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +4 -360
- package/dist/src/manifest.js +5 -43
- package/dist/src/mdx-entries.js +3 -26
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +3 -2
- package/dist/src/product.js +13 -0
- package/dist/src/references.js +14 -27
- package/dist/src/report-schema.js +272 -0
- package/dist/src/report.js +39 -42
- package/dist/src/reporters/sarif.js +4 -2
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +12 -26
- package/dist/src/roots.js +7 -17
- package/dist/src/run.js +10 -8
- package/dist/src/schema.js +4 -3
- package/dist/src/scope.js +4 -5
- package/dist/src/serialization-contract.js +4 -8
- package/dist/src/session.js +2 -1
- package/dist/src/setup-failure.js +2 -6
- package/dist/src/suppress-file.js +12 -13
- package/dist/src/suppress-inline.js +3 -2
- package/dist/src/suppress.js +29 -48
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +5 -15
- package/dist/src/test-globals.js +6 -28
- package/dist/src/test-joins.js +6 -6
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/{yaml-document.js → text/yaml.js} +38 -0
- package/dist/src/type-errors.js +14 -38
- package/dist/src/unseen-loads.js +2 -9
- package/dist/src/unwrap.js +23 -0
- package/dist/src/verbs/analyze.js +22 -15
- package/dist/src/verbs/describe.js +7 -7
- package/dist/src/verbs/explain.js +7 -4
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +4 -2
- package/dist/src/verbs/print-retained.js +4 -2
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +4 -3
- package/dist/src/workflow-steps.js +9 -46
- package/dist/src/workspace-manifests.js +2 -2
- package/dist/src/workspace-programs.js +5 -3
- package/dist/src/workspace-resolution.js +13 -17
- package/dist/src/workspace.js +28 -116
- package/jsr.json +1 -1
- package/package.json +2 -1
- package/src/analysis.ts +29 -54
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +17 -38
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +11 -15
- package/src/configuration-files.ts +27 -170
- package/src/conformance-record.ts +1 -1
- package/src/contract/contract.generated.ts +1148 -0
- package/src/contract/report.generated.ts +1157 -0
- package/src/conventions.ts +26 -74
- package/src/dependencies.ts +32 -50
- package/src/discover.ts +14 -39
- package/src/edges.ts +7 -21
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +3 -9
- package/src/entry-points.ts +2 -13
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +5 -74
- package/src/exempt.ts +17 -47
- package/src/file-facts.ts +6 -24
- package/src/finding.ts +9 -9
- package/src/findings/completion.ts +22 -23
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +6 -7
- package/src/findings/emitters.ts +6 -6
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +8 -8
- package/src/findings/non-code-artifacts.ts +5 -7
- package/src/findings/reads-and-writes.ts +15 -12
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +28 -27
- package/src/findings/visibility-narrowing.ts +9 -12
- package/src/findings-pass.ts +7 -16
- package/src/fs/manifest.ts +52 -0
- package/src/fs/tree.ts +110 -0
- package/src/git-ignore.ts +38 -25
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/intra-function-parts.ts +18 -28
- package/src/inventory.ts +2 -20
- package/src/json-document.ts +5 -0
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +6 -406
- package/src/manifest.ts +5 -46
- package/src/mdx-entries.ts +3 -26
- package/src/partial.ts +2 -1
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +3 -2
- package/src/product.ts +18 -0
- package/src/references.ts +14 -29
- package/src/report-schema.ts +364 -0
- package/src/report.ts +66 -229
- package/src/reporters/annotations.ts +2 -2
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -2
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +17 -12
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +31 -38
- package/src/roots.ts +7 -20
- package/src/run.ts +10 -14
- package/src/schema.ts +4 -3
- package/src/scope.ts +4 -10
- package/src/serialization-contract.ts +4 -9
- package/src/session.ts +2 -1
- package/src/setup-failure.ts +5 -7
- package/src/suppress-file.ts +11 -15
- package/src/suppress-inline.ts +2 -2
- package/src/suppress.ts +39 -55
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +5 -18
- package/src/test-globals.ts +9 -27
- package/src/test-joins.ts +6 -8
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/shell.ts +161 -0
- package/src/{yaml-document.ts → text/yaml.ts} +46 -0
- package/src/type-errors.ts +25 -36
- package/src/unseen-loads.ts +1 -12
- package/src/unwrap.ts +34 -0
- package/src/verbs/analyze.ts +38 -25
- package/src/verbs/describe.ts +13 -7
- package/src/verbs/explain.ts +7 -4
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +4 -2
- package/src/verbs/print-retained.ts +4 -2
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +0 -6
- package/src/verbs/version.ts +4 -3
- package/src/workflow-steps.ts +9 -44
- package/src/workspace-manifests.ts +2 -2
- package/src/workspace-programs.ts +5 -3
- package/src/workspace-resolution.ts +21 -17
- package/src/workspace.ts +35 -121
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/version.js +0 -7
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
- 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
|
|
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 {
|
package/dist/src/resolve.js
CHANGED
|
@@ -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
|
-
|
|
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, "",
|
|
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 {
|
|
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
|
-
|
|
51
|
-
|
|
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 ||
|
|
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 {
|
|
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:
|
|
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}: ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
233
|
+
diagnose(err, error.message);
|
|
232
234
|
return EXIT_FAILURE;
|
|
233
235
|
}
|
|
234
236
|
throw error;
|
package/dist/src/schema.js
CHANGED
|
@@ -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}: ${
|
|
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}: ${
|
|
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 =
|
|
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 :
|
|
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 =
|
|
114
|
+
const bound = parenthesesRemoved(expression.expression);
|
|
119
115
|
if (isPropertyAccessExpression(bound) && bound.name.text === "bind") {
|
|
120
116
|
return {
|
|
121
117
|
method: bound.name,
|
package/dist/src/session.js
CHANGED
|
@@ -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,
|
|
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
|
|
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,
|
|
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 (!
|
|
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:
|
|
101
|
+
refusals.push({ ...written, reported: CODE.suppressionWithoutReason });
|
|
103
102
|
}
|
|
104
103
|
if (written.path === "") {
|
|
105
|
-
refusals.push({ ...written, reported:
|
|
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}: ${
|
|
146
|
+
return malformed(`${shape.file}: ${message(error)}`);
|
|
148
147
|
}
|
|
149
|
-
if (!
|
|
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(
|
|
229
|
+
return refuse(message(error));
|
|
231
230
|
}
|
|
232
|
-
const held =
|
|
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(
|
|
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,
|
|
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:
|
|
278
|
+
reported: CODE.suppressionWithoutReason,
|
|
278
279
|
code,
|
|
279
280
|
symbol: "",
|
|
280
281
|
path: site.path,
|