Discussion
Loading...

Post

Log in
  • About
  • Code of conduct
  • Privacy
  • Users
  • Instances
  • About Bonfire
洪 民憙 (Hong Minhee)
洪 民憙 (Hong Minhee)
@hongminhee@hackers.pub  ·  activity timestamp 3 weeks ago

⁂ Article

Optique 0.8.0: Conditional parsing, pass-through options, and LogTape integration

English:

We're excited to announce Optique 0.8.0! This release introduces powerful new features for building sophisticated CLI applications: the conditional() combinator for discriminated union patterns, the passThrough() parser for wrapper tools, and the new @optique/logtape package for seamless logging configuration.

Optique is a type-safe combinatorial CLI parser for TypeScript, providing a functional approach to building command-line interfaces with composable parsers and full type inference.

New conditional parsing with conditional()

Ever needed to enable different sets of options based on a discriminator value? The new conditional() combinator makes this pattern first-class. It creates discriminated unions where certain options only become valid when a specific discriminator value is selected.

import { conditional, object } from "@optique/core/constructs";
import { option } from "@optique/core/primitives";
import { choice, string } from "@optique/core/valueparser";

const parser = conditional(
 option("--reporter", choice(["console", "junit", "html"])),
 {
 console: object({}),
 junit: object({ outputFile: option("--output-file", string()) }),
 html: object({ outputFile: option("--output-file", string()) }),
 }
);
// Result type: ["console", {}] | ["junit", { outputFile: string }] | ...

Key features:

  • Explicit discriminator option determines which branch is selected
  • Tuple result [discriminator, branchValue] for clear type narrowing
  • Optional default branch for when discriminator is not provided
  • Clear error messages indicating which options are required for each discriminator value

The conditional() parser provides a more structured alternative to or() for discriminated union patterns. Use it when you have an explicit discriminator option that determines which set of options is valid.

See the conditional() documentation for more details and examples.

Pass-through options with passThrough()

Building wrapper CLI tools that need to forward unrecognized options to an underlying tool? The new passThrough() parser enables legitimate wrapper/proxy patterns by capturing unknown options without validation errors.

import { object } from "@optique/core/constructs";
import { option, passThrough } from "@optique/core/primitives";

const parser = object({
 debug: option("--debug"),
 extra: passThrough(),
});

// mycli --debug --foo=bar --baz=qux
// → { debug: true, extra: ["--foo=bar", "--baz=qux"] }

Key features:

  • Three capture formats: "equalsOnly" (default, safest), "nextToken" (captures --opt val pairs), and "greedy" (captures all remaining tokens)
  • Lowest priority (−10) ensures explicit parsers always match first
  • Respects -- options terminator in "equalsOnly" and "nextToken" modes
  • Works seamlessly with object(), subcommands, and other combinators

This feature is designed for building Docker-like CLIs, build tool wrappers, or any tool that proxies commands to another process.

See the passThrough() documentation for usage patterns and best practices.

LogTape logging integration

The new @optique/logtape package provides seamless integration with LogTape, enabling you to configure logging through command-line arguments with various parsing strategies.

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

Quick start with the loggingOptions() preset:

import { loggingOptions, createLoggingConfig } from "@optique/logtape";
import { object } from "@optique/core/constructs";
import { parse } from "@optique/core/parser";
import { configure } from "@logtape/logtape";

const parser = object({
 logging: loggingOptions({ level: "verbosity" }),
});

const args = ["-vv", "--log-output=-"];
const result = parse(parser, args);
if (result.success) {
 const config = await createLoggingConfig(result.value.logging);
 await configure(config);
}

The package offers multiple approaches to control log verbosity:

  • verbosity() parser: The classic -v/-vv/-vvv pattern where each flag increases verbosity (no flags → "warning", -v → "info", -vv → "debug", -vvv → "trace")
  • debug() parser: Simple --debug/-d flag that toggles between normal and debug levels
  • logLevel() value parser: Explicit --log-level=debug option for direct level selection
  • logOutput() parser: Log output destination with - for console or file path for file output

