@optique/core 1.0.0-dev.661 → 1.0.0-dev.667

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.
@@ -16,6 +16,13 @@
16
16
  */
17
17
  const annotationKey = Symbol.for("@optique/core/parser/annotation");
18
18
  /**
19
+ * Internal marker attached during the first pass of `runWith()` so wrappers
20
+ * with side effects can defer work until dynamic contexts have resolved.
21
+ *
22
+ * @internal
23
+ */
24
+ const firstPassAnnotationKey = Symbol.for("@optique/core/parser/firstPass");
25
+ /**
19
26
  * Internal key for preserving primitive parser state values when annotations
20
27
  * are injected into non-object states.
21
28
  * @internal
@@ -234,6 +241,7 @@ exports.annotateFreshArray = annotateFreshArray;
234
241
  exports.annotationKey = annotationKey;
235
242
  exports.annotationStateValueKey = annotationStateValueKey;
236
243
  exports.annotationWrapperKey = annotationWrapperKey;
244
+ exports.firstPassAnnotationKey = firstPassAnnotationKey;
237
245
  exports.getAnnotations = getAnnotations;
238
246
  exports.inheritAnnotations = inheritAnnotations;
239
247
  exports.injectAnnotations = injectAnnotations;
@@ -14,6 +14,13 @@
14
14
  * @since 0.10.0
15
15
  */
16
16
  declare const annotationKey: unique symbol;
17
+ /**
18
+ * Internal marker attached during the first pass of `runWith()` so wrappers
19
+ * with side effects can defer work until dynamic contexts have resolved.
20
+ *
21
+ * @internal
22
+ */
23
+ declare const firstPassAnnotationKey: unique symbol;
17
24
  /**
18
25
  * Internal key for preserving primitive parser state values when annotations
19
26
  * are injected into non-object states.
@@ -127,4 +134,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
127
134
  */
128
135
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
129
136
  //#endregion
130
- export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
137
+ export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
@@ -14,6 +14,13 @@
14
14
  * @since 0.10.0
15
15
  */
16
16
  declare const annotationKey: unique symbol;
17
+ /**
18
+ * Internal marker attached during the first pass of `runWith()` so wrappers
19
+ * with side effects can defer work until dynamic contexts have resolved.
20
+ *
21
+ * @internal
22
+ */
23
+ declare const firstPassAnnotationKey: unique symbol;
17
24
  /**
18
25
  * Internal key for preserving primitive parser state values when annotations
19
26
  * are injected into non-object states.
@@ -127,4 +134,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
127
134
  */
128
135
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
129
136
  //#endregion
130
- export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
137
+ export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
@@ -15,6 +15,13 @@
15
15
  */
16
16
  const annotationKey = Symbol.for("@optique/core/parser/annotation");
17
17
  /**
18
+ * Internal marker attached during the first pass of `runWith()` so wrappers
19
+ * with side effects can defer work until dynamic contexts have resolved.
20
+ *
21
+ * @internal
22
+ */
23
+ const firstPassAnnotationKey = Symbol.for("@optique/core/parser/firstPass");
24
+ /**
18
25
  * Internal key for preserving primitive parser state values when annotations
19
26
  * are injected into non-object states.
20
27
  * @internal
@@ -229,4 +236,4 @@ function isInjectedAnnotationWrapper(value) {
229
236
  }
230
237
 
231
238
  //#endregion
232
- export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
239
+ export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
@@ -1,3 +1,4 @@
1
+ const require_annotations = require('./annotations.cjs');
1
2
  const require_message = require('./message.cjs');
2
3
  const require_dependency = require('./dependency.cjs');
3
4
  const require_mode_dispatch = require('./mode-dispatch.cjs');
@@ -6,6 +7,7 @@ const require_suggestion = require('./suggestion.cjs');
6
7
  const require_usage_internals = require('./usage-internals.cjs');
7
8
 
8
9
  //#region src/constructs.ts
10
+ const inheritParentAnnotationsKey = Symbol.for("@optique/core/inheritParentAnnotations");
9
11
  function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
10
12
  const options = /* @__PURE__ */ new Set();
11
13
  const commands = /* @__PURE__ */ new Set();
@@ -842,6 +844,31 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
842
844
  for (const key of parserKeys) state[key] = parsers[key].initialState;
843
845
  return state;
844
846
  };
847
+ const inheritedFieldStateCache = /* @__PURE__ */ new WeakMap();
848
+ const createFieldStateGetter = (parentState) => {
849
+ return (field, parser) => {
850
+ const fieldKey = field;
851
+ const cache = parentState != null && typeof parentState === "object" ? inheritedFieldStateCache.get(parentState) ?? (() => {
852
+ const stateCache = /* @__PURE__ */ new Map();
853
+ inheritedFieldStateCache.set(parentState, stateCache);
854
+ return stateCache;
855
+ })() : void 0;
856
+ if (cache?.has(fieldKey)) return cache.get(fieldKey);
857
+ const sourceState = parentState != null && typeof parentState === "object" && fieldKey in parentState ? parentState[fieldKey] : parser.initialState;
858
+ if (sourceState == null || typeof sourceState !== "object") {
859
+ cache?.set(fieldKey, sourceState);
860
+ return sourceState;
861
+ }
862
+ const annotations = require_annotations.getAnnotations(parentState);
863
+ if (annotations === void 0 || require_annotations.getAnnotations(sourceState) === annotations) {
864
+ cache?.set(fieldKey, sourceState);
865
+ return sourceState;
866
+ }
867
+ const inheritedState = Reflect.get(parser, inheritParentAnnotationsKey) === true ? require_annotations.injectAnnotations(sourceState, annotations) : require_annotations.inheritAnnotations(parentState, sourceState);
868
+ cache?.set(fieldKey, inheritedState);
869
+ return inheritedState;
870
+ };
871
+ };
845
872
  if (!options.allowDuplicates) checkDuplicateOptionNames(parserPairs.map(([field, parser]) => [field, parser.usage]));
846
873
  const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
847
874
  const combinedMode = parserKeys.some((k) => parsers[k].$mode === "async") ? "async" : "sync";
@@ -866,10 +893,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
866
893
  let madeProgress = true;
