shell-dsl 0.0.16 → 0.0.18

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.
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/parser/parser.ts"],
4
4
  "sourcesContent": [
5
- "import { ParseError } from \"../errors.cjs\";\nimport type { Token, KeywordValue } from \"../lexer/tokens.cjs\";\nimport type { ASTNode, Redirect, RedirectMode, CommandNode, IfNode, ForNode, WhileNode, UntilNode, CaseNode, CaseClause } from \"./ast.cjs\";\n\nexport class Parser {\n private tokens: Token[];\n private pos: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n parse(): ASTNode {\n const result = this.parseSequence();\n if (!this.isAtEnd()) {\n throw new ParseError(`Unexpected token: ${JSON.stringify(this.peek())}`);\n }\n return result;\n }\n\n // sequence := and_or ((';'|'\\n') and_or)*\n private parseSequence(): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n commands.push(this.parseAndOr());\n\n while (this.match(\"semicolon\") || this.match(\"newline\")) {\n this.skipNewlines();\n // Skip empty commands after separator, or stop at terminating keywords\n if (this.isAtEnd() || this.check(\"semicolon\") || this.check(\"newline\") || this.isTerminatingKeyword()) continue;\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private skipNewlines(): void {\n while (this.match(\"newline\")) {\n // keep consuming newlines\n }\n }\n\n private isTerminatingKeyword(): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return [\"then\", \"elif\", \"else\", \"fi\", \"do\", \"done\", \"esac\"].includes(token.value);\n }\n\n // and_or := pipeline (('&&'|'||') pipeline)*\n private parseAndOr(): ASTNode {\n let left = this.parsePipeline();\n\n while (this.check(\"and\") || this.check(\"or\")) {\n if (this.match(\"and\")) {\n const right = this.parsePipeline();\n left = { type: \"and\", left, right };\n } else if (this.match(\"or\")) {\n const right = this.parsePipeline();\n left = { type: \"or\", left, right };\n }\n }\n\n return left;\n }\n\n // pipeline := command ('|' command)*\n private parsePipeline(): ASTNode {\n const commands: ASTNode[] = [];\n commands.push(this.parseCompoundOrCommand());\n\n while (this.match(\"pipe\")) {\n this.skipNewlines();\n commands.push(this.parseCompoundOrCommand());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"pipeline\", commands };\n }\n\n // compound_or_command := compound_command | simple_command\n private parseCompoundOrCommand(): ASTNode {\n this.skipNewlines();\n const token = this.peek();\n\n if (token.type === \"keyword\") {\n switch (token.value) {\n case \"if\":\n return this.parseIf();\n case \"for\":\n return this.parseFor();\n case \"while\":\n return this.parseWhile();\n case \"until\":\n return this.parseUntil();\n case \"case\":\n return this.parseCase();\n }\n }\n\n return this.parseCommand();\n }\n\n // if := 'if' compound_list 'then' compound_list ('elif' compound_list 'then' compound_list)* ['else' compound_list] 'fi'\n private parseIf(): IfNode {\n this.expectKeyword(\"if\");\n const condition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const thenBranch = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n\n const elifBranches: Array<{ condition: ASTNode; body: ASTNode }> = [];\n while (this.checkKeyword(\"elif\")) {\n this.expectKeyword(\"elif\");\n const elifCondition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const elifBody = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n elifBranches.push({ condition: elifCondition, body: elifBody });\n }\n\n let elseBranch: ASTNode | undefined;\n if (this.checkKeyword(\"else\")) {\n this.expectKeyword(\"else\");\n elseBranch = this.parseCompoundList([\"fi\"]);\n }\n\n this.expectKeyword(\"fi\");\n\n return {\n type: \"if\",\n condition,\n thenBranch,\n elifBranches,\n elseBranch,\n };\n }\n\n // for := 'for' NAME ['in' word*] (';'|'\\n') 'do' compound_list 'done'\n private parseFor(): ForNode {\n this.expectKeyword(\"for\");\n\n // Get variable name\n const varToken = this.peek();\n if (varToken.type !== \"word\") {\n throw new ParseError(\"Expected variable name after 'for'\");\n }\n this.advance();\n const variable = varToken.value;\n\n // Parse optional 'in' clause\n const items: ASTNode[] = [];\n if (this.checkKeyword(\"in\")) {\n this.expectKeyword(\"in\");\n // Read items until semicolon, newline, or 'do'\n while (!this.isAtEnd() && !this.check(\"semicolon\") && !this.check(\"newline\") && !this.checkKeyword(\"do\")) {\n items.push(this.parseWordArg());\n }\n }\n\n // Consume separator (semicolon or newline)\n if (!this.match(\"semicolon\")) {\n this.match(\"newline\");\n }\n this.skipNewlines();\n\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"for\",\n variable,\n items,\n body,\n };\n }\n\n // while := 'while' compound_list 'do' compound_list 'done'\n private parseWhile(): WhileNode {\n this.expectKeyword(\"while\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"while\",\n condition,\n body,\n };\n }\n\n // until := 'until' compound_list 'do' compound_list 'done'\n private parseUntil(): UntilNode {\n this.expectKeyword(\"until\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"until\",\n condition,\n body,\n };\n }\n\n // case := 'case' word 'in' (pattern ('|' pattern)* ')' compound_list ';;')* 'esac'\n private parseCase(): CaseNode {\n this.expectKeyword(\"case\");\n const word = this.parseWordArg();\n this.expectKeyword(\"in\");\n this.skipNewlines();\n\n const clauses: CaseClause[] = [];\n\n while (!this.isAtEnd() && !this.checkKeyword(\"esac\")) {\n // Parse patterns separated by '|'\n // Skip leading '(' if present\n this.match(\"openParen\");\n\n const patterns: ASTNode[] = [];\n patterns.push(this.parseCasePattern());\n\n while (this.match(\"pipe\")) {\n patterns.push(this.parseCasePattern());\n }\n\n // Expect ')'\n if (!this.match(\"closeParen\")) {\n throw new ParseError(\"Expected ')' after case pattern\");\n }\n\n // Parse body until ';;' or 'esac'\n const body = this.parseCaseBody();\n\n clauses.push({ patterns, body });\n\n // ';;' is optional for the last clause\n this.match(\"doubleSemicolon\");\n this.skipNewlines();\n }\n\n this.expectKeyword(\"esac\");\n\n return {\n type: \"case\",\n word,\n clauses,\n };\n }\n\n private parseCasePattern(): ASTNode {\n const token = this.peek();\n\n // Handle glob patterns and words\n if (token.type === \"word\" || token.type === \"glob\" || token.type === \"singleQuote\" || token.type === \"doubleQuote\") {\n return this.parseWordArg();\n }\n\n throw new ParseError(`Expected pattern in case clause, got ${token.type}`);\n }\n\n private parseCaseBody(): ASTNode {\n const commands: ASTNode[] = [];\n this.skipNewlines();\n\n // Parse until ';;' or 'esac'\n while (!this.isAtEnd() && !this.check(\"doubleSemicolon\") && !this.checkKeyword(\"esac\")) {\n commands.push(this.parseAndOr());\n // Consume separator\n if (!this.match(\"semicolon\") && !this.match(\"newline\")) {\n break;\n }\n this.skipNewlines();\n // Check for terminators after consuming separators\n if (this.check(\"doubleSemicolon\") || this.checkKeyword(\"esac\")) {\n break;\n }\n }\n\n if (commands.length === 0) {\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n if (commands.length === 1) {\n return commands[0]!;\n }\n return { type: \"sequence\", commands };\n }\n\n // compound_list := and_or ((';'|'\\n') and_or)* [';'|'\\n']\n private parseCompoundList(terminators: KeywordValue[]): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n\n // Check for empty list\n if (this.isCompoundListTerminator(terminators)) {\n // Return a no-op command for empty list\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n\n commands.push(this.parseAndOr());\n\n while ((this.match(\"semicolon\") || this.match(\"newline\")) && !this.isAtEnd()) {\n this.skipNewlines();\n // Check for terminators\n if (this.isCompoundListTerminator(terminators)) {\n break;\n }\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private isCompoundListTerminator(terminators: KeywordValue[]): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return terminators.includes(token.value);\n }\n\n private checkKeyword(value: KeywordValue): boolean {\n const token = this.peek();\n return token.type === \"keyword\" && token.value === value;\n }\n\n private expectKeyword(value: KeywordValue): void {\n if (!this.checkKeyword(value)) {\n throw new ParseError(`Expected '${value}'`);\n }\n this.advance();\n // Don't skip newlines here - let the caller handle them\n // Newlines are significant as command separators in compound lists\n }\n\n // command := assignment* word+ redirect*\n private parseCommand(): CommandNode {\n const assignments: Array<{ name: string; value: ASTNode }> = [];\n const args: ASTNode[] = [];\n const redirects: Redirect[] = [];\n\n // Collect leading assignments\n while (this.check(\"assignment\")) {\n const token = this.advance() as Token & { type: \"assignment\" };\n assignments.push({\n name: token.name,\n value: this.tokenToNode(token.value),\n });\n }\n\n // Collect command name and arguments\n while (this.isWordToken()) {\n // Check if it's a heredoc token - convert to input redirect\n if (this.peek().type === \"heredoc\") {\n const heredocToken = this.advance() as Token & { type: \"heredoc\" };\n redirects.push({\n mode: \"<\",\n target: this.tokenToNode(heredocToken),\n heredocContent: true,\n });\n } else {\n args.push(this.parseWordArg());\n }\n }\n\n // Collect redirects\n while (this.check(\"redirect\")) {\n const redirect = this.parseRedirect();\n redirects.push(redirect);\n // After a redirect, there might be more words\n while (this.isWordToken()) {\n if (this.peek().type === \"heredoc\") {\n const heredocToken = this.advance() as Token & { type: \"heredoc\" };\n redirects.push({\n mode: \"<\",\n target: this.tokenToNode(heredocToken),\n heredocContent: true,\n });\n } else {\n args.push(this.parseWordArg());\n }\n }\n }\n\n if (args.length === 0 && assignments.length === 0 && redirects.length === 0) {\n throw new ParseError(\"Expected command\");\n }\n\n const name = args.shift() ?? { type: \"literal\" as const, value: redirects.length > 0 ? \":\" : \"\" };\n\n return {\n type: \"command\",\n name,\n args,\n redirects,\n assignments,\n };\n }\n\n private parseWordArg(): ASTNode {\n const token = this.advance();\n return this.tokenToNode(token);\n }\n\n private tokenToNode(token: Token | string | Token[]): ASTNode {\n if (typeof token === \"string\") {\n return { type: \"literal\", value: token };\n }\n\n if (Array.isArray(token)) {\n const parts = token.map((t) => this.tokenToNode(t));\n if (parts.length === 1) return parts[0]!;\n return { type: \"concat\", parts };\n }\n\n switch (token.type) {\n case \"word\":\n return { type: \"literal\", value: token.value };\n case \"singleQuote\":\n return { type: \"literal\", value: token.value };\n case \"doubleQuote\":\n return this.parseDoubleQuoteParts(token.parts);\n case \"variable\":\n return { type: \"variable\", name: token.name };\n case \"substitution\":\n // Parse the inner command\n const innerParser = new Parser(\n new (require(\"../lexer/lexer.ts\").Lexer)(token.command, { preserveNewlines: true }).tokenize()\n );\n return { type: \"substitution\", command: innerParser.parse() };\n case \"arithmetic\":\n return { type: \"arithmetic\", expression: token.expression };\n case \"glob\":\n return { type: \"glob\", pattern: token.pattern };\n case \"assignment\":\n return this.tokenToNode(token.value);\n case \"heredoc\":\n if (token.expand) {\n return this.parseHeredocContent(token.content);\n }\n return { type: \"literal\", value: token.content };\n default:\n throw new ParseError(`Unexpected token type: ${(token as Token).type}`);\n }\n }\n\n private parseDoubleQuoteParts(parts: Array<string | Token>): ASTNode {\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n\n if (parts.length === 1) {\n const part = parts[0]!;\n if (typeof part === \"string\") {\n return { type: \"literal\", value: part };\n }\n return this.tokenToNode(part);\n }\n\n const nodes: ASTNode[] = parts.map((part) => {\n if (typeof part === \"string\") {\n return { type: \"literal\" as const, value: part };\n }\n return this.tokenToNode(part);\n });\n\n return { type: \"concat\", parts: nodes };\n }\n\n private parseHeredocContent(content: string): ASTNode {\n // Parse content looking for $VAR and ${VAR} patterns\n const parts: ASTNode[] = [];\n let currentLiteral = \"\";\n let i = 0;\n\n while (i < content.length) {\n if (content[i] === \"$\") {\n // Flush current literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n currentLiteral = \"\";\n }\n\n i++; // consume $\n if (i >= content.length) {\n currentLiteral += \"$\";\n break;\n }\n\n if (content[i] === \"{\") {\n // ${VAR} syntax\n i++; // consume {\n let varName = \"\";\n while (i < content.length && content[i] !== \"}\") {\n varName += content[i];\n i++;\n }\n if (i < content.length && content[i] === \"}\") {\n i++; // consume }\n }\n if (varName) {\n parts.push({ type: \"variable\", name: varName });\n }\n } else if (/[a-zA-Z_]/.test(content[i] ?? \"\")) {\n // $VAR syntax\n let varName = \"\";\n while (i < content.length && /[a-zA-Z0-9_]/.test(content[i] ?? \"\")) {\n varName += content[i];\n i++;\n }\n parts.push({ type: \"variable\", name: varName });\n } else {\n // Not a variable, keep the $\n currentLiteral += \"$\";\n }\n } else {\n currentLiteral += content[i];\n i++;\n }\n }\n\n // Flush remaining literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n }\n\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n if (parts.length === 1) {\n return parts[0]!;\n }\n return { type: \"concat\", parts };\n }\n\n private parseRedirect(): Redirect {\n const token = this.advance() as Token & { type: \"redirect\" };\n const mode = token.mode as RedirectMode;\n\n // 2>&1 and 1>&2 don't have a target\n if (mode === \"2>&1\" || mode === \"1>&2\") {\n return { mode, target: { type: \"literal\", value: \"\" } };\n }\n\n if (!this.isWordToken()) {\n throw new ParseError(`Expected redirect target after ${mode}`);\n }\n\n const target = this.parseWordArg();\n return { mode, target };\n }\n\n private isWordToken(): boolean {\n const token = this.peek();\n return (\n token.type === \"word\" ||\n token.type === \"singleQuote\" ||\n token.type === \"doubleQuote\" ||\n token.type === \"variable\" ||\n token.type === \"substitution\" ||\n token.type === \"arithmetic\" ||\n token.type === \"glob\" ||\n token.type === \"heredoc\"\n );\n }\n\n private check(type: Token[\"type\"]): boolean {\n return this.peek().type === type;\n }\n\n private match(type: Token[\"type\"]): boolean {\n if (this.check(type)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n private peek(): Token {\n return this.tokens[this.pos] ?? { type: \"eof\" };\n }\n\n private advance(): Token {\n const token = this.peek();\n this.pos++;\n return token;\n }\n\n private isAtEnd(): boolean {\n return this.peek().type === \"eof\";\n }\n}\n\nexport function parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n}\n"
5
+ "import { ParseError } from \"../errors.cjs\";\nimport type { Token, KeywordValue } from \"../lexer/tokens.cjs\";\nimport type { ASTNode, Redirect, RedirectMode, CommandNode, IfNode, ForNode, WhileNode, UntilNode, CaseNode, CaseClause } from \"./ast.cjs\";\n\nexport class Parser {\n private tokens: Token[];\n private pos: number = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n parse(): ASTNode {\n const result = this.parseSequence();\n if (!this.isAtEnd()) {\n throw new ParseError(`Unexpected token: ${JSON.stringify(this.peek())}`);\n }\n return result;\n }\n\n // sequence := and_or ((';'|'\\n') and_or)*\n private parseSequence(): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n commands.push(this.parseAndOr());\n\n while (this.match(\"semicolon\") || this.match(\"newline\")) {\n this.skipNewlines();\n // Skip empty commands after separator, or stop at terminating keywords\n if (this.isAtEnd() || this.check(\"semicolon\") || this.check(\"newline\") || this.isTerminatingKeyword()) continue;\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private skipNewlines(): void {\n while (this.match(\"newline\")) {\n // keep consuming newlines\n }\n }\n\n private isTerminatingKeyword(): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return [\"then\", \"elif\", \"else\", \"fi\", \"do\", \"done\", \"esac\"].includes(token.value);\n }\n\n // and_or := pipeline (('&&'|'||') pipeline)*\n private parseAndOr(): ASTNode {\n let left = this.parsePipeline();\n\n while (this.check(\"and\") || this.check(\"or\")) {\n if (this.match(\"and\")) {\n const right = this.parsePipeline();\n left = { type: \"and\", left, right };\n } else if (this.match(\"or\")) {\n const right = this.parsePipeline();\n left = { type: \"or\", left, right };\n }\n }\n\n return left;\n }\n\n // pipeline := command ('|' command)*\n private parsePipeline(): ASTNode {\n const commands: ASTNode[] = [];\n commands.push(this.parseCompoundOrCommand());\n\n while (this.match(\"pipe\")) {\n this.skipNewlines();\n commands.push(this.parseCompoundOrCommand());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"pipeline\", commands };\n }\n\n // compound_or_command := compound_command | simple_command\n private parseCompoundOrCommand(): ASTNode {\n this.skipNewlines();\n const token = this.peek();\n\n if (token.type === \"keyword\") {\n switch (token.value) {\n case \"if\":\n return this.parseIf();\n case \"for\":\n return this.parseFor();\n case \"while\":\n return this.parseWhile();\n case \"until\":\n return this.parseUntil();\n case \"case\":\n return this.parseCase();\n }\n }\n\n return this.parseCommand();\n }\n\n // if := 'if' compound_list 'then' compound_list ('elif' compound_list 'then' compound_list)* ['else' compound_list] 'fi'\n private parseIf(): IfNode {\n this.expectKeyword(\"if\");\n const condition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const thenBranch = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n\n const elifBranches: Array<{ condition: ASTNode; body: ASTNode }> = [];\n while (this.checkKeyword(\"elif\")) {\n this.expectKeyword(\"elif\");\n const elifCondition = this.parseCompoundList([\"then\"]);\n this.expectKeyword(\"then\");\n const elifBody = this.parseCompoundList([\"elif\", \"else\", \"fi\"]);\n elifBranches.push({ condition: elifCondition, body: elifBody });\n }\n\n let elseBranch: ASTNode | undefined;\n if (this.checkKeyword(\"else\")) {\n this.expectKeyword(\"else\");\n elseBranch = this.parseCompoundList([\"fi\"]);\n }\n\n this.expectKeyword(\"fi\");\n\n return {\n type: \"if\",\n condition,\n thenBranch,\n elifBranches,\n elseBranch,\n };\n }\n\n // for := 'for' NAME ['in' word*] (';'|'\\n') 'do' compound_list 'done'\n private parseFor(): ForNode {\n this.expectKeyword(\"for\");\n\n // Get variable name\n const varToken = this.peek();\n if (varToken.type !== \"word\") {\n throw new ParseError(\"Expected variable name after 'for'\");\n }\n this.advance();\n const variable = varToken.value;\n\n // Parse optional 'in' clause\n const items: ASTNode[] = [];\n if (this.checkKeyword(\"in\")) {\n this.expectKeyword(\"in\");\n // Read items until semicolon, newline, or 'do'\n while (!this.isAtEnd() && !this.check(\"semicolon\") && !this.check(\"newline\") && !this.checkKeyword(\"do\")) {\n items.push(this.parseWordArg());\n }\n }\n\n // Consume separator (semicolon or newline)\n if (!this.match(\"semicolon\")) {\n this.match(\"newline\");\n }\n this.skipNewlines();\n\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"for\",\n variable,\n items,\n body,\n };\n }\n\n // while := 'while' compound_list 'do' compound_list 'done'\n private parseWhile(): WhileNode {\n this.expectKeyword(\"while\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"while\",\n condition,\n body,\n };\n }\n\n // until := 'until' compound_list 'do' compound_list 'done'\n private parseUntil(): UntilNode {\n this.expectKeyword(\"until\");\n const condition = this.parseCompoundList([\"do\"]);\n this.expectKeyword(\"do\");\n const body = this.parseCompoundList([\"done\"]);\n this.expectKeyword(\"done\");\n\n return {\n type: \"until\",\n condition,\n body,\n };\n }\n\n // case := 'case' word 'in' (pattern ('|' pattern)* ')' compound_list ';;')* 'esac'\n private parseCase(): CaseNode {\n this.expectKeyword(\"case\");\n const word = this.parseWordArg();\n this.expectKeyword(\"in\");\n this.skipNewlines();\n\n const clauses: CaseClause[] = [];\n\n while (!this.isAtEnd() && !this.checkKeyword(\"esac\")) {\n // Parse patterns separated by '|'\n // Skip leading '(' if present\n this.match(\"openParen\");\n\n const patterns: ASTNode[] = [];\n patterns.push(this.parseCasePattern());\n\n while (this.match(\"pipe\")) {\n patterns.push(this.parseCasePattern());\n }\n\n // Expect ')'\n if (!this.match(\"closeParen\")) {\n throw new ParseError(\"Expected ')' after case pattern\");\n }\n\n // Parse body until ';;' or 'esac'\n const body = this.parseCaseBody();\n\n clauses.push({ patterns, body });\n\n // ';;' is optional for the last clause\n this.match(\"doubleSemicolon\");\n this.skipNewlines();\n }\n\n this.expectKeyword(\"esac\");\n\n return {\n type: \"case\",\n word,\n clauses,\n };\n }\n\n private parseCasePattern(): ASTNode {\n const token = this.peek();\n\n // Handle glob patterns and words\n if (token.type === \"word\" || token.type === \"glob\" || token.type === \"singleQuote\" || token.type === \"doubleQuote\") {\n return this.parseWordArg();\n }\n\n throw new ParseError(`Expected pattern in case clause, got ${token.type}`);\n }\n\n private parseCaseBody(): ASTNode {\n const commands: ASTNode[] = [];\n this.skipNewlines();\n\n // Parse until ';;' or 'esac'\n while (!this.isAtEnd() && !this.check(\"doubleSemicolon\") && !this.checkKeyword(\"esac\")) {\n commands.push(this.parseAndOr());\n // Consume separator\n if (!this.match(\"semicolon\") && !this.match(\"newline\")) {\n break;\n }\n this.skipNewlines();\n // Check for terminators after consuming separators\n if (this.check(\"doubleSemicolon\") || this.checkKeyword(\"esac\")) {\n break;\n }\n }\n\n if (commands.length === 0) {\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n if (commands.length === 1) {\n return commands[0]!;\n }\n return { type: \"sequence\", commands };\n }\n\n // compound_list := and_or ((';'|'\\n') and_or)* [';'|'\\n']\n private parseCompoundList(terminators: KeywordValue[]): ASTNode {\n this.skipNewlines();\n const commands: ASTNode[] = [];\n\n // Check for empty list\n if (this.isCompoundListTerminator(terminators)) {\n // Return a no-op command for empty list\n return { type: \"command\", name: { type: \"literal\", value: \"true\" }, args: [], redirects: [], assignments: [] };\n }\n\n commands.push(this.parseAndOr());\n\n while ((this.match(\"semicolon\") || this.match(\"newline\")) && !this.isAtEnd()) {\n this.skipNewlines();\n // Check for terminators\n if (this.isCompoundListTerminator(terminators)) {\n break;\n }\n commands.push(this.parseAndOr());\n }\n\n if (commands.length === 1) {\n return commands[0]!;\n }\n\n return { type: \"sequence\", commands };\n }\n\n private isCompoundListTerminator(terminators: KeywordValue[]): boolean {\n const token = this.peek();\n if (token.type !== \"keyword\") return false;\n return terminators.includes(token.value);\n }\n\n private checkKeyword(value: KeywordValue): boolean {\n const token = this.peek();\n return token.type === \"keyword\" && token.value === value;\n }\n\n private expectKeyword(value: KeywordValue): void {\n if (!this.checkKeyword(value)) {\n throw new ParseError(`Expected '${value}'`);\n }\n this.advance();\n // Don't skip newlines here - let the caller handle them\n // Newlines are significant as command separators in compound lists\n }\n\n // command := assignment* word+ redirect*\n private parseCommand(): CommandNode {\n const assignments: Array<{ name: string; value: ASTNode }> = [];\n const args: ASTNode[] = [];\n const redirects: Redirect[] = [];\n\n // Collect leading assignments\n while (this.check(\"assignment\")) {\n const token = this.advance() as Token & { type: \"assignment\" };\n assignments.push({\n name: token.name,\n value: this.tokenToNode(token.value),\n });\n }\n\n // Collect command name and arguments\n while (this.isWordToken()) {\n // Check if it's a heredoc token - convert to input redirect\n if (this.peek().type === \"heredoc\") {\n const heredocToken = this.advance() as Token & { type: \"heredoc\" };\n redirects.push({\n mode: \"<\",\n target: this.tokenToNode(heredocToken),\n heredocContent: true,\n });\n } else {\n args.push(this.parseWordArg());\n }\n }\n\n // Collect redirects\n while (this.check(\"redirect\")) {\n const redirect = this.parseRedirect();\n redirects.push(redirect);\n // After a redirect, there might be more words\n while (this.isWordToken()) {\n if (this.peek().type === \"heredoc\") {\n const heredocToken = this.advance() as Token & { type: \"heredoc\" };\n redirects.push({\n mode: \"<\",\n target: this.tokenToNode(heredocToken),\n heredocContent: true,\n });\n } else {\n args.push(this.parseWordArg());\n }\n }\n }\n\n if (args.length === 0 && assignments.length === 0 && redirects.length === 0) {\n throw new ParseError(\"Expected command\");\n }\n\n const name = args.shift() ?? { type: \"literal\" as const, value: redirects.length > 0 ? \":\" : \"\" };\n\n return {\n type: \"command\",\n name,\n args,\n redirects,\n assignments,\n };\n }\n\n private parseWordArg(): ASTNode {\n const token = this.advance();\n return this.tokenToNode(token);\n }\n\n private tokenToNode(token: Token | string | Token[]): ASTNode {\n if (typeof token === \"string\") {\n return { type: \"literal\", value: token };\n }\n\n if (Array.isArray(token)) {\n const parts = token.map((t) => this.tokenToNode(t));\n if (parts.length === 1) return parts[0]!;\n return { type: \"concat\", parts };\n }\n\n switch (token.type) {\n case \"word\":\n return { type: \"literal\", value: token.value };\n case \"singleQuote\":\n return { type: \"literal\", value: token.value };\n case \"doubleQuote\":\n return this.parseDoubleQuoteParts(token.parts);\n case \"variable\":\n return { type: \"variable\", name: token.name };\n case \"substitution\":\n // Parse the inner command\n const innerParser = new Parser(\n new (require(\"../lexer/lexer.ts\").Lexer)(token.command, { preserveNewlines: true }).tokenize()\n );\n return { type: \"substitution\", command: innerParser.parse() };\n case \"arithmetic\":\n return { type: \"arithmetic\", expression: token.expression };\n case \"glob\":\n return { type: \"glob\", pattern: token.pattern };\n case \"assignment\":\n return this.tokenToNode(token.value);\n case \"heredoc\":\n if (token.expand) {\n return this.parseHeredocContent(token.content);\n }\n return { type: \"literal\", value: token.content };\n default:\n throw new ParseError(`Unexpected token type: ${(token as Token).type}`);\n }\n }\n\n private parseDoubleQuoteParts(parts: Array<string | Token>): ASTNode {\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n\n if (parts.length === 1) {\n const part = parts[0]!;\n if (typeof part === \"string\") {\n return { type: \"literal\", value: part };\n }\n return this.tokenToNode(part);\n }\n\n const nodes: ASTNode[] = parts.map((part) => {\n if (typeof part === \"string\") {\n return { type: \"literal\" as const, value: part };\n }\n return this.tokenToNode(part);\n });\n\n return { type: \"concat\", parts: nodes };\n }\n\n private parseHeredocContent(content: string): ASTNode {\n // Parse content looking for $VAR and ${VAR} patterns\n const parts: ASTNode[] = [];\n let currentLiteral = \"\";\n let i = 0;\n\n while (i < content.length) {\n if (content[i] === \"$\") {\n // Flush current literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n currentLiteral = \"\";\n }\n\n i++; // consume $\n if (i >= content.length) {\n currentLiteral += \"$\";\n break;\n }\n\n if (content[i] === \"{\") {\n // ${VAR} syntax\n i++; // consume {\n let varName = \"\";\n while (i < content.length && content[i] !== \"}\") {\n varName += content[i];\n i++;\n }\n if (i < content.length && content[i] === \"}\") {\n i++; // consume }\n }\n if (varName) {\n parts.push({ type: \"variable\", name: varName });\n }\n } else if (/[a-zA-Z_]/.test(content[i] ?? \"\")) {\n // $VAR syntax\n let varName = \"\";\n while (i < content.length && /[a-zA-Z0-9_]/.test(content[i] ?? \"\")) {\n varName += content[i];\n i++;\n }\n parts.push({ type: \"variable\", name: varName });\n } else {\n // Not a variable, keep the $\n currentLiteral += \"$\";\n }\n } else {\n currentLiteral += content[i];\n i++;\n }\n }\n\n // Flush remaining literal\n if (currentLiteral) {\n parts.push({ type: \"literal\", value: currentLiteral });\n }\n\n if (parts.length === 0) {\n return { type: \"literal\", value: \"\" };\n }\n if (parts.length === 1) {\n return parts[0]!;\n }\n return { type: \"concat\", parts };\n }\n\n private parseRedirect(): Redirect {\n const token = this.advance() as Token & { type: \"redirect\" };\n const mode = token.mode as RedirectMode;\n\n // 2>&1 and 1>&2 don't have a target\n if (mode === \"2>&1\" || mode === \"1>&2\") {\n return { mode, target: { type: \"literal\", value: \"\" } };\n }\n\n if (!this.isWordToken()) {\n throw new ParseError(`Expected redirect target after ${mode}`);\n }\n\n const target = this.parseWordArg();\n return { mode, target };\n }\n\n private isWordToken(): boolean {\n const token = this.peek();\n return (\n Array.isArray(token) ||\n token.type === \"word\" ||\n token.type === \"singleQuote\" ||\n token.type === \"doubleQuote\" ||\n token.type === \"variable\" ||\n token.type === \"substitution\" ||\n token.type === \"arithmetic\" ||\n token.type === \"glob\" ||\n token.type === \"heredoc\"\n );\n }\n\n private check(type: Token[\"type\"]): boolean {\n return this.peek().type === type;\n }\n\n private match(type: Token[\"type\"]): boolean {\n if (this.check(type)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n private peek(): Token {\n return this.tokens[this.pos] ?? { type: \"eof\" };\n }\n\n private advance(): Token {\n const token = this.peek();\n this.pos++;\n return token;\n }\n\n private isAtEnd(): boolean {\n return this.peek().type === \"eof\";\n }\n}\n\nexport function parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "8C083E4DFB31F65664756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5FEDDF7D68ED292664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "type": "module"
5
5
  }
