@optique/core 1.0.0-dev.562 → 1.0.0-dev.564

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.
@@ -146,7 +146,9 @@ interface SourceContext<TRequiredOptions = void> {
146
146
  /**
147
147
  * Optional asynchronous cleanup method. Called by `runWith()` in a
148
148
  * `finally` block after parsing completes. Takes precedence over
149
- * `[Symbol.dispose]` in async runners.
149
+ * `[Symbol.dispose]` in async runners. `runWithSync()` also calls this
150
+ * method when `[Symbol.dispose]` is absent, but throws if it returns a
151
+ * Promise.
150
152
  */
151
153
  [Symbol.asyncDispose]?(): void | PromiseLike<void>;
152
154
  }
package/dist/context.d.ts CHANGED
@@ -146,7 +146,9 @@ interface SourceContext<TRequiredOptions = void> {
146
146
  /**
147
147
  * Optional asynchronous cleanup method. Called by `runWith()` in a
148
148
  * `finally` block after parsing completes. Takes precedence over
149
- * `[Symbol.dispose]` in async runners.
149
+ * `[Symbol.dispose]` in async runners. `runWithSync()` also calls this
150
+ * method when `[Symbol.dispose]` is absent, but throws if it returns a
151
+ * Promise.
150
152
  */
151
153
  [Symbol.asyncDispose]?(): void | PromiseLike<void>;
152
154
  }
package/dist/facade.cjs CHANGED
@@ -391,20 +391,8 @@ function classifyResult(result, args, helpOptionNames, helpCommandNames, version
391
391
  function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionCommandDisplayName, completionOptionDisplayName, isOptionMode, sectionOrder) {
392
392
  const shellName = completionArgs[0] || "";
393
393
  const args = completionArgs.slice(1);
394
- const callOnError = (code) => {
395
- try {
396
- return onError(code);
397
- } catch {
398
- return onError();
399
- }
400
- };
401
- const callOnCompletion = (code) => {
402
- try {
403
- return onCompletion(code);
404
- } catch {
405
- return onCompletion();
406
- }
407
- };
394
+ const callOnError = (code) => onError(code);
395
+ const callOnCompletion = (code) => onCompletion(code);
408
396
  if (!shellName) {
409
397
  stderr("Error: Missing shell name for completion.\n");
410
398
  if (completionParser) {
@@ -489,20 +477,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
489
477
  const completionCommandConfig = norm(options.completion?.command);
490
478
  const completionOptionConfig = norm(options.completion?.option);
491
479
  const onCompletion = options.completion?.onShow ?? (() => ({}));
492
- const onCompletionResult = (code) => {
493
- try {
494
- return onCompletion(code);
495
- } catch {
496
- return onCompletion();
497
- }
498
- };
499
- const onErrorResult = (code) => {
500
- try {
501
- return onError(code);
502
- } catch {
503
- return onError();
504
- }
505
- };
480
+ const onCompletionResult = (code) => onCompletion(code);
481
+ const onErrorResult = (code) => onError(code);
506
482
  const helpOptionNames = helpOptionConfig?.names ?? ["--help"];
507
483
  const helpCommandNames = helpCommandConfig?.names ?? ["help"];
508
484
  const versionOptionNames = versionOptionConfig?.names ?? ["--version"];
@@ -565,11 +541,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
565
541
  case "success": return classified.value;
566
542
  case "version":
567
543
  stdout(versionValue);
568
- try {
569
- return onVersion(0);
570
- } catch {
571
- return onVersion();
572
- }
544
+ return onVersion(0);
573
545
  case "completion": throw new RunParserError("Completion should be handled by early return");
574
546
  case "help": {
575
547
  let helpGeneratorParser;
@@ -649,11 +621,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
649
621
  sectionOrder
650
622
  }));
651
623
  }
652
- try {
653
- return onHelp(0);
654
- } catch {
655
- return onHelp();
656
- }
624
+ return onHelp(0);
657
625
  };
