# core/lexers/invocation.lexer.ts

> 43 lines of code and 9 definitions.

Tree: GovLab Quality
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-lexers-invocation-lexer-ts
Source text: https://banes-lab.com/source/quality/core/lexers/invocation.lexer.ts.txt

Listed in [core/lexers](https://banes-lab.com/api/source/quality/core/lexers.md).

## Definitions

- `stepChar` (lexical_declaration, line 13)
- `tokenizeCommand` (lexical_declaration, line 37, exported)
- `QUOTES` (lexical_declaration, line 3)
- `SPACE` (lexical_declaration, line 4)
- `TokenState` (interface_declaration, line 6)
- `closing` (lexical_declaration, line 15)
- `state` (lexical_declaration, line 38, exported)
- `commandOf` (lexical_declaration, line 45, exported)
- `prefix]` (lexical_declaration, line 46, exported)

## Contained in

- [core/lexers](https://banes-lab.com/anatomy/quality/folder-quality-core-lexers.md)

## Linked from

- [core/lexers](https://banes-lab.com/anatomy/quality/folder-quality-core-lexers.md)

## Source

```typescript
import type { CommandInvocation } from "#types/tool.types";

const QUOTES = new Set(['"', "'"]);
const SPACE = " ";

interface TokenState {
    current: string;
    open: boolean;
    quote: string;
    tokens: string[];
}

const stepChar = function stepChar(state: TokenState, ch: string): TokenState {
    if (state.quote !== "") {
        const closing = ch === state.quote;
        return {
            current: closing ? state.current : state.current + ch,
            open: true,
            quote: closing ? "" : state.quote,
            tokens: state.tokens,
        };
    }
    if (QUOTES.has(ch)) {
        return { current: state.current, open: true, quote: ch, tokens: state.tokens };
    }
    if (ch === SPACE) {
        return {
            current: "",
            open: false,
            quote: "",
            tokens: state.open ? [...state.tokens, state.current] : state.tokens,
        };
    }
    return { current: state.current + ch, open: true, quote: "", tokens: state.tokens };
};

export const tokenizeCommand = function tokenizeCommand(command: string): string[] {
    let state: TokenState = { current: "", open: false, quote: "", tokens: [] };
    for (const ch of command) {
        state = stepChar(state, ch);
    }
    return state.open ? [...state.tokens, state.current] : state.tokens;
};

export const commandOf = function commandOf(command: string, fallback: string): CommandInvocation {
    const [bin = fallback, ...prefix] = tokenizeCommand(command);
    return { bin, prefix };
};
```
