@cplieger/deadset-ts 8.0.0-dev.12 → 8.0.0-dev.13
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/README.md +2 -0
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/src/build-scripts.js +6 -13
- package/dist/src/commands/read.js +156 -0
- package/dist/src/commands/shell.js +75 -0
- package/dist/src/commands/tools.js +460 -0
- package/dist/src/configuration-files.js +11 -25
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/dependencies.js +67 -115
- package/dist/src/load/synthesize.js +12 -5
- package/dist/src/manifest.js +27 -14
- package/dist/src/roots.js +18 -11
- package/dist/src/text/named-files.js +24 -3
- package/dist/src/text/yaml.js +464 -173
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/workflow-steps.js +111 -133
- package/jsr.json +2 -1
- package/package.json +4 -2
- package/src/build-scripts.ts +6 -13
- package/src/commands/read.ts +230 -0
- package/src/commands/shell.ts +126 -0
- package/src/commands/tools.ts +618 -0
- package/src/configuration-files.ts +10 -26
- package/src/conformance-record.ts +1 -1
- package/src/dependencies.ts +99 -123
- package/src/load/synthesize.ts +18 -5
- package/src/manifest.ts +43 -25
- package/src/roots.ts +20 -13
- package/src/text/named-files.ts +26 -3
- package/src/text/yaml.ts +503 -179
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/workflow-steps.ts +153 -154
- package/dist/src/text/shell.js +0 -159
- package/src/text/named-files.inputs.json +0 -1522
- package/src/text/shell.ts +0 -161
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Code generated by scripts/vendor-unbash.ts from unbash 6.0.0 (968c14992a43dc06ce29c9f51858abd4a87851ea). DO NOT EDIT.
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { Lexer, LexContext, Token } from "./lexer.js";
|
|
4
|
+
import { skipLineContinuations } from "./chars.js";
|
|
5
|
+
import { arrayPartsResolver, computeBareWordParts, embeddedPartsResolver, wordPartsResolver } from "./parts.js";
|
|
6
|
+
import { WordImpl } from "./word.js";
|
|
7
|
+
class ArrayValueImpl {
|
|
8
|
+
type = "ArrayValue";
|
|
9
|
+
pos;
|
|
10
|
+
end;
|
|
11
|
+
#source;
|
|
12
|
+
#depth;
|
|
13
|
+
#context;
|
|
14
|
+
#elements;
|
|
15
|
+
constructor(source, pos, end, depth, context) {
|
|
16
|
+
this.pos = pos;
|
|
17
|
+
this.end = end;
|
|
18
|
+
this.#source = source;
|
|
19
|
+
this.#depth = depth;
|
|
20
|
+
this.#context = context;
|
|
21
|
+
}
|
|
22
|
+
get elements() {
|
|
23
|
+
if (this.#elements)
|
|
24
|
+
return this.#elements;
|
|
25
|
+
const lexer = new Lexer(this.#source, this.pos + 1, this.end - 1, false, this.#context);
|
|
26
|
+
lexer._nestingDepth = this.#depth;
|
|
27
|
+
const elements = [];
|
|
28
|
+
while (lexer.peek(LexContext.ArrayElement).token !== Token.EOF) {
|
|
29
|
+
const token = lexer.next(LexContext.ArrayElement);
|
|
30
|
+
if (token.token !== Token.Word && token.token !== Token.Assignment)
|
|
31
|
+
continue;
|
|
32
|
+
const text = token.raw ? token.value : this.#source.slice(token.pos, token.end);
|
|
33
|
+
const indexed = text.charCodeAt(0) === 91;
|
|
34
|
+
const context = lexer.getSubstitutionContext();
|
|
35
|
+
const source = !indexed && token.raw && token.keywordEligible ? undefined : this.#source;
|
|
36
|
+
const resolver = source === undefined
|
|
37
|
+
? computeBareWordParts
|
|
38
|
+
: indexed
|
|
39
|
+
? arrayPartsResolver(context)
|
|
40
|
+
: wordPartsResolver(context);
|
|
41
|
+
elements.push(new WordImpl(text, token.pos, token.end, source, resolver, this.#depth));
|
|
42
|
+
}
|
|
43
|
+
this.#elements = elements;
|
|
44
|
+
return elements;
|
|
45
|
+
}
|
|
46
|
+
toJSON() {
|
|
47
|
+
return { type: this.type, pos: this.pos, end: this.end, elements: this.elements };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export class AssignmentImpl {
|
|
51
|
+
type = "Assignment";
|
|
52
|
+
pos;
|
|
53
|
+
end;
|
|
54
|
+
text;
|
|
55
|
+
#source;
|
|
56
|
+
#depth;
|
|
57
|
+
#context;
|
|
58
|
+
#operatorPos;
|
|
59
|
+
#name = null;
|
|
60
|
+
#append;
|
|
61
|
+
#index;
|
|
62
|
+
#value = null;
|
|
63
|
+
constructor(text, pos, end, source, operatorPos, depth, context) {
|
|
64
|
+
this.pos = pos;
|
|
65
|
+
this.end = end;
|
|
66
|
+
this.text = text;
|
|
67
|
+
this.#source = source;
|
|
68
|
+
this.#operatorPos = operatorPos;
|
|
69
|
+
this.#depth = depth;
|
|
70
|
+
this.#context = context;
|
|
71
|
+
}
|
|
72
|
+
get name() {
|
|
73
|
+
return this.#name ?? this.resolveTarget();
|
|
74
|
+
}
|
|
75
|
+
get append() {
|
|
76
|
+
if (this.#name === null)
|
|
77
|
+
this.resolveTarget();
|
|
78
|
+
return this.#append;
|
|
79
|
+
}
|
|
80
|
+
get index() {
|
|
81
|
+
if (this.#name === null)
|
|
82
|
+
this.resolveTarget();
|
|
83
|
+
return this.#index;
|
|
84
|
+
}
|
|
85
|
+
get value() {
|
|
86
|
+
if (this.#value !== null)
|
|
87
|
+
return this.#value;
|
|
88
|
+
const start = this.#operatorPos + 1;
|
|
89
|
+
const arrayStart = skipLineContinuations(this.#source, start, this.end);
|
|
90
|
+
this.#value =
|
|
91
|
+
this.#source.charCodeAt(arrayStart) === 40 && this.#source.charCodeAt(this.end - 1) === 41
|
|
92
|
+
? new ArrayValueImpl(this.#source, arrayStart, this.end, this.#depth, this.#context)
|
|
93
|
+
: new WordImpl(this.#source.slice(start, this.end), start, this.end, this.#source, wordPartsResolver(this.#context), this.#depth);
|
|
94
|
+
return this.#value;
|
|
95
|
+
}
|
|
96
|
+
resolveTarget() {
|
|
97
|
+
const equal = this.#operatorPos - this.pos;
|
|
98
|
+
let nameEnd = equal;
|
|
99
|
+
let appendPos = equal;
|
|
100
|
+
while (appendPos >= 2 && this.text.charCodeAt(appendPos - 2) === 92 && this.text.charCodeAt(appendPos - 1) === 10)
|
|
101
|
+
appendPos -= 2;
|
|
102
|
+
if (this.text.charCodeAt(appendPos - 1) === 43) {
|
|
103
|
+
this.#append = true;
|
|
104
|
+
nameEnd = appendPos - 1;
|
|
105
|
+
}
|
|
106
|
+
const bracket = this.text.indexOf("[");
|
|
107
|
+
if (bracket > 0 && bracket < nameEnd) {
|
|
108
|
+
const close = this.text.lastIndexOf("]", equal);
|
|
109
|
+
if (close > bracket) {
|
|
110
|
+
const start = this.pos + bracket + 1;
|
|
111
|
+
const end = this.pos + close;
|
|
112
|
+
this.#index = new WordImpl(this.#source.slice(start, end), start, end, this.#source, embeddedPartsResolver(this.#context), this.#depth);
|
|
113
|
+
nameEnd = bracket;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const name = this.text.slice(0, nameEnd);
|
|
117
|
+
return (this.#name = name.includes("\\\n") ? name.split("\\\n").join("") : name);
|
|
118
|
+
}
|
|
119
|
+
toJSON() {
|
|
120
|
+
return {
|
|
121
|
+
type: this.type,
|
|
122
|
+
pos: this.pos,
|
|
123
|
+
end: this.end,
|
|
124
|
+
text: this.text,
|
|
125
|
+
name: this.name,
|
|
126
|
+
append: this.append,
|
|
127
|
+
index: this.index,
|
|
128
|
+
value: this.value,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Code generated by scripts/vendor-unbash.ts from unbash 6.0.0 (968c14992a43dc06ce29c9f51858abd4a87851ea). DO NOT EDIT.
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
export const CH_TAB = 9;
|
|
4
|
+
export const CH_NL = 10;
|
|
5
|
+
export const CH_SPACE = 32;
|
|
6
|
+
export const CH_BANG = 33;
|
|
7
|
+
export const CH_DQUOTE = 34;
|
|
8
|
+
export const CH_HASH = 35;
|
|
9
|
+
export const CH_DOLLAR = 36;
|
|
10
|
+
export const CH_PERCENT = 37;
|
|
11
|
+
export const CH_AMP = 38;
|
|
12
|
+
export const CH_SQUOTE = 39;
|
|
13
|
+
export const CH_LPAREN = 40;
|
|
14
|
+
export const CH_RPAREN = 41;
|
|
15
|
+
export const CH_STAR = 42;
|
|
16
|
+
export const CH_PLUS = 43;
|
|
17
|
+
export const CH_COMMA = 44;
|
|
18
|
+
export const CH_DASH = 45;
|
|
19
|
+
export const CH_DOT = 46;
|
|
20
|
+
export const CH_SLASH = 47;
|
|
21
|
+
export const CH_0 = 48;
|
|
22
|
+
export const CH_9 = 57;
|
|
23
|
+
export const CH_COLON = 58;
|
|
24
|
+
export const CH_SEMI = 59;
|
|
25
|
+
export const CH_LT = 60;
|
|
26
|
+
export const CH_EQ = 61;
|
|
27
|
+
export const CH_GT = 62;
|
|
28
|
+
export const CH_QUESTION = 63;
|
|
29
|
+
export const CH_AT = 64;
|
|
30
|
+
export const CH_A = 65;
|
|
31
|
+
export const CH_Z = 90;
|
|
32
|
+
export const CH_LBRACKET = 91;
|
|
33
|
+
export const CH_BACKSLASH = 92;
|
|
34
|
+
export const CH_RBRACKET = 93;
|
|
35
|
+
export const CH_CARET = 94;
|
|
36
|
+
export const CH_UNDERSCORE = 95;
|
|
37
|
+
export const CH_BACKTICK = 96;
|
|
38
|
+
export const CH_a = 97;
|
|
39
|
+
export const CH_z = 122;
|
|
40
|
+
export const CH_LBRACE = 123;
|
|
41
|
+
export const CH_PIPE = 124;
|
|
42
|
+
export const CH_RBRACE = 125;
|
|
43
|
+
export const CH_TILDE = 126;
|
|
44
|
+
export function skipLineContinuations(source, pos, end) {
|
|
45
|
+
while (pos + 1 < end && source.charCodeAt(pos) === CH_BACKSLASH && source.charCodeAt(pos + 1) === CH_NL)
|
|
46
|
+
pos += 2;
|
|
47
|
+
return pos;
|
|
48
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const isArgument = (item) => item.type === "Word" || item.type === "Assignment";
|
|
2
|
+
export class CommandImpl {
|
|
3
|
+
type = "Command";
|
|
4
|
+
pos;
|
|
5
|
+
end;
|
|
6
|
+
name;
|
|
7
|
+
prefix;
|
|
8
|
+
suffix;
|
|
9
|
+
#args;
|
|
10
|
+
#redirects;
|
|
11
|
+
constructor(pos, end, name, prefix, suffix) {
|
|
12
|
+
this.pos = pos;
|
|
13
|
+
this.end = end;
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.prefix = prefix;
|
|
16
|
+
this.suffix = suffix;
|
|
17
|
+
}
|
|
18
|
+
get args() {
|
|
19
|
+
if (this.#args === undefined) {
|
|
20
|
+
const suffix = this.suffix;
|
|
21
|
+
this.#args = suffix.every(isArgument) ? suffix : suffix.filter(isArgument);
|
|
22
|
+
}
|
|
23
|
+
return this.#args;
|
|
24
|
+
}
|
|
25
|
+
get redirects() {
|
|
26
|
+
if (this.#redirects === undefined) {
|
|
27
|
+
const redirects = [];
|
|
28
|
+
for (const item of this.prefix)
|
|
29
|
+
if (item.type !== "Assignment")
|
|
30
|
+
redirects.push(item);
|
|
31
|
+
for (const item of this.suffix)
|
|
32
|
+
if (!isArgument(item))
|
|
33
|
+
redirects.push(item);
|
|
34
|
+
this.#redirects = redirects;
|
|
35
|
+
}
|
|
36
|
+
return this.#redirects;
|
|
37
|
+
}
|
|
38
|
+
toJSON() {
|
|
39
|
+
return { type: this.type, pos: this.pos, end: this.end, name: this.name, prefix: this.prefix, suffix: this.suffix };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// The window is held only until the script resolves; a part constructed without one has no script.
|
|
2
|
+
export class ScriptExpansionImpl {
|
|
3
|
+
static _resolveScript;
|
|
4
|
+
type;
|
|
5
|
+
pos;
|
|
6
|
+
end;
|
|
7
|
+
text;
|
|
8
|
+
#window;
|
|
9
|
+
#script = undefined;
|
|
10
|
+
constructor(type, pos, end, text, window) {
|
|
11
|
+
this.type = type;
|
|
12
|
+
this.pos = pos;
|
|
13
|
+
this.end = end;
|
|
14
|
+
this.text = text;
|
|
15
|
+
this.#window = window;
|
|
16
|
+
}
|
|
17
|
+
get script() {
|
|
18
|
+
const window = this.#window;
|
|
19
|
+
if (window !== undefined) {
|
|
20
|
+
const script = ScriptExpansionImpl._resolveScript(window.source, window.start, window.end, window.depth, window.parenBoundary, window.context);
|
|
21
|
+
if (window.context === undefined)
|
|
22
|
+
script.source = window.source;
|
|
23
|
+
this.script = script;
|
|
24
|
+
}
|
|
25
|
+
return this.#script;
|
|
26
|
+
}
|
|
27
|
+
set script(script) {
|
|
28
|
+
this.#script = script;
|
|
29
|
+
this.#window = undefined;
|
|
30
|
+
}
|
|
31
|
+
toJSON() {
|
|
32
|
+
return { type: this.type, pos: this.pos, end: this.end, text: this.text, script: this.script };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class ProcessSubstitutionImpl extends ScriptExpansionImpl {
|
|
36
|
+
operator;
|
|
37
|
+
constructor(pos, end, text, operator, window) {
|
|
38
|
+
super("ProcessSubstitution", pos, end, text, window);
|
|
39
|
+
this.operator = operator;
|
|
40
|
+
}
|
|
41
|
+
toJSON() {
|
|
42
|
+
return {
|
|
43
|
+
type: this.type,
|
|
44
|
+
pos: this.pos,
|
|
45
|
+
end: this.end,
|
|
46
|
+
text: this.text,
|
|
47
|
+
operator: this.operator,
|
|
48
|
+
script: this.script,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export class ArithmeticExpansionImpl {
|
|
53
|
+
static _resolveExpression;
|
|
54
|
+
type = "ArithmeticExpansion";
|
|
55
|
+
pos;
|
|
56
|
+
end;
|
|
57
|
+
text;
|
|
58
|
+
#window;
|
|
59
|
+
#expression = undefined;
|
|
60
|
+
constructor(pos, end, text, window) {
|
|
61
|
+
this.pos = pos;
|
|
62
|
+
this.end = end;
|
|
63
|
+
this.text = text;
|
|
64
|
+
this.#window = window;
|
|
65
|
+
}
|
|
66
|
+
get expression() {
|
|
67
|
+
const window = this.#window;
|
|
68
|
+
if (window !== undefined) {
|
|
69
|
+
this.expression = ArithmeticExpansionImpl._resolveExpression(window.body, window.offset, window.source, window.depth, window.context, window.depth + 1);
|
|
70
|
+
}
|
|
71
|
+
return this.#expression;
|
|
72
|
+
}
|
|
73
|
+
set expression(expression) {
|
|
74
|
+
this.#expression = expression;
|
|
75
|
+
this.#window = undefined;
|
|
76
|
+
}
|
|
77
|
+
toJSON() {
|
|
78
|
+
return { type: this.type, pos: this.pos, end: this.end, text: this.text, expression: this.expression };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { unescapeBareValue, wordPartsValue } from "./word-value.js";
|
|
2
|
+
import { CH_BACKSLASH, CH_BANG, CH_CARET, CH_COLON, CH_DASH, CH_DOT, CH_EQ, CH_LBRACKET, CH_LPAREN, CH_NL, CH_QUESTION, CH_RBRACKET, CH_STAR, skipLineContinuations, } from "./chars.js";
|
|
3
|
+
export function hasGlobCharacters(text) {
|
|
4
|
+
return /[*?[]/.test(text);
|
|
5
|
+
}
|
|
6
|
+
const bracketSyntax = new Uint8Array(128);
|
|
7
|
+
bracketSyntax[CH_BANG] = 1;
|
|
8
|
+
bracketSyntax[CH_CARET] = 1;
|
|
9
|
+
bracketSyntax[CH_LBRACKET] = 1;
|
|
10
|
+
bracketSyntax[CH_RBRACKET] = 1;
|
|
11
|
+
bracketSyntax[CH_COLON] = 1;
|
|
12
|
+
bracketSyntax[CH_DOT] = 1;
|
|
13
|
+
bracketSyntax[CH_EQ] = 1;
|
|
14
|
+
bracketSyntax[CH_DASH] = 1;
|
|
15
|
+
bracketSyntax[CH_BACKSLASH] = 1;
|
|
16
|
+
// Bracket extents follow Bash's matcher (lib/glob/sm_loop.c, BRACKMATCH and PARSE_SUBBRACKET on
|
|
17
|
+
// the path where no member matches): `[:name:]` and `[=c=]` end at the first `:]` or `=]` unless a
|
|
18
|
+
// raw `]` comes first, `[.sym.]` ends at the first `.]` even past a `]`, a class or equivalence
|
|
19
|
+
// never starts a range, and a `-` range end consumes one member, be it an escape, a plain `[` or a
|
|
20
|
+
// collating symbol (also behind an escaped `[`). Quoted and expanded parts are single opaque
|
|
21
|
+
// members; Bash additionally lets quoted `]`, `:`, `=`, `.` and `[` take part in symbol and range
|
|
22
|
+
// scanning after re-escaping them, which this scan leaves out.
|
|
23
|
+
function bracketEnds(source, start, end, parts, offset) {
|
|
24
|
+
let close = end - 1;
|
|
25
|
+
while (close > start && source.charCodeAt(close) !== CH_RBRACKET)
|
|
26
|
+
close--;
|
|
27
|
+
if (close === start)
|
|
28
|
+
return null;
|
|
29
|
+
// Tokens: each special character, and runs of plain members (continuations vanish, quoted or
|
|
30
|
+
// expanded parts are plain). Only specials change an extent, so a run acts as one member except
|
|
31
|
+
// as a range end, which consumes just its first member.
|
|
32
|
+
const positions = [];
|
|
33
|
+
const kinds = [];
|
|
34
|
+
const members = [];
|
|
35
|
+
let partIndex = 0;
|
|
36
|
+
let symbols = false;
|
|
37
|
+
for (let pos = start; pos < end; pos++) {
|
|
38
|
+
while (parts && partIndex < parts.length && parts[partIndex].end <= pos + offset)
|
|
39
|
+
partIndex++;
|
|
40
|
+
const part = parts?.[partIndex];
|
|
41
|
+
const tokenPos = pos;
|
|
42
|
+
let kind = 0;
|
|
43
|
+
if (part && part.pos <= pos + offset && part.type !== "Literal") {
|
|
44
|
+
pos = part.end - offset - 1;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
kind = source.charCodeAt(pos);
|
|
48
|
+
if (kind === CH_BACKSLASH && pos + 1 < end && source.charCodeAt(pos + 1) === CH_NL) {
|
|
49
|
+
pos++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (kind >= 128 || !bracketSyntax[kind])
|
|
53
|
+
kind = 0;
|
|
54
|
+
}
|
|
55
|
+
const last = kinds.length - 1;
|
|
56
|
+
if (kind === 0 && last >= 0 && kinds[last] === 0) {
|
|
57
|
+
members[last]++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (last >= 0 && kinds[last] === CH_LBRACKET && (kind === CH_COLON || kind === CH_EQ || kind === CH_DOT)) {
|
|
61
|
+
symbols = true;
|
|
62
|
+
}
|
|
63
|
+
positions.push(tokenPos);
|
|
64
|
+
kinds.push(kind);
|
|
65
|
+
members.push(1);
|
|
66
|
+
}
|
|
67
|
+
const count = kinds.length;
|
|
68
|
+
// PARSE_SUBBRACKET memoized per opener: symbolEnd[t] is the token after the `X]` closing the
|
|
69
|
+
// symbol that `[X` opens at token t, or -1. One right-to-left pass tracks the nearest raw `]`
|
|
70
|
+
// and the nearest `:]`, `=]` and `.]` beyond the opener. Escaped characters are separate tokens,
|
|
71
|
+
// so a `\]` still stops a `:` or `=` scan as it does in Bash.
|
|
72
|
+
let symbolEnd;
|
|
73
|
+
if (symbols) {
|
|
74
|
+
symbolEnd = new Int32Array(count).fill(-1);
|
|
75
|
+
let close = -1;
|
|
76
|
+
let colon = -1;
|
|
77
|
+
let eq = -1;
|
|
78
|
+
let dot = -1;
|
|
79
|
+
for (let i = count - 1; i >= 0; i--) {
|
|
80
|
+
// The scan for the opener at i starts two tokens in, so fold token i + 2 in first.
|
|
81
|
+
const kind = kinds[i + 2];
|
|
82
|
+
if (kind === CH_RBRACKET)
|
|
83
|
+
close = i + 2;
|
|
84
|
+
else if (kinds[i + 3] === CH_RBRACKET) {
|
|
85
|
+
if (kind === CH_COLON)
|
|
86
|
+
colon = i + 2;
|
|
87
|
+
else if (kind === CH_EQ)
|
|
88
|
+
eq = i + 2;
|
|
89
|
+
else if (kind === CH_DOT)
|
|
90
|
+
dot = i + 2;
|
|
91
|
+
}
|
|
92
|
+
if (kinds[i] !== CH_LBRACKET)
|
|
93
|
+
continue;
|
|
94
|
+
const type = kinds[i + 1];
|
|
95
|
+
const found = type === CH_COLON ? colon : type === CH_EQ ? eq : type === CH_DOT ? dot : -1;
|
|
96
|
+
if (found !== -1 && (type === CH_DOT || close === -1 || close > found))
|
|
97
|
+
symbolEnd[i] = found + 2;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const subBracket = (open) => (symbolEnd === undefined ? -1 : symbolEnd[open]);
|
|
101
|
+
// endFrom[t]: the token after the `]` closing a bracket whose next member starts at token t, or
|
|
102
|
+
// -1 when the pattern runs out and the opening `[` stays literal.
|
|
103
|
+
const endFrom = new Int32Array(count + 2).fill(-1);
|
|
104
|
+
const resume = (next, range) => {
|
|
105
|
+
if (next >= count)
|
|
106
|
+
return -1;
|
|
107
|
+
if (range && kinds[next] === CH_DASH && next + 1 < count && kinds[next + 1] !== CH_RBRACKET) {
|
|
108
|
+
let last = next + 1;
|
|
109
|
+
if (kinds[last] === CH_BACKSLASH) {
|
|
110
|
+
if (last + 1 >= count)
|
|
111
|
+
return -1;
|
|
112
|
+
last++;
|
|
113
|
+
}
|
|
114
|
+
let after = last + 1;
|
|
115
|
+
if (kinds[last] === CH_LBRACKET && kinds[last + 1] === CH_DOT) {
|
|
116
|
+
const symbol = subBracket(last);
|
|
117
|
+
if (symbol !== -1)
|
|
118
|
+
after = symbol;
|
|
119
|
+
}
|
|
120
|
+
else if (kinds[last] === 0 && members[last] > 1) {
|
|
121
|
+
// The run's later members stay members, and its last one may start the next range.
|
|
122
|
+
return endFrom[last];
|
|
123
|
+
}
|
|
124
|
+
if (after >= count)
|
|
125
|
+
return -1;
|
|
126
|
+
return kinds[after] === CH_RBRACKET ? after + 1 : endFrom[after];
|
|
127
|
+
}
|
|
128
|
+
return kinds[next] === CH_RBRACKET ? next + 1 : endFrom[next];
|
|
129
|
+
};
|
|
130
|
+
for (let t = count - 1; t >= 0; t--) {
|
|
131
|
+
const kind = kinds[t];
|
|
132
|
+
let after = t + 1;
|
|
133
|
+
let range = true;
|
|
134
|
+
if (kind === CH_BACKSLASH) {
|
|
135
|
+
if (t + 1 >= count)
|
|
136
|
+
continue;
|
|
137
|
+
after = t + 2;
|
|
138
|
+
}
|
|
139
|
+
else if (kind === CH_LBRACKET) {
|
|
140
|
+
const type = kinds[t + 1];
|
|
141
|
+
if (type === CH_COLON || type === CH_EQ || type === CH_DOT) {
|
|
142
|
+
const symbol = subBracket(t);
|
|
143
|
+
if (symbol !== -1) {
|
|
144
|
+
after = symbol;
|
|
145
|
+
range = type === CH_DOT;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
endFrom[t] = resume(after, range);
|
|
150
|
+
}
|
|
151
|
+
const ends = new Map();
|
|
152
|
+
for (let t = 0; t < count; t++) {
|
|
153
|
+
if (kinds[t] !== CH_LBRACKET)
|
|
154
|
+
continue;
|
|
155
|
+
let first = t + 1;
|
|
156
|
+
if (kinds[first] === CH_BANG || kinds[first] === CH_CARET)
|
|
157
|
+
first++;
|
|
158
|
+
if (first >= count)
|
|
159
|
+
continue;
|
|
160
|
+
const close = kinds[first] === CH_RBRACKET ? resume(first + 1, true) : endFrom[first];
|
|
161
|
+
if (close !== -1)
|
|
162
|
+
ends.set(positions[t], positions[close - 1] + 1);
|
|
163
|
+
}
|
|
164
|
+
return ends;
|
|
165
|
+
}
|
|
166
|
+
function appendRange(source, start, end, parts, index, offset, result) {
|
|
167
|
+
while (start < end) {
|
|
168
|
+
while (parts && index < parts.length && parts[index].end <= start + offset)
|
|
169
|
+
index++;
|
|
170
|
+
const part = parts?.[index];
|
|
171
|
+
if (part && part.pos === start + offset && part.end <= end + offset) {
|
|
172
|
+
result.push(part);
|
|
173
|
+
start = part.end - offset;
|
|
174
|
+
index++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const stop = part ? Math.min(end, (part.pos > start + offset ? part.pos : part.end) - offset) : end;
|
|
178
|
+
const text = source.slice(start, stop);
|
|
179
|
+
result.push({ type: "Literal", pos: start + offset, end: stop + offset, text, value: unescapeBareValue(text) });
|
|
180
|
+
start = stop;
|
|
181
|
+
}
|
|
182
|
+
return index;
|
|
183
|
+
}
|
|
184
|
+
export function parseGlobParts(source, start, end, parts, offset = 0) {
|
|
185
|
+
let result;
|
|
186
|
+
let brackets;
|
|
187
|
+
let partIndex = 0;
|
|
188
|
+
let emittedIndex = 0;
|
|
189
|
+
let literalStart = start;
|
|
190
|
+
for (let pos = start; pos < end; pos++) {
|
|
191
|
+
while (parts && partIndex < parts.length && parts[partIndex].end <= pos + offset)
|
|
192
|
+
partIndex++;
|
|
193
|
+
const part = parts?.[partIndex];
|
|
194
|
+
if (part && part.pos <= pos + offset && part.type !== "Literal") {
|
|
195
|
+
pos = part.end - offset - 1;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const character = source.charCodeAt(pos);
|
|
199
|
+
if (character === CH_BACKSLASH) {
|
|
200
|
+
pos++;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
let globEnd;
|
|
204
|
+
if (character === CH_STAR || character === CH_QUESTION) {
|
|
205
|
+
const limit = part ? Math.min(end, part.end - offset) : end;
|
|
206
|
+
// Embedded-word scans can leave extglob operators inside Literal parts.
|
|
207
|
+
const next = skipLineContinuations(source, pos + 1, limit);
|
|
208
|
+
if (next < limit && source.charCodeAt(next) === CH_LPAREN)
|
|
209
|
+
continue;
|
|
210
|
+
globEnd = pos + 1;
|
|
211
|
+
if (character === CH_STAR) {
|
|
212
|
+
while (globEnd < limit && source.charCodeAt(globEnd) === CH_STAR) {
|
|
213
|
+
const next = skipLineContinuations(source, globEnd + 1, limit);
|
|
214
|
+
if (next < limit && source.charCodeAt(next) === CH_LPAREN)
|
|
215
|
+
break;
|
|
216
|
+
globEnd++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (character === CH_LBRACKET) {
|
|
221
|
+
if (brackets === undefined)
|
|
222
|
+
brackets = bracketEnds(source, pos, end, parts, offset);
|
|
223
|
+
const close = brackets?.get(pos);
|
|
224
|
+
if (close === undefined)
|
|
225
|
+
continue;
|
|
226
|
+
globEnd = close;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (!result)
|
|
232
|
+
result = [];
|
|
233
|
+
emittedIndex = appendRange(source, literalStart, pos, parts, emittedIndex, offset, result);
|
|
234
|
+
const text = source.slice(pos, globEnd);
|
|
235
|
+
let glob;
|
|
236
|
+
if (character === CH_LBRACKET) {
|
|
237
|
+
const interior = [];
|
|
238
|
+
emittedIndex = appendRange(source, pos + 1, globEnd - 1, parts, emittedIndex, offset, interior);
|
|
239
|
+
glob = {
|
|
240
|
+
type: "Glob",
|
|
241
|
+
kind: "bracket",
|
|
242
|
+
pos: pos + offset,
|
|
243
|
+
end: globEnd + offset,
|
|
244
|
+
text,
|
|
245
|
+
value: "[" + wordPartsValue(interior) + "]",
|
|
246
|
+
parts: interior,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
glob = {
|
|
251
|
+
type: "Glob",
|
|
252
|
+
kind: character === CH_STAR ? "star" : "question",
|
|
253
|
+
pos: pos + offset,
|
|
254
|
+
end: globEnd + offset,
|
|
255
|
+
text,
|
|
256
|
+
value: text,
|
|
257
|
+
parts: undefined,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
result.push(glob);
|
|
261
|
+
literalStart = globEnd;
|
|
262
|
+
pos = globEnd - 1;
|
|
263
|
+
}
|
|
264
|
+
if (!result)
|
|
265
|
+
return parts ?? undefined;
|
|
266
|
+
appendRange(source, literalStart, end, parts, emittedIndex, offset, result);
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { computeHereDocBodyParts } from "./parts.js";
|
|
2
|
+
export class HereDocBodyImpl {
|
|
3
|
+
type = "HereDocBody";
|
|
4
|
+
pos;
|
|
5
|
+
end;
|
|
6
|
+
text = "";
|
|
7
|
+
#source;
|
|
8
|
+
#depth;
|
|
9
|
+
#context;
|
|
10
|
+
#parts;
|
|
11
|
+
constructor(source, pos, quoted, depth, context) {
|
|
12
|
+
this.pos = pos;
|
|
13
|
+
this.end = pos;
|
|
14
|
+
this.#source = source;
|
|
15
|
+
this.#depth = depth;
|
|
16
|
+
this.#context = context;
|
|
17
|
+
this.#parts = quoted ? undefined : null;
|
|
18
|
+
}
|
|
19
|
+
get parts() {
|
|
20
|
+
if (this.#parts === null)
|
|
21
|
+
this.#parts = computeHereDocBodyParts(this.#source, this, this.#depth, this.#context);
|
|
22
|
+
return this.#parts;
|
|
23
|
+
}
|
|
24
|
+
toJSON() {
|
|
25
|
+
return { type: this.type, pos: this.pos, end: this.end, text: this.text, parts: this.parts };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|