Something went wrong. Try again.
Shell parser/AST for POSIX/Bash/mksh/zsh, in TypeScript
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118import { describe, expect, it } from "vitest";import { parse } from "../parse";import { program, simple, stmt } from "../test-helpers/ast-builders";
describe("parse (phase 1: simple commands)", () => { it("parses empty input", () => { expect(parse("")).toMatchAst({ ast: program() }); });
it("parses a single simple command", () => { expect(parse("foo")).toMatchAst({ ast: program(stmt(simple("foo"))) }); });
it("parses multiple statements separated by newline or semicolon", () => { expect(parse("foo\nbar")).toMatchAst({ ast: program(stmt(simple("foo")), stmt(simple("bar"))), });
expect(parse("foo; bar;")).toMatchAst({ ast: program(stmt(simple("foo")), stmt(simple("bar"))), }); });
it("parses pipelines", () => { expect(parse("foo | bar")).toMatchAst({ ast: program( stmt({ type: "Pipeline", commands: [stmt(simple("foo")), stmt(simple("bar"))], }), ), });
expect(parse("foo | bar | baz")).toMatchAst({ ast: program( stmt({ type: "Pipeline", commands: [ stmt(simple("foo")), stmt(simple("bar")), stmt(simple("baz")), ], }), ), }); });
it("parses logical and/or", () => { expect(parse("foo && bar")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "and", left: stmt(simple("foo")), right: stmt(simple("bar")), }), ), });
expect(parse("foo || bar")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt(simple("foo")), right: stmt(simple("bar")), }), ), });
expect(parse("foo && bar || baz")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt({ type: "Logical", op: "and", left: stmt(simple("foo")), right: stmt(simple("bar")), }), right: stmt(simple("baz")), }), ), }); });
it("gives pipelines higher precedence than logical ops", () => { expect(parse("foo | bar || baz")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt({ type: "Pipeline", commands: [stmt(simple("foo")), stmt(simple("bar"))], }), right: stmt(simple("baz")), }), ), }); });
it("parses background commands", () => { expect(parse("foo &\nbar")).toMatchAst({ ast: program(stmt(simple("foo"), true), stmt(simple("bar"))), }); });});
describe("parse (phase 10: negation)", () => { it("parses negated commands", () => { expect(parse("! foo")).toMatchAst({ ast: program(stmt(simple("foo"), false, true)), }); });});