See the LogTape integration documentation for complete examples and configuration options.

Bug fix: negative integers now accepted

Fixed an issue where the integer() value parser rejected negative integers when using type: "number". The regex pattern has been updated from /^\d+$/ to /^-?\d+$/ to correctly handle values like -42. Note that type: "bigint" already accepted negative integers, so this change brings consistency between the two types.

Installation

# Deno
deno add jsr:@optique/core

# npm
npm add @optique/core

# pnpm
pnpm add @optique/core

# Yarn
yarn add @optique/core

# Bun
bun add @optique/core

For the LogTape integration:

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

# pnpm
pnpm add @optique/logtape @logtape/logtape

# Yarn
yarn add @optique/logtape @logtape/logtape

# Bun
bun add @optique/logtape @logtape/logtape

Looking forward

Optique 0.8.0 continues our focus on making CLI development more expressive and type-safe. The conditional() combinator brings discriminated union patterns to the forefront, passThrough() enables new wrapper tool use cases, and the LogTape integration makes logging configuration a breeze.

As always, all new features maintain full backward compatibility—your existing parsers continue to work unchanged.

We're grateful to the community for feedback and suggestions. If you have ideas for future improvements or encounter any issues, please let us know through GitHub Issues. For more information about Optique and its features, visit the documentation or check out the full changelog.

한국어:

Optique 0.8.0 출시를 발표하게 되어 기쁩니다! 이번 릴리스는 정교한 CLI 애플리케이션 구축을 위한 강력한 새 기능을 소개합니다: 판별 유니온 패턴을 위한 conditional() 조합기, 래퍼 도구를 위한 passThrough() 파서, 그리고 원활한 로깅 구성을 위한 새로운 @optique/logtape 패키지가 포함되어 있습니다.

Optique는 TypeScript를 위한 타입 안전 조합형 CLI 파서로, 조합 가능한 파서와 완전한 타입 추론을 통해 명령줄 인터페이스를 구축하는 함수형 접근 방식을 제공합니다.

conditional()을 이용한 새로운 조건부 파싱

판별자 값에 따라 다른 옵션 세트를 활성화해야 할 필요가 있었나요? 새로운 conditional() 조합기는 이 패턴을 일급 객체로 만듭니다. 특정 판별자 값이 선택되었을 때만 특정 옵션이 유효해지는 판별 유니온을 생성합니다.

import { conditional, object } from "@optique/core/constructs";
import { option } from "@optique/core/primitives";
import { choice, string } from "@optique/core/valueparser";

const parser = conditional(
 option("--reporter", choice(["console", "junit", "html"])),
 {
 console: object({}),
 junit: object({ outputFile: option("--output-file", string()) }),
 html: object({ outputFile: option("--output-file", string()) }),
 }
);
// Result type: ["console", {}] | ["junit", { outputFile: string }] | ...

주요 기능:

  • 명시적 판별자 옵션이 어떤 분기가 선택될지 결정
  • 명확한 타입 좁히기를 위한 튜플 결과 [discriminator, branchValue]
  • 판별자가 제공되지 않을 때를 위한 선택적 기본 분기
  • 각 판별자 값에 필요한 옵션을 명확히 표시하는 오류 메시지

conditional() 파서는 판별 유니온 패턴에 대한 or()의 더 구조화된 대안을 제공합니다. 어떤 옵션 세트가 유효한지 결정하는 명시적 판별자 옵션이 있을 때 사용하세요.

자세한 내용과 예제는 conditional() 문서를 참조하세요.

passThrough()를 이용한 패스스루 옵션

인식되지 않은 옵션을 기본 도구로 전달해야 하는 래퍼 CLI 도구를 구축하고 계신가요? 새로운 passThrough() 파서는 검증 오류 없이 알 수 없는 옵션을 캡처하여 정당한 래퍼/프록시 패턴을 가능하게 합니다.

import { object } from "@optique/core/constructs";
import { option, passThrough } from "@optique/core/primitives";

const parser = object({
 debug: option("--debug"),
 extra: passThrough(),
});

