@cplieger/deadset-ts 8.0.0-dev.17 → 8.0.0-dev.19
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/src/analysis.js +30 -72
- package/dist/src/augmentations.js +1 -1
- package/dist/src/calls.js +267 -48
- package/dist/src/commands/held.js +499 -0
- package/dist/src/commands/read.js +16 -10
- package/dist/src/commands/shell.js +109 -15
- package/dist/src/commands/tools.js +1540 -149
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/contract/contract.generated.js +9 -2
- package/dist/src/entries/conventions.js +7 -6
- package/dist/src/entries/test-runners.js +6 -40
- package/dist/src/entries/workflow-steps.js +202 -28
- package/dist/src/exempt.js +0 -26
- package/dist/src/exposure.js +400 -0
- package/dist/src/findings/completion.js +4 -17
- package/dist/src/findings/emitters.js +22 -33
- package/dist/src/findings/intra-function.js +3 -3
- package/dist/src/findings/non-code-artifacts.js +11 -5
- package/dist/src/findings/reads-and-writes.js +71 -15
- package/dist/src/findings/unused-declarations.js +2 -22
- package/dist/src/findings/visibility-narrowing.js +14 -20
- package/dist/src/inventory.js +18 -0
- package/dist/src/{components.js → liveness/components.js} +1 -1
- package/dist/src/{graph.js → liveness/graph.js} +38 -21
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/query.js +46 -0
- package/dist/src/references/sink.js +87 -1
- package/dist/src/references.js +1 -1
- package/dist/src/roots/manifest.js +47 -4
- package/dist/src/roots/published-reach.js +4 -4
- package/dist/src/roots/root-set.js +14 -16
- package/dist/src/text/named-files.js +257 -34
- package/dist/src/verbs/analyze.js +16 -1
- package/dist/src/verbs/explain.js +73 -152
- package/dist/src/verbs/print-retained.js +1 -1
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +54 -108
- package/src/augmentations.ts +1 -1
- package/src/calls.ts +326 -52
- package/src/commands/held.ts +632 -0
- package/src/commands/read.ts +26 -12
- package/src/commands/shell.ts +117 -15
- package/src/commands/tools.ts +1972 -202
- package/src/conformance-record.ts +1 -1
- package/src/contract/contract.generated.ts +9 -2
- package/src/dependencies.ts +1 -1
- package/src/entries/conventions.ts +8 -12
- package/src/entries/test-runners.ts +12 -45
- package/src/entries/workflow-steps.ts +227 -38
- package/src/exempt.ts +31 -46
- package/src/exposure.ts +492 -0
- package/src/file-facts.ts +5 -0
- package/src/finding.ts +1 -1
- package/src/findings/boundary.ts +7 -0
- package/src/findings/completion.ts +5 -19
- package/src/findings/emitters.ts +23 -41
- package/src/findings/interfaces.ts +3 -3
- package/src/findings/intra-function.ts +3 -3
- package/src/findings/non-code-artifacts.ts +16 -5
- package/src/findings/reads-and-writes.ts +99 -26
- package/src/findings/unused-declarations.ts +4 -28
- package/src/findings/visibility-narrowing.ts +25 -26
- package/src/interface-satisfaction.ts +1 -1
- package/src/inventory.ts +19 -0
- package/src/{components.ts → liveness/components.ts} +3 -3
- package/src/{graph.ts → liveness/graph.ts} +74 -26
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/query.ts +81 -0
- package/src/references/sink.ts +101 -0
- package/src/references.ts +8 -1
- package/src/roots/manifest.ts +53 -8
- package/src/roots/published-reach.ts +9 -4
- package/src/roots/root-set.ts +18 -16
- package/src/stores.ts +2 -1
- package/src/tests/file-class.ts +19 -2
- package/src/text/named-files.ts +333 -36
- package/src/verbs/analyze.ts +16 -1
- package/src/verbs/explain.ts +81 -199
- package/src/verbs/print-retained.ts +1 -1
- package/dist/src/matrix.js +0 -275
- package/dist/src/sweep.js +0 -234
- package/src/matrix.ts +0 -466
- package/src/sweep.ts +0 -384
|
@@ -1,31 +1,125 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layer 1 of the command reader: one command line, parsed by the vendored shell parser, as
|
|
3
|
-
* its and-or lists, their pipelines and the words of each simple command
|
|
4
|
-
*
|
|
3
|
+
* its and-or lists, their pipelines and the words of each simple command, and the one place
|
|
4
|
+
* that decides which parts of a word the shell computes and which words a brace expansion
|
|
5
|
+
* stands for, for layer 3 too.
|
|
5
6
|
*/
|
|
6
7
|
import { parse, } from "../vendor/unbash/parser.js";
|
|
7
|
-
/**
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The character that stands, in a word's text as layer 3 reads it, for a part only the run
|
|
10
|
+
* knows. It is a private-use character, so no path holds it, and the parser reads it as
|
|
11
|
+
* literal text.
|
|
12
|
+
*/
|
|
13
|
+
export const PART = "\uE000";
|
|
14
|
+
/** A GitHub Actions expression, which the runner substitutes before any shell reads the line. */
|
|
15
|
+
const EXPRESSION = /\$\{\{[\s\S]*?\}\}/gu;
|
|
16
|
+
/** `text` with each `${{ }}` expression in it read as a part only the run knows. */
|
|
17
|
+
export function expressionsAsParts(text) {
|
|
18
|
+
return text.replace(EXPRESSION, PART);
|
|
19
|
+
}
|
|
20
|
+
/** One command line parsed, each `${{ }}` expression in it read as a part only the run knows. */
|
|
21
|
+
export function parseLine(source) {
|
|
22
|
+
return parse(expressionsAsParts(source));
|
|
23
|
+
}
|
|
24
|
+
/** The words a word's brace expansions stand for, at most this many. */
|
|
25
|
+
const ALTERNATIVES = 64;
|
|
26
|
+
/**
|
|
27
|
+
* The text one part of a word stands for: a literal's, a quoted text's or an escape's value,
|
|
28
|
+
* and {@link PART} for every part the shell computes, a glob among them.
|
|
29
|
+
*/
|
|
30
|
+
function partText(part) {
|
|
9
31
|
switch (part.type) {
|
|
10
32
|
case "Literal":
|
|
11
33
|
case "SingleQuoted":
|
|
12
34
|
case "AnsiCQuoted":
|
|
13
|
-
return
|
|
35
|
+
return part.value;
|
|
14
36
|
case "DoubleQuoted":
|
|
15
|
-
return part.parts.
|
|
37
|
+
return part.parts.map((child) => (child.type === "Literal" ? child.value : PART)).join("");
|
|
16
38
|
default:
|
|
17
|
-
return
|
|
39
|
+
return PART;
|
|
18
40
|
}
|
|
19
41
|
}
|
|
42
|
+
/** The texts the word `piece` of a brace expansion stands for, or a part where it is no one word. */
|
|
43
|
+
function alternativeTexts(piece) {
|
|
44
|
+
if (piece === "") {
|
|
45
|
+
return [""];
|
|
46
|
+
}
|
|
47
|
+
const script = parse(piece);
|
|
48
|
+
const [statement, ...more] = script.commands;
|
|
49
|
+
const command = statement?.command;
|
|
50
|
+
return (script.errors ?? []).length === 0 &&
|
|
51
|
+
more.length === 0 &&
|
|
52
|
+
command?.type === "Command" &&
|
|
53
|
+
command.name !== undefined &&
|
|
54
|
+
command.prefix.length === 0 &&
|
|
55
|
+
command.suffix.length === 0
|
|
56
|
+
? heldTextsOf(command.name)
|
|
57
|
+
: [PART];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The texts a brace expansion stands for, its comma-separated alternatives, or a part where it
|
|
61
|
+
* has none, a sequence such as `{1..3}` among them.
|
|
62
|
+
*/
|
|
63
|
+
function braceTexts(text) {
|
|
64
|
+
const inner = text.slice(1, -1);
|
|
65
|
+
const pieces = [];
|
|
66
|
+
let depth = 0;
|
|
67
|
+
let from = 0;
|
|
68
|
+
let quote = "";
|
|
69
|
+
for (let at = 0; at < inner.length; at += 1) {
|
|
70
|
+
const char = inner.charAt(at);
|
|
71
|
+
if (char === "\\") {
|
|
72
|
+
at += 1;
|
|
73
|
+
}
|
|
74
|
+
else if (quote !== "") {
|
|
75
|
+
quote = char === quote ? "" : quote;
|
|
76
|
+
}
|
|
77
|
+
else if (char === "'" || char === '"') {
|
|
78
|
+
quote = char;
|
|
79
|
+
}
|
|
80
|
+
else if (char === "{" || char === "}") {
|
|
81
|
+
depth += char === "{" ? 1 : -1;
|
|
82
|
+
}
|
|
83
|
+
else if (char === "," && depth === 0) {
|
|
84
|
+
pieces.push(inner.slice(from, at));
|
|
85
|
+
from = at + 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (pieces.length === 0) {
|
|
89
|
+
return [PART];
|
|
90
|
+
}
|
|
91
|
+
pieces.push(inner.slice(from));
|
|
92
|
+
return pieces.flatMap(alternativeTexts);
|
|
93
|
+
}
|
|
20
94
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
95
|
+
* Each word the shell may expand `word` to, as layer 3 reads it: its quotes removed, each brace
|
|
96
|
+
* expansion read as its alternatives, past {@link ALTERNATIVES} words as a part, and each part
|
|
97
|
+
* it computes, a tilde that starts it unquoted among them, as {@link PART}.
|
|
23
98
|
*/
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
99
|
+
export function heldTextsOf(word) {
|
|
100
|
+
const { parts } = word;
|
|
101
|
+
const [first] = parts ?? [];
|
|
102
|
+
const tilde = parts === undefined
|
|
103
|
+
? word.text.startsWith("~")
|
|
104
|
+
: first?.type === "Literal" && first.text.startsWith("~");
|
|
105
|
+
let texts = [parts === undefined ? word.value : ""];
|
|
106
|
+
for (const part of parts ?? []) {
|
|
107
|
+
const options = part.type === "BraceExpansion" ? braceTexts(part.text) : [partText(part)];
|
|
108
|
+
const next = texts.flatMap((text) => options.map((option) => `${text}${option}`));
|
|
109
|
+
texts = next.length > ALTERNATIVES ? texts.map((text) => `${text}${PART}`) : next;
|
|
110
|
+
}
|
|
111
|
+
return tilde ? texts.map((text) => `${PART}${text.slice(1)}`) : texts;
|
|
112
|
+
}
|
|
113
|
+
/** One word as layer 1 reads it: static only where the shell expands it to one text with no part. */
|
|
114
|
+
export function wordOf(word) {
|
|
115
|
+
const [only, ...more] = heldTextsOf(word);
|
|
116
|
+
const one = more.length === 0 ? only : undefined;
|
|
117
|
+
const known = one !== undefined && !one.includes(PART);
|
|
118
|
+
return {
|
|
119
|
+
value: known ? word.value : undefined,
|
|
120
|
+
text: word.text,
|
|
121
|
+
...(one === undefined ? {} : { written: one }),
|
|
122
|
+
};
|
|
29
123
|
}
|
|
30
124
|
/**
|
|
31
125
|
* Whether one member of a pipeline, run in the line's own shell, may change that shell's
|
|
@@ -61,7 +155,7 @@ function pipelineOf(node, operator) {
|
|
|
61
155
|
* gives no words, and marks its pipeline where it may change the line's directory.
|
|
62
156
|
*/
|
|
63
157
|
export function shellLine(source) {
|
|
64
|
-
const script =
|
|
158
|
+
const script = parseLine(source);
|
|
65
159
|
if ((script.errors ?? []).length > 0) {
|
|
66
160
|
return [];
|
|
67
161
|
}
|