Skip to content
This repository was archived by the owner on Mar 17, 2026. It is now read-only.

woolkingx/bashjsast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bashjsast

Bash AST parser for JavaScript. Zero dependencies, complete syntax coverage, plain dict output.

Two core files (lexer.mjs + parser.mjs) parse any bash source into a JSON-serializable AST. No runtime validation overhead — factory functions produce plain objects directly.

Install

npm install bashjsast

Quick Start

import { parse, print, query } from 'bashjsast'

// Parse → plain dict AST
const ast = parse('echo hello | grep h > out.txt')
console.log(JSON.stringify(ast, null, 2))

// Print → canonical bash text
print(ast) // "echo hello | grep h > out.txt"

// Query → structured extraction
const q = query('FOO=bar echo hello | grep -i h > out.txt')
q.commands()    // ['echo', 'grep']
q.flags()       // ['-i']
q.writes()      // ['out.txt']
q.assignments() // [{ name: 'FOO', value: 'bar', append: false }]
q.pipeNames()   // [['echo', 'grep']]
q.analyze()     // all of the above in one call

API

parse(source) → AST

Returns a plain dict AST. Node types:

Node Description
Script Root node, commands[]
SimpleCommand name, args[], assignments[], redirects[]
Pipeline commands[], negated
List op (&&/`
If test, body, alternate
While / Until test, body
For name, items[], body (word list and arithmetic)
Case word, clauses[] (each: patterns[], body, terminator)
Select name, items[], body
Group body (braces { ... })
Subshell body (parens ( ... ))
Function name, body, hasKeyword
Arithmetic expression ((( ... )))
Condition condType, op, left, right ([[ ... ]])
Coproc name, body

print(ast) → string

Converts AST back to canonical bash text. Round-trip idempotent: print(parse(print(parse(src)))) === print(parse(src)).

query(source) → BashQuery

Structured extraction without manual AST traversal:

  • .commands() — all command names
  • .flags() — all flags (e.g. -i, --verbose)
  • .args() — all non-flag arguments
  • .pipes() — pipe chains as [{name, args}]
  • .pipeNames() — pipe chains as [name]
  • .writes() / .reads() — redirect targets
  • .assignments() — variable assignments
  • .functions() — function definitions
  • .subcommands()$() and ` ` subcommands
  • .analyze() — all of the above in one call

Lexer / T

Direct access to the tokenizer:

import { Lexer, T } from 'bashjsast'

const tokens = new Lexer('echo hello').tokenize()
// [{ type: 'WORD', value: 'echo' }, { type: 'WORD', value: 'hello' }, { type: 'EOF' }]

Compatibility Layer

Drop-in replacement for unbash in hook systems:

import { parse } from 'bashjsast/compat'

const result = parse('FOO=bar echo hello > out.txt')
// { type: 'simple', commands: [{ type: 'Command', name: {text: 'echo'}, prefix: [{text: 'FOO=bar'}], suffix: [{text: 'hello'}], redirects: [{operator: '>', content: 'out.txt'}] }], raw: '...' }

Syntax Coverage

Complete bash syntax support including:

  • Simple commands, pipelines, lists (&&, ||)
  • All compound commands: if/elif/else, while, until, for (word + arithmetic), case (;;/;&/;;&), select
  • Groups { }, subshells ( )
  • Functions (keyword and POSIX style)
  • Arithmetic (( )) and conditional [[ ]]
  • Coproc
  • Redirects: >, >>, <, <<, <<<, >&, <&, >|, &>, &>>, <>
  • Heredocs and here-strings
  • Process substitution <(), >()
  • Array assignments =()
  • Assignments (including +=)
  • Quoting: single, double, $'', $""
  • Command substitution $() and ` `
  • Line continuation \

Comparison with bashlex

bashjsast bashlex
Language JavaScript (ESM) Python
Dependencies 0 0
Core size 2 files, 1305 lines ~10 files
Output plain dict (JSON-safe) custom AST node classes
(( )) arithmetic yes NotImplementedError
[[ ]] conditional yes no
coproc yes NotImplementedError
select yes no
AST → text printer yes (round-trip idempotent) no
Structured query API yes (query().analyze()) no
bashlex test suite 72/72 (100%)
Performance ~0.05ms per parse ~ms (Python)

bashjsast passes every valid test case from bashlex's test suite and handles 5 syntax constructs bashlex explicitly does not support.

Architecture

src/
  lexer.mjs    — tokenizer (context-dependent reserved words)
  parser.mjs   — recursive descent → plain dict AST
  printer.mjs  — AST → canonical bash text
  query.mjs    — structured extraction layer
  compat.mjs   — unbash-compatible output
  index.mjs    — public exports
schema/        — 34 JSON Schema Draft-07 files (AST contract documentation)
test/          — 129+ tests (node:test)

Core is two files: lexer.mjs (441 lines) + parser.mjs (864 lines). Zero dependencies.

License

MIT

About

Bash AST parser for JavaScript — zero dependencies, complete syntax coverage | ⚠️ Moved to Codeberg: https://codeberg.org/woolkingx/bashjsast

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors