@optique/core 1.0.0-dev.1495 → 1.0.0-dev.1500
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.
- package/dist/constructs.cjs +183 -35
- package/dist/constructs.js +183 -35
- package/dist/context.cjs +1 -39
- package/dist/context.d.cts +1 -35
- package/dist/context.d.ts +1 -35
- package/dist/context.js +1 -37
- package/dist/dependency.cjs +42 -0
- package/dist/dependency.js +42 -0
- package/dist/facade.cjs +68 -268
- package/dist/facade.js +68 -268
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/modifiers.cjs +139 -21
- package/dist/modifiers.d.cts +41 -0
- package/dist/modifiers.d.ts +41 -0
- package/dist/modifiers.js +139 -21
- package/dist/parser.cjs +6 -2
- package/dist/parser.d.cts +28 -1
- package/dist/parser.d.ts +28 -1
- package/dist/parser.js +6 -2
- package/dist/primitives.cjs +44 -2
- package/dist/primitives.js +44 -2
- package/dist/suggestion.cjs +3 -0
- package/dist/suggestion.js +3 -0
- package/dist/valueparser.cjs +82 -1
- package/dist/valueparser.d.cts +125 -1
- package/dist/valueparser.d.ts +125 -1
- package/dist/valueparser.js +82 -1
- package/package.json +1 -1
package/dist/modifiers.cjs
CHANGED
|
@@ -2,7 +2,6 @@ const require_annotations = require('./annotations.cjs');
|
|
|
2
2
|
const require_message = require('./message.cjs');
|
|
3
3
|
const require_dependency = require('./dependency.cjs');
|
|
4
4
|
const require_mode_dispatch = require('./mode-dispatch.cjs');
|
|
5
|
-
const require_context = require('./context.cjs');
|
|
6
5
|
|
|
7
6
|
//#region src/modifiers.ts
|
|
8
7
|
/**
|
|
@@ -123,6 +122,7 @@ function optional(parser) {
|
|
|
123
122
|
$mode: parser.$mode,
|
|
124
123
|
$valueType: [],
|
|
125
124
|
$stateType: [],
|
|
125
|
+
placeholder: void 0,
|
|
126
126
|
priority: parser.priority,
|
|
127
127
|
usage: [{
|
|
128
128
|
type: "optional",
|
|
@@ -237,7 +237,7 @@ function withDefault(parser, defaultValue, options) {
|
|
|
237
237
|
}
|
|
238
238
|
const innerInitialState = syncParser.initialState;
|
|
239
239
|
const wrappedDependencyMarker = require_dependency.isPendingDependencySourceState(innerInitialState) ? { [require_dependency.wrappedDependencySourceMarker]: innerInitialState } : require_dependency.isWrappedDependencySource(parser) ? { [require_dependency.wrappedDependencySourceMarker]: parser[require_dependency.wrappedDependencySourceMarker] } : {};
|
|
240
|
-
|
|
240
|
+
const withDefaultParser = {
|
|
241
241
|
$mode: parser.$mode,
|
|
242
242
|
$valueType: [],
|
|
243
243
|
$stateType: [],
|
|
@@ -386,6 +386,14 @@ function withDefault(parser, defaultValue, options) {
|
|
|
386
386
|
return fragments;
|
|
387
387
|
}
|
|
388
388
|
};
|
|
389
|
+
if ("placeholder" in parser) Object.defineProperty(withDefaultParser, "placeholder", {
|
|
390
|
+
get() {
|
|
391
|
+
return parser.placeholder;
|
|
392
|
+
},
|
|
393
|
+
configurable: true,
|
|
394
|
+
enumerable: false
|
|
395
|
+
});
|
|
396
|
+
return withDefaultParser;
|
|
389
397
|
}
|
|
390
398
|
/**
|
|
391
399
|
* Creates a parser that transforms the result value of another parser using
|
|
@@ -406,6 +414,47 @@ function withDefault(parser, defaultValue, options) {
|
|
|
406
414
|
* @param transform A function that transforms the parsed value from type T to type U.
|
|
407
415
|
* @returns A {@link Parser} that produces the transformed value of type U
|
|
408
416
|
* while preserving the original parser's state type and parsing behavior.
|
|
417
|
+
* @throws Any exception thrown by `transform` when completing a non-deferred
|
|
418
|
+
* value. Errors from deferred placeholder transforms are caught and the
|
|
419
|
+
* mapped result falls back to `undefined` with `deferred: true`.
|
|
420
|
+
*
|
|
421
|
+
* ### Deferred prompt interaction
|
|
422
|
+
*
|
|
423
|
+
* During two-phase parsing, `map()` propagates the `deferred` flag from
|
|
424
|
+
* inner results but intentionally drops per-field `deferredKeys`. The
|
|
425
|
+
* inner key set describes the *input* shape, but `transform` produces an
|
|
426
|
+
* arbitrary *output* shape where keys may be renamed, dropped, or reused
|
|
427
|
+
* with different semantics. For `object()` results that are *not*
|
|
428
|
+
* wrapped in `map()`, per-field deferred stripping works normally.
|
|
429
|
+
*
|
|
430
|
+
* Because the `deferred` flag is propagated conservatively, mapped scalar
|
|
431
|
+
* results are treated as missing (`undefined`) during phase-two context
|
|
432
|
+
* collection — even when `transform` only used non-deferred fields.
|
|
433
|
+
* For example, `map(object({ apiKey: prompt(...), mode: option(...) }),
|
|
434
|
+
* v => v.mode)` makes phase-two contexts see `undefined` instead of the
|
|
435
|
+
* real `mode` value. This is the intentional trade-off: the alternative
|
|
436
|
+
* (not propagating `deferred`) would leak placeholder values into context
|
|
437
|
+
* resolution when `transform` *does* use deferred fields. The final
|
|
438
|
+
* parse always produces the correct result regardless.
|
|
439
|
+
*
|
|
440
|
+
* If the transform throws on a deferred placeholder value, the mapped
|
|
441
|
+
* result falls back to `undefined` with `deferred: true`, so the first
|
|
442
|
+
* pass does not abort.
|
|
443
|
+
*
|
|
444
|
+
* ### Transform purity
|
|
445
|
+
*
|
|
446
|
+
* The `transform` function must not mutate its input. Object and array
|
|
447
|
+
* values may be shared placeholder references during deferred prompt
|
|
448
|
+
* resolution, and in-place mutations would corrupt the placeholder for
|
|
449
|
+
* subsequent parses. Always return a new value:
|
|
450
|
+
*
|
|
451
|
+
* ```typescript
|
|
452
|
+
* // ✅ Correct — creates a new object
|
|
453
|
+
* map(parser, v => ({ ...v, host: "override" }))
|
|
454
|
+
*
|
|
455
|
+
* // ❌ Wrong — mutates the input in place
|
|
456
|
+
* map(parser, v => { v.host = "override"; return v; })
|
|
457
|
+
* ```
|
|
409
458
|
*
|
|
410
459
|
* @example
|
|
411
460
|
* ```typescript
|
|
@@ -423,16 +472,32 @@ function withDefault(parser, defaultValue, options) {
|
|
|
423
472
|
*/
|
|
424
473
|
function map(parser, transform) {
|
|
425
474
|
const complete = (state) => {
|
|
426
|
-
return require_mode_dispatch.mapModeValue(parser.$mode, parser.complete(state), (result) =>
|
|
427
|
-
success
|
|
428
|
-
|
|
429
|
-
|
|
475
|
+
return require_mode_dispatch.mapModeValue(parser.$mode, parser.complete(state), (result) => {
|
|
476
|
+
if (!result.success) return result;
|
|
477
|
+
if (result.deferred) try {
|
|
478
|
+
return {
|
|
479
|
+
success: true,
|
|
480
|
+
value: transform(result.value),
|
|
481
|
+
deferred: true
|
|
482
|
+
};
|
|
483
|
+
} catch {
|
|
484
|
+
return {
|
|
485
|
+
success: true,
|
|
486
|
+
value: void 0,
|
|
487
|
+
deferred: true
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
success: true,
|
|
492
|
+
value: transform(result.value)
|
|
493
|
+
};
|
|
494
|
+
});
|
|
430
495
|
};
|
|
431
496
|
const dependencyMarkers = require_dependency.isWrappedDependencySource(parser) ? {
|
|
432
497
|
[require_dependency.wrappedDependencySourceMarker]: parser[require_dependency.wrappedDependencySourceMarker],
|
|
433
498
|
[require_dependency.transformsDependencyValueMarker]: true
|
|
434
499
|
} : {};
|
|
435
|
-
|
|
500
|
+
const mappedParser = {
|
|
436
501
|
...parser,
|
|
437
502
|
$valueType: [],
|
|
438
503
|
complete,
|
|
@@ -441,6 +506,18 @@ function map(parser, transform) {
|
|
|
441
506
|
return parser.getDocFragments(state, void 0);
|
|
442
507
|
}
|
|
443
508
|
};
|
|
509
|
+
if ("placeholder" in parser) Object.defineProperty(mappedParser, "placeholder", {
|
|
510
|
+
get() {
|
|
511
|
+
try {
|
|
512
|
+
return transform(parser.placeholder);
|
|
513
|
+
} catch {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
configurable: true,
|
|
518
|
+
enumerable: false
|
|
519
|
+
});
|
|
520
|
+
return mappedParser;
|
|
444
521
|
}
|
|
445
522
|
/**
|
|
446
523
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
@@ -580,24 +657,41 @@ function multiple(parser, options = {}) {
|
|
|
580
657
|
complete(state) {
|
|
581
658
|
return require_mode_dispatch.dispatchByMode(parser.$mode, () => {
|
|
582
659
|
const result = [];
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
660
|
+
const deferredIndices = /* @__PURE__ */ new Map();
|
|
661
|
+
let hasDeferred = false;
|
|
662
|
+
for (let i = 0; i < state.length; i++) {
|
|
663
|
+
const valueResult = completeSyncWithUnwrappedFallback(state[i]);
|
|
664
|
+
if (valueResult.success) {
|
|
665
|
+
const unwrappedValue = unwrapInjectedWrapper(valueResult.value);
|
|
666
|
+
result.push(unwrappedValue);
|
|
667
|
+
if (valueResult.deferred) if (valueResult.deferredKeys) deferredIndices.set(i, valueResult.deferredKeys);
|
|
668
|
+
else if (unwrappedValue == null || typeof unwrappedValue !== "object") deferredIndices.set(i, null);
|
|
669
|
+
else hasDeferred = true;
|
|
670
|
+
} else return {
|
|
587
671
|
success: false,
|
|
588
672
|
error: valueResult.error
|
|
589
673
|
};
|
|
590
674
|
}
|
|
591
|
-
return validateMultipleResult(result);
|
|
675
|
+
return validateMultipleResult(result, deferredIndices, hasDeferred);
|
|
592
676
|
}, async () => {
|
|
593
677
|
const results = await Promise.all(state.map((s) => completeAsyncWithUnwrappedFallback(s)));
|
|
594
678
|
const values = [];
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
679
|
+
const deferredIndices = /* @__PURE__ */ new Map();
|
|
680
|
+
let hasDeferred = false;
|
|
681
|
+
for (let i = 0; i < results.length; i++) {
|
|
682
|
+
const valueResult = results[i];
|
|
683
|
+
if (valueResult.success) {
|
|
684
|
+
const unwrappedValue = unwrapInjectedWrapper(valueResult.value);
|
|
685
|
+
values.push(unwrappedValue);
|
|
686
|
+
if (valueResult.deferred) if (valueResult.deferredKeys) deferredIndices.set(i, valueResult.deferredKeys);
|
|
687
|
+
else if (unwrappedValue == null || typeof unwrappedValue !== "object") deferredIndices.set(i, null);
|
|
688
|
+
else hasDeferred = true;
|
|
689
|
+
} else return {
|
|
690
|
+
success: false,
|
|
691
|
+
error: valueResult.error
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return validateMultipleResult(values, deferredIndices, hasDeferred);
|
|
601
695
|
});
|
|
602
696
|
},
|
|
603
697
|
suggest(context, prefix) {
|
|
@@ -694,7 +788,7 @@ function multiple(parser, options = {}) {
|
|
|
694
788
|
return syncParser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
|
|
695
789
|
}
|
|
696
790
|
};
|
|
697
|
-
function validateMultipleResult(result) {
|
|
791
|
+
function validateMultipleResult(result, deferredIndices, hasDeferred = false) {
|
|
698
792
|
if (result.length < min) {
|
|
699
793
|
const customMessage = options.errors?.tooFew;
|
|
700
794
|
return {
|
|
@@ -708,11 +802,26 @@ function multiple(parser, options = {}) {
|
|
|
708
802
|
error: customMessage ? typeof customMessage === "function" ? customMessage(max, result.length) : customMessage : require_message.message`Expected at most ${require_message.text(max.toLocaleString("en"))} values, but got ${require_message.text(result.length.toLocaleString("en"))}.`
|
|
709
803
|
};
|
|
710
804
|
}
|
|
805
|
+
const isDeferred = deferredIndices.size > 0 || hasDeferred;
|
|
711
806
|
return {
|
|
712
807
|
success: true,
|
|
713
|
-
value: result
|
|
808
|
+
value: result,
|
|
809
|
+
...isDeferred ? {
|
|
810
|
+
deferred: true,
|
|
811
|
+
...deferredIndices.size > 0 ? { deferredKeys: deferredIndices } : {}
|
|
812
|
+
} : {}
|
|
714
813
|
};
|
|
715
814
|
}
|
|
815
|
+
Object.defineProperty(resultParser, "placeholder", {
|
|
816
|
+
get() {
|
|
817
|
+
try {
|
|
818
|
+
if (min > 0 && "placeholder" in parser) return Array.from({ length: min }, () => parser.placeholder);
|
|
819
|
+
} catch {}
|
|
820
|
+
return [];
|
|
821
|
+
},
|
|
822
|
+
configurable: true,
|
|
823
|
+
enumerable: false
|
|
824
|
+
});
|
|
716
825
|
return resultParser;
|
|
717
826
|
}
|
|
718
827
|
/**
|
|
@@ -771,13 +880,14 @@ function nonEmpty(parser) {
|
|
|
771
880
|
const result = await parser.parse(context);
|
|
772
881
|
return processNonEmptyResult(result);
|
|
773
882
|
};
|
|
774
|
-
|
|
883
|
+
const nonEmptyParser = {
|
|
775
884
|
$mode: parser.$mode,
|
|
776
885
|
$valueType: parser.$valueType,
|
|
777
886
|
$stateType: parser.$stateType,
|
|
778
887
|
priority: parser.priority,
|
|
779
888
|
usage: parser.usage,
|
|
780
889
|
initialState: parser.initialState,
|
|
890
|
+
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
|
|
781
891
|
parse(context) {
|
|
782
892
|
return require_mode_dispatch.dispatchByMode(parser.$mode, () => parseSync(context), () => parseAsync(context));
|
|
783
893
|
},
|
|
@@ -791,6 +901,14 @@ function nonEmpty(parser) {
|
|
|
791
901
|
return syncParser.getDocFragments(state, defaultValue);
|
|
792
902
|
}
|
|
793
903
|
};
|
|
904
|
+
if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
|
|
905
|
+
get() {
|
|
906
|
+
return parser.placeholder;
|
|
907
|
+
},
|
|
908
|
+
configurable: true,
|
|
909
|
+
enumerable: false
|
|
910
|
+
});
|
|
911
|
+
return nonEmptyParser;
|
|
794
912
|
}
|
|
795
913
|
|
|
796
914
|
//#endregion
|
package/dist/modifiers.d.cts
CHANGED
|
@@ -123,6 +123,47 @@ declare function withDefault<M extends Mode, TValue, TState, const TDefault = TV
|
|
|
123
123
|
* @param transform A function that transforms the parsed value from type T to type U.
|
|
124
124
|
* @returns A {@link Parser} that produces the transformed value of type U
|
|
125
125
|
* while preserving the original parser's state type and parsing behavior.
|
|
126
|
+
* @throws Any exception thrown by `transform` when completing a non-deferred
|
|
127
|
+
* value. Errors from deferred placeholder transforms are caught and the
|
|
128
|
+
* mapped result falls back to `undefined` with `deferred: true`.
|
|
129
|
+
*
|
|
130
|
+
* ### Deferred prompt interaction
|
|
131
|
+
*
|
|
132
|
+
* During two-phase parsing, `map()` propagates the `deferred` flag from
|
|
133
|
+
* inner results but intentionally drops per-field `deferredKeys`. The
|
|
134
|
+
* inner key set describes the *input* shape, but `transform` produces an
|
|
135
|
+
* arbitrary *output* shape where keys may be renamed, dropped, or reused
|
|
136
|
+
* with different semantics. For `object()` results that are *not*
|
|
137
|
+
* wrapped in `map()`, per-field deferred stripping works normally.
|
|
138
|
+
*
|
|
139
|
+
* Because the `deferred` flag is propagated conservatively, mapped scalar
|
|
140
|
+
* results are treated as missing (`undefined`) during phase-two context
|
|
141
|
+
* collection — even when `transform` only used non-deferred fields.
|
|
142
|
+
* For example, `map(object({ apiKey: prompt(...), mode: option(...) }),
|
|
143
|
+
* v => v.mode)` makes phase-two contexts see `undefined` instead of the
|
|
144
|
+
* real `mode` value. This is the intentional trade-off: the alternative
|
|
145
|
+
* (not propagating `deferred`) would leak placeholder values into context
|
|
146
|
+
* resolution when `transform` *does* use deferred fields. The final
|
|
147
|
+
* parse always produces the correct result regardless.
|
|
148
|
+
*
|
|
149
|
+
* If the transform throws on a deferred placeholder value, the mapped
|
|
150
|
+
* result falls back to `undefined` with `deferred: true`, so the first
|
|
151
|
+
* pass does not abort.
|
|
152
|
+
*
|
|
153
|
+
* ### Transform purity
|
|
154
|
+
*
|
|
155
|
+
* The `transform` function must not mutate its input. Object and array
|
|
156
|
+
* values may be shared placeholder references during deferred prompt
|
|
157
|
+
* resolution, and in-place mutations would corrupt the placeholder for
|
|
158
|
+
* subsequent parses. Always return a new value:
|
|
159
|
+
*
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // ✅ Correct — creates a new object
|
|
162
|
+
* map(parser, v => ({ ...v, host: "override" }))
|
|
163
|
+
*
|
|
164
|
+
* // ❌ Wrong — mutates the input in place
|
|
165
|
+
* map(parser, v => { v.host = "override"; return v; })
|
|
166
|
+
* ```
|
|
126
167
|
*
|
|
127
168
|
* @example
|
|
128
169
|
* ```typescript
|
package/dist/modifiers.d.ts
CHANGED
|
@@ -123,6 +123,47 @@ declare function withDefault<M extends Mode, TValue, TState, const TDefault = TV
|
|
|
123
123
|
* @param transform A function that transforms the parsed value from type T to type U.
|
|
124
124
|
* @returns A {@link Parser} that produces the transformed value of type U
|
|
125
125
|
* while preserving the original parser's state type and parsing behavior.
|
|
126
|
+
* @throws Any exception thrown by `transform` when completing a non-deferred
|
|
127
|
+
* value. Errors from deferred placeholder transforms are caught and the
|
|
128
|
+
* mapped result falls back to `undefined` with `deferred: true`.
|
|
129
|
+
*
|
|
130
|
+
* ### Deferred prompt interaction
|
|
131
|
+
*
|
|
132
|
+
* During two-phase parsing, `map()` propagates the `deferred` flag from
|
|
133
|
+
* inner results but intentionally drops per-field `deferredKeys`. The
|
|
134
|
+
* inner key set describes the *input* shape, but `transform` produces an
|
|
135
|
+
* arbitrary *output* shape where keys may be renamed, dropped, or reused
|
|
136
|
+
* with different semantics. For `object()` results that are *not*
|
|
137
|
+
* wrapped in `map()`, per-field deferred stripping works normally.
|
|
138
|
+
*
|
|
139
|
+
* Because the `deferred` flag is propagated conservatively, mapped scalar
|
|
140
|
+
* results are treated as missing (`undefined`) during phase-two context
|
|
141
|
+
* collection — even when `transform` only used non-deferred fields.
|
|
142
|
+
* For example, `map(object({ apiKey: prompt(...), mode: option(...) }),
|
|
143
|
+
* v => v.mode)` makes phase-two contexts see `undefined` instead of the
|
|
144
|
+
* real `mode` value. This is the intentional trade-off: the alternative
|
|
145
|
+
* (not propagating `deferred`) would leak placeholder values into context
|
|
146
|
+
* resolution when `transform` *does* use deferred fields. The final
|
|
147
|
+
* parse always produces the correct result regardless.
|
|
148
|
+
*
|
|
149
|
+
* If the transform throws on a deferred placeholder value, the mapped
|
|
150
|
+
* result falls back to `undefined` with `deferred: true`, so the first
|
|
151
|
+
* pass does not abort.
|
|
152
|
+
*
|
|
153
|
+
* ### Transform purity
|
|
154
|
+
*
|
|
155
|
+
* The `transform` function must not mutate its input. Object and array
|
|
156
|
+
* values may be shared placeholder references during deferred prompt
|
|
157
|
+
* resolution, and in-place mutations would corrupt the placeholder for
|
|
158
|
+
* subsequent parses. Always return a new value:
|
|
159
|
+
*
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // ✅ Correct — creates a new object
|
|
162
|
+
* map(parser, v => ({ ...v, host: "override" }))
|
|
163
|
+
*
|
|
164
|
+
* // ❌ Wrong — mutates the input in place
|
|
165
|
+
* map(parser, v => { v.host = "override"; return v; })
|
|
166
|
+
* ```
|
|
126
167
|
*
|
|
127
168
|
* @example
|
|
128
169
|
* ```typescript
|
package/dist/modifiers.js
CHANGED
|
@@ -2,7 +2,6 @@ import { annotateFreshArray, getAnnotations, inheritAnnotations, isInjectedAnnot
|
|
|
2
2
|
import { formatMessage, message, text } from "./message.js";
|
|
3
3
|
import { createDependencySourceState, dependencyId, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, transformsDependencyValue, transformsDependencyValueMarker, wrappedDependencySourceMarker } from "./dependency.js";
|
|
4
4
|
import { dispatchByMode, dispatchIterableByMode, mapModeValue } from "./mode-dispatch.js";
|
|
5
|
-
import { isPlaceholderValue } from "./context.js";
|
|
6
5
|
|
|
7
6
|
//#region src/modifiers.ts
|
|
8
7
|
/**
|
|
@@ -123,6 +122,7 @@ function optional(parser) {
|
|
|
123
122
|
$mode: parser.$mode,
|
|
124
123
|
$valueType: [],
|
|
125
124
|
$stateType: [],
|
|
125
|
+
placeholder: void 0,
|
|
126
126
|
priority: parser.priority,
|
|
127
127
|
usage: [{
|
|
128
128
|
type: "optional",
|
|
@@ -237,7 +237,7 @@ function withDefault(parser, defaultValue, options) {
|
|
|
237
237
|
}
|
|
238
238
|
const innerInitialState = syncParser.initialState;
|
|
239
239
|
const wrappedDependencyMarker = isPendingDependencySourceState(innerInitialState) ? { [wrappedDependencySourceMarker]: innerInitialState } : isWrappedDependencySource(parser) ? { [wrappedDependencySourceMarker]: parser[wrappedDependencySourceMarker] } : {};
|
|
240
|
-
|
|
240
|
+
const withDefaultParser = {
|
|
241
241
|
$mode: parser.$mode,
|
|
242
242
|
$valueType: [],
|
|
243
243
|
$stateType: [],
|
|
@@ -386,6 +386,14 @@ function withDefault(parser, defaultValue, options) {
|
|
|
386
386
|
return fragments;
|
|
387
387
|
}
|
|
388
388
|
};
|
|
389
|
+
if ("placeholder" in parser) Object.defineProperty(withDefaultParser, "placeholder", {
|
|
390
|
+
get() {
|
|
391
|
+
return parser.placeholder;
|
|
392
|
+
},
|
|
393
|
+
configurable: true,
|
|
394
|
+
enumerable: false
|
|
395
|
+
});
|
|
396
|
+
return withDefaultParser;
|
|
389
397
|
}
|
|
390
398
|
/**
|
|
391
399
|
* Creates a parser that transforms the result value of another parser using
|
|
@@ -406,6 +414,47 @@ function withDefault(parser, defaultValue, options) {
|
|
|
406
414
|
* @param transform A function that transforms the parsed value from type T to type U.
|
|
407
415
|
* @returns A {@link Parser} that produces the transformed value of type U
|
|
408
416
|
* while preserving the original parser's state type and parsing behavior.
|
|
417
|
+
* @throws Any exception thrown by `transform` when completing a non-deferred
|
|
418
|
+
* value. Errors from deferred placeholder transforms are caught and the
|
|
419
|
+
* mapped result falls back to `undefined` with `deferred: true`.
|
|
420
|
+
*
|
|
421
|
+
* ### Deferred prompt interaction
|
|
422
|
+
*
|
|
423
|
+
* During two-phase parsing, `map()` propagates the `deferred` flag from
|
|
424
|
+
* inner results but intentionally drops per-field `deferredKeys`. The
|
|
425
|
+
* inner key set describes the *input* shape, but `transform` produces an
|
|
426
|
+
* arbitrary *output* shape where keys may be renamed, dropped, or reused
|
|
427
|
+
* with different semantics. For `object()` results that are *not*
|
|
428
|
+
* wrapped in `map()`, per-field deferred stripping works normally.
|
|
429
|
+
*
|
|
430
|
+
* Because the `deferred` flag is propagated conservatively, mapped scalar
|
|
431
|
+
* results are treated as missing (`undefined`) during phase-two context
|
|
432
|
+
* collection — even when `transform` only used non-deferred fields.
|
|
433
|
+
* For example, `map(object({ apiKey: prompt(...), mode: option(...) }),
|
|
434
|
+
* v => v.mode)` makes phase-two contexts see `undefined` instead of the
|
|
435
|
+
* real `mode` value. This is the intentional trade-off: the alternative
|
|
436
|
+
* (not propagating `deferred`) would leak placeholder values into context
|
|
437
|
+
* resolution when `transform` *does* use deferred fields. The final
|
|
438
|
+
* parse always produces the correct result regardless.
|
|
439
|
+
*
|
|
440
|
+
* If the transform throws on a deferred placeholder value, the mapped
|
|
441
|
+
* result falls back to `undefined` with `deferred: true`, so the first
|
|
442
|
+
* pass does not abort.
|
|
443
|
+
*
|
|
444
|
+
* ### Transform purity
|
|
445
|
+
*
|
|
446
|
+
* The `transform` function must not mutate its input. Object and array
|
|
447
|
+
* values may be shared placeholder references during deferred prompt
|
|
448
|
+
* resolution, and in-place mutations would corrupt the placeholder for
|
|
449
|
+
* subsequent parses. Always return a new value:
|
|
450
|
+
*
|
|
451
|
+
* ```typescript
|
|
452
|
+
* // ✅ Correct — creates a new object
|
|
453
|
+
* map(parser, v => ({ ...v, host: "override" }))
|
|
454
|
+
*
|
|
455
|
+
* // ❌ Wrong — mutates the input in place
|
|
456
|
+
* map(parser, v => { v.host = "override"; return v; })
|
|
457
|
+
* ```
|
|
409
458
|
*
|
|
410
459
|
* @example
|
|
411
460
|
* ```typescript
|
|
@@ -423,16 +472,32 @@ function withDefault(parser, defaultValue, options) {
|
|
|
423
472
|
*/
|
|
424
473
|
function map(parser, transform) {
|
|
425
474
|
const complete = (state) => {
|
|
426
|
-
return mapModeValue(parser.$mode, parser.complete(state), (result) =>
|
|
427
|
-
success
|
|
428
|
-
|
|
429
|
-
|
|
475
|
+
return mapModeValue(parser.$mode, parser.complete(state), (result) => {
|
|
476
|
+
if (!result.success) return result;
|
|
477
|
+
if (result.deferred) try {
|
|
478
|
+
return {
|
|
479
|
+
success: true,
|
|
480
|
+
value: transform(result.value),
|
|
481
|
+
deferred: true
|
|
482
|
+
};
|
|
483
|
+
} catch {
|
|
484
|
+
return {
|
|
485
|
+
success: true,
|
|
486
|
+
value: void 0,
|
|
487
|
+
deferred: true
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
success: true,
|
|
492
|
+
value: transform(result.value)
|
|
493
|
+
};
|
|
494
|
+
});
|
|
430
495
|
};
|
|
431
496
|
const dependencyMarkers = isWrappedDependencySource(parser) ? {
|
|
432
497
|
[wrappedDependencySourceMarker]: parser[wrappedDependencySourceMarker],
|
|
433
498
|
[transformsDependencyValueMarker]: true
|
|
434
499
|
} : {};
|
|
435
|
-
|
|
500
|
+
const mappedParser = {
|
|
436
501
|
...parser,
|
|
437
502
|
$valueType: [],
|
|
438
503
|
complete,
|
|
@@ -441,6 +506,18 @@ function map(parser, transform) {
|
|
|
441
506
|
return parser.getDocFragments(state, void 0);
|
|
442
507
|
}
|
|
443
508
|
};
|
|
509
|
+
if ("placeholder" in parser) Object.defineProperty(mappedParser, "placeholder", {
|
|
510
|
+
get() {
|
|
511
|
+
try {
|
|
512
|
+
return transform(parser.placeholder);
|
|
513
|
+
} catch {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
configurable: true,
|
|
518
|
+
enumerable: false
|
|
519
|
+
});
|
|
520
|
+
return mappedParser;
|
|
444
521
|
}
|
|
445
522
|
/**
|
|
446
523
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
@@ -580,24 +657,41 @@ function multiple(parser, options = {}) {
|
|
|
580
657
|
complete(state) {
|
|
581
658
|
return dispatchByMode(parser.$mode, () => {
|
|
582
659
|
const result = [];
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
660
|
+
const deferredIndices = /* @__PURE__ */ new Map();
|
|
661
|
+
let hasDeferred = false;
|
|
662
|
+
for (let i = 0; i < state.length; i++) {
|
|
663
|
+
const valueResult = completeSyncWithUnwrappedFallback(state[i]);
|
|
664
|
+
if (valueResult.success) {
|
|
665
|
+
const unwrappedValue = unwrapInjectedWrapper(valueResult.value);
|
|
666
|
+
result.push(unwrappedValue);
|
|
667
|
+
if (valueResult.deferred) if (valueResult.deferredKeys) deferredIndices.set(i, valueResult.deferredKeys);
|
|
668
|
+
else if (unwrappedValue == null || typeof unwrappedValue !== "object") deferredIndices.set(i, null);
|
|
669
|
+
else hasDeferred = true;
|
|
670
|
+
} else return {
|
|
587
671
|
success: false,
|
|
588
672
|
error: valueResult.error
|
|
589
673
|
};
|
|
590
674
|
}
|
|
591
|
-
return validateMultipleResult(result);
|
|
675
|
+
return validateMultipleResult(result, deferredIndices, hasDeferred);
|
|
592
676
|
}, async () => {
|
|
593
677
|
const results = await Promise.all(state.map((s) => completeAsyncWithUnwrappedFallback(s)));
|
|
594
678
|
const values = [];
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
679
|
+
const deferredIndices = /* @__PURE__ */ new Map();
|
|
680
|
+
let hasDeferred = false;
|
|
681
|
+
for (let i = 0; i < results.length; i++) {
|
|
682
|
+
const valueResult = results[i];
|
|
683
|
+
if (valueResult.success) {
|
|
684
|
+
const unwrappedValue = unwrapInjectedWrapper(valueResult.value);
|
|
685
|
+
values.push(unwrappedValue);
|
|
686
|
+
if (valueResult.deferred) if (valueResult.deferredKeys) deferredIndices.set(i, valueResult.deferredKeys);
|
|
687
|
+
else if (unwrappedValue == null || typeof unwrappedValue !== "object") deferredIndices.set(i, null);
|
|
688
|
+
else hasDeferred = true;
|
|
689
|
+
} else return {
|
|
690
|
+
success: false,
|
|
691
|
+
error: valueResult.error
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return validateMultipleResult(values, deferredIndices, hasDeferred);
|
|
601
695
|
});
|
|
602
696
|
},
|
|
603
697
|
suggest(context, prefix) {
|
|
@@ -694,7 +788,7 @@ function multiple(parser, options = {}) {
|
|
|
694
788
|
return syncParser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
|
|
695
789
|
}
|
|
696
790
|
};
|
|
697
|
-
function validateMultipleResult(result) {
|
|
791
|
+
function validateMultipleResult(result, deferredIndices, hasDeferred = false) {
|
|
698
792
|
if (result.length < min) {
|
|
699
793
|
const customMessage = options.errors?.tooFew;
|
|
700
794
|
return {
|
|
@@ -708,11 +802,26 @@ function multiple(parser, options = {}) {
|
|
|
708
802
|
error: customMessage ? typeof customMessage === "function" ? customMessage(max, result.length) : customMessage : message`Expected at most ${text(max.toLocaleString("en"))} values, but got ${text(result.length.toLocaleString("en"))}.`
|
|
709
803
|
};
|
|
710
804
|
}
|
|
805
|
+
const isDeferred = deferredIndices.size > 0 || hasDeferred;
|
|
711
806
|
return {
|
|
712
807
|
success: true,
|
|
713
|
-
value: result
|
|
808
|
+
value: result,
|
|
809
|
+
...isDeferred ? {
|
|
810
|
+
deferred: true,
|
|
811
|
+
...deferredIndices.size > 0 ? { deferredKeys: deferredIndices } : {}
|
|
812
|
+
} : {}
|
|
714
813
|
};
|
|
715
814
|
}
|
|
815
|
+
Object.defineProperty(resultParser, "placeholder", {
|
|
816
|
+
get() {
|
|
817
|
+
try {
|
|
818
|
+
if (min > 0 && "placeholder" in parser) return Array.from({ length: min }, () => parser.placeholder);
|
|
819
|
+
} catch {}
|
|
820
|
+
return [];
|
|
821
|
+
},
|
|
822
|
+
configurable: true,
|
|
823
|
+
enumerable: false
|
|
824
|
+
});
|
|
716
825
|
return resultParser;
|
|
717
826
|
}
|
|
718
827
|
/**
|
|
@@ -771,13 +880,14 @@ function nonEmpty(parser) {
|
|
|
771
880
|
const result = await parser.parse(context);
|
|
772
881
|
return processNonEmptyResult(result);
|
|
773
882
|
};
|
|
774
|
-
|
|
883
|
+
const nonEmptyParser = {
|
|
775
884
|
$mode: parser.$mode,
|
|
776
885
|
$valueType: parser.$valueType,
|
|
777
886
|
$stateType: parser.$stateType,
|
|
778
887
|
priority: parser.priority,
|
|
779
888
|
usage: parser.usage,
|
|
780
889
|
initialState: parser.initialState,
|
|
890
|
+
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
|
|
781
891
|
parse(context) {
|
|
782
892
|
return dispatchByMode(parser.$mode, () => parseSync(context), () => parseAsync(context));
|
|
783
893
|
},
|
|
@@ -791,6 +901,14 @@ function nonEmpty(parser) {
|
|
|
791
901
|
return syncParser.getDocFragments(state, defaultValue);
|
|
792
902
|
}
|
|
793
903
|
};
|
|
904
|
+
if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
|
|
905
|
+
get() {
|
|
906
|
+
return parser.placeholder;
|
|
907
|
+
},
|
|
908
|
+
configurable: true,
|
|
909
|
+
enumerable: false
|
|
910
|
+
});
|
|
911
|
+
return nonEmptyParser;
|
|
794
912
|
}
|
|
795
913
|
|
|
796
914
|
//#endregion
|
package/dist/parser.cjs
CHANGED
|
@@ -60,7 +60,9 @@ function parseSync(parser, args, options) {
|
|
|
60
60
|
const endResult = parser.complete(context.state);
|
|
61
61
|
return endResult.success ? {
|
|
62
62
|
success: true,
|
|
63
|
-
value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
|
|
63
|
+
value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value,
|
|
64
|
+
...endResult.deferred ? { deferred: true } : {},
|
|
65
|
+
...endResult.deferredKeys ? { deferredKeys: endResult.deferredKeys } : {}
|
|
64
66
|
} : {
|
|
65
67
|
success: false,
|
|
66
68
|
error: endResult.error
|
|
@@ -110,7 +112,9 @@ async function parseAsync(parser, args, options) {
|
|
|
110
112
|
const endResult = await parser.complete(context.state);
|
|
111
113
|
return endResult.success ? {
|
|
112
114
|
success: true,
|
|
113
|
-
value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
|
|
115
|
+
value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value,
|
|
116
|
+
...endResult.deferred ? { deferred: true } : {},
|
|
117
|
+
...endResult.deferredKeys ? { deferredKeys: endResult.deferredKeys } : {}
|
|
114
118
|
} : {
|
|
115
119
|
success: false,
|
|
116
120
|
error: endResult.error
|