@cplieger/deadset-ts 8.0.0-dev.6 → 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 +25 -43
- 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 +2 -1
- package/dist/src/configuration-files.js +27 -168
- package/dist/src/contract/contract.generated.js +13 -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 +2 -4
- package/dist/src/exempt.js +6 -22
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/reads-and-writes.js +2 -1
- package/dist/src/findings/self-check.js +3 -2
- package/dist/src/findings-pass.js +6 -11
- 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/intra-function-parts.js +10 -13
- 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/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 +15 -16
- package/dist/src/report.js +22 -31
- package/dist/src/reporters/sarif.js +4 -2
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +11 -20
- package/dist/src/roots.js +7 -17
- package/dist/src/run.js +8 -7
- 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/suppress-file.js +8 -10
- 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 +15 -13
- package/dist/src/verbs/describe.js +4 -4
- package/dist/src/verbs/explain.js +5 -3
- package/dist/src/verbs/print-projects.js +2 -1
- package/dist/src/verbs/print-retained.js +2 -1
- package/dist/src/verbs/print-roots.js +2 -1
- package/dist/src/verbs/version.js +2 -1
- 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 +1 -1
- package/src/analysis.ts +26 -51
- 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 +4 -2
- package/src/configuration-files.ts +27 -170
- package/src/contract/contract.generated.ts +25 -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 +4 -4
- package/src/exempt.ts +5 -27
- package/src/file-facts.ts +6 -24
- package/src/findings/reads-and-writes.ts +2 -1
- package/src/findings/self-check.ts +3 -2
- package/src/findings-pass.ts +6 -12
- 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/intra-function-parts.ts +10 -14
- package/src/inventory.ts +2 -20
- package/src/json-document.ts +5 -0
- package/src/keyof-comparisons.ts +3 -7
- 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 +15 -17
- package/src/report.ts +24 -34
- package/src/reporters/sarif.ts +4 -4
- package/src/reporters/template.ts +4 -20
- package/src/resolve.ts +20 -27
- package/src/roots.ts +7 -20
- package/src/run.ts +8 -13
- 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/suppress-file.ts +8 -11
- 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 +22 -21
- package/src/verbs/describe.ts +4 -4
- package/src/verbs/explain.ts +5 -3
- package/src/verbs/print-projects.ts +2 -1
- package/src/verbs/print-retained.ts +2 -1
- package/src/verbs/print-roots.ts +2 -1
- package/src/verbs/version.ts +2 -1
- 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/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
package/dist/src/references.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isDecorator, isDeleteExpression, isElementAccessExpression, isExportDeclaration, isExpressionStatement, isExternalModuleReference, isForInStatement, isForOfStatement, isForStatement, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isInterfaceDeclaration, isMetaProperty, isModuleBlock, isModuleDeclaration, isNewExpression, isNamespaceExport, isNoSubstitutionTemplateLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, isStringLiteral, isVoidExpression, SyntaxKind, } from "@typescript/native/ast";
|
|
2
|
+
import { parenthesesRemoved } from "./unwrap.js";
|
|
2
3
|
import { aliasChains } from "./alias-chain.js";
|
|
3
4
|
import { contextualUses } from "./contextual-uses.js";
|
|
4
5
|
import { destructuring, propertyReadsOf } from "./destructuring.js";
|
|
5
6
|
import { specifierCandidates } from "./configuration-files.js";
|
|
6
7
|
import { namespaceUses } from "./namespace-objects.js";
|
|
7
|
-
import { globExpression } from "./glob.js";
|
|
8
8
|
import { declarationsByName, isParameterProperty, nodeKey, } from "./inventory.js";
|
|
9
9
|
import { ambientGlobalInterfaces, augmentationReferences } from "./augmentations.js";
|
|
10
10
|
import { elementAccessReferences } from "./element-access.js";
|
|
@@ -20,6 +20,8 @@ import { typeParameterReads } from "./type-parameter-reads.js";
|
|
|
20
20
|
import { typeQueryAliases } from "./type-query-alias.js";
|
|
21
21
|
import { computedKeyNames, iterationReferences, keyNameOf, keyedUses, } from "./symbol-keys.js";
|
|
22
22
|
import { handedOn, valuesOf } from "./value-flow.js";
|
|
23
|
+
import { bytewise } from "./text/compare.js";
|
|
24
|
+
import { globExpression } from "./text/glob.js";
|
|
23
25
|
/**
|
|
24
26
|
* The operators whose left side one assignment stores into. A compound assignment is
|
|
25
27
|
* among them: where its value is discarded it reads its target only to write the result
|
|
@@ -77,14 +79,6 @@ function valueDiscarded(node) {
|
|
|
77
79
|
function isName(node) {
|
|
78
80
|
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
|
|
79
81
|
}
|
|
80
|
-
/** The expression one node is, through however many parentheses are written around it. */
|
|
81
|
-
function unparenthesized(node) {
|
|
82
|
-
let held = node;
|
|
83
|
-
while (isParenthesizedExpression(held)) {
|
|
84
|
-
held = held.expression;
|
|
85
|
-
}
|
|
86
|
-
return held;
|
|
87
|
-
}
|
|
88
82
|
/**
|
|
89
83
|
* Records the name one store writes into.
|
|
90
84
|
*
|
|
@@ -94,7 +88,7 @@ function unparenthesized(node) {
|
|
|
94
88
|
* target writes each name it binds, through its spreads and nested patterns.
|
|
95
89
|
*/
|
|
96
90
|
function markWrite(target, writes, accesses) {
|
|
97
|
-
const held =
|
|
91
|
+
const held = parenthesesRemoved(target);
|
|
98
92
|
if (isName(held)) {
|
|
99
93
|
writes.add(held.pos);
|
|
100
94
|
return;
|
|
@@ -109,7 +103,7 @@ function markWrite(target, writes, accesses) {
|
|
|
109
103
|
accesses.add(held);
|
|
110
104
|
// A store through a member's value lands in storage every holder of the value
|
|
111
105
|
// reads, so it reads the member; a variable only ever stored into stays written.
|
|
112
|
-
if (!isPropertyAccessExpression(
|
|
106
|
+
if (!isPropertyAccessExpression(parenthesesRemoved(held.expression))) {
|
|
113
107
|
markWrite(held.expression, writes, accesses);
|
|
114
108
|
}
|
|
115
109
|
return;
|
|
@@ -181,7 +175,7 @@ function markStores(node, writes, reads, accesses) {
|
|
|
181
175
|
}
|
|
182
176
|
/** Whether one node is `import.meta.url`. */
|
|
183
177
|
function isImportMetaURL(node) {
|
|
184
|
-
const at =
|
|
178
|
+
const at = parenthesesRemoved(node);
|
|
185
179
|
return (isPropertyAccessExpression(at) &&
|
|
186
180
|
isMetaProperty(at.expression) &&
|
|
187
181
|
at.expression.keywordToken === SyntaxKind.ImportKeyword &&
|
|
@@ -190,7 +184,7 @@ function isImportMetaURL(node) {
|
|
|
190
184
|
/** The module URL one node builds, where it builds one. */
|
|
191
185
|
function moduleURLOf(node) {
|
|
192
186
|
const relative = (argument) => {
|
|
193
|
-
const at = argument === undefined ? undefined :
|
|
187
|
+
const at = argument === undefined ? undefined : parenthesesRemoved(argument);
|
|
194
188
|
return at !== undefined &&
|
|
195
189
|
(isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at)) &&
|
|
196
190
|
/^\.\.?\//u.test(at.text)
|
|
@@ -205,7 +199,7 @@ function moduleURLOf(node) {
|
|
|
205
199
|
: undefined;
|
|
206
200
|
}
|
|
207
201
|
if (isCallExpression(node)) {
|
|
208
|
-
const callee =
|
|
202
|
+
const callee = parenthesesRemoved(node.expression);
|
|
209
203
|
const specifier = relative(node.arguments[0]);
|
|
210
204
|
if (specifier !== undefined &&
|
|
211
205
|
isPropertyAccessExpression(callee) &&
|
|
@@ -490,7 +484,7 @@ export function testFileRulesOf(testFiles, paths, supportFiles = []) {
|
|
|
490
484
|
};
|
|
491
485
|
}),
|
|
492
486
|
...(support === 0 ? [] : [{ rule: TEST_SUPPORT_RULE, matched: support }]),
|
|
493
|
-
].sort((a, b) =>
|
|
487
|
+
].sort((a, b) => bytewise(a.rule, b.rule));
|
|
494
488
|
}
|
|
495
489
|
const importedCache = new WeakMap();
|
|
496
490
|
/**
|
|
@@ -609,20 +603,13 @@ function aloneIn(file, uses, writes, found) {
|
|
|
609
603
|
.filter(([, nodes]) => nodes.some((node) => inside(node, write.value)) &&
|
|
610
604
|
nodes.every((node) => sameTarget.some((one) => inside(node, one.value))))
|
|
611
605
|
.map(([name]) => name)
|
|
612
|
-
.sort(
|
|
606
|
+
.sort(bytewise);
|
|
613
607
|
if (names.length > 0) {
|
|
614
608
|
result.push({ index: write.index, names });
|
|
615
609
|
}
|
|
616
610
|
}
|
|
617
611
|
return result;
|
|
618
612
|
}
|
|
619
|
-
/** Two strings ordered bytewise, which is the order every set of a run is read in. */
|
|
620
|
-
function compare(a, b) {
|
|
621
|
-
if (a === b) {
|
|
622
|
-
return 0;
|
|
623
|
-
}
|
|
624
|
-
return a < b ? -1 : 1;
|
|
625
|
-
}
|
|
626
613
|
/**
|
|
627
614
|
* Every reference one project's own files make to the project's own declarations, in
|
|
628
615
|
* position order, and the files the test-file rules classified.
|
|
@@ -1192,14 +1179,14 @@ export function references(project, held, targetRoot, options) {
|
|
|
1192
1179
|
const scripts = new Set(walked.filter((one) => one.file.externalModuleIndicator === undefined).map((one) => one.fileId));
|
|
1193
1180
|
found.push(...augmentationReferences(held, found, scripts, libraryMerged(scripts)));
|
|
1194
1181
|
found.sort((a, b) => byPosition(a.position, b.position) ||
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1182
|
+
bytewise(a.to, b.to) ||
|
|
1183
|
+
bytewise(a.from, b.from) ||
|
|
1184
|
+
bytewise(a.use, b.use));
|
|
1198
1185
|
return {
|
|
1199
1186
|
references: consumer === undefined
|
|
1200
1187
|
? found
|
|
1201
1188
|
: found.map((reference) => ({ ...reference, consumer: consumer.id })),
|
|
1202
|
-
testFilePaths: tests.sort(
|
|
1189
|
+
testFilePaths: tests.sort(bytewise),
|
|
1203
1190
|
cost: {
|
|
1204
1191
|
batched,
|
|
1205
1192
|
fileBatches,
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* ECMAScript.
|
|
7
7
|
*/
|
|
8
8
|
import { REPORT_SCHEMAS } from "./contract/report.generated.js";
|
|
9
|
+
import { bytewise } from "./text/compare.js";
|
|
10
|
+
import { isRecord } from "./json-document.js";
|
|
9
11
|
/**
|
|
10
12
|
* Every keyword the validator evaluates or knows to carry no assertion. A schema naming
|
|
11
13
|
* another fails every check rather than passing values the keyword would refuse.
|
|
@@ -26,9 +28,6 @@ function pattern(source) {
|
|
|
26
28
|
}
|
|
27
29
|
return held;
|
|
28
30
|
}
|
|
29
|
-
function isObject(value) {
|
|
30
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
31
|
-
}
|
|
32
31
|
function typeOf(value) {
|
|
33
32
|
if (value === null) {
|
|
34
33
|
return "null";
|
|
@@ -50,9 +49,9 @@ function canonical(value) {
|
|
|
50
49
|
if (Array.isArray(value)) {
|
|
51
50
|
return `[${value.map(canonical).join(",")}]`;
|
|
52
51
|
}
|
|
53
|
-
if (
|
|
52
|
+
if (isRecord(value)) {
|
|
54
53
|
return `{${Object.keys(value)
|
|
55
|
-
.sort()
|
|
54
|
+
.sort(bytewise)
|
|
56
55
|
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
57
56
|
.join(",")}}`;
|
|
58
57
|
}
|
|
@@ -78,11 +77,11 @@ class Checker {
|
|
|
78
77
|
const target = file === "" ? doc : file;
|
|
79
78
|
let schema = this.documents[target];
|
|
80
79
|
for (const token of pointer.split("/").filter((one) => one !== "")) {
|
|
81
|
-
schema =
|
|
80
|
+
schema = isRecord(schema)
|
|
82
81
|
? schema[token.replaceAll("~1", "/").replaceAll("~0", "~")]
|
|
83
82
|
: undefined;
|
|
84
83
|
}
|
|
85
|
-
if (!
|
|
84
|
+
if (!isRecord(schema)) {
|
|
86
85
|
throw new Error(`report schema: ${ref} names no schema`);
|
|
87
86
|
}
|
|
88
87
|
return [target, schema];
|
|
@@ -115,7 +114,7 @@ class Checker {
|
|
|
115
114
|
if (Array.isArray(value)) {
|
|
116
115
|
this.checkArray(doc, schema, value, at, found, refuse);
|
|
117
116
|
}
|
|
118
|
-
else if (
|
|
117
|
+
else if (isRecord(value)) {
|
|
119
118
|
this.checkObject(doc, schema, value, at, found, refuse);
|
|
120
119
|
}
|
|
121
120
|
this.checkApplicators(doc, schema, value, at, found, refuse);
|
|
@@ -146,18 +145,18 @@ class Checker {
|
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
checkObject(doc, schema, value, at, found, refuse) {
|
|
149
|
-
const properties =
|
|
148
|
+
const properties = isRecord(schema["properties"]) ? schema["properties"] : {};
|
|
150
149
|
const additional = schema["additionalProperties"];
|
|
151
|
-
for (const name of Object.keys(value).sort()) {
|
|
150
|
+
for (const name of Object.keys(value).sort(bytewise)) {
|
|
152
151
|
const member = `${at}/${escape(name)}`;
|
|
153
152
|
const declared = properties[name];
|
|
154
|
-
if (
|
|
153
|
+
if (isRecord(declared)) {
|
|
155
154
|
this.check(doc, declared, value[name], member, found);
|
|
156
155
|
}
|
|
157
156
|
else if (additional === false) {
|
|
158
157
|
refuse("additionalProperties", `the member ${JSON.stringify(name)} is not one the schema declares`);
|
|
159
158
|
}
|
|
160
|
-
else if (
|
|
159
|
+
else if (isRecord(additional)) {
|
|
161
160
|
this.check(doc, additional, value[name], member, found);
|
|
162
161
|
}
|
|
163
162
|
}
|
|
@@ -173,7 +172,7 @@ class Checker {
|
|
|
173
172
|
}
|
|
174
173
|
checkArray(doc, schema, value, at, found, refuse) {
|
|
175
174
|
const items = schema["items"];
|
|
176
|
-
if (
|
|
175
|
+
if (isRecord(items)) {
|
|
177
176
|
value.forEach((item, i) => {
|
|
178
177
|
this.check(doc, items, item, `${at}/${String(i)}`, found);
|
|
179
178
|
});
|
|
@@ -200,12 +199,12 @@ class Checker {
|
|
|
200
199
|
if (schema["oneOf"] !== undefined && matching("oneOf") !== 1) {
|
|
201
200
|
refuse("oneOf", `the value matches ${String(matching("oneOf"))} of the alternatives, want exactly one`);
|
|
202
201
|
}
|
|
203
|
-
if (
|
|
202
|
+
if (isRecord(schema["not"]) && this.matches(doc, schema["not"], value, at)) {
|
|
204
203
|
refuse("not", "the value matches a schema it must not match");
|
|
205
204
|
}
|
|
206
|
-
if (
|
|
205
|
+
if (isRecord(schema["if"])) {
|
|
207
206
|
const branch = this.matches(doc, schema["if"], value, at) ? schema["then"] : schema["else"];
|
|
208
|
-
if (
|
|
207
|
+
if (isRecord(branch)) {
|
|
209
208
|
this.check(doc, branch, value, at, found);
|
|
210
209
|
}
|
|
211
210
|
}
|
package/dist/src/report.js
CHANGED
|
@@ -4,10 +4,8 @@
|
|
|
4
4
|
* renders this document, so no two renderings disagree about which findings exist.
|
|
5
5
|
*/
|
|
6
6
|
import { SCHEMA_VERSION, SCHEMA_VERSIONS } from "./contract/contract.generated.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/** The language this analyzer claims. */
|
|
10
|
-
export const LANGUAGE = "ts";
|
|
7
|
+
import { bytewise } from "./text/compare.js";
|
|
8
|
+
import { LANGUAGE, PRODUCT } from "./product.js";
|
|
11
9
|
/**
|
|
12
10
|
* Each component the findings name, once, with the members the first finding naming it
|
|
13
11
|
* carries, in the order the findings are: `findings` paired with their wire forms and
|
|
@@ -26,13 +24,6 @@ function componentsOf(findings) {
|
|
|
26
24
|
}
|
|
27
25
|
return [...listed.values()];
|
|
28
26
|
}
|
|
29
|
-
/** Two strings ordered bytewise. */
|
|
30
|
-
function compare(a, b) {
|
|
31
|
-
if (a === b) {
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
return a < b ? -1 : 1;
|
|
35
|
-
}
|
|
36
27
|
function wirePosition(position) {
|
|
37
28
|
return {
|
|
38
29
|
path: position.path,
|
|
@@ -140,19 +131,19 @@ function wireStale(stale) {
|
|
|
140
131
|
}
|
|
141
132
|
/** The canonical key over two findings: path, line, column, code, then the symbol reference. */
|
|
142
133
|
function canonical(a, b) {
|
|
143
|
-
return (
|
|
134
|
+
return (bytewise(a.position.path, b.position.path) ||
|
|
144
135
|
a.position.line - b.position.line ||
|
|
145
136
|
a.position.column - b.position.column ||
|
|
146
|
-
|
|
147
|
-
|
|
137
|
+
bytewise(a.code, b.code) ||
|
|
138
|
+
bytewise(a.symbol.ref, b.symbol.ref));
|
|
148
139
|
}
|
|
149
140
|
/** The canonical key over two stale suppressions, each component from the record's own member. */
|
|
150
141
|
function canonicalStale(a, b) {
|
|
151
|
-
return (
|
|
142
|
+
return (bytewise(a.position.path, b.position.path) ||
|
|
152
143
|
a.position.line - b.position.line ||
|
|
153
144
|
a.position.column - b.position.column ||
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
bytewise(a.code, b.code) ||
|
|
146
|
+
bytewise(a.symbol, b.symbol));
|
|
156
147
|
}
|
|
157
148
|
/** One declared gap as a report carries it, its members in the schema's order. */
|
|
158
149
|
function wireGap(gap) {
|
|
@@ -165,9 +156,9 @@ function wireGap(gap) {
|
|
|
165
156
|
}
|
|
166
157
|
/** Edge evaluations by edge, then side, then their compact encodings. */
|
|
167
158
|
function byEdge(a, b) {
|
|
168
|
-
return (
|
|
169
|
-
|
|
170
|
-
|
|
159
|
+
return (bytewise(a.edge, b.edge) ||
|
|
160
|
+
bytewise(a.side, b.side) ||
|
|
161
|
+
bytewise(JSON.stringify(a), JSON.stringify(b)));
|
|
171
162
|
}
|
|
172
163
|
/**
|
|
173
164
|
* The lines a reader deletes by acting on every finding: each distinct component a root
|
|
@@ -216,16 +207,16 @@ export function buildReport(input) {
|
|
|
216
207
|
const findings = paired.map(([wire]) => wire);
|
|
217
208
|
const evaluated = input.result.edgeEvaluations.flatMap((one) => one.finding === undefined ? [] : [[wireFinding(one.finding), one.finding]]);
|
|
218
209
|
const unavailable = [...new Map(input.unavailable.map((one) => [one.id, one])).values()]
|
|
219
|
-
.sort((a, b) =>
|
|
210
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
220
211
|
.map((one) => ({ id: one.id, role: "consumer", reason: one.reason }));
|
|
221
212
|
const loaded = [...input.loaded]
|
|
222
|
-
.sort((a, b) =>
|
|
213
|
+
.sort((a, b) => bytewise(a.id, b.id) || bytewise(a.path, b.path))
|
|
223
214
|
.map((one) => ({ id: one.id, role: "consumer", path: one.path }));
|
|
224
215
|
return {
|
|
225
216
|
schema_version: SCHEMA_VERSION,
|
|
226
217
|
contract_version: input.contractVersion,
|
|
227
218
|
analyzer: {
|
|
228
|
-
name:
|
|
219
|
+
name: PRODUCT,
|
|
229
220
|
version: input.version,
|
|
230
221
|
languages: [LANGUAGE],
|
|
231
222
|
schema_versions_accepted: SCHEMA_VERSIONS,
|
|
@@ -237,10 +228,10 @@ export function buildReport(input) {
|
|
|
237
228
|
},
|
|
238
229
|
target: { kind: input.target.kind, root: input.target.root, identity: input.target.identity },
|
|
239
230
|
configurations: [...input.configurations]
|
|
240
|
-
.sort((a, b) =>
|
|
231
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
241
232
|
.map((one) => ({ id: one.id, project: one.project })),
|
|
242
233
|
configurations_not_built: [...input.notBuilt]
|
|
243
|
-
.sort((a, b) =>
|
|
234
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
244
235
|
.map((one) => ({ id: one.id, project: one.project, error: one.error })),
|
|
245
236
|
consumers: { declared: loaded.length + unavailable.length, loaded, unavailable },
|
|
246
237
|
findings,
|
|
@@ -253,10 +244,10 @@ export function buildReport(input) {
|
|
|
253
244
|
// name, so the compact encodings alone order them.
|
|
254
245
|
declared_gaps: input.declaredGaps
|
|
255
246
|
.map(wireGap)
|
|
256
|
-
.sort((a, b) =>
|
|
247
|
+
.sort((a, b) => bytewise(JSON.stringify(a), JSON.stringify(b))),
|
|
257
248
|
excluded_by_cgo: [],
|
|
258
249
|
test_file_rules: [...input.testFileRules]
|
|
259
|
-
.sort((a, b) =>
|
|
250
|
+
.sort((a, b) => bytewise(a.rule, b.rule) || a.matched - b.matched)
|
|
260
251
|
.map((one) => ({ rule: one.rule, matched: one.matched })),
|
|
261
252
|
type_error_skips: [
|
|
262
253
|
...new Map(input.typeErrorSkips.map((one) => {
|
|
@@ -264,14 +255,14 @@ export function buildReport(input) {
|
|
|
264
255
|
return [JSON.stringify(skip), skip];
|
|
265
256
|
})),
|
|
266
257
|
]
|
|
267
|
-
.sort(([a, x], [b, y]) =>
|
|
258
|
+
.sort(([a, x], [b, y]) => bytewise(x.path, y.path) || x.line - y.line || bytewise(a, b))
|
|
268
259
|
.map(([, skip]) => skip),
|
|
269
260
|
notes: [...new Map((input.notes ?? []).map((one) => [JSON.stringify(one), one])).entries()]
|
|
270
|
-
.sort(([a, x], [b, y]) =>
|
|
261
|
+
.sort(([a, x], [b, y]) => bytewise(x.kind, y.kind) || bytewise(x.path, y.path) || bytewise(a, b))
|
|
271
262
|
.map(([, note]) => note),
|
|
272
263
|
unanswered_questions: [...input.unanswered]
|
|
273
|
-
.sort((a, b) =>
|
|
274
|
-
|
|
264
|
+
.sort((a, b) => bytewise(a.configuration, b.configuration) ||
|
|
265
|
+
bytewise(JSON.stringify(a), JSON.stringify(b)))
|
|
275
266
|
.map((one) => ({
|
|
276
267
|
configuration: one.configuration,
|
|
277
268
|
questions: one.questions,
|
|
@@ -5,6 +5,8 @@ import { lineHashes, symbolFingerprint } from "./fingerprint.js";
|
|
|
5
5
|
import { RenderError } from "./reporter.js";
|
|
6
6
|
import { utf8Bytes } from "./sha256.js";
|
|
7
7
|
import { withheldLine } from "./text.js";
|
|
8
|
+
import { bytewise } from "../text/compare.js";
|
|
9
|
+
import { message } from "../product.js";
|
|
8
10
|
const SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";
|
|
9
11
|
const VERSION = "2.1.0";
|
|
10
12
|
/** The unit a finding's column counts. */
|
|
@@ -101,7 +103,7 @@ function lineHashCache(read) {
|
|
|
101
103
|
text = read(at.path);
|
|
102
104
|
}
|
|
103
105
|
catch (error) {
|
|
104
|
-
throw new RenderError(`read ${at.path} for its line fingerprint: ${
|
|
106
|
+
throw new RenderError(`read ${at.path} for its line fingerprint: ${message(error)}`);
|
|
105
107
|
}
|
|
106
108
|
hashes = lineHashes(text);
|
|
107
109
|
held.set(at.path, hashes);
|
|
@@ -226,7 +228,7 @@ export function sarif(report, options) {
|
|
|
226
228
|
...report.findings.map((found) => findingResult(found, index, hashOf, members)),
|
|
227
229
|
...report.stale_suppressions.map((stale) => staleResult(stale, index, hashOf)),
|
|
228
230
|
];
|
|
229
|
-
const languages = [...report.analyzer.languages].sort().join("+");
|
|
231
|
+
const languages = [...report.analyzer.languages].sort(bytewise).join("+");
|
|
230
232
|
const withheld = withheldLine(report.totals);
|
|
231
233
|
const log = {
|
|
232
234
|
$schema: SCHEMA,
|
|
@@ -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,12 +1,15 @@
|
|
|
1
1
|
import { SEVERITIES, LANGUAGES, CONFIDENCES, FORMATS, FAMILY_KEY_LENGTH, } from "./contract/contract.generated.js";
|
|
2
2
|
import { ConfigError, defaultConfig, } from "./config.js";
|
|
3
3
|
import { CONVENTION_ROWS } from "./convention-rows.js";
|
|
4
|
+
import { EXEMPTION_CLASS_NAMES } from "./exempt-classes.js";
|
|
4
5
|
import { FIXED_SEVERITY_CODES, LIVE_CODES } from "./kinds.js";
|
|
5
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";
|
|
6
10
|
/** Names the command-line flags in a refusal, where a document is named by its path. */
|
|
7
11
|
const FLAGS_LABEL = "the command-line flags";
|
|
8
12
|
const SEVERITY_KEY = /^DS[0-9]{2}([0-9]{2})?$/u;
|
|
9
|
-
const EXEMPTION_CLASS = /^[a-z][a-z0-9-]*$/u;
|
|
10
13
|
const CONTRACT_VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+$/u;
|
|
11
14
|
const ANALYZER_NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/u;
|
|
12
15
|
const PROVIDER_SOURCE = /^(go|npm):[^ \t\r\n]+$/u;
|
|
@@ -43,9 +46,6 @@ function originOf(source, path) {
|
|
|
43
46
|
}
|
|
44
47
|
return { source: source.kind, label: source.label };
|
|
45
48
|
}
|
|
46
|
-
function isRecord(value) {
|
|
47
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
48
|
-
}
|
|
49
49
|
function member(parent, name) {
|
|
50
50
|
if (parent === undefined || !Object.hasOwn(parent, name)) {
|
|
51
51
|
return undefined;
|
|
@@ -292,7 +292,7 @@ function unimplementedSeverityKey(label, path, reason) {
|
|
|
292
292
|
* them all rather than the first one found.
|
|
293
293
|
*/
|
|
294
294
|
function fixedByContract(code) {
|
|
295
|
-
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);
|
|
296
296
|
}
|
|
297
297
|
/** The codes a refusal names: one on its own, and several with the last joined by and. */
|
|
298
298
|
function spellCodes(codes) {
|
|
@@ -321,7 +321,7 @@ function readSeverity(document, label) {
|
|
|
321
321
|
return undefined;
|
|
322
322
|
}
|
|
323
323
|
const severity = new Map();
|
|
324
|
-
for (const code of Object.keys(object).sort()) {
|
|
324
|
+
for (const code of Object.keys(object).sort(bytewise)) {
|
|
325
325
|
const path = `${SEVERITY_SECTION}.${code}`;
|
|
326
326
|
if (!SEVERITY_KEY.test(code)) {
|
|
327
327
|
throw unimplementedSeverityKey(label, path, "a severity key is one issue-kind code or one two-digit family prefix");
|
|
@@ -342,19 +342,10 @@ function readSeverity(document, label) {
|
|
|
342
342
|
}
|
|
343
343
|
return severity;
|
|
344
344
|
}
|
|
345
|
-
/** The exemption classes named for switching off. */
|
|
345
|
+
/** The exemption classes named for switching off, each one the vocabulary holds. */
|
|
346
346
|
function readExemptions(document, label) {
|
|
347
347
|
const exemptions = section(document, "exemptions", "exemptions", label);
|
|
348
|
-
|
|
349
|
-
if (disabled === undefined) {
|
|
350
|
-
return undefined;
|
|
351
|
-
}
|
|
352
|
-
for (const entry of disabled) {
|
|
353
|
-
if (!EXEMPTION_CLASS.test(entry)) {
|
|
354
|
-
throw malformed(label, "exemptions.disabled", `${JSON.stringify(entry)} is not an exemption class name`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
return disabled;
|
|
348
|
+
return readStrings(exemptions, "disabled", "exemptions.disabled", label, 0, EXEMPTION_CLASS_NAMES);
|
|
358
349
|
}
|
|
359
350
|
/** The members that name a declaration, each belonging to exactly one shape. */
|
|
360
351
|
const SHAPE_MEMBERS = ["symbol", "module", "name", "global"];
|
|
@@ -572,7 +563,7 @@ function parseDocument(text, node, label) {
|
|
|
572
563
|
value = JSON.parse(text);
|
|
573
564
|
}
|
|
574
565
|
catch (error) {
|
|
575
|
-
throw malformed(label, "",
|
|
566
|
+
throw malformed(label, "", message(error));
|
|
576
567
|
}
|
|
577
568
|
checkDocument(text, node, label);
|
|
578
569
|
return value;
|
|
@@ -656,7 +647,7 @@ function settleSeverity(provenance, sources) {
|
|
|
656
647
|
}
|
|
657
648
|
}
|
|
658
649
|
const severity = new Map();
|
|
659
|
-
for (const code of [...codes].sort()) {
|
|
650
|
+
for (const code of [...codes].sort(bytewise)) {
|
|
660
651
|
const path = `${SEVERITY_SECTION}.${code}`;
|
|
661
652
|
for (const source of sources) {
|
|
662
653
|
const value = source.doc.severity?.get(code);
|
|
@@ -692,7 +683,7 @@ function describeSource(named, text, label) {
|
|
|
692
683
|
* print a provenance value the closed key list refuses to read back.
|
|
693
684
|
*/
|
|
694
685
|
function checkLabels(provenance) {
|
|
695
|
-
for (const path of [...provenance.keys()].sort()) {
|
|
686
|
+
for (const path of [...provenance.keys()].sort(bytewise)) {
|
|
696
687
|
const origin = provenance.get(path);
|
|
697
688
|
if (origin !== undefined && origin.source !== "default" && origin.label === "") {
|
|
698
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
|
@@ -14,6 +14,7 @@ import { describeVerb } from "./verbs/describe.js";
|
|
|
14
14
|
import { EXPLAIN_OPTIONS, explainVerb } from "./verbs/explain.js";
|
|
15
15
|
import {} from "./verbs/verb.js";
|
|
16
16
|
import { versionVerb } from "./verbs/version.js";
|
|
17
|
+
import { diagnose, message, PRODUCT } from "./product.js";
|
|
17
18
|
/** Every verb this command answers, in the order the usage text lists them. */
|
|
18
19
|
const VERBS = [
|
|
19
20
|
{ name: "analyze", run: analyzeVerb, options: ANALYZE_OPTIONS },
|
|
@@ -25,7 +26,7 @@ const VERBS = [
|
|
|
25
26
|
{ name: "describe", run: describeVerb },
|
|
26
27
|
{ name: "version", run: versionVerb },
|
|
27
28
|
];
|
|
28
|
-
const USAGE = `usage:
|
|
29
|
+
const USAGE = `usage: ${PRODUCT} <verb> [options]\nverbs: ${VERBS.map((verb) => verb.name).join(", ")}\n`;
|
|
29
30
|
/**
|
|
30
31
|
* The tokens whose presence in an option's name makes that option a request to
|
|
31
32
|
* edit a source file. The set is closed, and a token is matched in any position of
|
|
@@ -109,7 +110,7 @@ function readFileOr(host, path, orUndefined) {
|
|
|
109
110
|
if (orUndefined) {
|
|
110
111
|
return undefined;
|
|
111
112
|
}
|
|
112
|
-
throw new ConfigError("malformed", "", `${path}: ${
|
|
113
|
+
throw new ConfigError("malformed", "", `${path}: ${message(error)}`);
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
/**
|
|
@@ -162,7 +163,7 @@ function scopeOf(host, options) {
|
|
|
162
163
|
export function run(args, out, err, host, openClient = openEngine) {
|
|
163
164
|
const editing = sourceEditOption(args);
|
|
164
165
|
if (editing !== undefined) {
|
|
165
|
-
err
|
|
166
|
+
diagnose(err, `${editing} is not supported: ${PRODUCT} reports and never edits a source file`);
|
|
166
167
|
err.write(USAGE);
|
|
167
168
|
return EXIT_USAGE;
|
|
168
169
|
}
|
|
@@ -172,7 +173,7 @@ export function run(args, out, err, host, openClient = openEngine) {
|
|
|
172
173
|
return invoke(verb.run, verb.options ?? NO_OPTIONS, args.slice(1), { out, err, host }, openClient);
|
|
173
174
|
}
|
|
174
175
|
if (name !== undefined) {
|
|
175
|
-
err
|
|
176
|
+
diagnose(err, `unknown verb ${JSON.stringify(name)}`);
|
|
176
177
|
}
|
|
177
178
|
err.write(USAGE);
|
|
178
179
|
return EXIT_USAGE;
|
|
@@ -211,7 +212,7 @@ function invoke(verb, own, args, streams, openClient) {
|
|
|
211
212
|
/** Turns one refusal into the exit code the Contract's table gives it. */
|
|
212
213
|
function refuse(error, err) {
|
|
213
214
|
if (error instanceof ConfigError) {
|
|
214
|
-
err
|
|
215
|
+
diagnose(err, error.message);
|
|
215
216
|
err.write(USAGE);
|
|
216
217
|
return EXIT_USAGE;
|
|
217
218
|
}
|
|
@@ -219,7 +220,7 @@ function refuse(error, err) {
|
|
|
219
220
|
for (const diagnostic of error.diagnostics) {
|
|
220
221
|
err.write(`${renderDiagnostic(diagnostic)}\n`);
|
|
221
222
|
}
|
|
222
|
-
err
|
|
223
|
+
diagnose(err, error.message);
|
|
223
224
|
return EXIT_FAILURE;
|
|
224
225
|
}
|
|
225
226
|
if (error instanceof SetupError) {
|
|
@@ -229,7 +230,7 @@ function refuse(error, err) {
|
|
|
229
230
|
return EXIT_FAILURE;
|
|
230
231
|
}
|
|
231
232
|
if (error instanceof ScopeError) {
|
|
232
|
-
err
|
|
233
|
+
diagnose(err, error.message);
|
|
233
234
|
return EXIT_FAILURE;
|
|
234
235
|
}
|
|
235
236
|
throw error;
|