shell-dsl 0.0.6 → 0.0.8

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.
Files changed (197) hide show
  1. package/README.md +3 -1
  2. package/dist/cjs/index.cjs +14 -4
  3. package/dist/cjs/index.cjs.map +3 -3
  4. package/dist/cjs/package.json +1 -1
  5. package/dist/cjs/src/commands/awk/awk.cjs +276 -0
  6. package/dist/cjs/src/commands/awk/awk.cjs.map +10 -0
  7. package/dist/cjs/src/commands/break-continue/break-continue.cjs +56 -0
  8. package/dist/cjs/src/commands/break-continue/break-continue.cjs.map +10 -0
  9. package/dist/cjs/src/commands/cat/cat.cjs +57 -0
  10. package/dist/cjs/src/commands/cat/cat.cjs.map +10 -0
  11. package/dist/cjs/src/commands/cp/cp.cjs +126 -0
  12. package/dist/cjs/src/commands/cp/cp.cjs.map +10 -0
  13. package/dist/cjs/src/commands/echo/echo.cjs +50 -0
  14. package/dist/cjs/src/commands/echo/echo.cjs.map +10 -0
  15. package/dist/cjs/src/commands/find/find.cjs +251 -0
  16. package/dist/cjs/src/commands/find/find.cjs.map +10 -0
  17. package/dist/cjs/src/commands/grep/grep.cjs +510 -0
  18. package/dist/cjs/src/commands/grep/grep.cjs.map +10 -0
  19. package/dist/cjs/src/commands/head/head.cjs +95 -0
  20. package/dist/cjs/src/commands/head/head.cjs.map +10 -0
  21. package/dist/cjs/src/commands/index.cjs +136 -0
  22. package/dist/cjs/src/commands/index.cjs.map +10 -0
  23. package/dist/cjs/src/commands/ls/ls.cjs +119 -0
  24. package/dist/cjs/src/commands/ls/ls.cjs.map +10 -0
  25. package/dist/cjs/src/commands/mkdir/mkdir.cjs +64 -0
  26. package/dist/cjs/src/commands/mkdir/mkdir.cjs.map +10 -0
  27. package/dist/cjs/src/commands/mv/mv.cjs +118 -0
  28. package/dist/cjs/src/commands/mv/mv.cjs.map +10 -0
  29. package/dist/cjs/src/commands/pwd/pwd.cjs +41 -0
  30. package/dist/cjs/src/commands/pwd/pwd.cjs.map +10 -0
  31. package/dist/cjs/src/commands/rm/rm.cjs +82 -0
  32. package/dist/cjs/src/commands/rm/rm.cjs.map +10 -0
  33. package/dist/cjs/src/commands/sed/sed.cjs +218 -0
  34. package/dist/cjs/src/commands/sed/sed.cjs.map +10 -0
  35. package/dist/cjs/src/commands/sort/sort.cjs +105 -0
  36. package/dist/cjs/src/commands/sort/sort.cjs.map +10 -0
  37. package/dist/cjs/src/commands/tail/tail.cjs +95 -0
  38. package/dist/cjs/src/commands/tail/tail.cjs.map +10 -0
  39. package/dist/cjs/src/commands/tee/tee.cjs +65 -0
  40. package/dist/cjs/src/commands/tee/tee.cjs.map +10 -0
  41. package/dist/cjs/src/commands/test/test.cjs +148 -0
  42. package/dist/cjs/src/commands/test/test.cjs.map +10 -0
  43. package/dist/cjs/src/commands/touch/touch.cjs +70 -0
  44. package/dist/cjs/src/commands/touch/touch.cjs.map +10 -0
  45. package/dist/cjs/src/commands/tree/tree.cjs +161 -0
  46. package/dist/cjs/src/commands/tree/tree.cjs.map +10 -0
  47. package/dist/cjs/src/commands/true-false/true-false.cjs +43 -0
  48. package/dist/cjs/src/commands/true-false/true-false.cjs.map +10 -0
  49. package/dist/cjs/src/commands/uniq/uniq.cjs +116 -0
  50. package/dist/cjs/src/commands/uniq/uniq.cjs.map +10 -0
  51. package/dist/cjs/src/commands/wc/wc.cjs +116 -0
  52. package/dist/cjs/src/commands/wc/wc.cjs.map +10 -0
  53. package/dist/cjs/src/index.cjs +10 -2
  54. package/dist/cjs/src/index.cjs.map +3 -3
  55. package/dist/cjs/src/interpreter/index.cjs +4 -2
  56. package/dist/cjs/src/interpreter/index.cjs.map +3 -3
  57. package/dist/cjs/src/interpreter/interpreter.cjs +390 -2
  58. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  59. package/dist/cjs/src/lexer/index.cjs +3 -2
  60. package/dist/cjs/src/lexer/index.cjs.map +3 -3
  61. package/dist/cjs/src/lexer/lexer.cjs +359 -8
  62. package/dist/cjs/src/lexer/lexer.cjs.map +3 -3
  63. package/dist/cjs/src/lexer/tokens.cjs +35 -2
  64. package/dist/cjs/src/lexer/tokens.cjs.map +3 -3
  65. package/dist/cjs/src/parser/ast.cjs +25 -1
  66. package/dist/cjs/src/parser/ast.cjs.map +3 -3
  67. package/dist/cjs/src/parser/index.cjs +7 -1
  68. package/dist/cjs/src/parser/index.cjs.map +3 -3
  69. package/dist/cjs/src/parser/parser.cjs +280 -8
  70. package/dist/cjs/src/parser/parser.cjs.map +3 -3
  71. package/dist/cjs/src/shell-dsl.cjs +2 -2
  72. package/dist/cjs/src/shell-dsl.cjs.map +3 -3
  73. package/dist/mjs/index.mjs +25 -5
  74. package/dist/mjs/index.mjs.map +3 -3
  75. package/dist/mjs/package.json +1 -1
  76. package/dist/mjs/src/commands/awk/awk.mjs +246 -0
  77. package/dist/mjs/src/commands/awk/awk.mjs.map +10 -0
  78. package/dist/mjs/src/commands/break-continue/break-continue.mjs +26 -0
  79. package/dist/mjs/src/commands/break-continue/break-continue.mjs.map +10 -0
  80. package/dist/mjs/src/commands/cat/cat.mjs +27 -0
  81. package/dist/mjs/src/commands/cat/cat.mjs.map +10 -0
  82. package/dist/mjs/src/commands/cp/cp.mjs +96 -0
  83. package/dist/mjs/src/commands/cp/cp.mjs.map +10 -0
  84. package/dist/mjs/src/commands/echo/echo.mjs +20 -0
  85. package/dist/mjs/src/commands/echo/echo.mjs.map +10 -0
  86. package/dist/mjs/src/commands/find/find.mjs +221 -0
  87. package/dist/mjs/src/commands/find/find.mjs.map +10 -0
  88. package/dist/mjs/src/commands/grep/grep.mjs +480 -0
  89. package/dist/mjs/src/commands/grep/grep.mjs.map +10 -0
  90. package/dist/mjs/src/commands/head/head.mjs +65 -0
  91. package/dist/mjs/src/commands/head/head.mjs.map +10 -0
  92. package/dist/mjs/src/commands/index.mjs +106 -0
  93. package/dist/mjs/src/commands/index.mjs.map +10 -0
  94. package/dist/mjs/src/commands/ls/ls.mjs +89 -0
  95. package/dist/mjs/src/commands/ls/ls.mjs.map +10 -0
  96. package/dist/mjs/src/commands/mkdir/mkdir.mjs +34 -0
  97. package/dist/mjs/src/commands/mkdir/mkdir.mjs.map +10 -0
  98. package/dist/mjs/src/commands/mv/mv.mjs +88 -0
  99. package/dist/mjs/src/commands/mv/mv.mjs.map +10 -0
  100. package/dist/mjs/src/commands/pwd/pwd.mjs +11 -0
  101. package/dist/mjs/src/commands/pwd/pwd.mjs.map +10 -0
  102. package/dist/mjs/src/commands/rm/rm.mjs +52 -0
  103. package/dist/mjs/src/commands/rm/rm.mjs.map +10 -0
  104. package/dist/mjs/src/commands/sed/sed.mjs +188 -0
  105. package/dist/mjs/src/commands/sed/sed.mjs.map +10 -0
  106. package/dist/mjs/src/commands/sort/sort.mjs +75 -0
  107. package/dist/mjs/src/commands/sort/sort.mjs.map +10 -0
  108. package/dist/mjs/src/commands/tail/tail.mjs +65 -0
  109. package/dist/mjs/src/commands/tail/tail.mjs.map +10 -0
  110. package/dist/mjs/src/commands/tee/tee.mjs +35 -0
  111. package/dist/mjs/src/commands/tee/tee.mjs.map +10 -0
  112. package/dist/mjs/src/commands/test/test.mjs +118 -0
  113. package/dist/mjs/src/commands/test/test.mjs.map +10 -0
  114. package/dist/mjs/src/commands/touch/touch.mjs +40 -0
  115. package/dist/mjs/src/commands/touch/touch.mjs.map +10 -0
  116. package/dist/mjs/src/commands/tree/tree.mjs +131 -0
  117. package/dist/mjs/src/commands/tree/tree.mjs.map +10 -0
  118. package/dist/mjs/src/commands/true-false/true-false.mjs +13 -0
  119. package/dist/mjs/src/commands/true-false/true-false.mjs.map +10 -0
  120. package/dist/mjs/src/commands/uniq/uniq.mjs +86 -0
  121. package/dist/mjs/src/commands/uniq/uniq.mjs.map +10 -0
  122. package/dist/mjs/src/commands/wc/wc.mjs +86 -0
  123. package/dist/mjs/src/commands/wc/wc.mjs.map +10 -0
  124. package/dist/mjs/src/index.mjs +18 -4
  125. package/dist/mjs/src/index.mjs.map +3 -3
  126. package/dist/mjs/src/interpreter/index.mjs +5 -3
  127. package/dist/mjs/src/interpreter/index.mjs.map +2 -2
  128. package/dist/mjs/src/interpreter/interpreter.mjs +390 -2
  129. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  130. package/dist/mjs/src/lexer/index.mjs +4 -3
  131. package/dist/mjs/src/lexer/index.mjs.map +2 -2
  132. package/dist/mjs/src/lexer/lexer.mjs +359 -8
  133. package/dist/mjs/src/lexer/lexer.mjs.map +3 -3
  134. package/dist/mjs/src/lexer/tokens.mjs +35 -2
  135. package/dist/mjs/src/lexer/tokens.mjs.map +3 -3
  136. package/dist/mjs/src/parser/ast.mjs +25 -1
  137. package/dist/mjs/src/parser/ast.mjs.map +3 -3
  138. package/dist/mjs/src/parser/index.mjs +14 -2
  139. package/dist/mjs/src/parser/index.mjs.map +3 -3
  140. package/dist/mjs/src/parser/parser.mjs +280 -8
  141. package/dist/mjs/src/parser/parser.mjs.map +3 -3
  142. package/dist/mjs/src/shell-dsl.mjs +2 -2
  143. package/dist/mjs/src/shell-dsl.mjs.map +3 -3
  144. package/dist/types/index.d.ts +2 -2
  145. package/dist/types/src/commands/awk/awk.d.ts +2 -0
  146. package/dist/types/src/commands/break-continue/break-continue.d.ts +3 -0
  147. package/dist/types/src/commands/cat/cat.d.ts +2 -0
  148. package/dist/types/src/commands/cp/cp.d.ts +2 -0
  149. package/dist/types/src/commands/echo/echo.d.ts +2 -0
  150. package/dist/types/src/commands/find/find.d.ts +2 -0
  151. package/dist/types/src/commands/grep/grep.d.ts +2 -0
  152. package/dist/types/src/commands/head/head.d.ts +2 -0
  153. package/dist/types/src/commands/index.d.ts +25 -0
  154. package/dist/types/src/commands/ls/ls.d.ts +2 -0
  155. package/dist/types/src/commands/mkdir/mkdir.d.ts +2 -0
  156. package/dist/types/src/commands/mv/mv.d.ts +2 -0
  157. package/dist/types/src/commands/pwd/pwd.d.ts +2 -0
  158. package/dist/types/src/commands/rm/rm.d.ts +2 -0
  159. package/dist/types/src/commands/sed/sed.d.ts +2 -0
  160. package/dist/types/src/commands/sort/sort.d.ts +2 -0
  161. package/dist/types/src/commands/tail/tail.d.ts +2 -0
  162. package/dist/types/src/commands/tee/tee.d.ts +2 -0
  163. package/dist/types/{commands → src/commands/test}/test.d.ts +1 -1
  164. package/dist/types/src/commands/touch/touch.d.ts +2 -0
  165. package/dist/types/src/commands/tree/tree.d.ts +2 -0
  166. package/dist/types/{commands → src/commands/true-false}/true-false.d.ts +1 -1
  167. package/dist/types/src/commands/uniq/uniq.d.ts +2 -0
  168. package/dist/types/src/commands/wc/wc.d.ts +2 -0
  169. package/dist/types/src/index.d.ts +3 -3
  170. package/dist/types/src/interpreter/index.d.ts +1 -1
  171. package/dist/types/src/interpreter/interpreter.d.ts +18 -0
  172. package/dist/types/src/lexer/index.d.ts +2 -2
  173. package/dist/types/src/lexer/lexer.d.ts +16 -2
  174. package/dist/types/src/lexer/tokens.d.ts +20 -0
  175. package/dist/types/src/parser/ast.d.ts +47 -1
  176. package/dist/types/src/parser/index.d.ts +2 -2
  177. package/dist/types/src/parser/parser.d.ts +15 -0
  178. package/package.json +1 -1
  179. package/dist/types/commands/cat.d.ts +0 -2
  180. package/dist/types/commands/cp.d.ts +0 -2
  181. package/dist/types/commands/echo.d.ts +0 -2
  182. package/dist/types/commands/find.d.ts +0 -2
  183. package/dist/types/commands/grep.d.ts +0 -2
  184. package/dist/types/commands/head.d.ts +0 -2
  185. package/dist/types/commands/index.d.ts +0 -22
  186. package/dist/types/commands/ls.d.ts +0 -2
  187. package/dist/types/commands/mkdir.d.ts +0 -2
  188. package/dist/types/commands/mv.d.ts +0 -2
  189. package/dist/types/commands/pwd.d.ts +0 -2
  190. package/dist/types/commands/rm.d.ts +0 -2
  191. package/dist/types/commands/sort.d.ts +0 -2
  192. package/dist/types/commands/tail.d.ts +0 -2
  193. package/dist/types/commands/tee.d.ts +0 -2
  194. package/dist/types/commands/touch.d.ts +0 -2
  195. package/dist/types/commands/tree.d.ts +0 -2
  196. package/dist/types/commands/uniq.d.ts +0 -2
  197. package/dist/types/commands/wc.d.ts +0 -2
