@mjakl/pi-processes 0.8.0

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.
@@ -0,0 +1,133 @@
1
+ // Shell AST helpers. Duplicated from pi-toolchain since cross-extension imports are not allowed.
2
+
3
+ import type {
4
+ Command,
5
+ Program,
6
+ SimpleCommand,
7
+ Statement,
8
+ Word,
9
+ WordPart,
10
+ } from "@aliou/sh";
11
+
12
+ /**
13
+ * Resolve a Word node to its literal string value.
14
+ * Concatenates Literal, SglQuoted, and simple DblQuoted parts.
15
+ * For parts containing parameter expansions, command substitutions, etc.,
16
+ * includes the raw text representation (e.g. `$VAR`).
17
+ */
18
+ export function wordToString(word: Word): string {
19
+ return word.parts.map(partToString).join("");
20
+ }
21
+
22
+ function partToString(part: WordPart): string {
23
+ switch (part.type) {
24
+ case "Literal":
25
+ return part.value;
26
+ case "SglQuoted":
27
+ return part.value;
28
+ case "DblQuoted":
29
+ return part.parts.map(partToString).join("");
30
+ case "ParamExp":
31
+ return part.short
32
+ ? `$${part.param.value}`
33
+ : `\${${part.param.value}${part.op ?? ""}${part.value ? wordToString(part.value) : ""}}`;
34
+ case "CmdSubst":
35
+ return "$(...)";
36
+ case "ArithExp":
37
+ return `$((${part.expr}))`;
38
+ case "ProcSubst":
39
+ return `${part.op}(...)`;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Walk the AST and call `callback` for every SimpleCommand found at any
45
+ * nesting depth. Returns early if callback returns `true`.
46
+ */
47
+ export function walkCommands(
48
+ node: Program,
49
+ callback: (cmd: SimpleCommand) => boolean | undefined,
50
+ ): void {
51
+ for (const stmt of node.body) {
52
+ if (walkStatement(stmt, callback)) return;
53
+ }
54
+ }
55
+
56
+ function walkStatement(
57
+ stmt: Statement,
58
+ callback: (cmd: SimpleCommand) => boolean | undefined,
59
+ ): boolean {
60
+ return walkCommand(stmt.command, callback);
61
+ }
62
+
63
+ function walkStatements(
64
+ stmts: Statement[],
65
+ callback: (cmd: SimpleCommand) => boolean | undefined,
66
+ ): boolean {
67
+ for (const stmt of stmts) {
68
+ if (walkStatement(stmt, callback)) return true;
69
+ }
70
+ return false;
71
+ }
72
+
73
+ function walkCommand(
74
+ cmd: Command,
75
+ callback: (cmd: SimpleCommand) => boolean | undefined,
76
+ ): boolean {
77
+ switch (cmd.type) {
78
+ case "SimpleCommand":
79
+ return callback(cmd) === true;
80
+
81
+ case "Pipeline":
82
+ return walkStatements(cmd.commands, callback);
83
+
84
+ case "Logical":
85
+ return (
86
+ walkStatement(cmd.left, callback) || walkStatement(cmd.right, callback)
87
+ );
88
+
89
+ case "Subshell":
90
+ case "Block":
91
+ return walkStatements(cmd.body, callback);
92
+
93
+ case "IfClause":
94
+ return (
95
+ walkStatements(cmd.cond, callback) ||
96
+ walkStatements(cmd.then, callback) ||
97
+ (cmd.else ? walkStatements(cmd.else, callback) : false)
98
+ );
99
+
100
+ case "ForClause":
101
+ case "SelectClause":
102
+ case "WhileClause":
103
+ return (
104
+ ("cond" in cmd && cmd.cond
105
+ ? walkStatements(cmd.cond, callback)
106
+ : false) || walkStatements(cmd.body, callback)
107
+ );
108
+
109
+ case "CaseClause":
110
+ for (const item of cmd.items) {
111
+ if (walkStatements(item.body, callback)) return true;
112
+ }
113
+ return false;
114
+
115
+ case "FunctionDecl":
116
+ return walkStatements(cmd.body, callback);
117
+
118
+ case "TimeClause":
119
+ return walkStatement(cmd.command, callback);
120
+
121
+ case "CoprocClause":
122
+ return walkStatement(cmd.body, callback);
123
+
124
+ case "CStyleLoop":
125
+ return walkStatements(cmd.body, callback);
126
+
127
+ case "TestClause":
128
+ case "ArithCmd":
129
+ case "DeclClause":
130
+ case "LetClause":
131
+ return false;
132
+ }
133
+ }