just-bash 2.5.5 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/README.md +2 -2
  2. package/dist/AGENTS.md +2 -2
  3. package/dist/ast/types.d.ts +100 -11
  4. package/dist/bin/chunks/alias-EGIS5LUE.js +7 -0
  5. package/dist/bin/chunks/awk2-GFEJOWML.js +21 -0
  6. package/dist/bin/chunks/bash-PGDTHIM2.js +6 -0
  7. package/dist/bin/chunks/chmod-TYLTHXFR.js +9 -0
  8. package/dist/bin/chunks/chunk-D5WP4CKS.js +3 -0
  9. package/dist/bin/chunks/chunk-FSAGDARS.js +74 -0
  10. package/dist/bin/chunks/chunk-FSZWFMB4.js +16 -0
  11. package/dist/bin/chunks/chunk-IRUD2E3M.js +17 -0
  12. package/dist/bin/chunks/chunk-K5IXNHO5.js +8 -0
  13. package/dist/bin/chunks/chunk-KD3EODLB.js +6 -0
  14. package/dist/bin/{shell/chunks/echo-WSKTON6U.js → chunks/echo-7I42V66Q.js} +2 -2
  15. package/dist/bin/chunks/env-7A4MH7BJ.js +9 -0
  16. package/dist/bin/chunks/expansion-BOR3ELLC.js +2 -0
  17. package/dist/bin/{shell/chunks/find-CBEJ35BR.js → chunks/find-PHDZK64M.js} +1 -1
  18. package/dist/bin/{shell/chunks/grep-IIVQXFNI.js → chunks/grep-VX7MJMVN.js} +2 -2
  19. package/dist/bin/chunks/{head-DYK37Z24.js → head-TJHLLIMR.js} +1 -1
  20. package/dist/bin/{shell/chunks/jq-XXZPU5CA.js → chunks/jq-RGZHJNXC.js} +1 -1
  21. package/dist/bin/chunks/od-KRKGC2U3.js +5 -0
  22. package/dist/bin/chunks/printf-YPXD4CRE.js +15 -0
  23. package/dist/bin/chunks/pwd-L26WH2K4.js +3 -0
  24. package/dist/bin/{shell/chunks/rg-Q4OTJOEF.js → chunks/rg-RSDLLECO.js} +1 -1
  25. package/dist/bin/chunks/rmdir-GOODLY5W.js +14 -0
  26. package/dist/bin/chunks/sed-JPDTWF4W.js +100 -0
  27. package/dist/bin/{shell/chunks/tail-BES27CZT.js → chunks/tail-YAUIERGN.js} +1 -1
  28. package/dist/bin/{shell/chunks/tar-C27YYUAS.js → chunks/tar-LFENC54A.js} +7 -7
  29. package/dist/bin/chunks/time-37F5EBPK.js +14 -0
  30. package/dist/bin/chunks/touch-IBPHJBM3.js +7 -0
  31. package/dist/bin/chunks/wc-SAOHEZYP.js +6 -0
  32. package/dist/bin/chunks/{which-73KOOLC6.js → which-FCDFBOMN.js} +1 -1
  33. package/dist/bin/chunks/whoami-JVLUNKSG.js +3 -0
  34. package/dist/bin/{shell/chunks/xan-6K2NGTHM.js → chunks/xan-5HNHTFMB.js} +19 -19
  35. package/dist/bin/chunks/{yq-MF2SNFGL.js → yq-PFV4T2PV.js} +1 -1
  36. package/dist/bin/just-bash.js +659 -135
  37. package/dist/bin/shell/chunks/alias-EGIS5LUE.js +7 -0
  38. package/dist/bin/shell/chunks/awk2-GFEJOWML.js +21 -0
  39. package/dist/bin/shell/chunks/bash-PGDTHIM2.js +6 -0
  40. package/dist/bin/shell/chunks/chmod-TYLTHXFR.js +9 -0
  41. package/dist/bin/shell/chunks/chunk-D5WP4CKS.js +3 -0
  42. package/dist/bin/shell/chunks/chunk-FSAGDARS.js +74 -0
  43. package/dist/bin/shell/chunks/chunk-FSZWFMB4.js +16 -0
  44. package/dist/bin/shell/chunks/chunk-IRUD2E3M.js +17 -0
  45. package/dist/bin/shell/chunks/chunk-K5IXNHO5.js +8 -0
  46. package/dist/bin/shell/chunks/chunk-KD3EODLB.js +6 -0
  47. package/dist/bin/{chunks/echo-WSKTON6U.js → shell/chunks/echo-7I42V66Q.js} +2 -2
  48. package/dist/bin/shell/chunks/env-7A4MH7BJ.js +9 -0
  49. package/dist/bin/shell/chunks/expansion-BOR3ELLC.js +2 -0
  50. package/dist/bin/{chunks/find-CBEJ35BR.js → shell/chunks/find-PHDZK64M.js} +1 -1
  51. package/dist/bin/{chunks/grep-IIVQXFNI.js → shell/chunks/grep-VX7MJMVN.js} +2 -2
  52. package/dist/bin/shell/chunks/{head-DYK37Z24.js → head-TJHLLIMR.js} +1 -1
  53. package/dist/bin/{chunks/jq-XXZPU5CA.js → shell/chunks/jq-RGZHJNXC.js} +1 -1
  54. package/dist/bin/shell/chunks/od-KRKGC2U3.js +5 -0
  55. package/dist/bin/shell/chunks/printf-YPXD4CRE.js +15 -0
  56. package/dist/bin/shell/chunks/pwd-L26WH2K4.js +3 -0
  57. package/dist/bin/{chunks/rg-Q4OTJOEF.js → shell/chunks/rg-RSDLLECO.js} +1 -1
  58. package/dist/bin/shell/chunks/rmdir-GOODLY5W.js +14 -0
  59. package/dist/bin/shell/chunks/sed-JPDTWF4W.js +100 -0
  60. package/dist/bin/{chunks/tail-BES27CZT.js → shell/chunks/tail-YAUIERGN.js} +1 -1
  61. package/dist/bin/{chunks/tar-C27YYUAS.js → shell/chunks/tar-LFENC54A.js} +7 -7
  62. package/dist/bin/shell/chunks/time-37F5EBPK.js +14 -0
  63. package/dist/bin/shell/chunks/touch-IBPHJBM3.js +7 -0
  64. package/dist/bin/shell/chunks/wc-SAOHEZYP.js +6 -0
  65. package/dist/bin/shell/chunks/{which-73KOOLC6.js → which-FCDFBOMN.js} +1 -1
  66. package/dist/bin/shell/chunks/whoami-JVLUNKSG.js +3 -0
  67. package/dist/bin/{chunks/xan-6K2NGTHM.js → shell/chunks/xan-5HNHTFMB.js} +19 -19
  68. package/dist/bin/shell/chunks/{yq-MF2SNFGL.js → yq-PFV4T2PV.js} +1 -1
  69. package/dist/bin/shell/shell.js +664 -140
  70. package/dist/bundle/browser.js +1251 -606
  71. package/dist/bundle/chunks/alias-ATFBB6D2.js +6 -0
  72. package/dist/bundle/chunks/awk2-6FBZTP57.js +20 -0
  73. package/dist/bundle/chunks/bash-OLRNM52U.js +5 -0
  74. package/dist/bundle/chunks/chmod-ODWUR7E6.js +8 -0
  75. package/dist/bundle/chunks/chunk-3AWP5CWK.js +73 -0
  76. package/dist/bundle/chunks/chunk-CXEWLFNE.js +16 -0
  77. package/dist/bundle/chunks/chunk-CZPA5RBA.js +5 -0
  78. package/dist/bundle/chunks/chunk-EEXR5ZDP.js +2 -0
  79. package/dist/bundle/chunks/chunk-HDQ56CKY.js +15 -0
  80. package/dist/bundle/chunks/chunk-PSW6BMXW.js +7 -0
  81. package/dist/bundle/chunks/{echo-VUHWYV6L.js → echo-6S7WE7XB.js} +2 -2
  82. package/dist/bundle/chunks/env-2UI6XINU.js +8 -0
  83. package/dist/bundle/chunks/expansion-RIGCFEMA.js +1 -0
  84. package/dist/bundle/chunks/{find-ACOAWALE.js → find-YGMSVGUV.js} +1 -1
  85. package/dist/bundle/chunks/{grep-ACVE42JK.js → grep-NIC6JNLH.js} +2 -2
  86. package/dist/bundle/chunks/{head-FZ6IQHYW.js → head-SA7P5NJ7.js} +1 -1
  87. package/dist/bundle/chunks/{jq-3YU5HRKE.js → jq-RLRYRPOJ.js} +1 -1
  88. package/dist/bundle/chunks/od-3FPDPLWJ.js +4 -0
  89. package/dist/bundle/chunks/printf-66XGXFCD.js +14 -0
  90. package/dist/bundle/chunks/pwd-S4NVAMC4.js +2 -0
  91. package/dist/bundle/chunks/{rg-YLZJWCEJ.js → rg-SRMB7L6G.js} +1 -1
  92. package/dist/bundle/chunks/rmdir-XFQE4ZYV.js +13 -0
  93. package/dist/bundle/chunks/sed-IV6HLDXU.js +99 -0
  94. package/dist/bundle/chunks/{tail-PD4RZR6J.js → tail-52LRAWXT.js} +1 -1
  95. package/dist/bundle/chunks/{tar-QWBXMF7K.js → tar-LWIHPMT6.js} +7 -7
  96. package/dist/bundle/chunks/time-UWXBG6CS.js +13 -0
  97. package/dist/bundle/chunks/touch-TDTEBHHI.js +6 -0
  98. package/dist/bundle/chunks/wc-HE5XARI4.js +5 -0
  99. package/dist/bundle/chunks/{which-M5MQ6QXQ.js → which-UBLRBDHN.js} +1 -1
  100. package/dist/bundle/chunks/whoami-YUDAIS32.js +2 -0
  101. package/dist/bundle/chunks/{xan-2R2APJJ4.js → xan-A6VPI4HJ.js} +19 -19
  102. package/dist/bundle/chunks/{yq-KANM4MD2.js → yq-L665QPQU.js} +1 -1
  103. package/dist/bundle/index.js +657 -133
  104. package/dist/commands/awk/ast.d.ts +1 -0
  105. package/dist/commands/awk/interpreter/context.d.ts +14 -0
  106. package/dist/commands/awk/interpreter/interpreter.d.ts +2 -0
  107. package/dist/commands/awk/interpreter/{helpers.d.ts → type-coercion.d.ts} +4 -1
  108. package/dist/commands/awk/parser2-print.d.ts +35 -0
  109. package/dist/commands/awk/parser2.d.ts +42 -34
  110. package/dist/commands/printf/strftime.d.ts +9 -0
  111. package/dist/commands/query-engine/builtins/array-builtins.d.ts +20 -0
  112. package/dist/commands/query-engine/builtins/control-builtins.d.ts +18 -0
  113. package/dist/commands/query-engine/builtins/date-builtins.d.ts +15 -0
  114. package/dist/commands/query-engine/builtins/format-builtins.d.ts +11 -0
  115. package/dist/commands/query-engine/builtins/index-builtins.d.ts +16 -0
  116. package/dist/commands/query-engine/builtins/index.d.ts +17 -0
  117. package/dist/commands/query-engine/builtins/math-builtins.d.ts +15 -0
  118. package/dist/commands/query-engine/builtins/navigation-builtins.d.ts +18 -0
  119. package/dist/commands/query-engine/builtins/object-builtins.d.ts +15 -0
  120. package/dist/commands/query-engine/builtins/path-builtins.d.ts +20 -0
  121. package/dist/commands/query-engine/builtins/sql-builtins.d.ts +16 -0
  122. package/dist/commands/query-engine/builtins/string-builtins.d.ts +15 -0
  123. package/dist/commands/query-engine/builtins/type-builtins.d.ts +11 -0
  124. package/dist/commands/query-engine/evaluator.d.ts +10 -2
  125. package/dist/commands/query-engine/parser-types.d.ts +171 -0
  126. package/dist/commands/query-engine/parser.d.ts +2 -132
  127. package/dist/commands/query-engine/path-operations.d.ts +15 -0
  128. package/dist/commands/query-engine/value-operations.d.ts +39 -0
  129. package/dist/commands/registry.d.ts +1 -1
  130. package/dist/commands/rmdir/rmdir.d.ts +2 -0
  131. package/dist/commands/sed/lexer.d.ts +12 -0
  132. package/dist/commands/sed/parser.d.ts +9 -0
  133. package/dist/commands/sed/sed-regex.d.ts +23 -0
  134. package/dist/commands/sed/types.d.ts +13 -1
  135. package/dist/commands/tar/tar-options.d.ts +36 -0
  136. package/dist/commands/time/time.d.ts +25 -0
  137. package/dist/commands/whoami/whoami.d.ts +9 -0
  138. package/dist/commands/xan/moonblade-tokenizer.d.ts +25 -0
  139. package/dist/fs/in-memory-fs/in-memory-fs.d.ts +12 -0
  140. package/dist/fs/interface.d.ts +16 -0
  141. package/dist/fs/mountable-fs/mountable-fs.d.ts +12 -0
  142. package/dist/fs/overlay-fs/overlay-fs.d.ts +13 -1
  143. package/dist/fs/read-write-fs/read-write-fs.d.ts +13 -1
  144. package/dist/interpreter/alias-expansion.d.ts +23 -0
  145. package/dist/interpreter/arithmetic.d.ts +1 -6
  146. package/dist/interpreter/assignment-expansion.d.ts +24 -0
  147. package/dist/interpreter/builtin-dispatch.d.ts +39 -0
  148. package/dist/interpreter/builtins/compgen.d.ts +26 -0
  149. package/dist/interpreter/builtins/complete.d.ts +17 -0
  150. package/dist/interpreter/builtins/compopt.d.ts +28 -0
  151. package/dist/interpreter/builtins/declare-array-parsing.d.ts +14 -0
  152. package/dist/interpreter/builtins/declare-print.d.ts +39 -0
  153. package/dist/interpreter/builtins/declare.d.ts +10 -4
  154. package/dist/interpreter/builtins/dirs.d.ts +29 -0
  155. package/dist/interpreter/builtins/eval.d.ts +1 -1
  156. package/dist/interpreter/builtins/export.d.ts +1 -0
  157. package/dist/interpreter/builtins/getopts.d.ts +18 -0
  158. package/dist/interpreter/builtins/hash.d.ts +19 -0
  159. package/dist/interpreter/builtins/help.d.ts +12 -0
  160. package/dist/interpreter/builtins/index.d.ts +9 -1
  161. package/dist/interpreter/builtins/local.d.ts +1 -1
  162. package/dist/interpreter/builtins/read.d.ts +1 -1
  163. package/dist/interpreter/builtins/set.d.ts +3 -0
  164. package/dist/interpreter/builtins/shift.d.ts +3 -0
  165. package/dist/interpreter/builtins/shopt.d.ts +7 -0
  166. package/dist/interpreter/builtins/unset.d.ts +5 -1
  167. package/dist/interpreter/builtins/variable-assignment.d.ts +66 -0
  168. package/dist/interpreter/command-resolution.d.ts +43 -0
  169. package/dist/interpreter/conditionals.d.ts +1 -1
  170. package/dist/interpreter/errors.d.ts +36 -1
  171. package/dist/interpreter/expansion/analysis.d.ts +15 -17
  172. package/dist/interpreter/expansion/arith-text-expansion.d.ts +20 -0
  173. package/dist/interpreter/expansion/array-pattern-ops.d.ts +21 -0
  174. package/dist/interpreter/expansion/array-prefix-suffix.d.ts +46 -0
  175. package/dist/interpreter/expansion/array-slice-transform.d.ts +36 -0
  176. package/dist/interpreter/expansion/array-word-expansion.d.ts +39 -0
  177. package/dist/interpreter/expansion/command-substitution.d.ts +23 -0
  178. package/dist/interpreter/expansion/glob-escape.d.ts +32 -0
  179. package/dist/interpreter/expansion/indirect-expansion.d.ts +42 -0
  180. package/dist/interpreter/expansion/parameter-ops.d.ts +113 -0
  181. package/dist/interpreter/expansion/pattern-expansion.d.ts +23 -0
  182. package/dist/interpreter/expansion/pattern-removal.d.ts +18 -0
  183. package/dist/interpreter/expansion/pattern.d.ts +2 -1
  184. package/dist/interpreter/expansion/positional-params.d.ts +59 -0
  185. package/dist/interpreter/expansion/prompt.d.ts +39 -0
  186. package/dist/interpreter/expansion/quoting.d.ts +13 -0
  187. package/dist/interpreter/expansion/tilde.d.ts +12 -0
  188. package/dist/interpreter/expansion/unquoted-expansion.d.ts +76 -0
  189. package/dist/interpreter/expansion/variable-attrs.d.ts +19 -0
  190. package/dist/interpreter/expansion/variable.d.ts +10 -1
  191. package/dist/interpreter/expansion/word-glob-expansion.d.ts +33 -0
  192. package/dist/interpreter/expansion/word-split.d.ts +11 -6
  193. package/dist/interpreter/expansion.d.ts +30 -4
  194. package/dist/interpreter/functions.d.ts +1 -1
  195. package/dist/interpreter/helpers/array.d.ts +20 -0
  196. package/dist/interpreter/helpers/ifs.d.ts +66 -5
  197. package/dist/interpreter/helpers/nameref.d.ts +65 -0
  198. package/dist/interpreter/helpers/quoting.d.ts +24 -0
  199. package/dist/interpreter/helpers/readonly.d.ts +28 -4
  200. package/dist/interpreter/helpers/shell-constants.d.ts +25 -0
  201. package/dist/interpreter/helpers/shellopts.d.ts +28 -0
  202. package/dist/interpreter/helpers/string-compare.d.ts +3 -1
  203. package/dist/interpreter/helpers/tilde.d.ts +13 -0
  204. package/dist/interpreter/helpers/variable-tests.d.ts +1 -1
  205. package/dist/interpreter/helpers/word-matching.d.ts +26 -0
  206. package/dist/interpreter/helpers/xtrace.d.ts +18 -0
  207. package/dist/interpreter/interpreter.d.ts +13 -14
  208. package/dist/interpreter/pipeline-execution.d.ts +16 -0
  209. package/dist/interpreter/redirections.d.ts +38 -1
  210. package/dist/interpreter/simple-command-assignments.d.ts +29 -0
  211. package/dist/interpreter/subshell-group.d.ts +32 -0
  212. package/dist/interpreter/type-command.d.ts +37 -0
  213. package/dist/interpreter/types.d.ts +255 -21
  214. package/dist/parser/arithmetic-parser.d.ts +2 -4
  215. package/dist/parser/arithmetic-primaries.d.ts +45 -0
  216. package/dist/parser/compound-parser.d.ts +21 -7
  217. package/dist/parser/expansion-parser.d.ts +7 -1
  218. package/dist/parser/lexer.d.ts +57 -0
  219. package/dist/parser/parser-substitution.d.ts +62 -0
  220. package/dist/parser/parser.d.ts +39 -2
  221. package/dist/parser/types.d.ts +1 -0
  222. package/dist/types.d.ts +17 -0
  223. package/package.json +4 -1
  224. package/dist/bin/chunks/alias-PCMLRCRW.js +0 -7
  225. package/dist/bin/chunks/awk2-D2US2LMM.js +0 -20
  226. package/dist/bin/chunks/bash-UT3MT5UU.js +0 -7
  227. package/dist/bin/chunks/chmod-3DIKREF7.js +0 -9
  228. package/dist/bin/chunks/chunk-ACRTDIBO.js +0 -6
  229. package/dist/bin/chunks/chunk-DV5HL4K2.js +0 -17
  230. package/dist/bin/chunks/chunk-J7BCMQDI.js +0 -16
  231. package/dist/bin/chunks/chunk-NWWB2XRE.js +0 -6
  232. package/dist/bin/chunks/chunk-PM2DS2YW.js +0 -3
  233. package/dist/bin/chunks/env-YLLSNZZN.js +0 -9
  234. package/dist/bin/chunks/od-SLM7SRWU.js +0 -7
  235. package/dist/bin/chunks/printf-HWUQKYUM.js +0 -14
  236. package/dist/bin/chunks/pwd-53KG2MCJ.js +0 -3
  237. package/dist/bin/chunks/sed-5LQMJYRJ.js +0 -80
  238. package/dist/bin/chunks/touch-TSNAXMZ2.js +0 -4
  239. package/dist/bin/chunks/wc-QSBRKIF5.js +0 -6
  240. package/dist/bin/shell/chunks/alias-PCMLRCRW.js +0 -7
  241. package/dist/bin/shell/chunks/awk2-D2US2LMM.js +0 -20
  242. package/dist/bin/shell/chunks/bash-UT3MT5UU.js +0 -7
  243. package/dist/bin/shell/chunks/chmod-3DIKREF7.js +0 -9
  244. package/dist/bin/shell/chunks/chunk-ACRTDIBO.js +0 -6
  245. package/dist/bin/shell/chunks/chunk-DV5HL4K2.js +0 -17
  246. package/dist/bin/shell/chunks/chunk-J7BCMQDI.js +0 -16
  247. package/dist/bin/shell/chunks/chunk-NWWB2XRE.js +0 -6
  248. package/dist/bin/shell/chunks/chunk-PM2DS2YW.js +0 -3
  249. package/dist/bin/shell/chunks/env-YLLSNZZN.js +0 -9
  250. package/dist/bin/shell/chunks/od-SLM7SRWU.js +0 -7
  251. package/dist/bin/shell/chunks/printf-HWUQKYUM.js +0 -14
  252. package/dist/bin/shell/chunks/pwd-53KG2MCJ.js +0 -3
  253. package/dist/bin/shell/chunks/sed-5LQMJYRJ.js +0 -80
  254. package/dist/bin/shell/chunks/touch-TSNAXMZ2.js +0 -4
  255. package/dist/bin/shell/chunks/wc-QSBRKIF5.js +0 -6
  256. package/dist/bundle/chunks/alias-4UGRF4DM.js +0 -6
  257. package/dist/bundle/chunks/awk2-46RTIZKB.js +0 -19
  258. package/dist/bundle/chunks/bash-ZILV3VHA.js +0 -6
  259. package/dist/bundle/chunks/chmod-FBHLEIY6.js +0 -8
  260. package/dist/bundle/chunks/chunk-4JO5BKO4.js +0 -5
  261. package/dist/bundle/chunks/chunk-BOJ3OAZB.js +0 -16
  262. package/dist/bundle/chunks/chunk-CG2HXOFG.js +0 -5
  263. package/dist/bundle/chunks/chunk-NWEGHOXL.js +0 -2
  264. package/dist/bundle/chunks/chunk-W2EKKAIL.js +0 -15
  265. package/dist/bundle/chunks/env-EG5SQSAQ.js +0 -8
  266. package/dist/bundle/chunks/od-ECWXNUB4.js +0 -6
  267. package/dist/bundle/chunks/printf-VG2POOXB.js +0 -13
  268. package/dist/bundle/chunks/pwd-AC4P3JKI.js +0 -2
  269. package/dist/bundle/chunks/sed-ZKODWZ6F.js +0 -79
  270. package/dist/bundle/chunks/touch-MVQSKQKT.js +0 -3
  271. package/dist/bundle/chunks/wc-DFQKWSIZ.js +0 -5
  272. package/dist/interpreter/builtins/variable-helpers.d.ts +0 -30
  273. /package/dist/bin/chunks/{curl-LCMREE7R.js → curl-TH7YRBSA.js} +0 -0
  274. /package/dist/bin/chunks/{file-LNCFDPQZ.js → file-6PCTL3MH.js} +0 -0
  275. /package/dist/bin/shell/chunks/{curl-LCMREE7R.js → curl-TH7YRBSA.js} +0 -0
  276. /package/dist/bin/shell/chunks/{file-LNCFDPQZ.js → file-6PCTL3MH.js} +0 -0
  277. /package/dist/bundle/chunks/{curl-TVZH24MD.js → curl-XLP4VABU.js} +0 -0
  278. /package/dist/bundle/chunks/{file-XPA6O6H2.js → file-NQP3CKRV.js} +0 -0
  279. /package/dist/commands/curl/{utils.d.ts → response-formatting.d.ts} +0 -0
  280. /package/dist/commands/xan/{xan-utils.d.ts → column-selection.d.ts} +0 -0
  281. /package/dist/fs/{utils.d.ts → encoding.d.ts} +0 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Simple Command Assignment Handling