867
894
  while (madeProgress && currentContext.buffer.length > 0) {
868
895
  madeProgress = false;
896
+ const getFieldState = createFieldStateGetter(currentContext.state);
869
897
  for (const [field, parser] of parserPairs) {
870
898
  const result = parser.parse({
871
899
  ...currentContext,
872
- state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
900
+ state: getFieldState(field, parser)
873
901
  });
874
902
  if (result.success && result.consumed.length > 0) {
875
903
  currentContext = {
@@ -895,8 +923,9 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
895
923
  };
896
924
  if (context.buffer.length === 0) {
897
925
  let allCanComplete = true;
926
+ const getFieldState = createFieldStateGetter(context.state);
898
927
  for (const [field, parser] of parserPairs) {
899
- const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
928
+ const fieldState = getFieldState(field, parser);
900
929
  const completeResult = parser.complete(fieldState);
901
930
  if (!completeResult.success) {
902
931
  allCanComplete = false;
@@ -922,10 +951,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
922
951
  let madeProgress = true;
923
952
  while (madeProgress && currentContext.buffer.length > 0) {
924
953
  madeProgress = false;
954
+ const getFieldState = createFieldStateGetter(currentContext.state);
925
955
  for (const [field, parser] of parserPairs) {
926
956
  const resultOrPromise = parser.parse({
927
957
  ...currentContext,
928
- state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
958
+ state: getFieldState(field, parser)
929
959
  });
930
960
  const result = await resultOrPromise;
931
961
  if (result.success && result.consumed.length > 0) {
@@ -952,8 +982,9 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
952
982
  };
953
983
  if (context.buffer.length === 0) {
954
984
  let allCanComplete = true;
985
+ const getFieldState = createFieldStateGetter(context.state);
955
986
  for (const [field, parser] of parserPairs) {
956
- const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
987
+ const fieldState = getFieldState(field, parser);
957
988
  const completeResult = await parser.complete(fieldState);
958
989
  if (!completeResult.success) {
959
990
  allCanComplete = false;
@@ -987,6 +1018,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
987
1018
  return require_mode_dispatch.dispatchByMode(combinedMode, () => {
988
1019
  const preCompletedState = {};
989
1020
  const preCompletedKeys = /* @__PURE__ */ new Set();
1021
+ const getFieldState = createFieldStateGetter(state);
990
1022
  for (const field of parserKeys) {
991
1023
  const fieldKey = field;
992
1024
  const fieldState = state[fieldKey];
@@ -1006,10 +1038,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1006
1038
  preCompletedState[fieldKey] = completed;
1007
1039
  preCompletedKeys.add(fieldKey);
1008
1040
  } else preCompletedState[fieldKey] = fieldState;
1009
- } else preCompletedState[fieldKey] = fieldState;
1041
+ } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1010
1042
  }
1011
1043
  const resolvedState = resolveDeferredParseStates(preCompletedState);
1012
1044
  const result = {};
1045
+ const getCompletionFieldState = createFieldStateGetter(state);
1013
1046
  for (const field of parserKeys) {
1014
1047
  const fieldKey = field;
1015
1048
  const fieldResolvedState = resolvedState[fieldKey];
@@ -1023,7 +1056,8 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1023
1056
  };
1024
1057
  continue;
1025
1058
  }
1026
- const valueResult = fieldParser.complete(fieldResolvedState);
1059
+ const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1060
+ const valueResult = fieldParser.complete(completionState);
1027
1061
  if (valueResult.success) result[fieldKey] = valueResult.value;
1028
1062
  else return {
1029
1063
  success: false,
@@ -1037,6 +1071,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1037
1071
  }, async () => {
1038
1072
  const preCompletedState = {};
1039
1073
  const preCompletedKeys = /* @__PURE__ */ new Set();
1074
+ const getFieldState = createFieldStateGetter(state);
1040
1075
  for (const field of parserKeys) {
1041
1076
  const fieldKey = field;
1042
1077
  const fieldState = state[fieldKey];
@@ -1056,10 +1091,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1056
1091
  preCompletedState[fieldKey] = completed;
1057
1092
  preCompletedKeys.add(fieldKey);
1058
1093
  } else preCompletedState[fieldKey] = fieldState;
1059
- } else preCompletedState[fieldKey] = fieldState;
1094
+ } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1060
1095
  }
1061
1096
  const resolvedState = await resolveDeferredParseStatesAsync(preCompletedState);
1062
1097
  const result = {};
1098
+ const getCompletionFieldState = createFieldStateGetter(state);
1063
1099
  for (const field of parserKeys) {
1064
1100
  const fieldKey = field;
1065
1101
  const fieldResolvedState = resolvedState[fieldKey];
@@ -1073,7 +1109,8 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1073
1109
  };
1074
1110
  continue;
1075
1111
  }
1076
- const valueResult = await fieldParser.complete(fieldResolvedState);
1112
+ const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1113
+ const valueResult = await fieldParser.complete(completionState);
1077
1114
  if (valueResult.success) result[fieldKey] = valueResult.value;
1078
1115
  else return {
1079
1116
  success: false,
@@ -1,3 +1,4 @@
1
+ import { getAnnotations, inheritAnnotations, injectAnnotations } from "./annotations.js";
1
2
  import { message, optionName, text, values } from "./message.js";
2
3
  import { DependencyRegistry, dependencyId, isDeferredParseState, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, wrappedDependencySourceMarker } from "./dependency.js";
3
4
  import { dispatchByMode, dispatchIterableByMode } from "./mode-dispatch.js";
@@ -6,6 +7,7 @@ import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggest
6
7
  import { collectLeadingCandidates } from "./usage-internals.js";
7
8
 
8
9
  //#region src/constructs.ts
10
+ const inheritParentAnnotationsKey = Symbol.for("@optique/core/inheritParentAnnotations");
9
11
  function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput, parsers, customFormatter) {
10
12
  const options = /* @__PURE__ */ new Set();
11
13
  const commands = /* @__PURE__ */ new Set();
@@ -842,6 +844,31 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
842
844
  for (const key of parserKeys) state[key] = parsers[key].initialState;
843
845
  return state;
844
846
  };
847
+ const inheritedFieldStateCache = /* @__PURE__ */ new WeakMap();
848
+ const createFieldStateGetter = (parentState) => {
849
+ return (field, parser) => {
850
+ const fieldKey = field;
851
+ const cache = parentState != null && typeof parentState === "object" ? inheritedFieldStateCache.get(parentState) ?? (() => {
852
+ const stateCache = /* @__PURE__ */ new Map();
853
+ inheritedFieldStateCache.set(parentState, stateCache);
854
+ return stateCache;
855
+ })() : void 0;
856
+ if (cache?.has(fieldKey)) return cache.get(fieldKey);
857
+ const sourceState = parentState != null && typeof parentState === "object" && fieldKey in parentState ? parentState[fieldKey] : parser.initialState;
858
+ if (sourceState == null || typeof sourceState !== "object") {
859
+ cache?.set(fieldKey, sourceState);
860
+ return sourceState;
861
+ }
862
+ const annotations = getAnnotations(parentState);
863
+ if (annotations === void 0 || getAnnotations(sourceState) === annotations) {
864
+ cache?.set(fieldKey, sourceState);
865
+ return sourceState;
866
+ }
867
+ const inheritedState = Reflect.get(parser, inheritParentAnnotationsKey) === true ? injectAnnotations(sourceState, annotations) : inheritAnnotations(parentState, sourceState);
868
+ cache?.set(fieldKey, inheritedState);
869
+ return inheritedState;
870
+ };
871
+ };
845
872
  if (!options.allowDuplicates) checkDuplicateOptionNames(parserPairs.map(([field, parser]) => [field, parser.usage]));
846
873
  const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
847
874
  const combinedMode = parserKeys.some((k) => parsers[k].$mode === "async") ? "async" : "sync";
@@ -866,10 +893,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
866
893
  let madeProgress = true;
867
894
  while (madeProgress && currentContext.buffer.length > 0) {
868
895
  madeProgress = false;
896
+ const getFieldState = createFieldStateGetter(currentContext.state);
869
897
  for (const [field, parser] of parserPairs) {
870
898
  const result = parser.parse({
871
899
  ...currentContext,
872
- state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
900
+ state: getFieldState(field, parser)
873
901
  });
874
902
  if (result.success && result.consumed.length > 0) {
875
903
  currentContext = {
@@ -895,8 +923,9 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
895
923
  };
896
924
  if (context.buffer.length === 0) {
897
925
  let allCanComplete = true;
926
+ const getFieldState = createFieldStateGetter(context.state);
898
927
  for (const [field, parser] of parserPairs) {
899
- const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
928
+ const fieldState = getFieldState(field, parser);
900
929
  const completeResult = parser.complete(fieldState);
901
930
  if (!completeResult.success) {
902
931
  allCanComplete = false;
@@ -922,10 +951,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
922
951
  let madeProgress = true;
923
952
  while (madeProgress && currentContext.buffer.length > 0) {
924
953
  madeProgress = false;
954
+ const getFieldState = createFieldStateGetter(currentContext.state);
925
955
  for (const [field, parser] of parserPairs) {
926
956
  const resultOrPromise = parser.parse({
927
957
  ...currentContext,
928
- state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
958
+ state: getFieldState(field, parser)
929
959
  });
930
960
  const result = await resultOrPromise;
931
961
  if (result.success && result.consumed.length > 0) {
@@ -952,8 +982,9 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
952
982
  };
953
983
  if (context.buffer.length === 0) {
954
984
  let allCanComplete = true;
985
+ const getFieldState = createFieldStateGetter(context.state);
955
986
  for (const [field, parser] of parserPairs) {
956
- const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
987
+ const fieldState = getFieldState(field, parser);
957
988
  const completeResult = await parser.complete(fieldState);
958
989
  if (!completeResult.success) {
959
990
  allCanComplete = false;
@@ -987,6 +1018,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
987
1018
  return dispatchByMode(combinedMode, () => {
988
1019
  const preCompletedState = {};
989
1020
  const preCompletedKeys = /* @__PURE__ */ new Set();
1021
+ const getFieldState = createFieldStateGetter(state);
990
1022
  for (const field of parserKeys) {
991
1023
  const fieldKey = field;
992
1024
  const fieldState = state[fieldKey];
@@ -1006,10 +1038,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1006
1038
  preCompletedState[fieldKey] = completed;
1007
1039
  preCompletedKeys.add(fieldKey);
1008
1040
  } else preCompletedState[fieldKey] = fieldState;
1009
- } else preCompletedState[fieldKey] = fieldState;
1041
+ } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1010
1042
  }
1011
1043
  const resolvedState = resolveDeferredParseStates(preCompletedState);
1012
1044
  const result = {};
1045
+ const getCompletionFieldState = createFieldStateGetter(state);
1013
1046
  for (const field of parserKeys) {
1014
1047
  const fieldKey = field;
1015
1048
  const fieldResolvedState = resolvedState[fieldKey];
@@ -1023,7 +1056,8 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1023
1056
  };
1024
1057
  continue;
1025
1058
  }
1026
- const valueResult = fieldParser.complete(fieldResolvedState);
1059
+ const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1060
+ const valueResult = fieldParser.complete(completionState);
1027
1061
  if (valueResult.success) result[fieldKey] = valueResult.value;
1028
1062
  else return {
1029
1063
  success: false,
@@ -1037,6 +1071,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1037
1071
  }, async () => {
1038
1072
  const preCompletedState = {};
1039
1073
  const preCompletedKeys = /* @__PURE__ */ new Set();
1074
+ const getFieldState = createFieldStateGetter(state);
1040
1075
  for (const field of parserKeys) {
1041
1076
  const fieldKey = field;
1042
1077
  const fieldState = state[fieldKey];
@@ -1056,10 +1091,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1056
1091
  preCompletedState[fieldKey] = completed;
1057
1092
  preCompletedKeys.add(fieldKey);
1058
1093
  } else preCompletedState[fieldKey] = fieldState;
1059
- } else preCompletedState[fieldKey] = fieldState;
1094
+ } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1060
1095
  }
1061
1096
  const resolvedState = await resolveDeferredParseStatesAsync(preCompletedState);
1062
1097
  const result = {};
1098
+ const getCompletionFieldState = createFieldStateGetter(state);
1063
1099
  for (const field of parserKeys) {
1064
1100
  const fieldKey = field;
1065
1101
  const fieldResolvedState = resolvedState[fieldKey];
@@ -1073,7 +1109,8 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1073
1109
  };
1074
1110
  continue;
1075
1111
  }
1076
- const valueResult = await fieldParser.complete(fieldResolvedState);
1112
+ const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1113
+ const valueResult = await fieldParser.complete(completionState);
1077
1114
  if (valueResult.success) result[fieldKey] = valueResult.value;
1078
1115
  else return {
1079
1116
  success: false,
package/dist/facade.cjs CHANGED
@@ -11,6 +11,159 @@ const require_primitives = require('./primitives.cjs');
11
11
  const require_parser = require('./parser.cjs');
12
12
 
13
13
  //#region src/facade.ts
14
+ const phase1ConfigAnnotationsKey = Symbol.for("@optique/config/phase1PromptAnnotations");
15
+ const phase2UndefinedParsedValueKey = Symbol.for("@optique/config/phase2UndefinedParsedValue");
16
+ const deferredPromptValueKey = Symbol.for("@optique/inquirer/deferredPromptValue");
17
+ function isDeferredPromptValue(value$1) {
18
+ return value$1 != null && typeof value$1 === "object" && deferredPromptValueKey in value$1;
19
+ }
20
+ function isPlainObject(value$1) {
21
+ const proto = Object.getPrototypeOf(value$1);
22
+ return proto === Object.prototype || proto === null;
23
+ }
24
+ function shouldSkipCollectionOwnKey(value$1, key) {
25
+ if (Array.isArray(value$1)) return key === "length" || typeof key === "string" && Number.isInteger(Number(key)) && String(Number(key)) === key;
26
+ return false;
27
+ }
28
+ function containsDeferredPromptValuesInOwnProperties(value$1, seen) {
29
+ for (const key of Reflect.ownKeys(value$1)) {
30
+ if (shouldSkipCollectionOwnKey(value$1, key)) continue;
31
+ const descriptor = Object.getOwnPropertyDescriptor(value$1, key);
32
+ if (descriptor != null && "value" in descriptor && containsDeferredPromptValuesForContexts(descriptor.value, seen)) return true;
33
+ }
34
+ return false;
35
+ }
36
+ function copySanitizedOwnProperties(source, target, seen) {
37
+ for (const key of Reflect.ownKeys(source)) {
38
+ if (shouldSkipCollectionOwnKey(source, key)) continue;
39
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
40
+ if (descriptor == null) continue;
41
+ if ("value" in descriptor) descriptor.value = stripDeferredPromptValuesForContexts(descriptor.value, seen);
42
+ Object.defineProperty(target, key, descriptor);
43
+ }
44
+ }
45
+ function createArrayCloneLike(value$1) {
46
+ try {
47
+ const arrayCtor = value$1.constructor;
48
+ return Reflect.construct(Array, [value$1.length], arrayCtor);
49
+ } catch {
50
+ return new Array(value$1.length);
51
+ }
52
+ }
53
+ function createSetCloneLike(value$1) {
54
+ try {
55
+ const setCtor = value$1.constructor;
56
+ return Reflect.construct(Set, [], setCtor);
57
+ } catch {
58
+ return /* @__PURE__ */ new Set();
59
+ }
60
+ }
61
+ function createMapCloneLike(value$1) {
62
+ try {
63
+ const mapCtor = value$1.constructor;
64
+ return Reflect.construct(Map, [], mapCtor);
65
+ } catch {
66
+ return /* @__PURE__ */ new Map();
67
+ }
68
+ }
69
+ function containsDeferredPromptValuesForContexts(value$1, seen = /* @__PURE__ */ new WeakSet()) {
70
+ if (isDeferredPromptValue(value$1)) return true;
71
+ if (value$1 == null || typeof value$1 !== "object") return false;
72
+ if (seen.has(value$1)) return false;
73
+ seen.add(value$1);
74
+ if (Array.isArray(value$1)) {
75
+ if (value$1.some((item) => containsDeferredPromptValuesForContexts(item, seen))) return true;
76
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
77
+ }
78
+ if (value$1 instanceof Set) {
79
+ for (const entryValue of value$1) if (containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
80
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
81
+ }
82
+ if (value$1 instanceof Map) {
83
+ for (const [key, entryValue] of value$1) if (containsDeferredPromptValuesForContexts(key, seen) || containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
84
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
85
+ }
86
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
87
+ }
88
+ function stripDeferredPromptValuesForContexts(value$1, seen = /* @__PURE__ */ new WeakMap()) {
89
+ if (isDeferredPromptValue(value$1)) return void 0;
90
+ if (value$1 == null || typeof value$1 !== "object") return value$1;
91
+ const cached = seen.get(value$1);
92
+ if (cached !== void 0) return cached;
93
+ if (Array.isArray(value$1)) {
94
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
95
+ const clone$1 = createArrayCloneLike(value$1);
96
+ seen.set(value$1, clone$1);
97
+ for (let i = 0; i < value$1.length; i++) clone$1[i] = stripDeferredPromptValuesForContexts(value$1[i], seen);
98
+ copySanitizedOwnProperties(value$1, clone$1, seen);
99
+ return clone$1;
100
+ }
101
+ if (value$1 instanceof Set) {
102
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
103
+ const clone$1 = createSetCloneLike(value$1);
104
+ seen.set(value$1, clone$1);
105
+ for (const entryValue of value$1) clone$1.add(stripDeferredPromptValuesForContexts(entryValue, seen));
106
+ copySanitizedOwnProperties(value$1, clone$1, seen);
107
+ return clone$1;
108
+ }
109
+ if (value$1 instanceof Map) {
110
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
111
+ const clone$1 = createMapCloneLike(value$1);
112
+ seen.set(value$1, clone$1);
113
+ for (const [key, entryValue] of value$1) clone$1.set(stripDeferredPromptValuesForContexts(key, seen), stripDeferredPromptValuesForContexts(entryValue, seen));
114
+ copySanitizedOwnProperties(value$1, clone$1, seen);
115
+ return clone$1;
116
+ }
117
+ if (!isPlainObject(value$1)) {
118
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
119
+ return createSanitizedNonPlainContextView(value$1, seen);
120
+ }
121
+ const clone = Object.create(Object.getPrototypeOf(value$1));
122
+ seen.set(value$1, clone);
123
+ for (const key of Reflect.ownKeys(value$1)) {
124
+ const descriptor = Object.getOwnPropertyDescriptor(value$1, key);
125
+ if (descriptor == null) continue;
126
+ if ("value" in descriptor) descriptor.value = stripDeferredPromptValuesForContexts(descriptor.value, seen);
127
+ Object.defineProperty(clone, key, descriptor);
128
+ }
129
+ return clone;
130
+ }
131
+ function finalizeParsedForContext(context, parsed) {
132
+ if (parsed !== void 0 || !Reflect.has(context, phase1ConfigAnnotationsKey)) return parsed;
133
+ return { [phase2UndefinedParsedValueKey]: true };
134
+ }
135
+ function createSanitizedNonPlainContextView(value$1, seen) {
136
+ const proxy = new Proxy(value$1, {
137
+ get(target, key, receiver) {
138
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
139
+ if (descriptor != null && "value" in descriptor) return stripDeferredPromptValuesForContexts(descriptor.value, seen);
140
+ return Reflect.get(target, key, receiver);
141
+ },
142
+ getOwnPropertyDescriptor(target, key) {
143
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
144
+ if (descriptor == null || !("value" in descriptor)) return descriptor;
145
+ return {
146
+ ...descriptor,
147
+ value: stripDeferredPromptValuesForContexts(descriptor.value, seen)
148
+ };
149
+ }
150
+ });
151
+ seen.set(value$1, proxy);
152
+ return proxy;
153
+ }
154
+ function prepareParsedForContexts(parsed) {
155
+ if (parsed == null || typeof parsed !== "object") return stripDeferredPromptValuesForContexts(parsed);
156
+ if (isDeferredPromptValue(parsed)) return void 0;
157
+ if (Array.isArray(parsed) || isPlainObject(parsed) || parsed instanceof Set || parsed instanceof Map) {
158
+ if (!containsDeferredPromptValuesForContexts(parsed)) return parsed;
159
+ return stripDeferredPromptValuesForContexts(parsed);
160
+ }
161
+ if (!containsDeferredPromptValuesForContexts(parsed)) return parsed;
162
+ return createSanitizedNonPlainContextView(parsed, /* @__PURE__ */ new WeakMap());
163
+ }
164
+ function withPreparedParsedForContext(context, preparedParsed, run) {
165
+ return run(finalizeParsedForContext(context, preparedParsed));
166
+ }
14
167
  /**
15
168
  * Creates help parsers based on the sub-config.
16
169
  */
@@ -850,10 +1003,14 @@ async function collectPhase1Annotations(contexts, options) {
850
1003
  for (const context of contexts) {
851
1004
  const result = context.getAnnotations(void 0, options);
852
1005
  hasDynamic ||= needsTwoPhaseContext(context, result);
853
- annotationsList.push(result instanceof Promise ? await result : result);
1006
+ const annotations = result instanceof Promise ? await result : result;
1007
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1008
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, void 0, annotations) : void 0;
1009
+ annotationsList.push(internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]));
854
1010
  }
855
1011
  return {
856
1012
  annotations: mergeAnnotations(annotationsList),
1013
+ annotationsList,
857
1014
  hasDynamic
858
1015
  };
859
1016
  }
@@ -867,11 +1024,21 @@ async function collectPhase1Annotations(contexts, options) {
867
1024
  */
868
1025
  async function collectAnnotations(contexts, parsed, options) {
869
1026
  const annotationsList = [];
1027
+ const preparedParsed = prepareParsedForContexts(parsed);
870
1028
  for (const context of contexts) {
871
- const result = context.getAnnotations(parsed, options);
872
- annotationsList.push(result instanceof Promise ? await result : result);
1029
+ const mergedAnnotations = await withPreparedParsedForContext(context, preparedParsed, async (contextParsed) => {
1030
+ const result = context.getAnnotations(contextParsed, options);
1031
+ const annotations = result instanceof Promise ? await result : result;
1032
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1033
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, contextParsed, annotations) : void 0;
1034
+ return internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]);
1035
+ });
1036
+ annotationsList.push(mergedAnnotations);
873
1037
  }
874
- return mergeAnnotations(annotationsList);
1038
+ return {
1039
+ annotations: mergeAnnotations(annotationsList),
1040
+ annotationsList
1041
+ };
875
1042
  }
876
1043
  /**
877
1044
  * Collects phase 1 annotations from all contexts synchronously and determines
@@ -889,10 +1056,13 @@ function collectPhase1AnnotationsSync(contexts, options) {
889
1056
  const result = context.getAnnotations(void 0, options);
890
1057
  if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
891
1058
  hasDynamic ||= needsTwoPhaseContext(context, result);
892
- annotationsList.push(result);
1059
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1060
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, void 0, result) : void 0;
1061
+ annotationsList.push(internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]));
893
1062
  }
894
1063
  return {
895
1064
  annotations: mergeAnnotations(annotationsList),
1065
+ annotationsList,
896
1066
  hasDynamic
897
1067
  };
898
1068
  }
@@ -919,12 +1089,27 @@ function needsTwoPhaseContext(context, result) {
919
1089
  */
920
1090
  function collectAnnotationsSync(contexts, parsed, options) {
921
1091
  const annotationsList = [];
1092
+ const preparedParsed = prepareParsedForContexts(parsed);
922
1093
  for (const context of contexts) {
923
- const result = context.getAnnotations(parsed, options);
924
- if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
925
- annotationsList.push(result);
1094
+ const mergedAnnotations = withPreparedParsedForContext(context, preparedParsed, (contextParsed) => {
1095
+ const result = context.getAnnotations(contextParsed, options);
1096
+ if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
1097
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1098
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, contextParsed, result) : void 0;
1099
+ return internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]);
1100
+ });
1101
+ annotationsList.push(mergedAnnotations);
926
1102
  }
927
- return mergeAnnotations(annotationsList);
1103
+ return {
1104
+ annotations: mergeAnnotations(annotationsList),
1105
+ annotationsList
1106
+ };
1107
+ }
1108
+ function mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList) {
1109
+ const mergedPerContext = [];
1110
+ const length = Math.max(phase1AnnotationsList.length, phase2AnnotationsList.length);
1111
+ for (let i = 0; i < length; i++) mergedPerContext.push(mergeAnnotations([phase2AnnotationsList[i] ?? {}, phase1AnnotationsList[i] ?? {}]));
1112
+ return mergeAnnotations(mergedPerContext);
928
1113
  }
929
1114
  /**
930
1115
  * Disposes all contexts that implement `AsyncDisposable` or `Disposable`.
@@ -1022,7 +1207,7 @@ async function runWith(parser, programName, contexts, options) {
1022
1207
  return Promise.resolve(runParser(parser, programName, args, options));
1023
1208
  }
1024
1209
  try {
1025
- const { annotations: phase1Annotations, hasDynamic: needsTwoPhase } = await collectPhase1Annotations(contexts, options);
1210
+ const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = await collectPhase1Annotations(contexts, options);
1026
1211
  if (!needsTwoPhase) {
1027
1212
  const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
1028
1213
  if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
@@ -1047,8 +1232,8 @@ async function runWith(parser, programName, contexts, options) {
1047
1232
  if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
1048
1233
  return Promise.resolve(runParser(augmentedParser, programName, args, options));
1049
1234
  }
1050
- const phase2Annotations = await collectAnnotations(contexts, firstPassResult, options);
1051
- const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
1235
+ const { annotationsList: phase2AnnotationsList } = await collectAnnotations(contexts, firstPassResult, options);
1236
+ const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
1052
1237
  const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
1053
1238
  if (parser.$mode === "async") return runParser(augmentedParser2, programName, args, options);
1054
1239
  return Promise.resolve(runParser(augmentedParser2, programName, args, options));
@@ -1079,7 +1264,7 @@ function runWithSync(parser, programName, contexts, options) {
1079
1264
  if (needsEarlyExit(args, options)) return runParser(parser, programName, args, options);
1080
1265
  if (contexts.length === 0) return runParser(parser, programName, args, options);
1081
1266
  try {
1082
- const { annotations: phase1Annotations, hasDynamic: needsTwoPhase } = collectPhase1AnnotationsSync(contexts, options);
1267
+ const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = collectPhase1AnnotationsSync(contexts, options);
1083
1268
  if (!needsTwoPhase) {
1084
1269
  const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
1085
1270
  return runParser(augmentedParser, programName, args, options);
@@ -1093,8 +1278,8 @@ function runWithSync(parser, programName, contexts, options) {
1093
1278
  } catch {
1094
1279
  return runParser(augmentedParser1, programName, args, options);
1095
1280
  }
1096
- const phase2Annotations = collectAnnotationsSync(contexts, firstPassResult, options);
1097
- const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
1281
+ const { annotationsList: phase2AnnotationsList } = collectAnnotationsSync(contexts, firstPassResult, options);
1282
+ const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
1098
1283
  const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
1099
1284
  return runParser(augmentedParser2, programName, args, options);
1100
1285
  } finally {
package/dist/facade.js CHANGED
@@ -11,6 +11,159 @@ import { argument, command, constant, flag, option } from "./primitives.js";
11
11
  import { getDocPage, parseAsync, parseSync, suggest, suggestAsync } from "./parser.js";
12
12
 
13
13
  //#region src/facade.ts
14
+ const phase1ConfigAnnotationsKey = Symbol.for("@optique/config/phase1PromptAnnotations");
15
+ const phase2UndefinedParsedValueKey = Symbol.for("@optique/config/phase2UndefinedParsedValue");
16
+ const deferredPromptValueKey = Symbol.for("@optique/inquirer/deferredPromptValue");
17
+ function isDeferredPromptValue(value$1) {
18
+ return value$1 != null && typeof value$1 === "object" && deferredPromptValueKey in value$1;
19
+ }
20
+ function isPlainObject(value$1) {
21
+ const proto = Object.getPrototypeOf(value$1);
22
+ return proto === Object.prototype || proto === null;
23
+ }
24
+ function shouldSkipCollectionOwnKey(value$1, key) {
25
+ if (Array.isArray(value$1)) return key === "length" || typeof key === "string" && Number.isInteger(Number(key)) && String(Number(key)) === key;
26
+ return false;
27
+ }
28
+ function containsDeferredPromptValuesInOwnProperties(value$1, seen) {
29
+ for (const key of Reflect.ownKeys(value$1)) {
30
+ if (shouldSkipCollectionOwnKey(value$1, key)) continue;
31
+ const descriptor = Object.getOwnPropertyDescriptor(value$1, key);
32
+ if (descriptor != null && "value" in descriptor && containsDeferredPromptValuesForContexts(descriptor.value, seen)) return true;
33
+ }
34
+ return false;
35
+ }
36
+ function copySanitizedOwnProperties(source, target, seen) {
37
+ for (const key of Reflect.ownKeys(source)) {
38
+ if (shouldSkipCollectionOwnKey(source, key)) continue;
39
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
40
+ if (descriptor == null) continue;
41
+ if ("value" in descriptor) descriptor.value = stripDeferredPromptValuesForContexts(descriptor.value, seen);
42
+ Object.defineProperty(target, key, descriptor);
43
+ }
44
+ }
45
+ function createArrayCloneLike(value$1) {
46
+ try {
47
+ const arrayCtor = value$1.constructor;
48
+ return Reflect.construct(Array, [value$1.length], arrayCtor);
49
+ } catch {
50
+ return new Array(value$1.length);
51
+ }
52
+ }
53
+ function createSetCloneLike(value$1) {
54
+ try {
55
+ const setCtor = value$1.constructor;
56
+ return Reflect.construct(Set, [], setCtor);
57
+ } catch {
58
+ return /* @__PURE__ */ new Set();
59
+ }
60
+ }
61
+ function createMapCloneLike(value$1) {
62
+ try {
63
+ const mapCtor = value$1.constructor;
64
+ return Reflect.construct(Map, [], mapCtor);
65
+ } catch {
66
+ return /* @__PURE__ */ new Map();
67
+ }
68
+ }
69
+ function containsDeferredPromptValuesForContexts(value$1, seen = /* @__PURE__ */ new WeakSet()) {
70
+ if (isDeferredPromptValue(value$1)) return true;
71
+ if (value$1 == null || typeof value$1 !== "object") return false;
72
+ if (seen.has(value$1)) return false;
73
+ seen.add(value$1);
74
+ if (Array.isArray(value$1)) {
75
+ if (value$1.some((item) => containsDeferredPromptValuesForContexts(item, seen))) return true;
76
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
77
+ }
78
+ if (value$1 instanceof Set) {
79
+ for (const entryValue of value$1) if (containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
80
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
81
+ }
82
+ if (value$1 instanceof Map) {
83
+ for (const [key, entryValue] of value$1) if (containsDeferredPromptValuesForContexts(key, seen) || containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
84
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
85
+ }
86
+ return containsDeferredPromptValuesInOwnProperties(value$1, seen);
87
+ }
88
+ function stripDeferredPromptValuesForContexts(value$1, seen = /* @__PURE__ */ new WeakMap()) {
89
+ if (isDeferredPromptValue(value$1)) return void 0;
90
+ if (value$1 == null || typeof value$1 !== "object") return value$1;
91
+ const cached = seen.get(value$1);
92
+ if (cached !== void 0) return cached;
93
+ if (Array.isArray(value$1)) {
94
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
95
+ const clone$1 = createArrayCloneLike(value$1);
96
+ seen.set(value$1, clone$1);
97
+ for (let i = 0; i < value$1.length; i++) clone$1[i] = stripDeferredPromptValuesForContexts(value$1[i], seen);
98
+ copySanitizedOwnProperties(value$1, clone$1, seen);
99
+ return clone$1;
100
+ }
101
+ if (value$1 instanceof Set) {
102
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
103
+ const clone$1 = createSetCloneLike(value$1);
104
+ seen.set(value$1, clone$1);
105
+ for (const entryValue of value$1) clone$1.add(stripDeferredPromptValuesForContexts(entryValue, seen));
106
+ copySanitizedOwnProperties(value$1, clone$1, seen);
107
+ return clone$1;
108
+ }
109
+ if (value$1 instanceof Map) {
110
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
111
+ const clone$1 = createMapCloneLike(value$1);
112
+ seen.set(value$1, clone$1);
113
+ for (const [key, entryValue] of value$1) clone$1.set(stripDeferredPromptValuesForContexts(key, seen), stripDeferredPromptValuesForContexts(entryValue, seen));
114
+ copySanitizedOwnProperties(value$1, clone$1, seen);
115
+ return clone$1;
116
+ }
117
+ if (!isPlainObject(value$1)) {
118
+ if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
119
+ return createSanitizedNonPlainContextView(value$1, seen);
120
+ }
121
+ const clone = Object.create(Object.getPrototypeOf(value$1));
122
+ seen.set(value$1, clone);
123
+ for (const key of Reflect.ownKeys(value$1)) {
124
+ const descriptor = Object.getOwnPropertyDescriptor(value$1, key);
125
+ if (descriptor == null) continue;
126
+ if ("value" in descriptor) descriptor.value = stripDeferredPromptValuesForContexts(descriptor.value, seen);
127
+ Object.defineProperty(clone, key, descriptor);
128
+ }
129
+ return clone;
130
+ }
131
+ function finalizeParsedForContext(context, parsed) {
132
+ if (parsed !== void 0 || !Reflect.has(context, phase1ConfigAnnotationsKey)) return parsed;
133
+ return { [phase2UndefinedParsedValueKey]: true };
134
+ }
135
+ function createSanitizedNonPlainContextView(value$1, seen) {
136
+ const proxy = new Proxy(value$1, {
137
+ get(target, key, receiver) {
138
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
139
+ if (descriptor != null && "value" in descriptor) return stripDeferredPromptValuesForContexts(descriptor.value, seen);
140
+ return Reflect.get(target, key, receiver);
141
+ },
142
+ getOwnPropertyDescriptor(target, key) {
143
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
144
+ if (descriptor == null || !("value" in descriptor)) return descriptor;
145
+ return {
146
+ ...descriptor,
147
+ value: stripDeferredPromptValuesForContexts(descriptor.value, seen)
148
+ };
149
+ }
150
+ });
151
+ seen.set(value$1, proxy);
152
+ return proxy;
153
+ }
154
+ function prepareParsedForContexts(parsed) {
155
+ if (parsed == null || typeof parsed !== "object") return stripDeferredPromptValuesForContexts(parsed);
156
+ if (isDeferredPromptValue(parsed)) return void 0;
157
+ if (Array.isArray(parsed) || isPlainObject(parsed) || parsed instanceof Set || parsed instanceof Map) {
158
+ if (!containsDeferredPromptValuesForContexts(parsed)) return parsed;
159
+ return stripDeferredPromptValuesForContexts(parsed);
160
+ }
161
+ if (!containsDeferredPromptValuesForContexts(parsed)) return parsed;
162
+ return createSanitizedNonPlainContextView(parsed, /* @__PURE__ */ new WeakMap());
163
+ }
164
+ function withPreparedParsedForContext(context, preparedParsed, run) {
165
+ return run(finalizeParsedForContext(context, preparedParsed));
166
+ }
14
167
  /**
15
168
  * Creates help parsers based on the sub-config.
16
169
  */
@@ -850,10 +1003,14 @@ async function collectPhase1Annotations(contexts, options) {
850
1003
  for (const context of contexts) {
851
1004
  const result = context.getAnnotations(void 0, options);
852
1005
  hasDynamic ||= needsTwoPhaseContext(context, result);
853
- annotationsList.push(result instanceof Promise ? await result : result);
1006
+ const annotations = result instanceof Promise ? await result : result;
1007
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1008
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, void 0, annotations) : void 0;
1009
+ annotationsList.push(internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]));
854
1010
  }
855
1011
  return {
856
1012
  annotations: mergeAnnotations(annotationsList),
1013
+ annotationsList,
857
1014
  hasDynamic
858
1015
  };
859
1016
  }
@@ -867,11 +1024,21 @@ async function collectPhase1Annotations(contexts, options) {
867
1024
  */
868
1025
  async function collectAnnotations(contexts, parsed, options) {
869
1026
  const annotationsList = [];
1027
+ const preparedParsed = prepareParsedForContexts(parsed);
870
1028
  for (const context of contexts) {
871
- const result = context.getAnnotations(parsed, options);
872
- annotationsList.push(result instanceof Promise ? await result : result);
1029
+ const mergedAnnotations = await withPreparedParsedForContext(context, preparedParsed, async (contextParsed) => {
1030
+ const result = context.getAnnotations(contextParsed, options);
1031
+ const annotations = result instanceof Promise ? await result : result;
1032
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1033
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, contextParsed, annotations) : void 0;
1034
+ return internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]);
1035
+ });
1036
+ annotationsList.push(mergedAnnotations);
873
1037
  }
874
- return mergeAnnotations(annotationsList);
1038
+ return {
1039
+ annotations: mergeAnnotations(annotationsList),
1040
+ annotationsList
1041
+ };
875
1042
  }
876
1043
  /**
877
1044
  * Collects phase 1 annotations from all contexts synchronously and determines
@@ -889,10 +1056,13 @@ function collectPhase1AnnotationsSync(contexts, options) {
889
1056
  const result = context.getAnnotations(void 0, options);
890
1057
  if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
891
1058
  hasDynamic ||= needsTwoPhaseContext(context, result);
892
- annotationsList.push(result);
1059
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1060
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, void 0, result) : void 0;
1061
+ annotationsList.push(internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]));
893
1062
  }
894
1063
  return {
895
1064
  annotations: mergeAnnotations(annotationsList),
1065
+ annotationsList,
896
1066
  hasDynamic
897
1067
  };
898
1068
  }
@@ -919,12 +1089,27 @@ function needsTwoPhaseContext(context, result) {
919
1089
  */
920
1090
  function collectAnnotationsSync(contexts, parsed, options) {
921
1091
  const annotationsList = [];
1092
+ const preparedParsed = prepareParsedForContexts(parsed);
922
1093
  for (const context of contexts) {
923
- const result = context.getAnnotations(parsed, options);
924
- if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
925
- annotationsList.push(result);
1094
+ const mergedAnnotations = withPreparedParsedForContext(context, preparedParsed, (contextParsed) => {
1095
+ const result = context.getAnnotations(contextParsed, options);
1096
+ if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
1097
+ const internalAnnotationsGetter = Reflect.get(context, phase1ConfigAnnotationsKey);
1098
+ const internalAnnotations = typeof internalAnnotationsGetter === "function" ? internalAnnotationsGetter.call(context, contextParsed, result) : void 0;
1099
+ return internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]);
1100
+ });
1101
+ annotationsList.push(mergedAnnotations);
926
1102
  }
