{"id":12274,"library":"unbash","title":"unbash: Fast Bash Parser","description":"unbash is a fast, zero-dependency library written in TypeScript for parsing Bash scripts into a structured Abstract Syntax Tree (AST). Currently stable at version 2.2.0, it differentiates itself by offering a pure JavaScript/TypeScript implementation without WASM or native bindings, providing a fully typed API, and delivering high performance, often outperforming alternatives by a significant margin. Its release cadence follows a typical Semantic Versioning approach, with updates for features and bug fixes. Key differentiators include its AST-centric output (unlike CST-focused parsers), tolerant parsing that collects errors rather than throwing exceptions, and built-in support for advanced Bash syntax such as process substitutions, coproc, `[[ ]]` test expressions, `(( ))` arithmetic evaluations, and extglob. It is designed for environments requiring a lightweight, synchronous parsing solution. While it excels at AST generation and speed, it does not offer incremental parsing, full token preservation for CSTs, or multi-shell dialect support (e.g., pure POSIX sh), features found in libraries like tree-sitter-bash or sh-syntax. It requires Node.js v14 or higher and maintains a small bundle size (13KB gzipped).","status":"active","version":"2.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/webpro-nl/unbash","tags":["javascript","ast","bash","lexer","parser","posix","scanner","tokenizer","typescript"],"install":[{"cmd":"npm install unbash","lang":"bash","label":"npm"},{"cmd":"yarn add unbash","lang":"bash","label":"yarn"},{"cmd":"pnpm add unbash","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"unbash is an ESM-first package since v2. Use named imports.","wrong":"const { parse } = require('unbash')","symbol":"parse","correct":"import { parse } from 'unbash'"},{"note":"The `print` utility is a sub-module and must be imported from 'unbash/print'.","wrong":"import { print } from 'unbash'","symbol":"print","correct":"import { print } from 'unbash/print'"},{"note":"Type imports are used for type definitions like `Script`.","symbol":"Script","correct":"import { type Script } from 'unbash'"}],"quickstart":{"code":"import { parse, type Script } from \"unbash\";\nimport { print } from \"unbash/print\";\n\n// Define a Bash script string to parse.\nconst bashScript = 'if [ -f \"$1\" ]; then\\n  echo \"File exists: $1\"\\n  cat \"$1\"\\nelse\\n  echo \"File not found: $1\"\\nfi';\n\n// Parse the script into an AST (Abstract Syntax Tree).\n// unbash performs tolerant parsing, meaning it attempts to create an AST even with syntax errors,\n// collecting any issues in the 'errors' property of the returned object.\nconst ast: Script = parse(bashScript);\n\n// Check if any parsing errors occurred.\nif (ast.errors && ast.errors.length > 0) {\n  console.warn(\"Parsing errors detected:\", ast.errors);\n  // Depending on your application, you might want to stop here or attempt to recover.\n} else {\n  console.log(\"Successfully parsed script into AST (truncated):\\n\", JSON.stringify(ast, null, 2).substring(0, 500) + \"...\");\n}\n\n// Use the built-in printer to convert the AST back into a Bash script string.\n// Note: The `print` function is opinionated and will reformat the script,\n// not necessarily preserving original whitespace, comments, or exact layout.\nconst printedScript = print(ast);\nconsole.log(\"\\nRe-printed script from AST:\\n\", printedScript);\n\n// Demonstrate parsing a script with an obvious error to show tolerant parsing\nconst erroneousScript = 'for i in 1 2 3; do echo $i fi;'; // Missing 'done'\nconst erroneousAst = parse(erroneousScript);\nif (erroneousAst.errors && erroneousAst.errors.length > 0) {\n  console.error(\"\\nDetected errors in erroneous script example:\", erroneousAst.errors);\n}\n","lang":"typescript","description":"Parses a sample Bash script into an AST, checks for collected parsing errors, and then prints the AST back into a formatted Bash script string, demonstrating core functionality and tolerant error handling."},"warnings":[{"fix":"Migrate your project to use ES Modules (`\"type\": \"module\"` in `package.json`) and use `import` statements, or use dynamic `import('unbash')` in a CommonJS context.","message":"unbash is an ES Module (ESM) package since version 2. Attempting to `require()` it in a CommonJS environment will result in a runtime error.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Understand that `print` is for generating a standardized output script from an AST, not for round-trip fidelity of the original script's formatting. Do not rely on it to preserve non-semantic elements.","message":"The `print` utility is an opinionated formatter. It does not preserve original whitespace, comments (except shebang), or exact input formatting. It generates a normalized Bash script from the AST.","severity":"gotcha","affected_versions":"*"},{"fix":"Always check `if (ast.errors && ast.errors.length > 0)` after calling `parse()` to detect and handle any syntax issues present in the input script.","message":"unbash uses tolerant parsing. This means syntax errors do not throw exceptions but are collected within the `errors` property of the returned AST object. Your application must explicitly check this property.","severity":"gotcha","affected_versions":"*"},{"fix":"Evaluate your parsing requirements. unbash is optimized for speed and AST generation for structural analysis, not for preserving every token or supporting incremental updates.","message":"unbash generates an Abstract Syntax Tree (AST) and does not support incremental parsing or Concrete Syntax Tree (CST) output. If you need full token preservation, granular error recovery with `ERROR` nodes, or incremental parsing for editor integration, alternatives like `tree-sitter-bash` might be more suitable.","severity":"gotcha","affected_versions":"*"},{"fix":"Ensure that the scripts you are parsing are predominantly Bash-compliant. For parsing diverse shell dialects, investigate libraries that offer broader shell compatibility.","message":"unbash is specifically designed for Bash syntax. It does not provide inherent support for other shell dialects such as pure POSIX sh, mksh, or others. For multi-dialect support, consider alternatives like `sh-syntax`.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Update your import statement to `import { parse } from 'unbash';` and ensure your Node.js project is configured for ESM (e.g., by adding `\"type\": \"module\"` to your `package.json`).","cause":"Attempting to use `require('unbash')` in a CommonJS module, but unbash v2+ is an ES Module.","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module ... from ... not supported. Instead, change the require of ... to a dynamic import() or top-level import statement."},{"fix":"Use a named import specifically: `import { parse } from 'unbash';` (and similarly for `print` from `unbash/print`).","cause":"Incorrectly trying to import `parse` as a default export or using a CommonJS-style named import when the package uses named ESM exports.","error":"SyntaxError: The requested module 'unbash' does not provide an export named 'parse'"},{"fix":"This is expected behavior. The purpose of `print` is to produce a well-formatted, functional Bash script from the AST, not to recreate the input verbatim. If exact formatting preservation is critical, `unbash`'s `print` might not be suitable for that specific task.","cause":"The `print` function is an opinionated code formatter. It intentionally re-formats the AST into a standardized Bash script string and does not preserve original non-semantic elements.","error":"My parsed and then printed script looks different from the original input; comments and exact whitespace are gone."},{"fix":"After every call to `parse()`, you must explicitly check the `ast.errors` property. For example: `const ast = parse(script); if (ast.errors && ast.errors.length > 0) { console.error('Parsing failed:', ast.errors); }`","cause":"unbash implements tolerant parsing, meaning it collects syntax errors in the `errors` array within the returned AST object instead of throwing an exception.","error":"My program didn't report any errors even when I fed it a syntactically incorrect Bash script."}],"ecosystem":"npm"}