shell-dsl 0.0.7 → 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 +381 -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 +202 -7
  62. package/dist/cjs/src/lexer/lexer.cjs.map +3 -3
  63. package/dist/cjs/src/lexer/tokens.cjs +31 -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 +211 -7
  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 +381 -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 +202 -7
  133. package/dist/mjs/src/lexer/lexer.mjs.map +3 -3
  134. package/dist/mjs/src/lexer/tokens.mjs +31 -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 +211 -7
  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 +11 -2
  174. package/dist/types/src/lexer/tokens.d.ts +16 -0
  175. package/dist/types/src/parser/ast.d.ts +46 -1
  176. package/dist/types/src/parser/index.d.ts +2 -2
  177. package/dist/types/src/parser/parser.d.ts +14 -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
@@ -0,0 +1,116 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+
29
+ // src/commands/wc/wc.ts
30
+ var exports_wc = {};
31
+ __export(exports_wc, {
32
+ wc: () => wc
33
+ });
34
+ module.exports = __toCommonJS(exports_wc);
35
+ var wc = async (ctx) => {
36
+ let showLines = false;
37
+ let showWords = false;
38
+ let showChars = false;
39
+ const files = [];
40
+ for (const arg of ctx.args) {
41
+ if (arg === "-l") {
42
+ showLines = true;
43
+ } else if (arg === "-w") {
44
+ showWords = true;
45
+ } else if (arg === "-c" || arg === "-m") {
46
+ showChars = true;
47
+ } else if (arg.startsWith("-")) {
48
+ for (const flag of arg.slice(1)) {
49
+ if (flag === "l")
50
+ showLines = true;
51
+ else if (flag === "w")
52
+ showWords = true;
53
+ else if (flag === "c" || flag === "m")
54
+ showChars = true;
55
+ }
56
+ } else {
57
+ files.push(arg);
58
+ }
59
+ }
60
+ if (!showLines && !showWords && !showChars) {
61
+ showLines = true;
62
+ showWords = true;
63
+ showChars = true;
64
+ }
65
+ const countContent = (content) => {
66
+ const lines = content.split(`
67
+ `).length - (content.endsWith(`
68
+ `) ? 1 : 0);
69
+ const words = content.split(/\s+/).filter((w) => w.length > 0).length;
70
+ const chars = content.length;
71
+ return { lines, words, chars };
72
+ };
73
+ const formatOutput = (counts, filename) => {
74
+ const parts = [];
75
+ if (showLines)
76
+ parts.push(String(counts.lines).padStart(8));
77
+ if (showWords)
78
+ parts.push(String(counts.words).padStart(8));
79
+ if (showChars)
80
+ parts.push(String(counts.chars).padStart(8));
81
+ if (filename)
82
+ parts.push(" " + filename);
83
+ return parts.join("") + `
84
+ `;
85
+ };
86
+ if (files.length === 0) {
87
+ const content = await ctx.stdin.text();
88
+ const counts = countContent(content);
89
+ await ctx.stdout.writeText(formatOutput(counts));
90
+ } else {
91
+ let totalLines = 0;
92
+ let totalWords = 0;
93
+ let totalChars = 0;
94
+ for (const file of files) {
95
+ try {
96
+ const path = ctx.fs.resolve(ctx.cwd, file);
97
+ const content = (await ctx.fs.readFile(path)).toString();
98
+ const counts = countContent(content);
99
+ totalLines += counts.lines;
100
+ totalWords += counts.words;
101
+ totalChars += counts.chars;
102
+ await ctx.stdout.writeText(formatOutput(counts, file));
103
+ } catch (err) {
104
+ await ctx.stderr.writeText(`wc: ${file}: No such file or directory
105
+ `);
106
+ return 1;
107
+ }
108
+ }
109
+ if (files.length > 1) {
110
+ await ctx.stdout.writeText(formatOutput({ lines: totalLines, words: totalWords, chars: totalChars }, "total"));
111
+ }
112
+ }
113
+ return 0;
114
+ };
115
+
116
+ //# debugId=075B5E90AE53867D64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/commands/wc/wc.ts"],
4
+ "sourcesContent": [
5
+ "import type { Command } from \"../../types.cjs\";\n\nexport const wc: Command = async (ctx) => {\n let showLines = false;\n let showWords = false;\n let showChars = false;\n const files: string[] = [];\n\n // Parse arguments\n for (const arg of ctx.args) {\n if (arg === \"-l\") {\n showLines = true;\n } else if (arg === \"-w\") {\n showWords = true;\n } else if (arg === \"-c\" || arg === \"-m\") {\n showChars = true;\n } else if (arg.startsWith(\"-\")) {\n // Handle combined flags\n for (const flag of arg.slice(1)) {\n if (flag === \"l\") showLines = true;\n else if (flag === \"w\") showWords = true;\n else if (flag === \"c\" || flag === \"m\") showChars = true;\n }\n } else {\n files.push(arg);\n }\n }\n\n // Default: show all\n if (!showLines && !showWords && !showChars) {\n showLines = true;\n showWords = true;\n showChars = true;\n }\n\n const countContent = (content: string) => {\n const lines = content.split(\"\\n\").length - (content.endsWith(\"\\n\") ? 1 : 0);\n const words = content.split(/\\s+/).filter((w) => w.length > 0).length;\n const chars = content.length;\n return { lines, words, chars };\n };\n\n const formatOutput = (counts: { lines: number; words: number; chars: number }, filename?: string) => {\n const parts: string[] = [];\n if (showLines) parts.push(String(counts.lines).padStart(8));\n if (showWords) parts.push(String(counts.words).padStart(8));\n if (showChars) parts.push(String(counts.chars).padStart(8));\n if (filename) parts.push(\" \" + filename);\n return parts.join(\"\") + \"\\n\";\n };\n\n if (files.length === 0) {\n // Read from stdin\n const content = await ctx.stdin.text();\n const counts = countContent(content);\n await ctx.stdout.writeText(formatOutput(counts));\n } else {\n let totalLines = 0;\n let totalWords = 0;\n let totalChars = 0;\n\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n const content = (await ctx.fs.readFile(path)).toString();\n const counts = countContent(content);\n totalLines += counts.lines;\n totalWords += counts.words;\n totalChars += counts.chars;\n await ctx.stdout.writeText(formatOutput(counts, file));\n } catch (err) {\n await ctx.stderr.writeText(`wc: ${file}: No such file or directory\\n`);\n return 1;\n }\n }\n\n if (files.length > 1) {\n await ctx.stdout.writeText(\n formatOutput({ lines: totalLines, words: totalWords, chars: totalChars }, \"total\")\n );\n }\n }\n\n return 0;\n};\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "075B5E90AE53867D64756E2164756E21",
9
+ "names": []
10
+ }
@@ -32,16 +32,22 @@ __export(exports_src, {
32
32
  tokenToString: () => import_lexer.tokenToString,
33
33
  parse: () => import_parser.parse,
34
34
  lex: () => import_lexer.lex,
35
+ isWhileNode: () => import_parser2.isWhileNode,
35
36
  isVariableNode: () => import_parser2.isVariableNode,
37
+ isUntilNode: () => import_parser2.isUntilNode,
36
38
  isSubstitutionNode: () => import_parser2.isSubstitutionNode,
37
39
  isSequenceNode: () => import_parser2.isSequenceNode,
38
40
  isRawValue: () => import_types.isRawValue,
39
41
  isPipelineNode: () => import_parser2.isPipelineNode,
40
42
  isOrNode: () => import_parser2.isOrNode,
41
43
  isLiteralNode: () => import_parser2.isLiteralNode,
44
+ isIfNode: () => import_parser2.isIfNode,
42
45
  isGlobNode: () => import_parser2.isGlobNode,
46
+ isForNode: () => import_parser2.isForNode,
43
47
  isConcatNode: () => import_parser2.isConcatNode,
44
48
  isCommandNode: () => import_parser2.isCommandNode,
49
+ isCaseNode: () => import_parser2.isCaseNode,
50
+ isArithmeticNode: () => import_parser2.isArithmeticNode,
45
51
  isAndNode: () => import_parser2.isAndNode,
46
52
  escapeForInterpolation: () => import_utils.escapeForInterpolation,
47
53
  escape: () => import_utils.escape,
@@ -63,7 +69,9 @@ __export(exports_src, {
63
69
  Lexer: () => import_lexer.Lexer,
64
70
  LexError: () => import_errors.LexError,
65
71
  Interpreter: () => import_interpreter.Interpreter,
66
- FileSystem: () => import_fs2.FileSystem
72
+ FileSystem: () => import_fs2.FileSystem,
73
+ ContinueException: () => import_interpreter.ContinueException,
74
+ BreakException: () => import_interpreter.BreakException
67
75
  });
68
76
  module.exports = __toCommonJS(exports_src);
69
77
  var import_shell_dsl = require("./shell-dsl.cjs");
@@ -80,4 +88,4 @@ var import_io = require("./io/index.cjs");
80
88
  var import_io2 = require("./io/index.cjs");
81
89
  var import_utils = require("./utils/index.cjs");
82
90
 
83
- //# debugId=308511120A1E796164756E2164756E21
91
+ //# debugId=A00B7F9271C525C564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation } from \"./utils/index.cjs\";\n"
5
+ "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n ArithmeticNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n isArithmeticNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation } from \"./utils/index.cjs\";\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAgB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AA0BO,IAXP;AAcqD,IAArD;AAGgC,IAAhC;AAOO,IANP;AASuC,IAAvC;AACwF,IAAxF;AAG+C,IAA/C;",
8
- "debugId": "308511120A1E796164756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAgB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAuCO,IAjBP;AAoBwF,IAAxF;AAGgC,IAAhC;AAOO,IANP;AASuC,IAAvC;AACwF,IAAxF;AAG+C,IAA/C;",
8
+ "debugId": "A00B7F9271C525C564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -30,10 +30,12 @@ var __export = (target, all) => {
30
30
  var exports_interpreter = {};
31
31
  __export(exports_interpreter, {
32
32
  createCommandContext: () => import_context.createCommandContext,
33
- Interpreter: () => import_interpreter.Interpreter
33
+ Interpreter: () => import_interpreter.Interpreter,
34
+ ContinueException: () => import_interpreter.ContinueException,
35
+ BreakException: () => import_interpreter.BreakException
34
36
  });
35
37
  module.exports = __toCommonJS(exports_interpreter);
36
38
  var import_interpreter = require("./interpreter.cjs");
37
39
  var import_context = require("./context.cjs");
38
40
 
39
- //# debugId=1DFD5D0BB70402B864756E2164756E21
41
+ //# debugId=50C2A317A8EA744B64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/interpreter/index.ts"],
4
4
  "sourcesContent": [
5
- "export { Interpreter, type InterpreterOptions } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
5
+ "export { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqD,IAArD;AAC0D,IAA1D;",
8
- "debugId": "1DFD5D0BB70402B864756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAwF,IAAxF;AAC0D,IAA1D;",
8
+ "debugId": "50C2A317A8EA744B64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -29,19 +29,38 @@ var __export = (target, all) => {
29
29
  // src/interpreter/interpreter.ts
30
30
  var exports_interpreter = {};
31
31
  __export(exports_interpreter, {
32
- Interpreter: () => Interpreter
32
+ Interpreter: () => Interpreter,
33
+ ContinueException: () => ContinueException,
34
+ BreakException: () => BreakException
33
35
  });
34
36
  module.exports = __toCommonJS(exports_interpreter);
35
37
  var import_context = require("./context.cjs");
36
38
  var import_stdin = require("../io/stdin.cjs");
37
39
  var import_stdout = require("../io/stdout.cjs");
38
40
 
41
+ class BreakException extends Error {
42
+ levels;
43
+ constructor(levels = 1) {
44
+ super("break");
45
+ this.levels = levels;
46
+ }
47
+ }
48
+
49
+ class ContinueException extends Error {
50
+ levels;
51
+ constructor(levels = 1) {
52
+ super("continue");
53
+ this.levels = levels;
54
+ }
55
+ }
56
+
39
57
  class Interpreter {
40
58
  fs;
41
59
  cwd;
42
60
  env;
43
61
  commands;
44
62
  redirectObjects;
63
+ loopDepth = 0;
45
64
  constructor(options) {
46
65
  this.fs = options.fs;
47
66
  this.cwd = options.cwd;
@@ -49,6 +68,9 @@ class Interpreter {
49
68
  this.commands = options.commands;
50
69
  this.redirectObjects = options.redirectObjects ?? {};
51
70
  }
71
+ getLoopDepth() {
72
+ return this.loopDepth;
73
+ }
52
74
  async execute(ast) {
53
75
  const stdout = import_stdout.createStdout();
54
76
  const stderr = import_stdout.createStderr();
@@ -73,6 +95,16 @@ class Interpreter {
73
95
  return this.executeAnd(node.left, node.right, stdinSource, stdout, stderr);
74
96
  case "or":
75
97
  return this.executeOr(node.left, node.right, stdinSource, stdout, stderr);
98
+ case "if":
99
+ return this.executeIf(node, stdinSource, stdout, stderr);
100
+ case "for":
101
+ return this.executeFor(node, stdinSource, stdout, stderr);
102
+ case "while":
103
+ return this.executeWhile(node, stdinSource, stdout, stderr);
104
+ case "until":
105
+ return this.executeUntil(node, stdinSource, stdout, stderr);
106
+ case "case":
107
+ return this.executeCase(node, stdinSource, stdout, stderr);
76
108
  default:
77
109
  throw new Error(`Cannot execute node type: ${node.type}`);
78
110
  }
@@ -145,6 +177,9 @@ class Interpreter {
145
177
  try {
146
178
  exitCode = await command(ctx);
147
179
  } catch (err) {
180
+ if (err instanceof BreakException || err instanceof ContinueException) {
181
+ throw err;
182
+ }
148
183
  const message = err instanceof Error ? err.message : String(err);
149
184
  await stderr.writeText(`${name}: ${message}
150
185
  `);
@@ -348,6 +383,183 @@ class Interpreter {
348
383
  }
349
384
  return this.executeNode(right, stdinSource, stdout, stderr);
350
385
  }
386
+ async executeIf(node, stdinSource, stdout, stderr) {
387
+ const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
388
+ if (conditionCode === 0) {
389
+ return this.executeNode(node.thenBranch, stdinSource, stdout, stderr);
390
+ }
391
+ for (const elif of node.elifBranches) {
392
+ const elifConditionCode = await this.executeNode(elif.condition, stdinSource, stdout, stderr);
393
+ if (elifConditionCode === 0) {
394
+ return this.executeNode(elif.body, stdinSource, stdout, stderr);
395
+ }
396
+ }
397
+ if (node.elseBranch) {
398
+ return this.executeNode(node.elseBranch, stdinSource, stdout, stderr);
399
+ }
400
+ return 0;
401
+ }
402
+ async executeFor(node, stdinSource, stdout, stderr) {
403
+ const expandedItems = [];
404
+ for (const item of node.items) {
405
+ const evaluated = await this.evaluateNode(item);
406
+ if (item.type === "glob") {
407
+ const matches = await this.fs.glob(evaluated, { cwd: this.cwd });
408
+ if (matches.length > 0) {
409
+ expandedItems.push(...matches);
410
+ } else {
411
+ expandedItems.push(evaluated);
412
+ }
413
+ } else {
414
+ expandedItems.push(evaluated);
415
+ }
416
+ }
417
+ if (expandedItems.length === 0) {
418
+ return 0;
419
+ }
420
+ let lastExitCode = 0;
421
+ this.loopDepth++;
422
+ try {
423
+ for (const value of expandedItems) {
424
+ this.env[node.variable] = value;
425
+ try {
426
+ lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
427
+ } catch (e) {
428
+ if (e instanceof ContinueException) {
429
+ if (e.levels > 1) {
430
+ e.levels--;
431
+ throw e;
432
+ }
433
+ continue;
434
+ }
435
+ if (e instanceof BreakException) {
436
+ if (e.levels > 1) {
437
+ e.levels--;
438
+ throw e;
439
+ }
440
+ break;
441
+ }
442
+ throw e;
443
+ }
444
+ }
445
+ } finally {
446
+ this.loopDepth--;
447
+ }
448
+ return lastExitCode;
449
+ }
450
+ async executeWhile(node, stdinSource, stdout, stderr) {
451
+ let lastExitCode = 0;
452
+ this.loopDepth++;
453
+ try {
454
+ while (true) {
455
+ const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
456
+ if (conditionCode !== 0) {
457
+ break;
458
+ }
459
+ try {
460
+ lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
461
+ } catch (e) {
462
+ if (e instanceof ContinueException) {
463
+ if (e.levels > 1) {
464
+ e.levels--;
465
+ throw e;
466
+ }
467
+ continue;
468
+ }
469
+ if (e instanceof BreakException) {
470
+ if (e.levels > 1) {
471
+ e.levels--;
472
+ throw e;
473
+ }
474
+ break;
475
+ }
476
+ throw e;
477
+ }
478
+ }
479
+ } finally {
480
+ this.loopDepth--;
481
+ }
482
+ return lastExitCode;
483
+ }
484
+ async executeUntil(node, stdinSource, stdout, stderr) {
485
+ let lastExitCode = 0;
486
+ this.loopDepth++;
487
+ try {
488
+ while (true) {
489
+ const conditionCode = await this.executeNode(node.condition, stdinSource, stdout, stderr);
490
+ if (conditionCode === 0) {
491
+ break;
492
+ }
493
+ try {
494
+ lastExitCode = await this.executeNode(node.body, stdinSource, stdout, stderr);
495
+ } catch (e) {
496
+ if (e instanceof ContinueException) {
497
+ if (e.levels > 1) {
498
+ e.levels--;
499
+ throw e;
500
+ }
501
+ continue;
502
+ }
503
+ if (e instanceof BreakException) {
504
+ if (e.levels > 1) {
505
+ e.levels--;
506
+ throw e;
507
+ }
508
+ break;
509
+ }
510
+ throw e;
511
+ }
512
+ }
513
+ } finally {
514
+ this.loopDepth--;
515
+ }
516
+ return lastExitCode;
517
+ }
518
+ async executeCase(node, stdinSource, stdout, stderr) {
519
+ const word = await this.evaluateNode(node.word);
520
+ for (const clause of node.clauses) {
521
+ for (const patternNode of clause.patterns) {
522
+ const pattern = await this.evaluateNode(patternNode);
523
+ if (this.matchCasePattern(word, pattern)) {
524
+ return this.executeNode(clause.body, stdinSource, stdout, stderr);
525
+ }
526
+ }
527
+ }
528
+ return 0;
529
+ }
530
+ matchCasePattern(word, pattern) {
531
+ let regexStr = "^";
532
+ for (let i = 0;i < pattern.length; i++) {
533
+ const char = pattern[i];
534
+ if (char === "*") {
535
+ regexStr += ".*";
536
+ } else if (char === "?") {
537
+ regexStr += ".";
538
+ } else if (char === "[") {
539
+ let j = i + 1;
540
+ while (j < pattern.length && pattern[j] !== "]") {
541
+ j++;
542
+ }
543
+ if (j < pattern.length) {
544
+ regexStr += pattern.slice(i, j + 1);
545
+ i = j;
546
+ } else {
547
+ regexStr += "\\[";
548
+ }
549
+ } else if (/[.+^${}()|\\]/.test(char)) {
550
+ regexStr += "\\" + char;
551
+ } else {
552
+ regexStr += char;
553
+ }
554
+ }
555
+ regexStr += "$";
556
+ try {
557
+ const regex = new RegExp(regexStr);
558
+ return regex.test(word);
559
+ } catch {
560
+ return word === pattern;
561
+ }
562
+ }
351
563
  async evaluateNode(node, localEnv) {
352
564
  const env = localEnv ?? this.env;
353
565
  switch (node.type) {
@@ -369,10 +581,177 @@ class Interpreter {
369
581
  const output = await subStdout.collect();
370
582
  return output.toString("utf-8").replace(/\n+$/, "");
371
583
  }
584
+ case "arithmetic": {
585
+ const result = this.evaluateArithmetic(node.expression, env);
586
+ return String(result);
587
+ }
372
588
  default:
373
589
  throw new Error(`Cannot evaluate node type: ${node.type}`);
374
590
  }
375
591
  }
592
+ evaluateArithmetic(expression, env) {
593
+ let expandedExpr = expression;
594
+ expandedExpr = expandedExpr.replace(/\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_, name) => {
595
+ return env[name] ?? "0";
596
+ });
597
+ expandedExpr = expandedExpr.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {
598
+ return env[name] ?? "0";
599
+ });
600
+ expandedExpr = expandedExpr.replace(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g, (match) => {
601
+ if (/^\d+$/.test(match))
602
+ return match;
603
+ return env[match] ?? "0";
604
+ });
605
+ return this.parseArithmeticExpr(expandedExpr.trim());
606
+ }
607
+ parseArithmeticExpr(expr) {
608
+ let pos = 0;
609
+ const skipWhitespace = () => {
610
+ while (pos < expr.length && /\s/.test(expr[pos]))
611
+ pos++;
612
+ };
613
+ const parseNumber = () => {
614
+ skipWhitespace();
615
+ let numStr = "";
616
+ const negative = expr[pos] === "-";
617
+ if (negative) {
618
+ pos++;
619
+ skipWhitespace();
620
+ }
621
+ while (pos < expr.length && /[0-9]/.test(expr[pos])) {
622
+ numStr += expr[pos];
623
+ pos++;
624
+ }
625
+ if (numStr === "")
626
+ return 0;
627
+ return negative ? -parseInt(numStr, 10) : parseInt(numStr, 10);
628
+ };
629
+ const parsePrimary = () => {
630
+ skipWhitespace();
631
+ if (expr[pos] === "(") {
632
+ pos++;
633
+ const result = parseOr();
634
+ skipWhitespace();
635
+ if (expr[pos] === ")")
636
+ pos++;
637
+ return result;
638
+ }
639
+ return parseNumber();
640
+ };
641
+ const parseUnary = () => {
642
+ skipWhitespace();
643
+ if (expr[pos] === "-" && !/[0-9]/.test(expr[pos + 1] ?? "")) {
644
+ pos++;
645
+ return -parseUnary();
646
+ }
647
+ if (expr[pos] === "!") {
648
+ pos++;
649
+ return parseUnary() === 0 ? 1 : 0;
650
+ }
651
+ return parsePrimary();
652
+ };
653
+ const parseMulDiv = () => {
654
+ let left = parseUnary();
655
+ while (true) {
656
+ skipWhitespace();
657
+ const op = expr[pos];
658
+ if (op === "*" || op === "/" || op === "%") {
659
+ pos++;
660
+ const right = parseUnary();
661
+ if (op === "*")
662
+ left = left * right;
663
+ else if (op === "/")
664
+ left = right === 0 ? 0 : Math.trunc(left / right);
665
+ else
666
+ left = right === 0 ? 0 : left % right;
667
+ } else {
668
+ break;
669
+ }
670
+ }
671
+ return left;
672
+ };
673
+ const parseAddSub = () => {
674
+ let left = parseMulDiv();
675
+ while (true) {
676
+ skipWhitespace();
677
+ const op = expr[pos];
678
+ if (op === "+" || op === "-" && !/[0-9]/.test(expr[pos + 1] ?? "")) {
679
+ pos++;
680
+ const right = parseMulDiv();
681
+ if (op === "+")
682
+ left = left + right;
683
+ else
684
+ left = left - right;
685
+ } else {
686
+ break;
687
+ }
688
+ }
689
+ return left;
690
+ };
691
+ const parseComparison = () => {
692
+ let left = parseAddSub();
693
+ while (true) {
694
+ skipWhitespace();
695
+ if (expr.slice(pos, pos + 2) === "<=") {
696
+ pos += 2;
697
+ const right = parseAddSub();
698
+ left = left <= right ? 1 : 0;
699
+ } else if (expr.slice(pos, pos + 2) === ">=") {
700
+ pos += 2;
701
+ const right = parseAddSub();
702
+ left = left >= right ? 1 : 0;
703
+ } else if (expr.slice(pos, pos + 2) === "==") {
704
+ pos += 2;
705
+ const right = parseAddSub();
706
+ left = left === right ? 1 : 0;
707
+ } else if (expr.slice(pos, pos + 2) === "!=") {
708
+ pos += 2;
709
+ const right = parseAddSub();
710
+ left = left !== right ? 1 : 0;
711
+ } else if (expr[pos] === "<") {
712
+ pos++;
713
+ const right = parseAddSub();
714
+ left = left < right ? 1 : 0;
715
+ } else if (expr[pos] === ">") {
716
+ pos++;
717
+ const right = parseAddSub();
718
+ left = left > right ? 1 : 0;
719
+ } else {
720
+ break;
721
+ }
722
+ }
723
+ return left;
724
+ };
725
+ const parseAnd = () => {
726
+ let left = parseComparison();
727
+ while (true) {
728
+ skipWhitespace();
729
+ if (expr.slice(pos, pos + 2) === "&&") {
730
+ pos += 2;
731
+ const right = parseComparison();
732
+ left = left !== 0 && right !== 0 ? 1 : 0;
733
+ } else {
734
+ break;
735
+ }
736
+ }
737
+ return left;
738
+ };
739
+ const parseOr = () => {
740
+ let left = parseAnd();
741
+ while (true) {
742
+ skipWhitespace();
743
+ if (expr.slice(pos, pos + 2) === "||") {
744
+ pos += 2;
745
+ const right = parseAnd();
746
+ left = left !== 0 || right !== 0 ? 1 : 0;
747
+ } else {
748
+ break;
749
+ }
750
+ }
751
+ return left;
752
+ };
753
+ return parseOr();
754
+ }
376
755
  setCwd(cwd) {
377
756
  this.cwd = cwd;
378
757
  }
@@ -387,4 +766,4 @@ class Interpreter {
387
766
  }
388
767
  }
389
768
 
390
- //# debugId=5AFD9CE7FC1DFBCF64756E2164756E21
769
+ //# debugId=E87B7B56CD04A5F564756E2164756E21