927
- return mergeAnnotations(annotationsList);
1103
+ return {
1104
+ annotations: mergeAnnotations(annotationsList),
1105
+ annotationsList
1106
+ };
1107
+ }
1108
+ function mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList) {
1109
+ const mergedPerContext = [];
1110
+ const length = Math.max(phase1AnnotationsList.length, phase2AnnotationsList.length);
1111
+ for (let i = 0; i < length; i++) mergedPerContext.push(mergeAnnotations([phase2AnnotationsList[i] ?? {}, phase1AnnotationsList[i] ?? {}]));
1112
+ return mergeAnnotations(mergedPerContext);
928
1113
  }
929
1114
  /**
930
1115
  * Disposes all contexts that implement `AsyncDisposable` or `Disposable`.
@@ -1022,7 +1207,7 @@ async function runWith(parser, programName, contexts, options) {
1022
1207
  return Promise.resolve(runParser(parser, programName, args, options));
1023
1208
  }
1024
1209
  try {
1025
- const { annotations: phase1Annotations, hasDynamic: needsTwoPhase } = await collectPhase1Annotations(contexts, options);
1210
+ const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = await collectPhase1Annotations(contexts, options);
1026
1211
  if (!needsTwoPhase) {
1027
1212
  const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
1028
1213
  if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
@@ -1047,8 +1232,8 @@ async function runWith(parser, programName, contexts, options) {
1047
1232
  if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
1048
1233
  return Promise.resolve(runParser(augmentedParser, programName, args, options));
1049
1234
  }
1050
- const phase2Annotations = await collectAnnotations(contexts, firstPassResult, options);
1051
- const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
1235
+ const { annotationsList: phase2AnnotationsList } = await collectAnnotations(contexts, firstPassResult, options);
1236
+ const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
1052
1237
  const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
1053
1238
  if (parser.$mode === "async") return runParser(augmentedParser2, programName, args, options);
1054
1239
  return Promise.resolve(runParser(augmentedParser2, programName, args, options));
@@ -1079,7 +1264,7 @@ function runWithSync(parser, programName, contexts, options) {
1079
1264
  if (needsEarlyExit(args, options)) return runParser(parser, programName, args, options);
1080
1265
  if (contexts.length === 0) return runParser(parser, programName, args, options);
1081
1266
  try {
1082
- const { annotations: phase1Annotations, hasDynamic: needsTwoPhase } = collectPhase1AnnotationsSync(contexts, options);
1267
+ const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = collectPhase1AnnotationsSync(contexts, options);
1083
1268
  if (!needsTwoPhase) {
1084
1269
  const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
1085
1270
  return runParser(augmentedParser, programName, args, options);
@@ -1093,8 +1278,8 @@ function runWithSync(parser, programName, contexts, options) {
1093
1278
  } catch {
1094
1279
  return runParser(augmentedParser1, programName, args, options);
1095
1280
  }
1096
- const phase2Annotations = collectAnnotationsSync(contexts, firstPassResult, options);
1097
- const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
1281
+ const { annotationsList: phase2AnnotationsList } = collectAnnotationsSync(contexts, firstPassResult, options);
1282
+ const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
1098
1283
  const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
1099
1284
  return runParser(augmentedParser2, programName, args, options);
1100
1285
  } finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.661+a4060a75",
3
+ "version": "1.0.0-dev.667+b4962990",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",