@@ -49,10 +49,12 @@ class Parser {
49
49
  return result;
50
50
  }
51
51
  parseSequence() {
52
+ this.skipNewlines();
52
53
  const commands = [];
53
54
  commands.push(this.parseAndOr());
54
- while (this.match("semicolon")) {
55
- if (this.isAtEnd() || this.check("semicolon"))
55
+ while (this.match("semicolon") || this.match("newline")) {
56
+ this.skipNewlines();
57
+ if (this.isAtEnd() || this.check("semicolon") || this.check("newline") || this.isTerminatingKeyword())
56
58
  continue;
57
59
  commands.push(this.parseAndOr());
58
60
  }
@@ -61,6 +63,15 @@ class Parser {
61
63
  }
62
64
  return { type: "sequence", commands };
63
65
  }
66
+ skipNewlines() {
67
+ while (this.match("newline")) {}
68
+ }
69
+ isTerminatingKeyword() {
70
+ const token = this.peek();
71
+ if (token.type !== "keyword")
72
+ return false;
73
+ return ["then", "elif", "else", "fi", "do", "done", "esac"].includes(token.value);
74
+ }
64
75
  parseAndOr() {
65
76
  let left = this.parsePipeline();
66
77
  while (this.check("and") || this.check("or")) {
@@ -76,15 +87,206 @@ class Parser {
76
87
  }
77
88
  parsePipeline() {
78
89
  const commands = [];
79
- commands.push(this.parseCommand());
90
+ commands.push(this.parseCompoundOrCommand());
80
91
  while (this.match("pipe")) {
81
- commands.push(this.parseCommand());
92
+ this.skipNewlines();
93
+ commands.push(this.parseCompoundOrCommand());
82
94
  }
83
95
  if (commands.length === 1) {
84
96
  return commands[0];
85
97
  }
86
98
  return { type: "pipeline", commands };
87
99
  }
100
+ parseCompoundOrCommand() {
101
+ this.skipNewlines();
102
+ const token = this.peek();
103
+ if (token.type === "keyword") {
104
+ switch (token.value) {
105
+ case "if":
106
+ return this.parseIf();
107
+ case "for":
108
+ return this.parseFor();
109
+ case "while":
110
+ return this.parseWhile();
111
+ case "until":
112
+ return this.parseUntil();
113
+ case "case":
114
+ return this.parseCase();
115
+ }
116
+ }
117
+ return this.parseCommand();
118
+ }
119
+ parseIf() {
120
+ this.expectKeyword("if");
121
+ const condition = this.parseCompoundList(["then"]);
122
+ this.expectKeyword("then");
123
+ const thenBranch = this.parseCompoundList(["elif", "else", "fi"]);
124
+ const elifBranches = [];
125
+ while (this.checkKeyword("elif")) {
126
+ this.expectKeyword("elif");
127
+ const elifCondition = this.parseCompoundList(["then"]);
128
+ this.expectKeyword("then");
129
+ const elifBody = this.parseCompoundList(["elif", "else", "fi"]);
130
+ elifBranches.push({ condition: elifCondition, body: elifBody });
131
+ }
132
+ let elseBranch;
133
+ if (this.checkKeyword("else")) {
134
+ this.expectKeyword("else");
135
+ elseBranch = this.parseCompoundList(["fi"]);
136
+ }
137
+ this.expectKeyword("fi");
138
+ return {
139
+ type: "if",
140
+ condition,
141
+ thenBranch,
142
+ elifBranches,
143
+ elseBranch
144
+ };
145
+ }
146
+ parseFor() {
147
+ this.expectKeyword("for");
148
+ const varToken = this.peek();
149
+ if (varToken.type !== "word") {
150
+ throw new import_errors.ParseError("Expected variable name after 'for'");
151
+ }
152
+ this.advance();
153
+ const variable = varToken.value;
154
+ const items = [];
155
+ if (this.checkKeyword("in")) {
156
+ this.expectKeyword("in");
157
+ while (!this.isAtEnd() && !this.check("semicolon") && !this.check("newline") && !this.checkKeyword("do")) {
158
+ items.push(this.parseWordArg());
159
+ }
160
+ }
161
+ if (!this.match("semicolon")) {
162
+ this.match("newline");
163
+ }
164
+ this.skipNewlines();
165
+ this.expectKeyword("do");
166
+ const body = this.parseCompoundList(["done"]);
167
+ this.expectKeyword("done");
168
+ return {
169
+ type: "for",
170
+ variable,
171
+ items,
172
+ body
173
+ };
174
+ }
175
+ parseWhile() {
176
+ this.expectKeyword("while");
177
+ const condition = this.parseCompoundList(["do"]);
178
+ this.expectKeyword("do");
179
+ const body = this.parseCompoundList(["done"]);
180
+ this.expectKeyword("done");
181
+ return {
182
+ type: "while",
183
+ condition,
184
+ body
185
+ };
186
+ }
187
+ parseUntil() {
188
+ this.expectKeyword("until");
189
+ const condition = this.parseCompoundList(["do"]);
190
+ this.expectKeyword("do");
191
+ const body = this.parseCompoundList(["done"]);
192
+ this.expectKeyword("done");
193
+ return {
194
+ type: "until",
195
+ condition,
196
+ body
197
+ };
198
+ }
199
+ parseCase() {
200
+ this.expectKeyword("case");
201
+ const word = this.parseWordArg();
202
+ this.expectKeyword("in");
203
+ this.skipNewlines();
204
+ const clauses = [];
205
+ while (!this.isAtEnd() && !this.checkKeyword("esac")) {
206
+ this.match("openParen");
207
+ const patterns = [];
208
+ patterns.push(this.parseCasePattern());
209
+ while (this.match("pipe")) {
210
+ patterns.push(this.parseCasePattern());
211
+ }
212
+ if (!this.match("closeParen")) {
213
+ throw new import_errors.ParseError("Expected ')' after case pattern");
214
+ }
215
+ const body = this.parseCaseBody();
216
+ clauses.push({ patterns, body });
217
+ this.match("doubleSemicolon");
218
+ this.skipNewlines();
219
+ }
220
+ this.expectKeyword("esac");
221
+ return {
222
+ type: "case",
223
+ word,
224
+ clauses
225
+ };
226
+ }
227
+ parseCasePattern() {
228
+ const token = this.peek();
229
+ if (token.type === "word" || token.type === "glob" || token.type === "singleQuote" || token.type === "doubleQuote") {
230
+ return this.parseWordArg();
231
+ }
232
+ throw new import_errors.ParseError(`Expected pattern in case clause, got ${token.type}`);
233
+ }
234
+ parseCaseBody() {
235
+ const commands = [];
236
+ this.skipNewlines();
237
+ while (!this.isAtEnd() && !this.check("doubleSemicolon") && !this.checkKeyword("esac")) {
238
+ commands.push(this.parseAndOr());
239
+ if (!this.match("semicolon") && !this.match("newline")) {
240
+ break;
241
+ }
242
+ this.skipNewlines();
243
+ if (this.check("doubleSemicolon") || this.checkKeyword("esac")) {
244
+ break;
245
+ }
246
+ }
247
+ if (commands.length === 0) {
248
+ return { type: "command", name: { type: "literal", value: "true" }, args: [], redirects: [], assignments: [] };
249
+ }
250
+ if (commands.length === 1) {
251
+ return commands[0];
252
+ }
253
+ return { type: "sequence", commands };
254
+ }
255
+ parseCompoundList(terminators) {
256
+ this.skipNewlines();
257
+ const commands = [];
258
+ if (this.isCompoundListTerminator(terminators)) {
259
+ return { type: "command", name: { type: "literal", value: "true" }, args: [], redirects: [], assignments: [] };
260
+ }
261
+ commands.push(this.parseAndOr());
262
+ while ((this.match("semicolon") || this.match("newline")) && !this.isAtEnd()) {
263
+ this.skipNewlines();
264
+ if (this.isCompoundListTerminator(terminators)) {
265
+ break;
266
+ }
267
+ commands.push(this.parseAndOr());
268
+ }
269
+ if (commands.length === 1) {
270
+ return commands[0];
271
+ }
272
+ return { type: "sequence", commands };
273
+ }
274
+ isCompoundListTerminator(terminators) {
275
+ const token = this.peek();
276
+ if (token.type !== "keyword")
277
+ return false;
278
+ return terminators.includes(token.value);
279
+ }
280
+ checkKeyword(value) {
281
+ const token = this.peek();
282
+ return token.type === "keyword" && token.value === value;
283
+ }
284
+ expectKeyword(value) {
285
+ if (!this.checkKeyword(value)) {
286
+ throw new import_errors.ParseError(`Expected '${value}'`);
287
+ }
288
+ this.advance();
289
+ }
88
290
  parseCommand() {
89
291
  const assignments = [];
90
292
  const args = [];
@@ -97,7 +299,16 @@ class Parser {
97
299
  });
98
300
  }
99
301
  while (this.isWordToken()) {
100
- args.push(this.parseWordArg());
302
+ if (this.peek().type === "heredoc") {
303
+ const heredocToken = this.advance();
304
+ redirects.push({
305
+ mode: "<",
306
+ target: this.tokenToNode(heredocToken),
307
+ heredocContent: true
308
+ });
309
+ } else {
310
+ args.push(this.parseWordArg());
311
+ }
101
312
  }
102
313
  while (this.check("redirect")) {
103
314
  const redirect = this.parseRedirect();
@@ -142,12 +353,19 @@ class Parser {
142
353
  case "variable":
143
354
  return { type: "variable", name: token.name };
144
355
  case "substitution":
145
- const innerParser = new Parser(new (require("../lexer/lexer.ts")).Lexer(token.command).tokenize());
356
+ const innerParser = new Parser(new (require("../lexer/lexer.ts")).Lexer(token.command, { preserveNewlines: true }).tokenize());
146
357
  return { type: "substitution", command: innerParser.parse() };
358
+ case "arithmetic":
359
+ return { type: "arithmetic", expression: token.expression };
147
360
  case "glob":
148
361
  return { type: "glob", pattern: token.pattern };
149
362
  case "assignment":
150
363
  return this.tokenToNode(token.value);
364
+ case "heredoc":
365
+ if (token.expand) {
366
+ return this.parseHeredocContent(token.content);
367
+ }
368
+ return { type: "literal", value: token.content };
151
369
  default:
152
370
  throw new import_errors.ParseError(`Unexpected token type: ${token.type}`);
153
371
  }
@@ -171,6 +389,60 @@ class Parser {
171
389
  });
172
390
  return { type: "concat", parts: nodes };
173
391
  }
392
+ parseHeredocContent(content) {
393
+ const parts = [];
394
+ let currentLiteral = "";
395
+ let i = 0;
396
+ while (i < content.length) {
397
+ if (content[i] === "$") {
398
+ if (currentLiteral) {
399
+ parts.push({ type: "literal", value: currentLiteral });
400
+ currentLiteral = "";
401
+ }
402
+ i++;
403
+ if (i >= content.length) {
404
+ currentLiteral += "$";
405
+ break;
406
+ }
407
+ if (content[i] === "{") {
408
+ i++;
409
+ let varName = "";
410
+ while (i < content.length && content[i] !== "}") {
411
+ varName += content[i];
412
+ i++;
413
+ }
414
+ if (i < content.length && content[i] === "}") {
415
+ i++;
416
+ }
417
+ if (varName) {
418
+ parts.push({ type: "variable", name: varName });
419
+ }
420
+ } else if (/[a-zA-Z_]/.test(content[i] ?? "")) {
421
+ let varName = "";
422
+ while (i < content.length && /[a-zA-Z0-9_]/.test(content[i] ?? "")) {
423
+ varName += content[i];
424
+ i++;
425
+ }
426
+ parts.push({ type: "variable", name: varName });
427
+ } else {
428
+ currentLiteral += "$";
429
+ }
430
+ } else {
431
+ currentLiteral += content[i];
432
+ i++;
433
+ }
434
+ }
435
+ if (currentLiteral) {
436
+ parts.push({ type: "literal", value: currentLiteral });
437
+ }
438
+ if (parts.length === 0) {
439
+ return { type: "literal", value: "" };
440
+ }
441
+ if (parts.length === 1) {
442
+ return parts[0];
443
+ }
444
+ return { type: "concat", parts };
445
+ }
174
446
  parseRedirect() {
175
447
  const token = this.advance();
176
448
  const mode = token.mode;
@@ -185,7 +457,7 @@ class Parser {
185
457
  }
186
458
  isWordToken() {
187
459
  const token = this.peek();
188
- return token.type === "word" || token.type === "singleQuote" || token.type === "doubleQuote" || token.type === "variable" || token.type === "substitution" || token.type === "glob";
460
+ return token.type === "word" || token.type === "singleQuote" || token.type === "doubleQuote" || token.type === "variable" || token.type === "substitution" || token.type === "arithmetic" || token.type === "glob" || token.type === "heredoc";
189
461
  }
190
462
  check(type) {
191
463
  return this.peek().type === type;
@@ -213,4 +485,4 @@ function parse(tokens) {
213
485
  return new Parser(tokens).parse();
214
486
  }
215
487
 
216
- //# debugId=5BD2AD8F21A9287464756E2164756E21
488
+ //# debugId=5BCD131068F902F564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/parser/parser.ts"],
4
4
  "sourcesContent": [
5
- "import { ParseError } from \"../errors.cjs\";\nimport type { Token } from \"../lexer/tokens.cjs\";\nimport type { ASTNode, Redirect, RedirectMode, CommandNode } from \"./ast.cjs\";\n\nexport class Parser {\n private tokens: Token[];\n private pos: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n parse(): ASTNode {\n const result = this.parseSequence();\n if (!this.isAtEnd()) {\n throw new ParseError(`Unexpected token: ${JSON.stringify(this.peek())}`);\n }\n return result;\n }\n\n // sequence := and_or (';' and_or)*\n private parseSequence(): ASTNode {\n const commands: ASTNode[] = [];\n commands.push(this.parseAndOr());\n\n while (this.match(\"semicolon\")) {\n // Skip empty commands after semicolon\n if (this.isAtEnd() || this.check(\"semicolon\")) continue;\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n // and_or := pipeline (('&&'|'||') pipeline)*\n private parseAndOr(): ASTNode {\n let left = this.parsePipeline();\n\n while (this.check(\"and\") || this.check(\"or\")) {\n if (this.match(\"and\")) {\n const right = this.parsePipeline();\n left = { type: \"and\", left, right };\n } else if (this.match(\"or\")) {\n const right = this.parsePipeline();\n left = { type: \"or\", left, right };\n }\n }\n\n return left;\n }\n\n // pipeline := command ('|' command)*\n private parsePipeline(): ASTNode {\n const commands: ASTNode[] = [];\n commands.push(this.parseCommand());\n\n while (this.match(\"pipe\")) {\n commands.push(this.parseCommand());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"pipeline\", commands };\n }\n\n // command := assignment* word+ redirect*\n private parseCommand(): CommandNode {\n const assignments: Array<{ name: string; value: ASTNode }> = [];\n const args: ASTNode[] = [];\n const redirects: Redirect[] = [];\n\n // Collect leading assignments\n while (this.check(\"assignment\")) {\n const token = this.advance() as Token & { type: \"assignment\" };\n assignments.push({\n name: token.name,\n value: this.tokenToNode(token.value),\n });\n }\n\n // Collect command name and arguments\n while (this.isWordToken()) {\n args.push(this.parseWordArg());\n }\n\n // Collect redirects\n while (this.check(\"redirect\")) {\n const redirect = this.parseRedirect();\n redirects.push(redirect);\n // After a redirect, there might be more words\n while (this.isWordToken()) {\n args.push(this.parseWordArg());\n }\n }\n\n if (args.length === 0 && assignments.length === 0) {\n throw new ParseError(\"Expected command\");\n }\n\n const name = args.shift() ?? { type: \"literal\" as const, value: \"\" };\n\n return {\n type: \"command\",\n name,\n args,\n redirects,\n assignments,\n };\n }\n\n private parseWordArg(): ASTNode {\n const token = this.advance();\n return this.tokenToNode(token);\n }\n\n private tokenToNode(token: Token | string | Token[]): ASTNode {\n if (typeof token === \"string\") {\n return { type: \"literal\", value: token };\n }\n\n if (Array.isArray(token)) {\n const parts = token.map((t) => this.tokenToNode(t));\n if (parts.length === 1) return parts[0]!;\n return { type: \"concat\", parts };\n }\n\n switch (token.type) {\n case \"word\":\n return { type: \"literal\", value: token.value };\n case \"singleQuote\":\n return { type: \"literal\", value: token.value };\n case \"doubleQuote\":\n return this.parseDoubleQuoteParts(token.parts);\n case \"variable\":\n return { type: \"variable\", name: token.name };\n case \"substitution\":\n // Parse the inner command\n const innerParser = new Parser(\n new (require(\"../lexer/lexer.ts\").Lexer)(token.command).tokenize()\n );\n return { type: \"substitution\", command: innerParser.parse() };\n case \"glob\":\n return { type: \"glob\", pattern: token.pattern };\n case \"assignment\":\n return this.tokenToNode(token.value);\n default:\n throw new ParseError(`Unexpected token type: ${token.type}`);\n }\n }\n\n private parseDoubleQuoteParts(parts: Array<string | Token>): ASTNode {\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n\n if (parts.length === 1) {\n const part = parts[0]!;\n if (typeof part === \"string\") {\n return { type: \"literal\", value: part };\n }\n return this.tokenToNode(part);\n }\n\n const nodes: ASTNode[] = parts.map((part) => {\n if (typeof part === \"string\") {\n return { type: \"literal\" as const, value: part };\n }\n return this.tokenToNode(part);\n });\n\n return { type: \"concat\", parts: nodes };\n }\n\n private parseRedirect(): Redirect {\n const token = this.advance() as Token & { type: \"redirect\" };\n const mode = token.mode as RedirectMode;\n\n // 2>&1 and 1>&2 don't have a target\n if (mode === \"2>&1\" || mode === \"1>&2\") {\n return { mode, target: { type: \"literal\", value: \"\" } };\n }\n\n if (!this.isWordToken()) {\n throw new ParseError(`Expected redirect target after ${mode}`);\n }\n\n const target = this.parseWordArg();\n return { mode, target };\n }\n\n private isWordToken(): boolean {\n const token = this.peek();\n return (\n token.type === \"word\" ||\n token.type === \"singleQuote\" ||\n token.type === \"doubleQuote\" ||\n token.type === \"variable\" ||\n token.type === \"substitution\" ||\n token.type === \"glob\"\n );\n }\n\n private check(type: Token[\"type\"]): boolean {\n return this.peek().type === type;\n }\n\n private match(type: Token[\"type\"]): boolean {\n if (this.check(type)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n private peek(): Token {\n return this.tokens[this.pos] ?? { type: \"eof\" };\n }\n\n private advance(): Token {\n const token = this.peek();\n this.pos++;\n return token;\n }\n\n private isAtEnd(): boolean {\n return this.peek().type === \"eof\";\n }\n}\n\nexport function parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n}\n"
5
+ "import { ParseError } from \"../errors.cjs\";\nimport type { Token, KeywordValue } from \"../lexer/tokens.cjs\";\nimport type { ASTNode, Redirect, RedirectMode, CommandNode, IfNode, ForNode, WhileNode, UntilNode, CaseNode, CaseClause } from \"./ast.cjs\";\n\nexport class Parser {\n private tokens: Token[];\n private pos: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n parse(): ASTNode {\n const result = this.parseSequence();\n if (!this.isAtEnd()) {\n throw new ParseError(`Unexpected token: ${JSON.stringify(this.peek())}`);\n }\n return result;\n }\n\n // sequence := and_or ((';'|'\\n') and_or)*\n private parseSequence(): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n commands.push(this.parseAndOr());\n\n while (this.match(\"semicolon\") || this.match(\"newline\")) {\n this.skipNewlines();\n // Skip empty commands after separator, or stop at terminating keywords\n if (this.isAtEnd() || this.check(\"semicolon\") || this.check(\"newline\") || this.isTerminatingKeyword()) continue;\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private skipNewlines(): void {\n while (this.match(\"newline\")) {\n // keep consuming newlines\n }\n }\n\n private isTerminatingKeyword(): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return [\"then\", \"elif\", \"else\", \"fi\", \"do\", \"done\", \"esac\"].includes(token.value);\n }\n\n // and_or := pipeline (('&&'|'||') pipeline)*\n private parseAndOr(): ASTNode {\n let left = this.parsePipeline();\n\n while (this.check(\"and\") || this.check(\"or\")) {\n if (this.match(\"and\")) {\n const right = this.parsePipeline();\n left = { type: \"and\", left, right };\n } else if (this.match(\"or\")) {\n const right = this.parsePipeline();\n left = { type: \"or\", left, right };\n }\n }\n\n return left;\n }\n\n // pipeline := command ('|' command)*\n private parsePipeline(): ASTNode {\n const commands: ASTNode[] = [];\n commands.push(this.parseCompoundOrCommand());\n\n while (this.match(\"pipe\")) {\n this.skipNewlines();\n commands.push(this.parseCompoundOrCommand());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"pipeline\", commands };\n }\n\n // compound_or_command := compound_command | simple_command\n private parseCompoundOrCommand(): ASTNode {\n this.skipNewlines();\n const token = this.peek();\n\n if (token.type === \"keyword\") {\n switch (token.value) {\n case \"if\":\n return this.parseIf();\n case \"for\":\n return this.parseFor();\n case \"while\":\n return this.parseWhile();\n case \"until\":\n return this.parseUntil();\n case \"case\":\n return this.parseCase();\n }\n }\n\n return this.parseCommand();\n }\n\n // if := 'if' compound_list 'then' compound_list ('elif' compound_list 'then' compound_list)* ['else' compound_list] 'fi'\n private parseIf(): IfNode {\n this.expectKeyword(\"if\");\n const condition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const thenBranch = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n\n const elifBranches: Array<{ condition: ASTNode; body: ASTNode }> = [];\n while (this.checkKeyword(\"elif\")) {\n this.expectKeyword(\"elif\");\n const elifCondition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const elifBody = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n elifBranches.push({ condition: elifCondition, body: elifBody });\n }\n\n let elseBranch: ASTNode | undefined;\n if (this.checkKeyword(\"else\")) {\n this.expectKeyword(\"else\");\n elseBranch = this.parseCompoundList([\"fi\"]);\n }\n\n this.expectKeyword(\"fi\");\n\n return {\n type: \"if\",\n condition,\n thenBranch,\n elifBranches,\n elseBranch,\n };\n }\n\n // for := 'for' NAME ['in' word*] (';'|'\\n') 'do' compound_list 'done'\n private parseFor(): ForNode {\n this.expectKeyword(\"for\");\n\n // Get variable name\n const varToken = this.peek();\n if (varToken.type !== \"word\") {\n throw new ParseError(\"Expected variable name after 'for'\");\n }\n this.advance();\n const variable = varToken.value;\n\n // Parse optional 'in' clause\n const items: ASTNode[] = [];\n if (this.checkKeyword(\"in\")) {\n this.expectKeyword(\"in\");\n // Read items until semicolon, newline, or 'do'\n while (!this.isAtEnd() && !this.check(\"semicolon\") && !this.check(\"newline\") && !this.checkKeyword(\"do\")) {\n items.push(this.parseWordArg());\n }\n }\n\n // Consume separator (semicolon or newline)\n if (!this.match(\"semicolon\")) {\n this.match(\"newline\");\n }\n this.skipNewlines();\n\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"for\",\n variable,\n items,\n body,\n };\n }\n\n // while := 'while' compound_list 'do' compound_list 'done'\n private parseWhile(): WhileNode {\n this.expectKeyword(\"while\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"while\",\n condition,\n body,\n };\n }\n\n // until := 'until' compound_list 'do' compound_list 'done'\n private parseUntil(): UntilNode {\n this.expectKeyword(\"until\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"until\",\n condition,\n body,\n };\n }\n\n // case := 'case' word 'in' (pattern ('|' pattern)* ')' compound_list ';;')* 'esac'\n private parseCase(): CaseNode {\n this.expectKeyword(\"case\");\n const word = this.parseWordArg();\n this.expectKeyword(\"in\");\n this.skipNewlines();\n\n const clauses: CaseClause[] = [];\n\n while (!this.isAtEnd() && !this.checkKeyword(\"esac\")) {\n // Parse patterns separated by '|'\n // Skip leading '(' if present\n this.match(\"openParen\");\n\n const patterns: ASTNode[] = [];\n patterns.push(this.parseCasePattern());\n\n while (this.match(\"pipe\")) {\n patterns.push(this.parseCasePattern());\n }\n\n // Expect ')'\n if (!this.match(\"closeParen\")) {\n throw new ParseError(\"Expected ')' after case pattern\");\n }\n\n // Parse body until ';;' or 'esac'\n const body = this.parseCaseBody();\n\n clauses.push({ patterns, body });\n\n // ';;' is optional for the last clause\n this.match(\"doubleSemicolon\");\n this.skipNewlines();\n }\n\n this.expectKeyword(\"esac\");\n\n return {\n type: \"case\",\n word,\n clauses,\n };\n }\n\n private parseCasePattern(): ASTNode {\n const token = this.peek();\n\n // Handle glob patterns and words\n if (token.type === \"word\" || token.type === \"glob\" || token.type === \"singleQuote\" || token.type === \"doubleQuote\") {\n return this.parseWordArg();\n }\n\n throw new ParseError(`Expected pattern in case clause, got ${token.type}`);\n }\n\n private parseCaseBody(): ASTNode {\n const commands: ASTNode[] = [];\n this.skipNewlines();\n\n // Parse until ';;' or 'esac'\n while (!this.isAtEnd() && !this.check(\"doubleSemicolon\") && !this.checkKeyword(\"esac\")) {\n commands.push(this.parseAndOr());\n // Consume separator\n if (!this.match(\"semicolon\") && !this.match(\"newline\")) {\n break;\n }\n this.skipNewlines();\n // Check for terminators after consuming separators\n if (this.check(\"doubleSemicolon\") || this.checkKeyword(\"esac\")) {\n break;\n }\n }\n\n if (commands.length === 0) {\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n if (commands.length === 1) {\n return commands[0]!;\n }\n return { type: \"sequence\", commands };\n }\n\n // compound_list := and_or ((';'|'\\n') and_or)* [';'|'\\n']\n private parseCompoundList(terminators: KeywordValue[]): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n\n // Check for empty list\n if (this.isCompoundListTerminator(terminators)) {\n // Return a no-op command for empty list\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n\n commands.push(this.parseAndOr());\n\n while ((this.match(\"semicolon\") || this.match(\"newline\")) && !this.isAtEnd()) {\n this.skipNewlines();\n // Check for terminators\n if (this.isCompoundListTerminator(terminators)) {\n break;\n }\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private isCompoundListTerminator(terminators: KeywordValue[]): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return terminators.includes(token.value);\n }\n\n private checkKeyword(value: KeywordValue): boolean {\n const token = this.peek();\n return token.type === \"keyword\" && token.value === value;\n }\n\n private expectKeyword(value: KeywordValue): void {\n if (!this.checkKeyword(value)) {\n throw new ParseError(`Expected '${value}'`);\n }\n this.advance();\n // Don't skip newlines here - let the caller handle them\n // Newlines are significant as command separators in compound lists\n }\n\n // command := assignment* word+ redirect*\n private parseCommand(): CommandNode {\n const assignments: Array<{ name: string; value: ASTNode }> = [];\n const args: ASTNode[] = [];\n const redirects: Redirect[] = [];\n\n // Collect leading assignments\n while (this.check(\"assignment\")) {\n const token = this.advance() as Token & { type: \"assignment\" };\n assignments.push({\n name: token.name,\n value: this.tokenToNode(token.value),\n });\n }\n\n // Collect command name and arguments\n while (this.isWordToken()) {\n // Check if it's a heredoc token - convert to input redirect\n if (this.peek().type === \"heredoc\") {\n const heredocToken = this.advance() as Token & { type: \"heredoc\" };\n redirects.push({\n mode: \"<\",\n target: this.tokenToNode(heredocToken),\n heredocContent: true,\n });\n } else {\n args.push(this.parseWordArg());\n }\n }\n\n // Collect redirects\n while (this.check(\"redirect\")) {\n const redirect = this.parseRedirect();\n redirects.push(redirect);\n // After a redirect, there might be more words\n while (this.isWordToken()) {\n args.push(this.parseWordArg());\n }\n }\n\n if (args.length === 0 && assignments.length === 0) {\n throw new ParseError(\"Expected command\");\n }\n\n const name = args.shift() ?? { type: \"literal\" as const, value: \"\" };\n\n return {\n type: \"command\",\n name,\n args,\n redirects,\n assignments,\n };\n }\n\n private parseWordArg(): ASTNode {\n const token = this.advance();\n return this.tokenToNode(token);\n }\n\n private tokenToNode(token: Token | string | Token[]): ASTNode {\n if (typeof token === \"string\") {\n return { type: \"literal\", value: token };\n }\n\n if (Array.isArray(token)) {\n const parts = token.map((t) => this.tokenToNode(t));\n if (parts.length === 1) return parts[0]!;\n return { type: \"concat\", parts };\n }\n\n switch (token.type) {\n case \"word\":\n return { type: \"literal\", value: token.value };\n case \"singleQuote\":\n return { type: \"literal\", value: token.value };\n case \"doubleQuote\":\n return this.parseDoubleQuoteParts(token.parts);\n case \"variable\":\n return { type: \"variable\", name: token.name };\n case \"substitution\":\n // Parse the inner command\n const innerParser = new Parser(\n new (require(\"../lexer/lexer.ts\").Lexer)(token.command, { preserveNewlines: true }).tokenize()\n );\n return { type: \"substitution\", command: innerParser.parse() };\n case \"arithmetic\":\n return { type: \"arithmetic\", expression: token.expression };\n case \"glob\":\n return { type: \"glob\", pattern: token.pattern };\n case \"assignment\":\n return this.tokenToNode(token.value);\n case \"heredoc\":\n if (token.expand) {\n return this.parseHeredocContent(token.content);\n }\n return { type: \"literal\", value: token.content };\n default:\n throw new ParseError(`Unexpected token type: ${(token as Token).type}`);\n }\n }\n\n private parseDoubleQuoteParts(parts: Array<string | Token>): ASTNode {\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n\n if (parts.length === 1) {\n const part = parts[0]!;\n if (typeof part === \"string\") {\n return { type: \"literal\", value: part };\n }\n return this.tokenToNode(part);\n }\n\n const nodes: ASTNode[] = parts.map((part) => {\n if (typeof part === \"string\") {\n return { type: \"literal\" as const, value: part };\n }\n return this.tokenToNode(part);\n });\n\n return { type: \"concat\", parts: nodes };\n }\n\n private parseHeredocContent(content: string): ASTNode {\n // Parse content looking for $VAR and ${VAR} patterns\n const parts: ASTNode[] = [];\n let currentLiteral = \"\";\n let i = 0;\n\n while (i < content.length) {\n if (content[i] === \"$\") {\n // Flush current literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n currentLiteral = \"\";\n }\n\n i++; // consume $\n if (i >= content.length) {\n currentLiteral += \"$\";\n break;\n }\n\n if (content[i] === \"{\") {\n // ${VAR} syntax\n i++; // consume {\n let varName = \"\";\n while (i < content.length && content[i] !== \"}\") {\n varName += content[i];\n i++;\n }\n if (i < content.length && content[i] === \"}\") {\n i++; // consume }\n }\n if (varName) {\n parts.push({ type: \"variable\", name: varName });\n }\n } else if (/[a-zA-Z_]/.test(content[i] ?? \"\")) {\n // $VAR syntax\n let varName = \"\";\n while (i < content.length && /[a-zA-Z0-9_]/.test(content[i] ?? \"\")) {\n varName += content[i];\n i++;\n }\n parts.push({ type: \"variable\", name: varName });\n } else {\n // Not a variable, keep the $\n currentLiteral += \"$\";\n }\n } else {\n currentLiteral += content[i];\n i++;\n }\n }\n\n // Flush remaining literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n }\n\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n if (parts.length === 1) {\n return parts[0]!;\n }\n return { type: \"concat\", parts };\n }\n\n private parseRedirect(): Redirect {\n const token = this.advance() as Token & { type: \"redirect\" };\n const mode = token.mode as RedirectMode;\n\n // 2>&1 and 1>&2 don't have a target\n if (mode === \"2>&1\" || mode === \"1>&2\") {\n return { mode, target: { type: \"literal\", value: \"\" } };\n }\n\n if (!this.isWordToken()) {\n throw new ParseError(`Expected redirect target after ${mode}`);\n }\n\n const target = this.parseWordArg();\n return { mode, target };\n }\n\n private isWordToken(): boolean {\n const token = this.peek();\n return (\n token.type === \"word\" ||\n token.type === \"singleQuote\" ||\n token.type === \"doubleQuote\" ||\n token.type === \"variable\" ||\n token.type === \"substitution\" ||\n token.type === \"arithmetic\" ||\n token.type === \"glob\" ||\n token.type === \"heredoc\"\n );\n }\n\n private check(type: Token[\"type\"]): boolean {\n return this.peek().type === type;\n }\n\n private match(type: Token[\"type\"]): boolean {\n if (this.check(type)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n private peek(): Token {\n return this.tokens[this.pos] ?? { type: \"eof\" };\n }\n\n private advance(): Token {\n const token = this.peek();\n this.pos++;\n return token;\n }\n\n private isAtEnd(): boolean {\n return this.peek().type === \"eof\";\n }\n}\n\nexport function parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "5BD2AD8F21A9287464756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5BCD131068F902F564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -134,7 +134,7 @@ class ShellDSL {
134
134
  return import_escape.escape(str);
135
135
  }
136
136
  lex(source) {
137
- return new import_lexer.Lexer(source).tokenize();
137
+ return new import_lexer.Lexer(source, { preserveNewlines: true }).tokenize();
138
138
  }
139
139
  parse(tokens) {
140
140
  return new import_parser.Parser(tokens).parse();
@@ -184,4 +184,4 @@ function createShellDSL(config) {
184
184
  return tag;
185
185
  }
186
186
 
187
- //# debugId=35D814EA2D605E7064756E2164756E21
187
+ //# debugId=78A5C98BA672517064756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/shell-dsl.ts"],
4
4
  "sourcesContent": [
5
- "import type { ShellConfig, Command, VirtualFS, ExecResult, RedirectObjectMap } from \"./types.cjs\";\nimport { isRawValue, isRedirectObject } from \"./types.cjs\";\nimport type { Token } from \"./lexer/tokens.cjs\";\nimport type { ASTNode } from \"./parser/ast.cjs\";\nimport { Lexer } from \"./lexer/lexer.cjs\";\nimport { Parser } from \"./parser/parser.cjs\";\nimport { Interpreter } from \"./interpreter/interpreter.cjs\";\nimport { ShellPromise } from \"./shell-promise.cjs\";\nimport { escape, escapeForInterpolation } from \"./utils/escape.cjs\";\n\nexport interface Program {\n ast: ASTNode;\n source: string;\n}\n\nexport class ShellDSL {\n private fs: VirtualFS;\n private initialCwd: string;\n private initialEnv: Record<string, string>;\n private currentCwd: string;\n private currentEnv: Record<string, string>;\n private commands: Record<string, Command>;\n private shouldThrow: boolean = true;\n\n constructor(config: ShellConfig) {\n this.fs = config.fs;\n this.initialCwd = config.cwd;\n this.initialEnv = { ...config.env };\n this.currentCwd = config.cwd;\n this.currentEnv = { ...config.env };\n this.commands = config.commands;\n }\n\n // Template tag function\n tag(strings: TemplateStringsArray, ...values: unknown[]): ShellPromise {\n // Build the command string with escaped interpolations\n let source = strings[0] ?? \"\";\n const redirectObjects: RedirectObjectMap = {};\n let objIndex = 0;\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n const precedingString = strings[i] ?? \"\";\n\n if (isRawValue(value)) {\n source += value.raw;\n } else if (this.isRedirectTarget(precedingString, value)) {\n // Value appears after a redirect operator - store as redirect object\n const marker = `__REDIR_OBJ_${objIndex++}__`;\n redirectObjects[marker] = value as Buffer | Blob | Response | string;\n source += marker;\n } else {\n source += escapeForInterpolation(value);\n }\n source += strings[i + 1] ?? \"\";\n }\n\n return this.createPromise(source, { redirectObjects });\n }\n\n private isRedirectTarget(precedingString: string, value: unknown): boolean {\n // Check if value is a redirect object type AND appears after redirect operator\n if (!isRedirectObject(value) || isRawValue(value)) {\n return false;\n }\n // Check if preceding string ends with redirect operator\n const trimmed = precedingString.trimEnd();\n const afterRedirectOp = /(<|>|>>|2>|2>>|&>|&>>)\\s*$/.test(trimmed);\n\n if (!afterRedirectOp) {\n return false;\n }\n\n // Buffer, Blob, Response are always treated as redirect objects\n if (Buffer.isBuffer(value) || value instanceof Blob || value instanceof Response) {\n return true;\n }\n\n // For strings after input redirect (<), treat as content per spec\n // For strings after output redirect (>), they must be Buffers\n if (typeof value === \"string\") {\n // Only input redirection supports string content\n return /<\\s*$/.test(trimmed);\n }\n\n return false;\n }\n\n private createPromise(source: string, options?: { cwd?: string; env?: Record<string, string>; shouldThrow?: boolean; redirectObjects?: RedirectObjectMap }): ShellPromise {\n const shell = this;\n\n return new ShellPromise({\n execute: async (overrides) => {\n const cwd = overrides?.cwd ?? options?.cwd ?? shell.currentCwd;\n const env = { ...shell.currentEnv, ...options?.env, ...overrides?.env };\n\n const interpreter = new Interpreter({\n fs: shell.fs,\n cwd,\n env,\n commands: shell.commands,\n redirectObjects: options?.redirectObjects,\n });\n\n const tokens = shell.lex(source);\n const ast = shell.parse(tokens);\n return interpreter.execute(ast);\n },\n cwdOverride: options?.cwd,\n envOverride: options?.env,\n shouldThrow: options?.shouldThrow ?? this.shouldThrow,\n });\n }\n\n // Global defaults\n cwd(path: string): void {\n this.currentCwd = path;\n }\n\n env(vars: Record<string, string>): void {\n Object.assign(this.currentEnv, vars);\n }\n\n throws(enable: boolean): void {\n this.shouldThrow = enable;\n }\n\n resetCwd(): void {\n this.currentCwd = this.initialCwd;\n }\n\n resetEnv(): void {\n this.currentEnv = { ...this.initialEnv };\n }\n\n // Utility\n escape(str: string): string {\n return escape(str);\n }\n\n // Low-level API\n lex(source: string): Token[] {\n return new Lexer(source).tokenize();\n }\n\n parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n }\n\n compile(ast: ASTNode): Program {\n // For now, the \"program\" is just the AST with source reconstruction\n return {\n ast,\n source: \"\", // Could reconstruct source from AST if needed\n };\n }\n\n async run(program: Program): Promise<ExecResult> {\n const interpreter = new Interpreter({\n fs: this.fs,\n cwd: this.currentCwd,\n env: this.currentEnv,\n commands: this.commands,\n });\n\n return interpreter.execute(program.ast);\n }\n}\n\n// Factory function that returns a callable template tag\nexport function createShellDSL(config: ShellConfig): ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise) {\n const shell = new ShellDSL(config);\n\n // Create a function that acts as both tag and shell instance\n const tag = (strings: TemplateStringsArray, ...values: unknown[]) => {\n return shell.tag(strings, ...values);\n };\n\n // Copy all properties and methods from shell to tag function\n Object.setPrototypeOf(tag, ShellDSL.prototype);\n Object.assign(tag, {\n fs: (shell as any).fs,\n initialCwd: (shell as any).initialCwd,\n initialEnv: (shell as any).initialEnv,\n currentCwd: (shell as any).currentCwd,\n currentEnv: (shell as any).currentEnv,\n commands: (shell as any).commands,\n shouldThrow: (shell as any).shouldThrow,\n });\n\n // Bind methods\n (tag as any).cwd = shell.cwd.bind(shell);\n (tag as any).env = shell.env.bind(shell);\n (tag as any).throws = shell.throws.bind(shell);\n (tag as any).resetCwd = shell.resetCwd.bind(shell);\n (tag as any).resetEnv = shell.resetEnv.bind(shell);\n (tag as any).escape = shell.escape.bind(shell);\n (tag as any).lex = shell.lex.bind(shell);\n (tag as any).parse = shell.parse.bind(shell);\n (tag as any).compile = shell.compile.bind(shell);\n (tag as any).run = shell.run.bind(shell);\n (tag as any).tag = shell.tag.bind(shell);\n\n return tag as ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise);\n}\n"
5
+ "import type { ShellConfig, Command, VirtualFS, ExecResult, RedirectObjectMap } from \"./types.cjs\";\nimport { isRawValue, isRedirectObject } from \"./types.cjs\";\nimport type { Token } from \"./lexer/tokens.cjs\";\nimport type { ASTNode } from \"./parser/ast.cjs\";\nimport { Lexer } from \"./lexer/lexer.cjs\";\nimport { Parser } from \"./parser/parser.cjs\";\nimport { Interpreter } from \"./interpreter/interpreter.cjs\";\nimport { ShellPromise } from \"./shell-promise.cjs\";\nimport { escape, escapeForInterpolation } from \"./utils/escape.cjs\";\n\nexport interface Program {\n ast: ASTNode;\n source: string;\n}\n\nexport class ShellDSL {\n private fs: VirtualFS;\n private initialCwd: string;\n private initialEnv: Record<string, string>;\n private currentCwd: string;\n private currentEnv: Record<string, string>;\n private commands: Record<string, Command>;\n private shouldThrow: boolean = true;\n\n constructor(config: ShellConfig) {\n this.fs = config.fs;\n this.initialCwd = config.cwd;\n this.initialEnv = { ...config.env };\n this.currentCwd = config.cwd;\n this.currentEnv = { ...config.env };\n this.commands = config.commands;\n }\n\n // Template tag function\n tag(strings: TemplateStringsArray, ...values: unknown[]): ShellPromise {\n // Build the command string with escaped interpolations\n let source = strings[0] ?? \"\";\n const redirectObjects: RedirectObjectMap = {};\n let objIndex = 0;\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n const precedingString = strings[i] ?? \"\";\n\n if (isRawValue(value)) {\n source += value.raw;\n } else if (this.isRedirectTarget(precedingString, value)) {\n // Value appears after a redirect operator - store as redirect object\n const marker = `__REDIR_OBJ_${objIndex++}__`;\n redirectObjects[marker] = value as Buffer | Blob | Response | string;\n source += marker;\n } else {\n source += escapeForInterpolation(value);\n }\n source += strings[i + 1] ?? \"\";\n }\n\n return this.createPromise(source, { redirectObjects });\n }\n\n private isRedirectTarget(precedingString: string, value: unknown): boolean {\n // Check if value is a redirect object type AND appears after redirect operator\n if (!isRedirectObject(value) || isRawValue(value)) {\n return false;\n }\n // Check if preceding string ends with redirect operator\n const trimmed = precedingString.trimEnd();\n const afterRedirectOp = /(<|>|>>|2>|2>>|&>|&>>)\\s*$/.test(trimmed);\n\n if (!afterRedirectOp) {\n return false;\n }\n\n // Buffer, Blob, Response are always treated as redirect objects\n if (Buffer.isBuffer(value) || value instanceof Blob || value instanceof Response) {\n return true;\n }\n\n // For strings after input redirect (<), treat as content per spec\n // For strings after output redirect (>), they must be Buffers\n if (typeof value === \"string\") {\n // Only input redirection supports string content\n return /<\\s*$/.test(trimmed);\n }\n\n return false;\n }\n\n private createPromise(source: string, options?: { cwd?: string; env?: Record<string, string>; shouldThrow?: boolean; redirectObjects?: RedirectObjectMap }): ShellPromise {\n const shell = this;\n\n return new ShellPromise({\n execute: async (overrides) => {\n const cwd = overrides?.cwd ?? options?.cwd ?? shell.currentCwd;\n const env = { ...shell.currentEnv, ...options?.env, ...overrides?.env };\n\n const interpreter = new Interpreter({\n fs: shell.fs,\n cwd,\n env,\n commands: shell.commands,\n redirectObjects: options?.redirectObjects,\n });\n\n const tokens = shell.lex(source);\n const ast = shell.parse(tokens);\n return interpreter.execute(ast);\n },\n cwdOverride: options?.cwd,\n envOverride: options?.env,\n shouldThrow: options?.shouldThrow ?? this.shouldThrow,\n });\n }\n\n // Global defaults\n cwd(path: string): void {\n this.currentCwd = path;\n }\n\n env(vars: Record<string, string>): void {\n Object.assign(this.currentEnv, vars);\n }\n\n throws(enable: boolean): void {\n this.shouldThrow = enable;\n }\n\n resetCwd(): void {\n this.currentCwd = this.initialCwd;\n }\n\n resetEnv(): void {\n this.currentEnv = { ...this.initialEnv };\n }\n\n // Utility\n escape(str: string): string {\n return escape(str);\n }\n\n // Low-level API\n lex(source: string): Token[] {\n return new Lexer(source, { preserveNewlines: true }).tokenize();\n }\n\n parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n }\n\n compile(ast: ASTNode): Program {\n // For now, the \"program\" is just the AST with source reconstruction\n return {\n ast,\n source: \"\", // Could reconstruct source from AST if needed\n };\n }\n\n async run(program: Program): Promise<ExecResult> {\n const interpreter = new Interpreter({\n fs: this.fs,\n cwd: this.currentCwd,\n env: this.currentEnv,\n commands: this.commands,\n });\n\n return interpreter.execute(program.ast);\n }\n}\n\n// Factory function that returns a callable template tag\nexport function createShellDSL(config: ShellConfig): ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise) {\n const shell = new ShellDSL(config);\n\n // Create a function that acts as both tag and shell instance\n const tag = (strings: TemplateStringsArray, ...values: unknown[]) => {\n return shell.tag(strings, ...values);\n };\n\n // Copy all properties and methods from shell to tag function\n Object.setPrototypeOf(tag, ShellDSL.prototype);\n Object.assign(tag, {\n fs: (shell as any).fs,\n initialCwd: (shell as any).initialCwd,\n initialEnv: (shell as any).initialEnv,\n currentCwd: (shell as any).currentCwd,\n currentEnv: (shell as any).currentEnv,\n commands: (shell as any).commands,\n shouldThrow: (shell as any).shouldThrow,\n });\n\n // Bind methods\n (tag as any).cwd = shell.cwd.bind(shell);\n (tag as any).env = shell.env.bind(shell);\n (tag as any).throws = shell.throws.bind(shell);\n (tag as any).resetCwd = shell.resetCwd.bind(shell);\n (tag as any).resetEnv = shell.resetEnv.bind(shell);\n (tag as any).escape = shell.escape.bind(shell);\n (tag as any).lex = shell.lex.bind(shell);\n (tag as any).parse = shell.parse.bind(shell);\n (tag as any).compile = shell.compile.bind(shell);\n (tag as any).run = shell.run.bind(shell);\n (tag as any).tag = shell.tag.bind(shell);\n\n return tag as ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "35D814EA2D605E7064756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "78A5C98BA672517064756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,6 +1,6 @@
1
1
  // index.ts
2
2
  export * from "./src/index.mjs";
3
- import { builtinCommands } from "./commands/index.mjs";
3
+ import { builtinCommands } from "./src/commands/index.mjs";
4
4
  import {
5
5
  echo,
6
6
  cat,
@@ -17,26 +17,46 @@ import {
17
17
  test,
18
18
  bracket,
19
19
  trueCmd,
20
- falseCmd
21
- } from "./commands/index.mjs";
20
+ falseCmd,
21
+ touch,
22
+ cp,
23
+ mv,
24
+ tee,
25
+ tree,
26
+ find,
27
+ sed,
28
+ awk,
29
+ breakCmd,
30
+ continueCmd
31
+ } from "./src/commands/index.mjs";
22
32
  export {
23
33
  wc,
24
34
  uniq,
25
35
  trueCmd,
36
+ tree,
37
+ touch,
26
38
  test,
39
+ tee,
27
40
  tail,
28
41
  sort,
42
+ sed,
29
43
  rm,
30
44
  pwd,
45
+ mv,
31
46
  mkdir,
32
47
  ls,
33
48
  head,
34
49
  grep,
50
+ find,
35
51
  falseCmd,
36
52
  echo,
53
+ cp,
54
+ continueCmd,
37
55
  cat,
38
56
  builtinCommands,
39
- bracket
57
+ breakCmd,
58
+ bracket,
59
+ awk
40
60
  };
41
61
 
42
- //# debugId=8985A8E9C45DB77F64756E2164756E21
62
+ //# debugId=07F8C2FAEC0518F564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../index.ts"],
4
4
  "sourcesContent": [
5
- "// Re-export everything from src\nexport * from \"./src/index.mjs\";\n\n// Re-export built-in commands\nexport { builtinCommands } from \"./commands/index.mjs\";\nexport {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n bracket,\n trueCmd,\n falseCmd,\n} from \"./commands/index.mjs\";\n"
5
+ "// Re-export everything from src\nexport * from \"./src/index.mjs\";\n\n// Re-export built-in commands\nexport { builtinCommands } from \"./src/commands/index.mjs\";\nexport {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n bracket,\n trueCmd,\n falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n breakCmd,\n continueCmd,\n} from \"./src/commands/index.mjs\";\n"
6
6
  ],
7
- "mappings": ";AACA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
8
- "debugId": "8985A8E9C45DB77F64756E2164756E21",
7
+ "mappings": ";AACA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
8
+ "debugId": "07F8C2FAEC0518F564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "type": "module"
5
5
  }