-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Summary
Introduce a small “decode layer” between stdout and validation so parse() and safeParse() can handle YAML in addition to JSON without breaking existing behavior. Callers can opt into YAML explicitly or rely on auto-detection. The same decode path is used by runParse() and safeRunParse().
Motivation
- Many CLIs emit YAML by default (kubectl, helm, aws with
--output yaml). - Today
parse()assumes JSON, forcing extra conversion steps. - A format-agnostic decoder keeps the fluent API unchanged while adding YAML support and future extensibility (TOML, INI, CSV).
Scope
- Add a tiny decoder interface and registry.
- Provide built-in JSON and YAML decoders (
yamlpackage). - Add optional parse options to
parse()andsafeParse(), and torunParse()andsafeRunParse(). - Default behavior remains backward compatible: auto-detect with JSON first, then YAML.
Public API changes
Add types:
export type ParseFormat = 'json' | 'yaml' | 'auto';
export interface ParseOptions {
from?: ParseFormat; // default: 'auto'
allowEmpty?: boolean; // empty -> {} when true
yamlMulti?: 'first' | 'all' | 'error'; // multi-doc handling
}
export interface Decoder {
name: Exclude<ParseFormat, 'auto'>;
test?(s: string): boolean;
parse(s: string, opts?: ParseOptions): unknown;
}Extend ShellOptions:
export interface ShellOptions<Mode extends OutputMode = 'capture'> extends OverridableCommandOptions<Mode> {
throwMode?: 'simple' | 'raw';
logger?: ShellLogger;
decoders?: Decoder[]; // default: [JsonDecoder, YamlDecoder]
defaultParse?: ParseOptions; // default: { from: 'auto', yamlMulti: 'first' }
}Update method signatures (non-breaking; options are optional):
// Fluent
parse<T extends StandardSchemaV1>(schema: T, options?: ParseOptions): Promise<StandardSchemaV1.InferOutput<T>>;
safeParse<T extends StandardSchemaV1>(schema: T, options?: ParseOptions): Promise<ValidationResult<StandardSchemaV1.InferOutput<T>>>;
// Eager
runParse<T extends StandardSchemaV1, Mode extends OutputMode = DefaultMode>(
cmd: string | string[], schema: T, options?: RunOptions<Mode> & { parse?: ParseOptions }
): Promise<StandardSchemaV1.InferOutput<T>>;
safeRunParse<T extends StandardSchemaV1, Mode extends OutputMode = DefaultMode>(
cmd: string | string[], schema: T, options?: RunOptions<Mode> & { parse?: ParseOptions }
): Promise<ValidationResult<StandardSchemaV1.InferOutput<T>>>;Internal changes
-
Add
this.decodersandthis.defaultParsetoShell. -
Implement
private decode(stdout: string, opts?: ParseOptions): unknown:- If
fromis set, use that decoder. - If
auto, try JSON first (cheap and strict), then YAML. - Support multi-document YAML via
yaml.parseAllDocuments.
- If
Built-in decoders
JsonDecoder: usesJSON.parse, optionalteston leading{or[.YamlDecoder: usesyamllibrary; supports multi-document (first|all|error).
Usage examples
Explicit YAML:
const $ = createShell().asFluent();
const cfg = await $('kubectl get cm app -o yaml').parse(ConfigSchema, { from: 'yaml' });Auto-detect:
const info = await $('aws eks describe-cluster --name x --output yaml').parse(ClusterSchema);Multi-doc:
const docs = await $('helm template mychart').parse(HelmSchema, { from: 'yaml', yamlMulti: 'all' });Safe path:
const r = await $('cat values.yaml').safeParse(ValuesSchema, { from: 'yaml', allowEmpty: true });Acceptance criteria
parse()andsafeParse()successfully validate YAML and JSON outputs using the same schemas.- Auto-detection prefers JSON, falls back to YAML; errors are clear when decoding fails.
- Multi-document YAML behaves according to
yamlMulti. - No regressions for existing JSON-only users.
- Documentation updated with examples and guidance.
Risks and notes
- JSON is valid YAML; ordering the auto-detect as JSON → YAML avoids overly permissive parsing.
- Users who want deterministic behavior should pass
{ from: 'yaml' }explicitly. - Streaming (
live) remains unsupported for parsing; this is already enforced in Fluent mode.
Tasks
- Add
ParseOptions,ParseFormat, andDecodertypes. - Implement
JsonDecoderandYamlDecoder(addyamldependency). - Extend
ShellOptionswithdecodersanddefaultParse. - Add
decode()helper and wire it intoparse()/safeParse()(fluent). - Wire
decode()intorunParse()/safeRunParse()(eager). - Unit tests: JSON, YAML, auto-detect, empty output, error paths, multi-doc modes.
- Update README with examples and migration notes.
- Changelog entry.
Out of scope
- Additional formats (TOML, INI, CSV).
- Tagged template escaping or live mode parsing.
Metadata
Metadata
Assignees
Labels
No labels