@@ -155,7 +155,30 @@ function buildMatcher(options) {
155
155
  if (options.fixedStrings) {
156
156
  patterns = patterns.map(escapeRegex);
157
157
  } else {
158
- patterns = patterns.map((p) => p.replace(/\\\|/g, "|").replace(/\\\(/g, "(").replace(/\\\)/g, ")"));
158
+ patterns = patterns.map((p) => {
159
+ const hasBRE = /\\\||\\\(|\\\)/.test(p);
160
+ if (!hasBRE)
161
+ return p;
162
+ let result = "";
163
+ for (let i = 0;i < p.length; i++) {
164
+ const ch = p[i];
165
+ if (ch === "\\" && i + 1 < p.length) {
166
+ const next = p[i + 1];
167
+ if (next === "|" || next === "(" || next === ")") {
168
+ result += next;
169
+ i++;
170
+ } else {
171
+ result += ch + next;
172
+ i++;
173
+ }
174
+ } else if ("()+?{}".includes(ch)) {
175
+ result += "\\" + ch;
176
+ } else {
177
+ result += ch;
178
+ }
179
+ }
180
+ return result;
181
+ });
159
182
  }
160
183
  let combined = patterns.length > 1 ? patterns.map((p) => `(?:${p})`).join("|") : patterns[0] || "";
161
184
  if (options.wholeWord) {
@@ -506,4 +529,4 @@ export {
506
529
  grep
507
530
  };
508
531
 
509
- //# debugId=0E1412C2E9C31AE364756E2164756E21
532
+ //# debugId=AB66DEE3D4E2ECCE64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/commands/grep/grep.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition, type FlagError } from \"../../utils/flag-parser.mjs\";\n\ninterface GrepOptions {\n patterns: string[];\n extendedRegex: boolean; // -E (default for JS)\n fixedStrings: boolean; // -F\n ignoreCase: boolean; // -i\n wholeWord: boolean; // -w\n wholeLine: boolean; // -x\n invert: boolean; // -v\n countOnly: boolean; // -c\n filesWithMatches: boolean; // -l\n filesWithoutMatches: boolean; // -L\n showLineNumbers: boolean; // -n\n onlyMatching: boolean; // -o\n quiet: boolean; // -q\n maxMatches: number; // -m (0 = unlimited)\n showFilename: boolean | null; // null=auto, true=-H, false=-h\n beforeContext: number; // -B\n afterContext: number; // -A\n recursive: boolean; // -r/-R\n include: string[]; // --include\n exclude: string[]; // --exclude\n}\n\nconst spec = {\n name: \"grep\",\n flags: [\n { short: \"E\", long: \"extended-regexp\" },\n { short: \"F\", long: \"fixed-strings\" },\n { short: \"i\", long: \"ignore-case\" },\n { short: \"w\", long: \"word-regexp\" },\n { short: \"x\", long: \"line-regexp\" },\n { short: \"v\", long: \"invert-match\" },\n { short: \"c\", long: \"count\" },\n { short: \"l\", long: \"files-with-matches\" },\n { short: \"L\", long: \"files-without-match\" },\n { short: \"n\", long: \"line-number\" },\n { short: \"o\", long: \"only-matching\" },\n { short: \"q\", long: \"quiet\" },\n { short: \"H\", long: \"with-filename\" },\n { short: \"h\", long: \"no-filename\" },\n { short: \"r\", long: \"recursive\" },\n { short: \"R\" },\n { short: \"e\", long: \"regexp\", takesValue: true },\n { short: \"m\", long: \"max-count\", takesValue: true },\n { short: \"A\", long: \"after-context\", takesValue: true },\n { short: \"B\", long: \"before-context\", takesValue: true },\n { short: \"C\", long: \"context\", takesValue: true },\n { long: \"include\", takesValue: true },\n { long: \"exclude\", takesValue: true },\n ] as FlagDefinition[],\n usage: \"grep [-ivnclLqHhEFwxorR] [-e pattern] [-m num] pattern [file ...]\",\n};\n\nfunction createDefaults(): GrepOptions {\n return {\n patterns: [],\n extendedRegex: true, // JS regex is extended by default\n fixedStrings: false,\n ignoreCase: false,\n wholeWord: false,\n wholeLine: false,\n invert: false,\n countOnly: false,\n filesWithMatches: false,\n filesWithoutMatches: false,\n showLineNumbers: false,\n onlyMatching: false,\n quiet: false,\n maxMatches: 0,\n showFilename: null,\n beforeContext: 0,\n afterContext: 0,\n recursive: false,\n include: [],\n exclude: [],\n };\n}\n\nconst handler = (flags: GrepOptions, flag: FlagDefinition, value?: string) => {\n switch (flag.short) {\n case \"E\": flags.extendedRegex = true; break;\n case \"F\": flags.fixedStrings = true; break;\n case \"i\": flags.ignoreCase = true; break;\n case \"w\": flags.wholeWord = true; break;\n case \"x\": flags.wholeLine = true; break;\n case \"v\": flags.invert = true; break;\n case \"c\": flags.countOnly = true; break;\n case \"l\": flags.filesWithMatches = true; break;\n case \"L\": flags.filesWithoutMatches = true; break;\n case \"n\": flags.showLineNumbers = true; break;\n case \"o\": flags.onlyMatching = true; break;\n case \"q\": flags.quiet = true; break;\n case \"H\": flags.showFilename = true; break;\n case \"h\": flags.showFilename = false; break;\n case \"r\":\n case \"R\": flags.recursive = true; break;\n case \"e\": if (value) flags.patterns.push(value); break;\n case \"m\": if (value) flags.maxMatches = parseInt(value, 10); break;\n case \"A\": if (value) flags.afterContext = parseInt(value, 10); break;\n case \"B\": if (value) flags.beforeContext = parseInt(value, 10); break;\n case \"C\":\n if (value) {\n const num = parseInt(value, 10);\n flags.beforeContext = num;\n flags.afterContext = num;\n }\n break;\n default:\n // Handle long-only flags\n if (flag.long === \"include\" && value) flags.include.push(value);\n else if (flag.long === \"exclude\" && value) flags.exclude.push(value);\n break;\n }\n};\n\nfunction matchGlob(str: string, pattern: string): boolean {\n // Convert shell glob to regex: * -> .*, ? -> ., rest escaped\n let re = \"^\";\n for (const ch of pattern) {\n if (ch === \"*\") re += \".*\";\n else if (ch === \"?\") re += \".\";\n else if (/[.+^${}()|[\\]\\\\]/.test(ch)) re += \"\\\\\" + ch;\n else re += ch;\n }\n re += \"$\";\n return new RegExp(re).test(str);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction buildMatcher(options: GrepOptions): RegExp {\n let patterns = options.patterns;\n\n // If fixed strings mode, escape regex metacharacters\n if (options.fixedStrings) {\n patterns = patterns.map(escapeRegex);\n } else {\n // Support BRE-style \\| \\( \\) even in ERE mode for compatibility\n patterns = patterns.map(p => p.replace(/\\\\\\|/g, \"|\").replace(/\\\\\\(/g, \"(\").replace(/\\\\\\)/g, \")\"));\n }\n\n // Combine multiple patterns with OR\n let combined = patterns.length > 1 ? patterns.map(p => `(?:${p})`).join(\"|\") : patterns[0] || \"\";\n\n // Whole word match\n if (options.wholeWord) {\n combined = `\\\\b(?:${combined})\\\\b`;\n }\n\n // Whole line match\n if (options.wholeLine) {\n combined = `^(?:${combined})$`;\n }\n\n const flags = options.ignoreCase ? \"gi\" : \"g\";\n return new RegExp(combined, flags);\n}\n\nexport const grep: Command = async (ctx) => {\n // Create fresh parser with fresh defaults for each invocation\n const parser = createFlagParser(spec, createDefaults(), handler);\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const options = result.flags;\n const args = result.args;\n\n // First positional arg is pattern if no -e patterns\n let files: string[];\n if (options.patterns.length === 0) {\n if (args.length === 0) {\n await ctx.stderr.writeText(\"grep: missing pattern\\n\");\n return 1;\n }\n options.patterns.push(args[0]!);\n files = args.slice(1);\n } else {\n files = args;\n }\n\n let regex: RegExp;\n try {\n regex = buildMatcher(options);\n } catch (err) {\n await ctx.stderr.writeText(`grep: invalid pattern: ${options.patterns.join(\", \")}\\n`);\n return 1;\n }\n\n let globalFound = false;\n let globalMatchCount = 0;\n let earlyExit = false;\n\n // Determine filename display mode\n let showFilenames = options.showFilename;\n\n // Expand files if recursive\n let expandedFiles = files;\n if (options.recursive && files.length > 0) {\n expandedFiles = [];\n for (const file of files) {\n const path = ctx.fs.resolve(ctx.cwd, file);\n try {\n const stat = await ctx.fs.stat(path);\n if (stat.isDirectory()) {\n // Glob all files in directory\n const globbed = await ctx.fs.glob(\"**/*\", { cwd: path });\n for (const f of globbed) {\n const fullPath = ctx.fs.resolve(path, f);\n try {\n const s = await ctx.fs.stat(fullPath);\n if (s.isFile()) {\n expandedFiles.push(fullPath);\n }\n } catch {\n // Skip if can't stat\n }\n }\n } else {\n expandedFiles.push(path);\n }\n } catch {\n expandedFiles.push(path); // Will error later\n }\n }\n // Filter by include/exclude patterns\n if (options.include.length > 0 || options.exclude.length > 0) {\n expandedFiles = expandedFiles.filter((f) => {\n const basename = ctx.fs.basename(f);\n if (options.include.length > 0) {\n const included = options.include.some((pat) => matchGlob(basename, pat));\n if (!included) return false;\n }\n if (options.exclude.length > 0) {\n const excluded = options.exclude.some((pat) => matchGlob(basename, pat));\n if (excluded) return false;\n }\n return true;\n });\n }\n\n // Default to showing filenames for recursive\n if (showFilenames === null) {\n showFilenames = true;\n }\n }\n\n // Default: show filenames if multiple files\n if (showFilenames === null) {\n showFilenames = expandedFiles.length > 1;\n }\n\n const processContent = async (\n lines: string[],\n filename?: string\n ): Promise<{ found: boolean; count: number }> => {\n let fileFound = false;\n let fileMatchCount = 0;\n\n // For context lines, we need a buffer approach\n const hasContext = options.beforeContext > 0 || options.afterContext > 0;\n\n if (hasContext) {\n return await processWithContext(lines, filename);\n }\n\n for (let lineIdx = 0; lineIdx < lines.length && !earlyExit; lineIdx++) {\n const line = lines[lineIdx]!;\n const lineNum = lineIdx + 1;\n\n // Reset regex lastIndex for each line\n regex.lastIndex = 0;\n const matches = regex.test(line);\n const shouldOutput = options.invert ? !matches : matches;\n\n if (shouldOutput) {\n fileFound = true;\n fileMatchCount++;\n\n // Quiet mode: exit immediately on first match\n if (options.quiet) {\n earlyExit = true;\n return { found: true, count: 1 };\n }\n\n // -l mode: we found a match in this file, stop processing this file\n if (options.filesWithMatches) {\n return { found: true, count: 1 };\n }\n\n // Output the match (unless countOnly or filesWithoutMatches)\n if (!options.countOnly && !options.filesWithoutMatches) {\n if (options.onlyMatching && !options.invert) {\n // Output only the matched parts\n regex.lastIndex = 0;\n let match;\n while ((match = regex.exec(line)) !== null) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += match[0] + \"\\n\";\n await ctx.stdout.writeText(output);\n // Prevent infinite loop for zero-width matches\n if (match[0].length === 0) regex.lastIndex++;\n }\n } else {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n // Check max matches\n if (options.maxMatches > 0 && fileMatchCount >= options.maxMatches) {\n earlyExit = true;\n return { found: true, count: fileMatchCount };\n }\n }\n }\n\n return { found: fileFound, count: fileMatchCount };\n };\n\n const processWithContext = async (\n lines: string[],\n filename?: string\n ): Promise<{ found: boolean; count: number }> => {\n let fileFound = false;\n let fileMatchCount = 0;\n let lastPrintedLine = -1;\n\n // First pass: find all matching lines\n const matchingLines = new Set<number>();\n for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {\n const line = lines[lineIdx]!;\n regex.lastIndex = 0;\n const matches = regex.test(line);\n const shouldOutput = options.invert ? !matches : matches;\n if (shouldOutput) {\n matchingLines.add(lineIdx);\n }\n }\n\n // Determine which lines to print (matches + context)\n const linesToPrint = new Set<number>();\n for (const matchIdx of matchingLines) {\n // Add before context\n for (let i = Math.max(0, matchIdx - options.beforeContext); i < matchIdx; i++) {\n linesToPrint.add(i);\n }\n // Add the match itself\n linesToPrint.add(matchIdx);\n // Add after context\n for (let i = matchIdx + 1; i <= Math.min(lines.length - 1, matchIdx + options.afterContext); i++) {\n linesToPrint.add(i);\n }\n }\n\n // Sort and print\n const sortedLines = Array.from(linesToPrint).sort((a, b) => a - b);\n\n for (let i = 0; i < sortedLines.length && !earlyExit; i++) {\n const lineIdx = sortedLines[i]!;\n const line = lines[lineIdx]!;\n const lineNum = lineIdx + 1;\n const isMatch = matchingLines.has(lineIdx);\n\n // Print separator if there's a gap\n if (lastPrintedLine >= 0 && lineIdx > lastPrintedLine + 1) {\n await ctx.stdout.writeText(\"--\\n\");\n }\n\n if (isMatch) {\n fileFound = true;\n fileMatchCount++;\n\n if (options.quiet) {\n earlyExit = true;\n return { found: true, count: 1 };\n }\n\n if (options.filesWithMatches) {\n return { found: true, count: 1 };\n }\n\n if (!options.countOnly && !options.filesWithoutMatches) {\n if (options.onlyMatching && !options.invert) {\n regex.lastIndex = 0;\n let match;\n while ((match = regex.exec(line)) !== null) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += match[0] + \"\\n\";\n await ctx.stdout.writeText(output);\n if (match[0].length === 0) regex.lastIndex++;\n }\n } else {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n if (options.maxMatches > 0 && fileMatchCount >= options.maxMatches) {\n // Still need to output remaining context lines after this match\n // Continue to output context but mark we should stop looking for more matches\n const remainingContextLines = sortedLines.slice(i + 1).filter(idx => !matchingLines.has(idx));\n for (const contextIdx of remainingContextLines) {\n const contextLine = lines[contextIdx]!;\n const contextLineNum = contextIdx + 1;\n // Check if it's within after-context of current match\n if (contextIdx <= lineIdx + options.afterContext) {\n if (lastPrintedLine >= 0 && contextIdx > lastPrintedLine + 1) {\n await ctx.stdout.writeText(\"--\\n\");\n }\n if (!options.countOnly && !options.filesWithoutMatches) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \"-\";\n if (options.showLineNumbers) output += contextLineNum + \"-\";\n output += contextLine + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n lastPrintedLine = contextIdx;\n }\n }\n earlyExit = true;\n return { found: true, count: fileMatchCount };\n }\n } else {\n // Context line\n if (!options.countOnly && !options.filesWithoutMatches) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \"-\";\n if (options.showLineNumbers) output += lineNum + \"-\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n lastPrintedLine = lineIdx;\n }\n\n return { found: fileFound, count: fileMatchCount };\n };\n\n if (expandedFiles.length === 0) {\n // Read from stdin\n const content = await ctx.stdin.text();\n const lines = content.split(\"\\n\");\n // Remove trailing empty line if content ends with newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n\n const { found, count } = await processContent(lines);\n globalFound = found;\n globalMatchCount = count;\n\n if (options.countOnly && !options.quiet && !options.filesWithMatches && !options.filesWithoutMatches) {\n await ctx.stdout.writeText(globalMatchCount + \"\\n\");\n }\n } else {\n // Read from files\n const perFileResults: Map<string, { found: boolean; count: number }> = new Map();\n\n for (const file of expandedFiles) {\n if (earlyExit && options.quiet) break;\n\n try {\n const path = file.startsWith(\"/\") ? file : ctx.fs.resolve(ctx.cwd, file);\n const stat = await ctx.fs.stat(path);\n\n if (stat.isDirectory()) {\n if (!options.recursive) {\n await ctx.stderr.writeText(`grep: ${file}: Is a directory\\n`);\n }\n continue;\n }\n\n const content = await ctx.fs.readFile(path);\n const lines = content.toString().split(\"\\n\");\n\n // Remove trailing empty line if file ends with newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n\n // Use original filename for display, not resolved path\n const displayName = files.includes(file) ? file :\n (options.recursive ? path : file);\n\n const { found, count } = await processContent(lines, displayName);\n perFileResults.set(displayName, { found, count });\n\n if (found) {\n globalFound = true;\n globalMatchCount += count;\n }\n } catch (err) {\n await ctx.stderr.writeText(`grep: ${file}: No such file or directory\\n`);\n // Continue to other files instead of immediately returning\n if (expandedFiles.length === 1) {\n return 1;\n }\n }\n }\n\n // Handle -l, -L, -c output modes\n let hasFilesWithoutMatches = false;\n if (options.filesWithMatches) {\n for (const [filename, result] of perFileResults) {\n if (result.found && !options.quiet) {\n await ctx.stdout.writeText(filename + \"\\n\");\n }\n }\n } else if (options.filesWithoutMatches) {\n for (const [filename, result] of perFileResults) {\n if (!result.found) {\n hasFilesWithoutMatches = true;\n await ctx.stdout.writeText(filename + \"\\n\");\n }\n }\n } else if (options.countOnly && !options.quiet) {\n for (const [filename, result] of perFileResults) {\n if (showFilenames) {\n await ctx.stdout.writeText(`${filename}:${result.count}\\n`);\n } else {\n await ctx.stdout.writeText(result.count + \"\\n\");\n }\n }\n }\n\n // Determine exit code for file processing\n if (options.filesWithoutMatches) {\n // -L: success if any file had NO matches\n return hasFilesWithoutMatches ? 0 : 1;\n }\n }\n\n // Determine exit code\n return globalFound ? 0 : 1;\n};\n"
5
+ "import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition, type FlagError } from \"../../utils/flag-parser.mjs\";\n\ninterface GrepOptions {\n patterns: string[];\n extendedRegex: boolean; // -E (default for JS)\n fixedStrings: boolean; // -F\n ignoreCase: boolean; // -i\n wholeWord: boolean; // -w\n wholeLine: boolean; // -x\n invert: boolean; // -v\n countOnly: boolean; // -c\n filesWithMatches: boolean; // -l\n filesWithoutMatches: boolean; // -L\n showLineNumbers: boolean; // -n\n onlyMatching: boolean; // -o\n quiet: boolean; // -q\n maxMatches: number; // -m (0 = unlimited)\n showFilename: boolean | null; // null=auto, true=-H, false=-h\n beforeContext: number; // -B\n afterContext: number; // -A\n recursive: boolean; // -r/-R\n include: string[]; // --include\n exclude: string[]; // --exclude\n}\n\nconst spec = {\n name: \"grep\",\n flags: [\n { short: \"E\", long: \"extended-regexp\" },\n { short: \"F\", long: \"fixed-strings\" },\n { short: \"i\", long: \"ignore-case\" },\n { short: \"w\", long: \"word-regexp\" },\n { short: \"x\", long: \"line-regexp\" },\n { short: \"v\", long: \"invert-match\" },\n { short: \"c\", long: \"count\" },\n { short: \"l\", long: \"files-with-matches\" },\n { short: \"L\", long: \"files-without-match\" },\n { short: \"n\", long: \"line-number\" },\n { short: \"o\", long: \"only-matching\" },\n { short: \"q\", long: \"quiet\" },\n { short: \"H\", long: \"with-filename\" },\n { short: \"h\", long: \"no-filename\" },\n { short: \"r\", long: \"recursive\" },\n { short: \"R\" },\n { short: \"e\", long: \"regexp\", takesValue: true },\n { short: \"m\", long: \"max-count\", takesValue: true },\n { short: \"A\", long: \"after-context\", takesValue: true },\n { short: \"B\", long: \"before-context\", takesValue: true },\n { short: \"C\", long: \"context\", takesValue: true },\n { long: \"include\", takesValue: true },\n { long: \"exclude\", takesValue: true },\n ] as FlagDefinition[],\n usage: \"grep [-ivnclLqHhEFwxorR] [-e pattern] [-m num] pattern [file ...]\",\n};\n\nfunction createDefaults(): GrepOptions {\n return {\n patterns: [],\n extendedRegex: true, // JS regex is extended by default\n fixedStrings: false,\n ignoreCase: false,\n wholeWord: false,\n wholeLine: false,\n invert: false,\n countOnly: false,\n filesWithMatches: false,\n filesWithoutMatches: false,\n showLineNumbers: false,\n onlyMatching: false,\n quiet: false,\n maxMatches: 0,\n showFilename: null,\n beforeContext: 0,\n afterContext: 0,\n recursive: false,\n include: [],\n exclude: [],\n };\n}\n\nconst handler = (flags: GrepOptions, flag: FlagDefinition, value?: string) => {\n switch (flag.short) {\n case \"E\": flags.extendedRegex = true; break;\n case \"F\": flags.fixedStrings = true; break;\n case \"i\": flags.ignoreCase = true; break;\n case \"w\": flags.wholeWord = true; break;\n case \"x\": flags.wholeLine = true; break;\n case \"v\": flags.invert = true; break;\n case \"c\": flags.countOnly = true; break;\n case \"l\": flags.filesWithMatches = true; break;\n case \"L\": flags.filesWithoutMatches = true; break;\n case \"n\": flags.showLineNumbers = true; break;\n case \"o\": flags.onlyMatching = true; break;\n case \"q\": flags.quiet = true; break;\n case \"H\": flags.showFilename = true; break;\n case \"h\": flags.showFilename = false; break;\n case \"r\":\n case \"R\": flags.recursive = true; break;\n case \"e\": if (value) flags.patterns.push(value); break;\n case \"m\": if (value) flags.maxMatches = parseInt(value, 10); break;\n case \"A\": if (value) flags.afterContext = parseInt(value, 10); break;\n case \"B\": if (value) flags.beforeContext = parseInt(value, 10); break;\n case \"C\":\n if (value) {\n const num = parseInt(value, 10);\n flags.beforeContext = num;\n flags.afterContext = num;\n }\n break;\n default:\n // Handle long-only flags\n if (flag.long === \"include\" && value) flags.include.push(value);\n else if (flag.long === \"exclude\" && value) flags.exclude.push(value);\n break;\n }\n};\n\nfunction matchGlob(str: string, pattern: string): boolean {\n // Convert shell glob to regex: * -> .*, ? -> ., rest escaped\n let re = \"^\";\n for (const ch of pattern) {\n if (ch === \"*\") re += \".*\";\n else if (ch === \"?\") re += \".\";\n else if (/[.+^${}()|[\\]\\\\]/.test(ch)) re += \"\\\\\" + ch;\n else re += ch;\n }\n re += \"$\";\n return new RegExp(re).test(str);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction buildMatcher(options: GrepOptions): RegExp {\n let patterns = options.patterns;\n\n // If fixed strings mode, escape regex metacharacters\n if (options.fixedStrings) {\n patterns = patterns.map(escapeRegex);\n } else {\n // Convert BRE patterns to ERE/JavaScript RegExp\n // In BRE: \\| \\( \\) are special; bare ( ) + ? { } are literal\n // In ERE/JS: | ( ) + ? { } are special; \\| \\( \\) are literal\n patterns = patterns.map(p => {\n const hasBRE = /\\\\\\||\\\\\\(|\\\\\\)/.test(p);\n if (!hasBRE) return p;\n let result = \"\";\n for (let i = 0; i < p.length; i++) {\n const ch = p[i]!;\n if (ch === \"\\\\\" && i + 1 < p.length) {\n const next = p[i + 1]!;\n if (next === \"|\" || next === \"(\" || next === \")\") {\n // BRE special → ERE special (emit unescaped)\n result += next;\n i++;\n } else {\n result += ch + next;\n i++;\n }\n } else if (\"()+?{}\".includes(ch)) {\n // Bare metachar is literal in BRE → escape for ERE\n result += \"\\\\\" + ch;\n } else {\n result += ch;\n }\n }\n return result;\n });\n }\n\n // Combine multiple patterns with OR\n let combined = patterns.length > 1 ? patterns.map(p => `(?:${p})`).join(\"|\") : patterns[0] || \"\";\n\n // Whole word match\n if (options.wholeWord) {\n combined = `\\\\b(?:${combined})\\\\b`;\n }\n\n // Whole line match\n if (options.wholeLine) {\n combined = `^(?:${combined})$`;\n }\n\n const flags = options.ignoreCase ? \"gi\" : \"g\";\n return new RegExp(combined, flags);\n}\n\nexport const grep: Command = async (ctx) => {\n // Create fresh parser with fresh defaults for each invocation\n const parser = createFlagParser(spec, createDefaults(), handler);\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const options = result.flags;\n const args = result.args;\n\n // First positional arg is pattern if no -e patterns\n let files: string[];\n if (options.patterns.length === 0) {\n if (args.length === 0) {\n await ctx.stderr.writeText(\"grep: missing pattern\\n\");\n return 1;\n }\n options.patterns.push(args[0]!);\n files = args.slice(1);\n } else {\n files = args;\n }\n\n let regex: RegExp;\n try {\n regex = buildMatcher(options);\n } catch (err) {\n await ctx.stderr.writeText(`grep: invalid pattern: ${options.patterns.join(\", \")}\\n`);\n return 1;\n }\n\n let globalFound = false;\n let globalMatchCount = 0;\n let earlyExit = false;\n\n // Determine filename display mode\n let showFilenames = options.showFilename;\n\n // Expand files if recursive\n let expandedFiles = files;\n if (options.recursive && files.length > 0) {\n expandedFiles = [];\n for (const file of files) {\n const path = ctx.fs.resolve(ctx.cwd, file);\n try {\n const stat = await ctx.fs.stat(path);\n if (stat.isDirectory()) {\n // Glob all files in directory\n const globbed = await ctx.fs.glob(\"**/*\", { cwd: path });\n for (const f of globbed) {\n const fullPath = ctx.fs.resolve(path, f);\n try {\n const s = await ctx.fs.stat(fullPath);\n if (s.isFile()) {\n expandedFiles.push(fullPath);\n }\n } catch {\n // Skip if can't stat\n }\n }\n } else {\n expandedFiles.push(path);\n }\n } catch {\n expandedFiles.push(path); // Will error later\n }\n }\n // Filter by include/exclude patterns\n if (options.include.length > 0 || options.exclude.length > 0) {\n expandedFiles = expandedFiles.filter((f) => {\n const basename = ctx.fs.basename(f);\n if (options.include.length > 0) {\n const included = options.include.some((pat) => matchGlob(basename, pat));\n if (!included) return false;\n }\n if (options.exclude.length > 0) {\n const excluded = options.exclude.some((pat) => matchGlob(basename, pat));\n if (excluded) return false;\n }\n return true;\n });\n }\n\n // Default to showing filenames for recursive\n if (showFilenames === null) {\n showFilenames = true;\n }\n }\n\n // Default: show filenames if multiple files\n if (showFilenames === null) {\n showFilenames = expandedFiles.length > 1;\n }\n\n const processContent = async (\n lines: string[],\n filename?: string\n ): Promise<{ found: boolean; count: number }> => {\n let fileFound = false;\n let fileMatchCount = 0;\n\n // For context lines, we need a buffer approach\n const hasContext = options.beforeContext > 0 || options.afterContext > 0;\n\n if (hasContext) {\n return await processWithContext(lines, filename);\n }\n\n for (let lineIdx = 0; lineIdx < lines.length && !earlyExit; lineIdx++) {\n const line = lines[lineIdx]!;\n const lineNum = lineIdx + 1;\n\n // Reset regex lastIndex for each line\n regex.lastIndex = 0;\n const matches = regex.test(line);\n const shouldOutput = options.invert ? !matches : matches;\n\n if (shouldOutput) {\n fileFound = true;\n fileMatchCount++;\n\n // Quiet mode: exit immediately on first match\n if (options.quiet) {\n earlyExit = true;\n return { found: true, count: 1 };\n }\n\n // -l mode: we found a match in this file, stop processing this file\n if (options.filesWithMatches) {\n return { found: true, count: 1 };\n }\n\n // Output the match (unless countOnly or filesWithoutMatches)\n if (!options.countOnly && !options.filesWithoutMatches) {\n if (options.onlyMatching && !options.invert) {\n // Output only the matched parts\n regex.lastIndex = 0;\n let match;\n while ((match = regex.exec(line)) !== null) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += match[0] + \"\\n\";\n await ctx.stdout.writeText(output);\n // Prevent infinite loop for zero-width matches\n if (match[0].length === 0) regex.lastIndex++;\n }\n } else {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n // Check max matches\n if (options.maxMatches > 0 && fileMatchCount >= options.maxMatches) {\n earlyExit = true;\n return { found: true, count: fileMatchCount };\n }\n }\n }\n\n return { found: fileFound, count: fileMatchCount };\n };\n\n const processWithContext = async (\n lines: string[],\n filename?: string\n ): Promise<{ found: boolean; count: number }> => {\n let fileFound = false;\n let fileMatchCount = 0;\n let lastPrintedLine = -1;\n\n // First pass: find all matching lines\n const matchingLines = new Set<number>();\n for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {\n const line = lines[lineIdx]!;\n regex.lastIndex = 0;\n const matches = regex.test(line);\n const shouldOutput = options.invert ? !matches : matches;\n if (shouldOutput) {\n matchingLines.add(lineIdx);\n }\n }\n\n // Determine which lines to print (matches + context)\n const linesToPrint = new Set<number>();\n for (const matchIdx of matchingLines) {\n // Add before context\n for (let i = Math.max(0, matchIdx - options.beforeContext); i < matchIdx; i++) {\n linesToPrint.add(i);\n }\n // Add the match itself\n linesToPrint.add(matchIdx);\n // Add after context\n for (let i = matchIdx + 1; i <= Math.min(lines.length - 1, matchIdx + options.afterContext); i++) {\n linesToPrint.add(i);\n }\n }\n\n // Sort and print\n const sortedLines = Array.from(linesToPrint).sort((a, b) => a - b);\n\n for (let i = 0; i < sortedLines.length && !earlyExit; i++) {\n const lineIdx = sortedLines[i]!;\n const line = lines[lineIdx]!;\n const lineNum = lineIdx + 1;\n const isMatch = matchingLines.has(lineIdx);\n\n // Print separator if there's a gap\n if (lastPrintedLine >= 0 && lineIdx > lastPrintedLine + 1) {\n await ctx.stdout.writeText(\"--\\n\");\n }\n\n if (isMatch) {\n fileFound = true;\n fileMatchCount++;\n\n if (options.quiet) {\n earlyExit = true;\n return { found: true, count: 1 };\n }\n\n if (options.filesWithMatches) {\n return { found: true, count: 1 };\n }\n\n if (!options.countOnly && !options.filesWithoutMatches) {\n if (options.onlyMatching && !options.invert) {\n regex.lastIndex = 0;\n let match;\n while ((match = regex.exec(line)) !== null) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += match[0] + \"\\n\";\n await ctx.stdout.writeText(output);\n if (match[0].length === 0) regex.lastIndex++;\n }\n } else {\n let output = \"\";\n if (filename && showFilenames) output += filename + \":\";\n if (options.showLineNumbers) output += lineNum + \":\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n if (options.maxMatches > 0 && fileMatchCount >= options.maxMatches) {\n // Still need to output remaining context lines after this match\n // Continue to output context but mark we should stop looking for more matches\n const remainingContextLines = sortedLines.slice(i + 1).filter(idx => !matchingLines.has(idx));\n for (const contextIdx of remainingContextLines) {\n const contextLine = lines[contextIdx]!;\n const contextLineNum = contextIdx + 1;\n // Check if it's within after-context of current match\n if (contextIdx <= lineIdx + options.afterContext) {\n if (lastPrintedLine >= 0 && contextIdx > lastPrintedLine + 1) {\n await ctx.stdout.writeText(\"--\\n\");\n }\n if (!options.countOnly && !options.filesWithoutMatches) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \"-\";\n if (options.showLineNumbers) output += contextLineNum + \"-\";\n output += contextLine + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n lastPrintedLine = contextIdx;\n }\n }\n earlyExit = true;\n return { found: true, count: fileMatchCount };\n }\n } else {\n // Context line\n if (!options.countOnly && !options.filesWithoutMatches) {\n let output = \"\";\n if (filename && showFilenames) output += filename + \"-\";\n if (options.showLineNumbers) output += lineNum + \"-\";\n output += line + \"\\n\";\n await ctx.stdout.writeText(output);\n }\n }\n\n lastPrintedLine = lineIdx;\n }\n\n return { found: fileFound, count: fileMatchCount };\n };\n\n if (expandedFiles.length === 0) {\n // Read from stdin\n const content = await ctx.stdin.text();\n const lines = content.split(\"\\n\");\n // Remove trailing empty line if content ends with newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n\n const { found, count } = await processContent(lines);\n globalFound = found;\n globalMatchCount = count;\n\n if (options.countOnly && !options.quiet && !options.filesWithMatches && !options.filesWithoutMatches) {\n await ctx.stdout.writeText(globalMatchCount + \"\\n\");\n }\n } else {\n // Read from files\n const perFileResults: Map<string, { found: boolean; count: number }> = new Map();\n\n for (const file of expandedFiles) {\n if (earlyExit && options.quiet) break;\n\n try {\n const path = file.startsWith(\"/\") ? file : ctx.fs.resolve(ctx.cwd, file);\n const stat = await ctx.fs.stat(path);\n\n if (stat.isDirectory()) {\n if (!options.recursive) {\n await ctx.stderr.writeText(`grep: ${file}: Is a directory\\n`);\n }\n continue;\n }\n\n const content = await ctx.fs.readFile(path);\n const lines = content.toString().split(\"\\n\");\n\n // Remove trailing empty line if file ends with newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n\n // Use original filename for display, not resolved path\n const displayName = files.includes(file) ? file :\n (options.recursive ? path : file);\n\n const { found, count } = await processContent(lines, displayName);\n perFileResults.set(displayName, { found, count });\n\n if (found) {\n globalFound = true;\n globalMatchCount += count;\n }\n } catch (err) {\n await ctx.stderr.writeText(`grep: ${file}: No such file or directory\\n`);\n // Continue to other files instead of immediately returning\n if (expandedFiles.length === 1) {\n return 1;\n }\n }\n }\n\n // Handle -l, -L, -c output modes\n let hasFilesWithoutMatches = false;\n if (options.filesWithMatches) {\n for (const [filename, result] of perFileResults) {\n if (result.found && !options.quiet) {\n await ctx.stdout.writeText(filename + \"\\n\");\n }\n }\n } else if (options.filesWithoutMatches) {\n for (const [filename, result] of perFileResults) {\n if (!result.found) {\n hasFilesWithoutMatches = true;\n await ctx.stdout.writeText(filename + \"\\n\");\n }\n }\n } else if (options.countOnly && !options.quiet) {\n for (const [filename, result] of perFileResults) {\n if (showFilenames) {\n await ctx.stdout.writeText(`${filename}:${result.count}\\n`);\n } else {\n await ctx.stdout.writeText(result.count + \"\\n\");\n }\n }\n }\n\n // Determine exit code for file processing\n if (options.filesWithoutMatches) {\n // -L: success if any file had NO matches\n return hasFilesWithoutMatches ? 0 : 1;\n }\n }\n\n // Determine exit code\n return globalFound ? 0 : 1;\n};\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "0E1412C2E9C31AE364756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "AB66DEE3D4E2ECCE64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -32,6 +32,9 @@ class Lexer {
32
32
  this.source = source;
33
33
  this.preserveNewlines = options?.preserveNewlines ?? false;
34
34
  }
35
+ isWordLikeToken(token) {
36
+ return token.type === "word" || token.type === "singleQuote" || token.type === "doubleQuote" || token.type === "variable" || token.type === "substitution" || token.type === "arithmetic" || token.type === "glob";
37
+ }
35
38
  tokenize() {
36
39
  const tokens = [];
37
40
  while (!this.isAtEnd() || this.tokenQueue.length > 0) {
@@ -39,12 +42,23 @@ class Lexer {
39
42
  tokens.push(this.tokenQueue.shift());
40
43
  continue;
41
44
  }
45
+ const posBeforeWhitespace = this.pos;
42
46
  this.skipWhitespaceExceptNewlines();
47
+ const hadWhitespace = this.pos > posBeforeWhitespace;
43
48
  if (this.isAtEnd())
44
49
  break;
45
50
  const token = this.nextToken();
46
51
  if (token) {
47
- tokens.push(token);
52
+ const prev = tokens[tokens.length - 1];
53
+ if (!hadWhitespace && prev && this.isWordLikeToken(token) && (Array.isArray(prev) || this.isWordLikeToken(prev))) {
54
+ if (Array.isArray(prev)) {
55
+ prev.push(token);
56
+ } else {
57
+ tokens[tokens.length - 1] = [prev, token];
58
+ }
59
+ } else {
60
+ tokens.push(token);
61
+ }
48
62
  }
49
63
  }
50
64
  tokens.push({ type: "eof" });
@@ -653,4 +667,4 @@ export {
653
667
  Lexer
654
668
  };
655
669
 
656
- //# debugId=11B4DB819B360AA764756E2164756E21
670
+ //# debugId=36D55E5610E7EAAF64756E2164756E21