3
+ *
4
+ * Handles variable assignments in simple commands:
5
+ * - Array assignments: VAR=(a b c)
6
+ * - Subscript assignments: VAR[idx]=value
7
+ * - Scalar assignments with nameref resolution
8
+ */
9
+ import type { SimpleCommandNode } from "../ast/types.js";
10
+ import type { ExecResult } from "../types.js";
11
+ import type { InterpreterContext } from "./types.js";
12
+ /**
13
+ * Result of processing assignments in a simple command
14
+ */
15
+ export interface AssignmentResult {
16
+ /** Whether to continue to the next statement (skip command execution) */
17
+ continueToNext: boolean;
18
+ /** Accumulated xtrace output for assignments */
19
+ xtraceOutput: string;
20
+ /** Temporary assignments for prefix bindings (FOO=bar cmd) */
21
+ tempAssignments: Record<string, string | undefined>;
22
+ /** Error result if assignment failed */
23
+ error?: ExecResult;
24
+ }
25
+ /**
26
+ * Process all assignments in a simple command.
27
+ * Returns assignment results including temp bindings and any errors.
28
+ */
29
+ export declare function processAssignments(ctx: InterpreterContext, node: SimpleCommandNode): Promise<AssignmentResult>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Subshell, Group, and Script Execution
3
+ *
4
+ * Handles execution of subshells (...), groups { ...; }, and user scripts
5
+ */
6
+ import type { GroupNode, ScriptNode, StatementNode, SubshellNode } from "../ast/types.js";
7
+ import type { ExecResult } from "../types.js";
8
+ import type { InterpreterContext } from "./types.js";
9
+ /**
10
+ * Type for executeStatement callback
11
+ */
12
+ export type ExecuteStatementFn = (stmt: StatementNode) => Promise<ExecResult>;
13
+ /**
14
+ * Execute a subshell node (...).
15
+ * Creates an isolated execution environment that doesn't affect the parent.
16
+ */
17
+ export declare function executeSubshell(ctx: InterpreterContext, node: SubshellNode, stdin: string, executeStatement: ExecuteStatementFn): Promise<ExecResult>;
18
+ /**
19
+ * Execute a group node { ...; }.
20
+ * Runs commands in the current execution environment.
21
+ */
22
+ export declare function executeGroup(ctx: InterpreterContext, node: GroupNode, stdin: string, executeStatement: ExecuteStatementFn): Promise<ExecResult>;
23
+ /**
24
+ * Type for executeScript callback
25
+ */
26
+ export type ExecuteScriptFn = (node: ScriptNode) => Promise<ExecResult>;
27
+ /**
28
+ * Execute a user script file found in PATH.
29
+ * This handles executable files that don't have registered command handlers.
30
+ * The script runs in a subshell-like environment with its own positional parameters.
31
+ */
32
+ export declare function executeUserScript(ctx: InterpreterContext, scriptPath: string, args: string[], stdin: string, executeScript: ExecuteScriptFn): Promise<ExecResult>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Type Command Implementation
3
+ *
4
+ * Implements the `type` builtin command and related functionality:
5
+ * - type [-afptP] name...
6
+ * - command -v/-V name...
7
+ *
8
+ * Also includes helpers for function source serialization.
9
+ */
10
+ import type { IFileSystem } from "../fs/interface.js";
11
+ import type { CommandRegistry, ExecResult } from "../types.js";
12
+ import type { InterpreterState } from "./types.js";
13
+ /**
14
+ * Context needed for type command operations
15
+ */
16
+ export interface TypeCommandContext {
17
+ state: InterpreterState;
18
+ fs: IFileSystem;
19
+ commands: CommandRegistry;
20
+ }
21
+ /**
22
+ * Handle the `type` builtin command.
23
+ * type [-afptP] name...
24
+ */
25
+ export declare function handleType(ctx: TypeCommandContext, args: string[], findFirstInPath: (name: string) => Promise<string | null>, findCommandInPath: (name: string) => Promise<string[]>): Promise<ExecResult>;
26
+ /**
27
+ * Handle `command -v` and `command -V` flags
28
+ * -v: print the name or path of the command (simple output)
29
+ * -V: print a description like `type` does (verbose output)
30
+ */
31
+ export declare function handleCommandV(ctx: TypeCommandContext, names: string[], _showPath: boolean, verboseDescribe: boolean): Promise<ExecResult>;
32
+ /**
33
+ * Find the first occurrence of a command in PATH.
34
+ * Returns the full path if found, null otherwise.
35
+ * Only returns executable files, not directories.
36
+ */
37
+ export declare function findFirstInPath(ctx: TypeCommandContext, name: string): Promise<string | null>;
@@ -6,6 +6,23 @@ import type { IFileSystem } from "../fs/interface.js";
6
6
  import type { ExecutionLimits } from "../limits.js";
