first commit
This commit is contained in:
69
docs/media/audio/audio-cli/src/pipeline/parser.md
Normal file
69
docs/media/audio/audio-cli/src/pipeline/parser.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# `pipeline/parser` — `parsePipeline` and `validatePipeline`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module turns a CLI user's free-form pipeline expression into a typed
|
||||
`[opName, params]` chain that the rest of the CLI feeds into
|
||||
`AudioDocument.run`. It supports both the **pipe-form** string —
|
||||
`"trim 30s | normalize -16lufs | fade 0.5s 1s"` — and the **positional
|
||||
bare-op** token array — `["trim", "30s", "normalize", "-16lufs"]` — and
|
||||
collapses both surface forms onto the same internal representation so there is
|
||||
exactly one downstream code path.
|
||||
|
||||
It also exposes `validatePipeline(chain, knownOps)` which the CLI calls before
|
||||
opening any file, so an unknown op name throws `AUDIO_CLI.UNKNOWN_OP` fast and
|
||||
no I/O is wasted.
|
||||
|
||||
## Features
|
||||
|
||||
- `tokenise` respects double-quoted strings (`"a b"`) and backslash escapes
|
||||
(`a\ b`) so a single op can carry a string parameter with spaces.
|
||||
- Unit suffix coercion: `30s → start=30`, `500ms → start=0.5`,
|
||||
`-16lufs → lufs=-16`, `6db → db=6`, `44100hz → rate=44100`,
|
||||
`48khz → rate=48000`.
|
||||
- `key=value` arguments (`foo=bar`) become named params; numeric literals
|
||||
without a unit become positional `start`/`duration`.
|
||||
- `validatePipeline` lists the registry up-front so the diagnostic names the
|
||||
offending op alongside the sorted set of known ops.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parsePipeline } from "@suaveplan/audio-cli/pipeline/parser";
|
||||
|
||||
const chain = parsePipeline("trim 30s | normalize -16lufs");
|
||||
// → [["trim", { start: 30 }], ["normalize", { lufs: -16 }]]
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { parsePipeline, validatePipeline } from "@suaveplan/audio-cli/pipeline/parser";
|
||||
import { OpRegistry } from "@suaveplan/audio-core";
|
||||
|
||||
const registry = OpRegistry.createWithDefaults();
|
||||
const known = new Set(registry.list().map((d) => d.name));
|
||||
const chain = parsePipeline(["trim", "30s", "normalize", "-16lufs", "fade", "0.5s", "1s"]);
|
||||
validatePipeline(chain, known); // throws AUDIO_CLI.UNKNOWN_OP if a name is unknown
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `ParsedPipeline` — `ReadonlyArray<readonly [string, Record<string, unknown>]>`.
|
||||
- `parsePipeline(spec: string | readonly string[])` — produce the chain.
|
||||
- `validatePipeline(chain, knownOps: ReadonlySet<string>)` — throws
|
||||
`AudioCliError(AUDIO_CLI.UNKNOWN_OP)` on the first unknown op name.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The hand-written tokenizer is deliberately small: a single forward pass with
|
||||
two flags (`inQuote`, `escaped`) and a per-stage accumulator. The pipe-form
|
||||
splits on `|`; the bare-op form treats every identifier-shaped token (matching
|
||||
`/^[a-zA-Z][a-zA-Z0-9_-]*$/`) as the start of a new stage so positional
|
||||
arguments belonging to the previous op are correctly grouped. Unit coercion
|
||||
runs as a small regex per argument so `trim 30s` always lands as
|
||||
`{ start: 30 }` regardless of which surface form it arrived through.
|
||||
Reference in New Issue
Block a user