658
626
  if (classified.commands.length > 0) {
659
627
  let validationContext = {
@@ -965,16 +933,35 @@ function collectAnnotationsSync(contexts, parsed, options) {
965
933
  * @param contexts Source contexts to dispose.
966
934
  */
967
935
  async function disposeContexts(contexts) {
968
- for (const context of contexts) if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") await context[Symbol.asyncDispose]();
969
- else if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
936
+ const errors = [];
937
+ for (const context of contexts) try {
938
+ if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") await context[Symbol.asyncDispose]();
939
+ else if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
940
+ } catch (error) {
941
+ errors.push(error);
942
+ }
943
+ if (errors.length === 1) throw errors[0];
944
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose one or more source contexts.");
970
945
  }
971
946
  /**
972
947
  * Disposes all contexts that implement `Disposable` synchronously.
948
+ * Falls back to `[Symbol.asyncDispose]` when it completes synchronously.
973
949
  *
974
950
  * @param contexts Source contexts to dispose.
975
951
  */
976
952
  function disposeContextsSync(contexts) {
977
- for (const context of contexts) if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
953
+ const errors = [];
954
+ for (const context of contexts) try {
955
+ if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
956
+ else if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") {
957
+ const result = context[Symbol.asyncDispose]();
958
+ if (typeof result === "object" && result !== null && "then" in result && typeof result.then === "function") throw new TypeError(`Context ${String(context.id)} returned a Promise from Symbol.asyncDispose in sync mode. Use runWith() or runWithAsync() for async disposal.`);
959
+ }
960
+ } catch (error) {
961
+ errors.push(error);
962
+ }
963
+ if (errors.length === 1) throw errors[0];
964
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose one or more source contexts.");
978
965
  }
979
966
  /**
980
967
  * Runs a parser with multiple source contexts.
@@ -1083,7 +1070,8 @@ async function runWith(parser, programName, contexts, options) {
1083
1070
  * @param contexts Source contexts to use (priority: earlier overrides later).
1084
1071
  * @param options Run options including args, help, version, etc.
1085
1072
  * @returns The parsed result.
1086
- * @throws Error if any context returns a Promise.
1073
+ * @throws Error if any context returns a Promise or if a context's
1074
+ * `[Symbol.asyncDispose]` returns a Promise.
1087
1075
  * @since 0.10.0
1088
1076
  */
1089
1077
  function runWithSync(parser, programName, contexts, options) {
package/dist/facade.d.cts CHANGED
@@ -431,7 +431,8 @@ declare function runWith<TParser extends Parser<Mode, unknown, unknown>, TContex
431
431
  * @param contexts Source contexts to use (priority: earlier overrides later).
432
432
  * @param options Run options including args, help, version, etc.
433
433
  * @returns The parsed result.
434
- * @throws Error if any context returns a Promise.
434
+ * @throws Error if any context returns a Promise or if a context's
435
+ * `[Symbol.asyncDispose]` returns a Promise.
435
436
  * @since 0.10.0
436
437
  */
437
438
  declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, TContexts extends readonly SourceContext<unknown>[], THelp = void, TError = never>(parser: TParser, programName: string, contexts: TContexts, options: RunWithOptions<THelp, TError> & ExtractRequiredOptions<TContexts, InferValue<TParser>>): InferValue<TParser>;
package/dist/facade.d.ts CHANGED
@@ -431,7 +431,8 @@ declare function runWith<TParser extends Parser<Mode, unknown, unknown>, TContex
431
431
  * @param contexts Source contexts to use (priority: earlier overrides later).
432
432
  * @param options Run options including args, help, version, etc.
433
433
  * @returns The parsed result.
434
- * @throws Error if any context returns a Promise.
434
+ * @throws Error if any context returns a Promise or if a context's
435
+ * `[Symbol.asyncDispose]` returns a Promise.
435
436
  * @since 0.10.0
436
437
  */
437
438
  declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, TContexts extends readonly SourceContext<unknown>[], THelp = void, TError = never>(parser: TParser, programName: string, contexts: TContexts, options: RunWithOptions<THelp, TError> & ExtractRequiredOptions<TContexts, InferValue<TParser>>): InferValue<TParser>;
package/dist/facade.js CHANGED
@@ -391,20 +391,8 @@ function classifyResult(result, args, helpOptionNames, helpCommandNames, version
391
391
  function handleCompletion(completionArgs, programName, parser, completionParser, stdout, stderr, onCompletion, onError, availableShells, colors, maxWidth, completionCommandDisplayName, completionOptionDisplayName, isOptionMode, sectionOrder) {
392
392
  const shellName = completionArgs[0] || "";
393
393
  const args = completionArgs.slice(1);
394
- const callOnError = (code) => {
395
- try {
396
- return onError(code);
397
- } catch {
398
- return onError();
399
- }
400
- };
401
- const callOnCompletion = (code) => {
402
- try {
403
- return onCompletion(code);
404
- } catch {
405
- return onCompletion();
406
- }
407
- };
394
+ const callOnError = (code) => onError(code);
395
+ const callOnCompletion = (code) => onCompletion(code);
408
396
  if (!shellName) {
409
397
  stderr("Error: Missing shell name for completion.\n");
410
398
  if (completionParser) {
@@ -489,20 +477,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
489
477
  const completionCommandConfig = norm(options.completion?.command);
490
478
  const completionOptionConfig = norm(options.completion?.option);
491
479
  const onCompletion = options.completion?.onShow ?? (() => ({}));
492
- const onCompletionResult = (code) => {
493
- try {
494
- return onCompletion(code);
495
- } catch {
496
- return onCompletion();
497
- }
498
- };
499
- const onErrorResult = (code) => {
500
- try {
501
- return onError(code);
502
- } catch {
503
- return onError();
504
- }
505
- };
480
+ const onCompletionResult = (code) => onCompletion(code);
481
+ const onErrorResult = (code) => onError(code);
506
482
  const helpOptionNames = helpOptionConfig?.names ?? ["--help"];
507
483
  const helpCommandNames = helpCommandConfig?.names ?? ["help"];
508
484
  const versionOptionNames = versionOptionConfig?.names ?? ["--version"];
@@ -565,11 +541,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
565
541
  case "success": return classified.value;
566
542
  case "version":
567
543
  stdout(versionValue);
568
- try {
569
- return onVersion(0);
570
- } catch {
571
- return onVersion();
572
- }
544
+ return onVersion(0);
573
545
  case "completion": throw new RunParserError("Completion should be handled by early return");
574
546
  case "help": {
575
547
  let helpGeneratorParser;
@@ -649,11 +621,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
649
621
  sectionOrder
650
622
  }));
651
623
  }
652
- try {
653
- return onHelp(0);
654
- } catch {
655
- return onHelp();
656
- }
624
+ return onHelp(0);
657
625
  };
658
626
  if (classified.commands.length > 0) {
659
627
  let validationContext = {
@@ -965,16 +933,35 @@ function collectAnnotationsSync(contexts, parsed, options) {
965
933
  * @param contexts Source contexts to dispose.
966
934
  */
967
935
  async function disposeContexts(contexts) {
968
- for (const context of contexts) if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") await context[Symbol.asyncDispose]();
969
- else if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
936
+ const errors = [];
937
+ for (const context of contexts) try {
938
+ if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") await context[Symbol.asyncDispose]();
939
+ else if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
940
+ } catch (error) {
941
+ errors.push(error);
942
+ }
943
+ if (errors.length === 1) throw errors[0];
944
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose one or more source contexts.");
970
945
  }
971
946
  /**
972
947
  * Disposes all contexts that implement `Disposable` synchronously.
948
+ * Falls back to `[Symbol.asyncDispose]` when it completes synchronously.
973
949
  *
974
950
  * @param contexts Source contexts to dispose.
975
951
  */
976
952
  function disposeContextsSync(contexts) {
977
- for (const context of contexts) if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
953
+ const errors = [];
954
+ for (const context of contexts) try {
955
+ if (Symbol.dispose in context && typeof context[Symbol.dispose] === "function") context[Symbol.dispose]();
956
+ else if (Symbol.asyncDispose in context && typeof context[Symbol.asyncDispose] === "function") {
957
+ const result = context[Symbol.asyncDispose]();
958
+ if (typeof result === "object" && result !== null && "then" in result && typeof result.then === "function") throw new TypeError(`Context ${String(context.id)} returned a Promise from Symbol.asyncDispose in sync mode. Use runWith() or runWithAsync() for async disposal.`);
959
+ }
960
+ } catch (error) {
961
+ errors.push(error);
962
+ }
963
+ if (errors.length === 1) throw errors[0];
964
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose one or more source contexts.");
978
965
  }
979
966
  /**
980
967
  * Runs a parser with multiple source contexts.
@@ -1083,7 +1070,8 @@ async function runWith(parser, programName, contexts, options) {
1083
1070
  * @param contexts Source contexts to use (priority: earlier overrides later).
1084
1071
  * @param options Run options including args, help, version, etc.
1085
1072
  * @returns The parsed result.
1086
- * @throws Error if any context returns a Promise.
1073
+ * @throws Error if any context returns a Promise or if a context's
1074
+ * `[Symbol.asyncDispose]` returns a Promise.
1087
1075
  * @since 0.10.0
1088
1076
  */
1089
1077
  function runWithSync(parser, programName, contexts, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.562+295508a4",
3
+ "version": "1.0.0-dev.564+e2374449",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",