7
7
  import type { SecureFetch } from "../network/index.js";
8
8
  import type { CommandRegistry, ExecResult, TraceCallback } from "../types.js";
9
+ /**
10
+ * Completion specification for a command, set by the `complete` builtin.
11
+ */
12
+ export interface CompletionSpec {
13
+ /** Word list for -W option */
14
+ wordlist?: string;
15
+ /** Function name for -F option */
16
+ function?: string;
17
+ /** Command to run for -C option */
18
+ command?: string;
19
+ /** Completion options (nospace, filenames, etc.) */
20
+ options?: string[];
21
+ /** Actions to perform (from -A option) */
22
+ actions?: string[];
23
+ /** Whether this is a default completion (-D) */
24
+ isDefault?: boolean;
25
+ }
9
26
  export interface ShellOptions {
10
27
  /** set -e: Exit immediately if a command exits with non-zero status */
11
28
  errexit: boolean;
@@ -17,44 +34,261 @@ export interface ShellOptions {
17
34
  xtrace: boolean;
18
35
  /** set -v: Print shell input lines as they are read (verbose) */
19
36
  verbose: boolean;
37
+ /** set -o posix: POSIX mode for stricter compliance */
38
+ posix: boolean;
39
+ /** set -a: Export all variables */
40
+ allexport: boolean;
41
+ /** set -C: Prevent overwriting files with redirection */
42
+ noclobber: boolean;
43
+ /** set -f: Disable filename expansion (globbing) */
44
+ noglob: boolean;
45
+ /** set -n: Read commands but do not execute them (syntax check mode) */
46
+ noexec: boolean;
47
+ /** set -o vi: Use vi-style line editing (mutually exclusive with emacs) */
48
+ vi: boolean;
49
+ /** set -o emacs: Use emacs-style line editing (mutually exclusive with vi) */
50
+ emacs: boolean;
20
51
  }
21
- export interface InterpreterState {
22
- env: Record<string, string>;
23
- cwd: string;
24
- previousDir: string;
25
- functions: Map<string, FunctionDefNode>;
52
+ export interface ShoptOptions {
53
+ /** shopt -s extglob: Enable extended globbing patterns @(), *(), +(), ?(), !() */
54
+ extglob: boolean;
55
+ /** shopt -s dotglob: Include dotfiles in glob expansion */
56
+ dotglob: boolean;
57
+ /** shopt -s nullglob: Return empty for non-matching globs instead of literal pattern */
58
+ nullglob: boolean;
59
+ /** shopt -s failglob: Fail if glob pattern has no matches */
60
+ failglob: boolean;
61
+ /** shopt -s globstar: Enable ** recursive glob patterns */
62
+ globstar: boolean;
63
+ /** shopt -s globskipdots: Skip . and .. in glob patterns (default: true in bash >=5.2) */
64
+ globskipdots: boolean;
65
+ /** shopt -s nocaseglob: Case-insensitive glob matching */
66
+ nocaseglob: boolean;
67
+ /** shopt -s nocasematch: Case-insensitive pattern matching in [[ ]] and case */
68
+ nocasematch: boolean;
69
+ /** shopt -s expand_aliases: Enable alias expansion */
70
+ expand_aliases: boolean;
71
+ /** shopt -s lastpipe: Run last command of pipeline in current shell context */
72
+ lastpipe: boolean;
73
+ /** shopt -s xpg_echo: Make echo interpret backslash escapes by default (like echo -e) */
74
+ xpg_echo: boolean;
75
+ }
76
+ /**
77
+ * Tracks variable type attributes (declare -i, -l, -u, -n, -a, -A, etc.)
78
+ * and export status. These affect how variables are read, written, and expanded.
79
+ */
80
+ export interface VariableAttributeState {
81
+ /** Set of variable names that are readonly */
82
+ readonlyVars?: Set<string>;
83
+ /** Set of variable names that are associative arrays */
84
+ associativeArrays?: Set<string>;
85
+ /** Set of variable names that are namerefs (declare -n) */
86
+ namerefs?: Set<string>;
87
+ /**
88
+ * Set of nameref variable names that were "bound" to valid targets at creation time.
89
+ * A bound nameref will always resolve through to its target, even if the target
90
+ * is later unset. An unbound nameref (target didn't exist at creation) acts like
91
+ * a regular variable, returning its raw value.
92
+ */
93
+ boundNamerefs?: Set<string>;
94
+ /**
95
+ * Set of nameref variable names that were created with an invalid target.
96
+ * Invalid namerefs always read/write their value directly, never resolving.
97
+ * For example, after `ref=1; typeset -n ref`, ref has an invalid target "1".
98
+ */
99
+ invalidNamerefs?: Set<string>;
100
+ /** Set of variable names that have integer attribute (declare -i) */
101
+ integerVars?: Set<string>;
102
+ /** Set of variable names that have lowercase attribute (declare -l) */
103
+ lowercaseVars?: Set<string>;
104
+ /** Set of variable names that have uppercase attribute (declare -u) */
105
+ uppercaseVars?: Set<string>;
106
+ /** Set of exported variable names */
107
+ exportedVars?: Set<string>;
108
+ /** Set of temporarily exported variable names (for prefix assignments like FOO=bar cmd) */
109
+ tempExportedVars?: Set<string>;
110
+ /**
111
+ * Stack of sets tracking variables exported within each local scope.
112
+ * When a function returns and a local scope is popped, if a variable was
113
+ * exported only in that scope (not before entering), the export attribute
114
+ * should be removed. This enables bash's scoped export behavior where
115
+ * `local V=x; export V` only exports the local, not the global.
116
+ */
117
+ localExportedVars?: Set<string>[];
118
+ /** Set of variable names that have been declared but not assigned a value */
119
+ declaredVars?: Set<string>;
120
+ }
121
+ /**
122
+ * Tracks the complex local variable scoping machinery.
123
+ * Bash's local variable behavior is intricate: variables are dynamically scoped,
124
+ * can be declared multiple times in nested contexts, and have different unset
125
+ * behaviors depending on whether the unset happens in the declaring scope.
126
+ */
127
+ export interface LocalScopingState {
128
+ /** Stack of local variable scopes (one Map per function call) */
26
129
  localScopes: Map<string, string | undefined>[];
130
+ /**
131
+ * Tracks at which call depth each local variable was declared.
132
+ * Used for bash-specific unset scoping behavior:
133
+ * - local-unset (same scope): value-unset (clears value, keeps local cell)
134
+ * - dynamic-unset (different scope): cell-unset (removes local cell, exposes outer value)
135
+ */
136
+ localVarDepth?: Map<string, number>;
137
+ /**
138
+ * Stack of saved values for each local variable, supporting bash's localvar-nest behavior.
139
+ * Each entry contains the saved (outer) value and the scope index where it was saved.
140
+ * This allows multiple nested `local` declarations of the same variable (e.g., in nested evals)
141
+ * to each have their own cell that can be unset independently.
142
+ */
143
+ localVarStack?: Map<string, Array<{
144
+ value: string | undefined;
145
+ scopeIndex: number;
146
+ }>>;
147
+ /**
148
+ * Map of variable names to scope index where they were fully unset.
149
+ * Used to prevent tempenv restoration after all local cells are removed.
150
+ * Entries are cleared when their scope returns.
151
+ */
152
+ fullyUnsetLocals?: Map<string, number>;
153
+ /**
154
+ * Stack of temporary environment bindings from prefix assignments (e.g., FOO=bar cmd).
155
+ * Each entry maps variable names to their saved (underlying) values.
156
+ * Used for bash-specific unset behavior: when unsetting a variable that has a
157
+ * tempenv binding, the unset should reveal the underlying value, not completely
158
+ * remove the variable.
159
+ */
160
+ tempEnvBindings?: Map<string, string | undefined>[];
161
+ /**
162
+ * Set of tempenv variable names that have been explicitly written to within
163
+ * the current function context (after the prefix assignment, before local).
164
+ * Used to distinguish between "fresh" tempenvs (local-unset = value-unset)
165
+ * and "mutated" tempenvs (local-unset reveals the mutated value).
166
+ */
167
+ mutatedTempEnvVars?: Set<string>;
168
+ /**
169
+ * Set of tempenv variable names that have been accessed (read or written)
170
+ * within the current function context. Used to determine if a tempenv was
171
+ * "observed" before a local declaration.
172
+ */
173
+ accessedTempEnvVars?: Set<string>;
174
+ }
175
+ /**
176
+ * Tracks the function call stack and source file nesting.
177
+ * This state powers the FUNCNAME, BASH_LINENO, and BASH_SOURCE arrays,
178
+ * and determines the behavior of `return` in different contexts.
179
+ */
180
+ export interface CallStackState {
181
+ /** Function definitions (name -> AST node) */
182
+ functions: Map<string, FunctionDefNode>;
183
+ /** Current function call depth (for recursion limits and local scoping) */
27
184
  callDepth: number;
28
185
  /** Current source script nesting depth (for return in sourced scripts) */
29
186
  sourceDepth: number;
30
- commandCount: number;
31
- lastExitCode: number;
32
- /** Last argument of previous command, for $_ expansion */
33
- lastArg: string;
34
- /** Time when shell started (for $SECONDS) */
35
- startTime: number;
36
- /** PID of last background job (for $!) */
37
- lastBackgroundPid: number;
38
- /** Current line number being executed (for $LINENO) */
39
- currentLine: number;
40
- /** Shell options (set -e, etc.) */
41
- options: ShellOptions;
187
+ /** Stack of call line numbers for BASH_LINENO */
188
+ callLineStack?: number[];
189
+ /** Stack of function names for FUNCNAME */
190
+ funcNameStack?: string[];
191
+ /** Stack of source files for BASH_SOURCE (tracks where functions were defined) */
192
+ sourceStack?: string[];
193
+ /** Current source file context (for function definitions) */
194
+ currentSource?: string;
195
+ }
196
+ /**
197
+ * Tracks loop nesting and condition context.
198
+ * Used to implement break/continue commands and to suppress errexit
199
+ * in condition contexts (if, while, until, ||, &&).
200
+ */
201
+ export interface ControlFlowState {
42
202
  /** True when executing condition for if/while/until (errexit doesn't apply) */
43
203
  inCondition: boolean;
44
204
  /** Current loop nesting depth (for break/continue) */
45
205
  loopDepth: number;
46
206
  /** True if this subshell was spawned from within a loop context (for break/continue to exit subshell) */
47
207
  parentHasLoopContext?: boolean;
208
+ /** True when the last executed statement's exit code is "safe" for errexit purposes
209
+ * (e.g., from a &&/|| chain where the failure wasn't the final command) */
210
+ errexitSafe?: boolean;
211
+ }
212
+ /**
213
+ * Tracks process IDs, timing, and execution counts.
214
+ * Powers special variables like $$, $BASHPID, $!, and $SECONDS.
215
+ */
216
+ export interface ProcessState {
217
+ /** Total commands executed (for execution limits) */
218
+ commandCount: number;
219
+ /** Time when shell started (for $SECONDS) */
220
+ startTime: number;
221
+ /** PID of last background job (for $!) */
222
+ lastBackgroundPid: number;
223
+ /** Current BASHPID (changes in subshells, unlike $$) */
224
+ bashPid: number;
225
+ /** Counter for generating unique virtual PIDs for subshells */
226
+ nextVirtualPid: number;
227
+ }
228
+ /**
229
+ * Tracks file descriptors and stdin content for I/O operations.
230
+ * Used for process substitution, here-documents, and compound command stdin.
231
+ */
232
+ export interface IOState {
48
233
  /** Stdin available for commands in compound commands (groups, subshells, while loops with piped input) */
49
234
  groupStdin?: string;
50
- /** Set of variable names that are readonly */
51
- readonlyVars?: Set<string>;
235
+ /** File descriptors for process substitution and here-docs */
236
+ fileDescriptors?: Map<number, string>;
237
+ /** Next available file descriptor for {varname}>file allocation (starts at 10) */
238
+ nextFd?: number;
239
+ }
240
+ /**
241
+ * Captures errors that occur during parameter expansion.
242
+ * Some expansion errors need to be reported after expansion completes,
243
+ * with their exit codes and stderr preserved.
244
+ */
245
+ export interface ExpansionState {
52
246
  /** Exit code from expansion errors (arithmetic, etc.) - overrides command exit code */
53
247
  expansionExitCode?: number;
54
248
  /** Stderr from expansion errors */
55
249
  expansionStderr?: string;
56
- /** Set of variable names that are associative arrays */
57
- associativeArrays?: Set<string>;
250
+ }
251
+ /**
252
+ * Complete interpreter state for bash script execution.
253
+ *
254
+ * This interface is composed from focused sub-interfaces:
255
+ * - {@link VariableAttributeState} - Variable type attributes (readonly, integer, etc.)
256
+ * - {@link LocalScopingState} - Local variable scoping machinery
257
+ * - {@link CallStackState} - Function calls and source file tracking
258
+ * - {@link ControlFlowState} - Loop nesting and condition context
259
+ * - {@link ProcessState} - PIDs, timing, execution counts
260
+ * - {@link IOState} - File descriptors and stdin
261
+ * - {@link ExpansionState} - Expansion error capture
262
+ */
263
+ export interface InterpreterState extends VariableAttributeState, LocalScopingState, CallStackState, ControlFlowState, ProcessState, IOState, ExpansionState {
264
+ /** Environment variables (exported to commands) */
265
+ env: Record<string, string>;
266
+ /** Current working directory */
267
+ cwd: string;
268
+ /** Previous directory (for `cd -`) */
269
+ previousDir: string;
270
+ /** Exit code of last executed command */
271
+ lastExitCode: number;
272
+ /** Last argument of previous command, for $_ expansion */
273
+ lastArg: string;
274
+ /** Current line number being executed (for $LINENO) */
275
+ currentLine: number;
276
+ /** Shell options (set -e, etc.) */
277
+ options: ShellOptions;
278
+ /** Shopt options (shopt -s, etc.) */
279
+ shoptOptions: ShoptOptions;
280
+ /** Completion specifications set by the `complete` builtin */
281
+ completionSpecs?: Map<string, CompletionSpec>;
282
+ /** Directory stack for pushd/popd/dirs */
283
+ directoryStack?: string[];
284
+ /** Hash table for PATH command lookup caching */
285
+ hashTable?: Map<string, string>;
286
+ /**
287
+ * Suppress verbose mode output (set -v) when inside command substitutions.
288
+ * bash only prints verbose output for the main script, not for commands
289
+ * inside $(...) or backticks.
290
+ */
291
+ suppressVerbose?: boolean;
58
292
  }
59
293
  export interface InterpreterContext {
60
294
  state: InterpreterState;
@@ -10,7 +10,9 @@
10
10
  * All functions take a Parser instance as the first argument for shared state access.
11
11
  */
12
12
  import type { ArithExpr, ArithmeticExpressionNode } from "../ast/types.js";
13
+ import { parseArithNumber } from "./arithmetic-primaries.js";
13
14
  import type { Parser } from "./parser.js";
15
+ export { parseArithNumber };
14
16
  /**
15
17
  * Parse an arithmetic expression string into an AST node
16
18
  */
@@ -19,7 +21,3 @@ export declare function parseArithExpr(p: Parser, input: string, pos: number): {
19
21
  expr: ArithExpr;
20
22
  pos: number;
21
23
  };
22
- /**
23
- * Parse a number string with various bases (decimal, hex, octal, base#num)
24
- */
25
- export declare function parseArithNumber(str: string): number;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Helper functions for parsing primary arithmetic expressions
3
+ */
4
+ import type { ArithExpr } from "../ast/types.js";
5
+ import type { Parser } from "./parser.js";
6
+ /**
7
+ * Skip whitespace in arithmetic expression input.
8
+ * Also handles line continuations (backslash followed by newline).
9
+ */
10
+ export declare function skipArithWhitespace(input: string, pos: number): number;
11
+ /**
12
+ * Assignment operators in arithmetic expressions
13
+ */
14
+ export declare const ARITH_ASSIGN_OPS: readonly ["=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^="];
15
+ /**
16
+ * Parse a number string with various bases (decimal, hex, octal, base#num)
17
+ * Returns NaN for invalid numbers.
18
+ */
19
+ export declare function parseArithNumber(str: string): number;
20
+ /**
21
+ * Parse nested arithmetic expression: $((expr))
22
+ */
23
+ export declare function parseNestedArithmetic(parseArithExpr: (p: Parser, input: string, pos: number) => {
24
+ expr: ArithExpr;
25
+ pos: number;
26
+ }, p: Parser, input: string, currentPos: number): {
27
+ expr: ArithExpr;
28
+ pos: number;
29
+ } | null;
30
+ /**
31
+ * Parse ANSI-C quoting: $'...'
32
+ * Returns the numeric value of the string content
33
+ */
34
+ export declare function parseAnsiCQuoting(input: string, currentPos: number): {
35
+ expr: ArithExpr;
36
+ pos: number;
37
+ } | null;
38
+ /**
39
+ * Parse localization quoting: $"..."
40
+ * Returns the numeric value of the string content
41
+ */
42
+ export declare function parseLocalizationQuoting(input: string, currentPos: number): {
43
+ expr: ArithExpr;
44
+ pos: number;
45
+ } | null;
@@ -5,10 +5,24 @@
5
5
  */
6
6
  import { type CaseNode, type CStyleForNode, type ForNode, type GroupNode, type IfNode, type SubshellNode, type UntilNode, type WhileNode } from "../ast/types.js";
7
7
  import type { Parser } from "./parser.js";
8
- export declare function parseIf(p: Parser): IfNode;
9
- export declare function parseFor(p: Parser): ForNode | CStyleForNode;
10
- export declare function parseWhile(p: Parser): WhileNode;
11
- export declare function parseUntil(p: Parser): UntilNode;
12
- export declare function parseCase(p: Parser): CaseNode;
13
- export declare function parseSubshell(p: Parser): SubshellNode | CStyleForNode;
14
- export declare function parseGroup(p: Parser): GroupNode;
8
+ export declare function parseIf(p: Parser, options?: {
9
+ skipRedirections?: boolean;
10
+ }): IfNode;
11
+ export declare function parseFor(p: Parser, options?: {
12
+ skipRedirections?: boolean;
13
+ }): ForNode | CStyleForNode;
14
+ export declare function parseWhile(p: Parser, options?: {
15
+ skipRedirections?: boolean;
16
+ }): WhileNode;
17
+ export declare function parseUntil(p: Parser, options?: {
18
+ skipRedirections?: boolean;
19
+ }): UntilNode;
20
+ export declare function parseCase(p: Parser, options?: {
21
+ skipRedirections?: boolean;
22
+ }): CaseNode;
23
+ export declare function parseSubshell(p: Parser, options?: {
24
+ skipRedirections?: boolean;
25
+ }): SubshellNode | CStyleForNode;
26
+ export declare function parseGroup(p: Parser, options?: {
27
+ skipRedirections?: boolean;
28
+ }): GroupNode;
@@ -7,4 +7,10 @@ import { type WordPart } from "../ast/types.js";
7
7
  import type { Parser } from "./parser.js";
8
8
  export declare function parseWordParts(p: Parser, value: string, quoted?: boolean, singleQuoted?: boolean, isAssignment?: boolean, hereDoc?: boolean,
9
9
  /** When true, single quotes are treated as literal characters, not quote delimiters */
10
- singleQuotesAreLiteral?: boolean): WordPart[];
10
+ singleQuotesAreLiteral?: boolean,
11
+ /** When true, brace expansion is disabled (used in [[ ]] conditionals) */
12
+ noBraceExpansion?: boolean,
13
+ /** When true, all backslash escapes create Escaped nodes (for regex patterns in [[ =~ ]]) */
14
+ regexPattern?: boolean,
15
+ /** When true, \} is treated as escaped } (used in parameter expansion default values) */
16
+ inParameterExpansion?: boolean): WordPart[];
@@ -63,6 +63,7 @@ export declare enum TokenType {
63
63
  NAME = "NAME",// Valid variable name
64
64
  NUMBER = "NUMBER",// For redirections like 2>&1
65
65
  ASSIGNMENT_WORD = "ASSIGNMENT_WORD",// VAR=value
66
+ FD_VARIABLE = "FD_VARIABLE",// {varname} before redirect operator
66
67
  COMMENT = "COMMENT",
67
68
  HEREDOC_CONTENT = "HEREDOC_CONTENT"
68
69
  }
@@ -78,6 +79,14 @@ export interface Token {
78
79
  quoted?: boolean;
79
80
  singleQuoted?: boolean;
80
81
  }
82
+ /**
83
+ * Error thrown when the lexer encounters invalid input
84
+ */
85
+ export declare class LexerError extends Error {
86
+ line: number;
87
+ column: number;
88
+ constructor(message: string, line: number, column: number);
89
+ }
81
90
  /**
82
91
  * Lexer class
83
92
  */
@@ -88,6 +97,7 @@ export declare class Lexer {
88
97
  private column;
89
98
  private tokens;
90
99
  private pendingHeredocs;
100
+ private dparenDepth;
91
101
  constructor(input: string);
92
102
  /**
93
103
  * Tokenize the entire input
@@ -95,6 +105,13 @@ export declare class Lexer {
95
105
  tokenize(): Token[];
96
106
  private skipWhitespace;
97
107
  private nextToken;
108
+ /**
109
+ * Look ahead from position after (( to determine if this is nested subshells
110
+ * like ((cmd) || (cmd2)) rather than arithmetic like ((1+2)).
111
+ *
112
+ * Returns true if it looks like nested subshells (command invocation).
113
+ */
114
+ private looksLikeNestedSubshells;
98
115
  private makeToken;
99
116
  private readComment;
100
117
  private readWord;
@@ -132,4 +149,44 @@ export declare class Lexer {
132
149
  * This is used when {} contains something but it's not a valid brace expansion.
133
150
  */
134
151
  private scanLiteralBraceWord;
152
+ /**
153
+ * Scan an extglob pattern starting at the opening parenthesis.
154
+ * Extglob patterns are: @(...), *(...), +(...), ?(...), !(...)
155
+ * The operator (@, *, +, ?, !) is already consumed; we start at the (.
156
+ * Returns the content including parentheses, or null if not a valid extglob.
157
+ */
158
+ private scanExtglobPattern;
159
+ /**
160
+ * Scan for FD variable syntax: {varname} immediately followed by a redirect operator.
161
+ * This is the bash 4.1+ feature where {fd}>file allocates an FD and stores it in variable.
162
+ * Returns the variable name and end position if found, null otherwise.
163
+ *
164
+ * Valid patterns:
165
+ * - {varname}>file, {varname}>>file, {varname}>|file
166
+ * - {varname}<file, {varname}<<word, {varname}<<<word
167
+ * - {varname}<>file
168
+ * - {varname}>&N, {varname}<&N
169
+ * - {varname}>&-, {varname}<&- (close FD)
170
+ */
171
+ private scanFdVariable;
172
+ /**
173
+ * Scan ahead from a $(( position to determine if it should be treated as
174
+ * $( ( subshell ) ) instead of $(( arithmetic )).
175
+ * This handles cases like:
176
+ * echo $(( echo 1
177
+ * echo 2
178
+ * ) )
179
+ * which should be a command substitution containing a subshell, not arithmetic.
180
+ *
181
+ * @param startPos - position at the second ( (i.e., at input[startPos] === "(")
182
+ * @returns true if this is a subshell (closes with ) )), false if arithmetic (closes with )))
183
+ */
184
+ private dollarDparenIsSubshell;
185
+ /**
186
+ * Scan ahead from a (( position to determine if it closes with ) ) (nested subshells)
187
+ * or )) (arithmetic). We need to track paren depth and quotes to find the matching close.
188
+ * @param startPos - position after the (( (i.e., at the first char of content)
189
+ * @returns true if it closes with ) ) (space between parens), false otherwise
190
+ */
191
+ private dparenClosesWithSpacedParens;
135
192
  }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Command and Arithmetic Substitution Parsing Helpers
3
+ *
4
+ * Contains pure string analysis functions and substitution parsing utilities
5
+ * extracted from the main parser.
6
+ */
7
+ import { type CommandSubstitutionPart, type ScriptNode } from "../ast/types.js";
8
+ /**
9
+ * Type for a parser factory function that creates new parser instances.
10
+ * Used to avoid circular dependencies.
11
+ */
12
+ export type ParserFactory = () => {
13
+ parse(input: string): ScriptNode;
14
+ };
15
+ /**
16
+ * Type for an error reporting function.
17
+ */
18
+ export type ErrorFn = (message: string) => never;
19
+ /**
20
+ * Check if $(( at position `start` in `value` is a command substitution with nested
21
+ * subshell rather than arithmetic expansion. This uses similar logic to the lexer's
22
+ * dparenClosesWithSpacedParens but operates on a string within a word/expansion.
23
+ *
24
+ * The key heuristics are:
25
+ * 1. If it closes with `) )` (separated by whitespace or content), it's a subshell
26
+ * 2. If at depth 1 we see `||`, `&&`, or single `|`, it's a command context
27
+ * 3. If it closes with `))`, it's arithmetic
28
+ *
29
+ * @param value The string containing the expansion
30
+ * @param start Position of the `$` in `$((` (so `$((` is at start..start+2)
31
+ * @returns true if this should be parsed as command substitution, false for arithmetic
32
+ */
33
+ export declare function isDollarDparenSubshell(value: string, start: number): boolean;
34
+ /**
35
+ * Parse a command substitution starting at the given position.
36
+ * Handles $(...) syntax with proper depth tracking for nested substitutions.
37
+ *
38
+ * @param value The string containing the substitution
39
+ * @param start Position of the `$` in `$(`
40
+ * @param createParser Factory function to create a new parser instance
41
+ * @param error Error reporting function
42
+ * @returns The parsed command substitution part and the ending index
43
+ */
44
+ export declare function parseCommandSubstitutionFromString(value: string, start: number, createParser: ParserFactory, error: ErrorFn): {
45
+ part: CommandSubstitutionPart;
46
+ endIndex: number;
47
+ };
48
+ /**
49
+ * Parse a backtick command substitution starting at the given position.
50
+ * Handles `...` syntax with proper escape processing.
51
+ *
52
+ * @param value The string containing the substitution
53
+ * @param start Position of the opening backtick
54
+ * @param inDoubleQuotes Whether the backtick is inside double quotes
55
+ * @param createParser Factory function to create a new parser instance
56
+ * @param error Error reporting function
57
+ * @returns The parsed command substitution part and the ending index
58
+ */
59
+ export declare function parseBacktickSubstitutionFromString(value: string, start: number, inDoubleQuotes: boolean, createParser: ParserFactory, error: ErrorFn): {
60
+ part: CommandSubstitutionPart;
61
+ endIndex: number;
62
+ };