// mycli --debug --foo=bar --baz=qux
// → { debug: true, extra: ["--foo=bar", "--baz=qux"] }

주요 기능:

  • 세 가지 캡처 형식: "equalsOnly" (기본값, 가장 안전), "nextToken" (--opt val 쌍 캡처), "greedy" (남은 모든 토큰 캡처)
  • 가장 낮은 우선순위(-10)로 명시적 파서가 항상 먼저 일치하도록 보장
  • "equalsOnly"와 "nextToken" 모드에서 -- 옵션 종결자 존중
  • object(), 서브커맨드 및 기타 조합기와 원활하게 작동

이 기능은 Docker와 같은 CLI, 빌드 도구 래퍼 또는 다른 프로세스에 명령을 프록시하는 모든 도구를 구축하기 위해 설계되었습니다.

사용 패턴과 모범 사례는 passThrough() 문서를 참조하세요.

LogTape 로깅 통합

새로운 @optique/logtape 패키지는 LogTape와의 원활한 통합을 제공하여 다양한 파싱 전략을 통해 명령줄 인수로 로깅을 구성할 수 있게 합니다.

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

loggingOptions() 프리셋으로 빠르게 시작하기:

import { loggingOptions, createLoggingConfig } from "@optique/logtape";
import { object } from "@optique/core/constructs";
import { parse } from "@optique/core/parser";
import { configure } from "@logtape/logtape";

const parser = object({
 logging: loggingOptions({ level: "verbosity" }),
});

const args = ["-vv", "--log-output=-"];
const result = parse(parser, args);
if (result.success) {
 const config = await createLoggingConfig(result.value.logging);
 await configure(config);
}

이 패키지는 로그 상세도를 제어하기 위한 여러 접근 방식을 제공합니다:

  • verbosity() 파서: 각 플래그가 상세도를 높이는 고전적인 -v/-vv/-vvv 패턴 (플래그 없음 → "warning", -v → "info", -vv → "debug", -vvv → "trace")
  • debug() 파서: 일반 레벨과 디버그 레벨 사이를 전환하는 간단한 --debug/-d 플래그
  • logLevel() 값 파서: 직접 레벨 선택을 위한 명시적 --log-level=debug 옵션
  • logOutput() 파서: 콘솔을 위한 - 또는 파일 출력을 위한 파일 경로로 로그 출력 대상 지정

전체 예제와 구성 옵션은 LogTape 통합 문서를 참조하세요.

버그 수정: 음수 정수 이제 허용

type: "number"를 사용할 때 integer() 값 파서가 음수 정수를 거부하는 문제를 수정했습니다. 정규식 패턴이 /^\d+$/에서 /^-?\d+$/로 업데이트되어 -42와 같은 값을 올바르게 처리합니다. type: "bigint"는 이미 음수 정수를 허용했으므로, 이 변경으로 두 타입 간의 일관성이 확보되었습니다.

설치

# Deno
deno add jsr:@optique/core

# npm
npm add @optique/core

# pnpm
pnpm add @optique/core

# Yarn
yarn add @optique/core

# Bun
bun add @optique/core

LogTape 통합을 위한 설치:

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

# pnpm
pnpm add @optique/logtape @logtape/logtape

# Yarn
yarn add @optique/logtape @logtape/logtape

# Bun
bun add @optique/logtape @logtape/logtape

앞으로의 계획

Optique 0.8.0은 CLI 개발을 더 표현력 있고 타입 안전하게 만드는 데 계속 초점을 맞추고 있습니다. conditional() 조합기는 판별 유니온 패턴을 전면에 내세우고, passThrough()는 새로운 래퍼 도구 사용 사례를 가능하게 하며, LogTape 통합은 로깅 구성을 간편하게 만듭니다.

항상 그렇듯이, 모든 새로운 기능은 완전한 하위 호환성을 유지합니다—기존 파서는 변경 없이 계속 작동합니다.

피드백과 제안을 해주신 커뮤니티에 감사드립니다. 향후 개선 사항에 대한 아이디어가 있거나 문제가 발생하면 GitHub Issues를 통해 알려주세요. Optique와 그 기능에 대한 자세한 정보는 문서를 방문하거나 전체 변경 로그를 확인하세요.

한국어(대한민국):

Optique 0.8.0 출시를 발표하게 되어 기쁩니다! 이번 릴리스는 정교한 CLI 애플리케이션을 구축하기 위한 강력한 새 기능을 소개합니다: 판별 유니온 패턴을 위한 conditional() 조합기, 래퍼 도구를 위한 passThrough() 파서, 그리고 원활한 로깅 구성을 위한 새로운 @optique/logtape 패키지가 포함되어 있습니다.

Optique는 TypeScript를 위한 타입 안전 조합형 CLI 파서로, 조합 가능한 파서와 완전한 타입 추론을 통해 명령줄 인터페이스를 구축하는 함수형 접근 방식을 제공합니다.

conditional()을 이용한 새로운 조건부 파싱

판별자 값에 따라 다른 옵션 세트를 활성화해야 할 필요가 있었나요? 새로운 conditional() 조합기는 이 패턴을 일급 객체로 만듭니다. 특정 판별자 값이 선택되었을 때만 특정 옵션이 유효해지는 판별 유니온을 생성합니다.

import { conditional, object } from "@optique/core/constructs";
import { option } from "@optique/core/primitives";
import { choice, string } from "@optique/core/valueparser";

const parser = conditional(
 option("--reporter", choice(["console", "junit", "html"])),
 {
 console: object({}),
 junit: object({ outputFile: option("--output-file", string()) }),
 html: object({ outputFile: option("--output-file", string()) }),
 }
);
// Result type: ["console", {}] | ["junit", { outputFile: string }] | ...

주요 기능:

  • 명시적 판별자 옵션이 어떤 분기가 선택될지 결정
  • 명확한 타입 좁히기를 위한 튜플 결과 [discriminator, branchValue]
  • 판별자가 제공되지 않을 때를 위한 선택적 기본 분기
  • 각 판별자 값에 필요한 옵션을 명확히 표시하는 오류 메시지

conditional() 파서는 판별 유니온 패턴에 대한 or()의 더 구조화된 대안을 제공합니다. 어떤 옵션 세트가 유효한지 결정하는 명시적 판별자 옵션이 있을 때 사용하세요.

자세한 내용과 예제는 conditional() 문서를 참조하세요.

passThrough()를 이용한 패스스루 옵션

인식되지 않은 옵션을 기본 도구로 전달해야 하는 래퍼 CLI 도구를 구축하고 계신가요? 새로운 passThrough() 파서는 유효성 검사 오류 없이 알 수 없는 옵션을 캡처하여 정당한 래퍼/프록시 패턴을 가능하게 합니다.

import { object } from "@optique/core/constructs";
import { option, passThrough } from "@optique/core/primitives";

const parser = object({
 debug: option("--debug"),
 extra: passThrough(),
});

// mycli --debug --foo=bar --baz=qux
// → { debug: true, extra: ["--foo=bar", "--baz=qux"] }

주요 기능:

  • 세 가지 캡처 형식: "equalsOnly" (기본값, 가장 안전), "nextToken" (--opt val 쌍 캡처), "greedy" (남은 모든 토큰 캡처)
  • 가장 낮은 우선순위(-10)로 명시적 파서가 항상 먼저 일치하도록 보장
  • "equalsOnly"와 "nextToken" 모드에서 -- 옵션 종결자 존중
  • object(), 서브커맨드 및 기타 조합기와 원활하게 작동

이 기능은 Docker와 같은 CLI, 빌드 도구 래퍼 또는 명령을 다른 프로세스로 프록시하는 모든 도구를 구축하기 위해 설계되었습니다.

사용 패턴과 모범 사례는 passThrough() 문서를 참조하세요.

LogTape 로깅 통합

새로운 @optique/logtape 패키지는 LogTape와의 원활한 통합을 제공하여 다양한 파싱 전략을 통해 명령줄 인수로 로깅을 구성할 수 있게 합니다.

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

loggingOptions() 프리셋을 사용한 빠른 시작:

import { loggingOptions, createLoggingConfig } from "@optique/logtape";
import { object } from "@optique/core/constructs";
import { parse } from "@optique/core/parser";
import { configure } from "@logtape/logtape";

const parser = object({
 logging: loggingOptions({ level: "verbosity" }),
});

const args = ["-vv", "--log-output=-"];
const result = parse(parser, args);
if (result.success) {
 const config = await createLoggingConfig(result.value.logging);
 await configure(config);
}

이 패키지는 로그 상세 수준을 제어하기 위한 여러 접근 방식을 제공합니다:

  • verbosity() 파서: 각 플래그가 상세 수준을 높이는 고전적인 -v/-vv/-vvv 패턴 (플래그 없음 → "warning", -v → "info", -vv → "debug", -vvv → "trace")
  • debug() 파서: 일반 수준과 디버그 수준 사이를 전환하는 간단한 --debug/-d 플래그
  • logLevel() 값 파서: 직접적인 수준 선택을 위한 명시적 --log-level=debug 옵션
  • logOutput() 파서: 콘솔을 위한 - 또는 파일 출력을 위한 파일 경로의 로그 출력 대상

전체 예제와 구성 옵션은 LogTape 통합 문서를 참조하세요.

버그 수정: 음수 정수 이제 허용

type: "number"를 사용할 때 integer() 값 파서가 음수 정수를 거부하는 문제가 수정되었습니다. 정규식 패턴이 /^\d+$/에서 /^-?\d+$/로 업데이트되어 -42와 같은 값을 올바르게 처리합니다. type: "bigint"는 이미 음수 정수를 허용했으므로, 이 변경으로 두 타입 간의 일관성이 유지됩니다.

설치

# Deno
deno add jsr:@optique/core

# npm
npm add @optique/core

# pnpm
pnpm add @optique/core

# Yarn
yarn add @optique/core

# Bun
bun add @optique/core

LogTape 통합을 위한 설치:

# Deno
deno add --jsr @optique/logtape @logtape/logtape

# npm
npm add @optique/logtape @logtape/logtape

# pnpm
pnpm add @optique/logtape @logtape/logtape

# Yarn
yarn add @optique/logtape @logtape/logtape

# Bun
bun add @optique/logtape @logtape/logtape

앞으로의 계획

Optique 0.8.0은 CLI 개발을 더 표현력 있고 타입 안전하게 만드는 데 계속 집중하고 있습니다. conditional() 조합기는 판별 유니온 패턴을 전면에 내세우고, passThrough()는 새로운 래퍼 도구 사용 사례를 가능하게 하며, LogTape 통합은 로깅 구성을 쉽게 만듭니다.

항상 그렇듯이, 모든 새로운 기능은 완전한 하위 호환성을 유지합니다—기존 파서는 변경 없이 계속 작동합니다.

피드백과 제안을 해주신 커뮤니티에 감사드립니다. 향후 개선 사항에 대한 아이디어가 있거나 문제가 발생하면 GitHub Issues를 통해 알려주세요. Optique와 그 기능에 대한 자세한 정보는 문서를 방문하거나 전체 변경 로그를 확인하세요.

Construct combinators | Optique

Construct combinators compose multiple parsers into complex structures using object(), tuple(), or(), and merge() to build sophisticated CLI interfaces with full type inference.

Primitive parsers | Optique

Primitive parsers are the foundational building blocks that handle basic CLI elements like options, arguments, commands, and constants with full type safety and clear error messages.

LogTape integration | Optique

Integrate LogTape logging with Optique CLI applications using various parsing strategies for log levels, verbosity flags, and output destinations.

Optique changelog | Optique

Type-safe combinatorial CLI parser for TypeScript
  • Copy link
  • Flag this article
  • Block

bonfire.cafe

A space for Bonfire maintainers and contributors to communicate

bonfire.cafe: About · Code of conduct · Privacy · Users · Instances
Bonfire social · 1.0.1-alpha.40 no JS en
Automatic federation enabled
Log in
  • Explore
  • About
  • Members
  • Code of Conduct