@amritk/generate-parsers 0.10.0 → 0.11.1
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.
|
@@ -571,22 +571,10 @@ const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnin
|
|
|
571
571
|
preamble.push(`const _hasOnlyKnownKeys${typeName} = (input: Record<string, unknown>): boolean => {\n for (const _k in input) if (${strictKeyCheck.isUnknown('_k')}) return false;\n return true;\n};`);
|
|
572
572
|
}
|
|
573
573
|
const fallbackObject = generateFallbackObject(schema, useRefImports, typeName, suffix, subTypeNames);
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
lines.push(assertionLine);
|
|
579
|
-
}
|
|
580
|
-
if (strictKeys) {
|
|
581
|
-
lines.push(` for (const _k in input) {`);
|
|
582
|
-
lines.push(` if (${strictKeyCheck.isUnknown('_k')}) throw new Error(\`[${typeName}] unknown property "\${_k}"\`);`);
|
|
583
|
-
lines.push(` }`);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
else {
|
|
587
|
-
lines.push(` if (!isObject(input)) return ${fallbackObject};`);
|
|
588
|
-
}
|
|
589
|
-
// First pass: determine if we can generate a fast path
|
|
574
|
+
// First pass: gather per-property info and decide whether a fast path is
|
|
575
|
+
// possible. A fast path returns the input (or a direct strip-build) for
|
|
576
|
+
// already-valid input without re-running per-property validation, so it may
|
|
577
|
+
// only fire when every property can be cheaply proven in-shape.
|
|
590
578
|
const propInfo = [];
|
|
591
579
|
// Disable fast path when allOf $ref parsers need to be spread — the fast path
|
|
592
580
|
// returns input as-is and would skip those coercions.
|
|
@@ -600,162 +588,293 @@ const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnin
|
|
|
600
588
|
const isRequired = isPropertyRequired(key, schema);
|
|
601
589
|
const varName = toVarName(key);
|
|
602
590
|
propInfo.push({ key, varName, isRequired, propSchema });
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
591
|
+
if (!canFastPath)
|
|
592
|
+
continue;
|
|
593
|
+
// Records of refs require iterating every value to check shape — too
|
|
594
|
+
// expensive to inline into the parser's fast path. Disable.
|
|
595
|
+
if (shouldUseRecordRefImport(propSchema, useRefImports)) {
|
|
596
|
+
canFastPath = false;
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
const subName = subTypeNames.get(key);
|
|
600
|
+
// Inline nested objects fast-path through their private shape predicate, the
|
|
601
|
+
// same way $ref properties use the imported one.
|
|
602
|
+
const check = subName
|
|
603
|
+
? `${shapeValidatorName(subName)}(${varName})`
|
|
604
|
+
: generatePropertyTypeCheck(varName, propSchema, useRefImports, suffix);
|
|
605
|
+
if (check === null) {
|
|
606
|
+
canFastPath = false;
|
|
607
|
+
}
|
|
608
|
+
else if (isRequired) {
|
|
609
|
+
fastPathChecks.push(check);
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
fastPathChecks.push(`(${varName} === undefined || ${check})`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// The `{ ...input }` fast path preserves extras, so when stripping it may only
|
|
616
|
+
// fire on inputs that carry no undeclared key. For strict + additionalProperties:
|
|
617
|
+
// false the cold path rejects extras instead; folding the known-keys term into
|
|
618
|
+
// the guard lets the guard run *before* that rejection, so a valid clean input
|
|
619
|
+
// never pays for the per-property assertions.
|
|
620
|
+
if (stripKeys) {
|
|
621
|
+
fastPathChecks.push(`_hasOnlyKnownKeys${typeName}(input)`);
|
|
622
|
+
}
|
|
623
|
+
// The deep guard proves the whole shape (so `{ ...input }` can be returned),
|
|
624
|
+
// using the nested shape predicates and the known-keys term above.
|
|
625
|
+
const deepGuard = canFastPath && fastPathChecks.length > 0 ? fastPathChecks.join(' && ') : null;
|
|
626
|
+
// The shallow guard powers the strict strip-build fast path (stripUnknown
|
|
627
|
+
// without additionalProperties: false): it proves every scalar is well-typed
|
|
628
|
+
// and every nested object is an object, but neither walks nested shapes deeply
|
|
629
|
+
// nor requires the absence of extras. That lets it fire on the common
|
|
630
|
+
// stripUnknown input — which carries extras the build removes, and nested
|
|
631
|
+
// extras each sub-parser removes — while the cold path's per-property
|
|
632
|
+
// assertions still produce the precise error on a genuine mismatch.
|
|
633
|
+
let canShallowGuard = strict && stripUnknown && !strictKeys;
|
|
634
|
+
const shallowChecks = [];
|
|
635
|
+
if (canShallowGuard) {
|
|
636
|
+
for (const { key, varName, isRequired, propSchema } of propInfo) {
|
|
637
|
+
const subName = subTypeNames.get(key);
|
|
638
|
+
let check;
|
|
639
|
+
if (subName) {
|
|
640
|
+
// Nested inline object: a shallow `isObject` is enough — the sub-parser
|
|
641
|
+
// validates and strips it.
|
|
642
|
+
check = `isObject(${varName})`;
|
|
643
|
+
}
|
|
644
|
+
else if (isSchemaObject(propSchema) &&
|
|
645
|
+
!hasEnum(propSchema) &&
|
|
646
|
+
!hasRef(propSchema) &&
|
|
647
|
+
!hasOneOf(propSchema) &&
|
|
648
|
+
!hasAnyOf(propSchema) &&
|
|
649
|
+
!hasAllOf(propSchema) &&
|
|
650
|
+
!('not' in propSchema) &&
|
|
651
|
+
!shouldUseRefImport(propSchema, useRefImports) &&
|
|
652
|
+
!shouldUseArrayRefImport(propSchema, useRefImports) &&
|
|
653
|
+
!shouldUseRecordRefImport(propSchema, useRefImports)) {
|
|
654
|
+
// Plain scalar / array / object: its own type check is already shallow
|
|
655
|
+
// (arrays are not walked, objects only `isObject`-checked).
|
|
656
|
+
check = generatePropertyTypeCheck(varName, propSchema, useRefImports, suffix);
|
|
609
657
|
}
|
|
610
658
|
else {
|
|
611
|
-
|
|
612
|
-
// Inline nested objects fast-path through their private shape
|
|
613
|
-
// predicate, the same way $ref properties use the imported one.
|
|
614
|
-
const check = subName
|
|
615
|
-
? `${shapeValidatorName(subName)}(${varName})`
|
|
616
|
-
: generatePropertyTypeCheck(varName, propSchema, useRefImports, suffix);
|
|
617
|
-
if (check === null) {
|
|
618
|
-
canFastPath = false;
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
if (isRequired) {
|
|
622
|
-
fastPathChecks.push(check);
|
|
623
|
-
}
|
|
624
|
-
else {
|
|
625
|
-
fastPathChecks.push(`(${varName} === undefined || ${check})`);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
659
|
+
check = null;
|
|
628
660
|
}
|
|
661
|
+
if (check === null) {
|
|
662
|
+
canShallowGuard = false;
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
shallowChecks.push(isRequired ? check : `(${varName} === undefined || ${check})`);
|
|
629
666
|
}
|
|
630
667
|
}
|
|
631
|
-
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
|
|
635
|
-
if (stripKeys && !(strict && strictKeys)) {
|
|
636
|
-
fastPathChecks.push(`_hasOnlyKnownKeys${typeName}(input)`);
|
|
637
|
-
}
|
|
638
|
-
// Second pass: generate variable declarations only for properties that need them
|
|
668
|
+
const shallowGuard = canShallowGuard && shallowChecks.length > 0 ? shallowChecks.join(' && ') : null;
|
|
669
|
+
// Variable declarations for properties that need them (the build and guards
|
|
670
|
+
// read each cached value once instead of re-accessing `input`).
|
|
671
|
+
const varDeclLines = [];
|
|
639
672
|
for (const { key, varName, propSchema } of propInfo) {
|
|
640
673
|
if (shouldCacheVariable(propSchema, canFastPath, useRefImports)) {
|
|
641
|
-
|
|
674
|
+
varDeclLines.push(` const ${varName} = ${safeAccessor('input', key)};`);
|
|
642
675
|
}
|
|
643
676
|
}
|
|
644
|
-
// Emit a warning for any input key not declared in the schema's properties
|
|
677
|
+
// Emit a warning for any input key not declared in the schema's properties.
|
|
678
|
+
const warnLines = [];
|
|
645
679
|
if (logWarnings && propInfo.length > 0) {
|
|
646
680
|
const warnKeyCheck = unknownKeyCheck(propInfo.map(({ key }) => key), '_knownKeys');
|
|
647
681
|
for (const declaration of warnKeyCheck.declarations) {
|
|
648
|
-
|
|
682
|
+
warnLines.push(` ${declaration};`);
|
|
649
683
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
//
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
684
|
+
warnLines.push(` for (const _k in input) {`);
|
|
685
|
+
warnLines.push(` if (${warnKeyCheck.isUnknown('_k')}) {`);
|
|
686
|
+
warnLines.push(` console.warn(\`[${typeName}] Unknown property "\${_k}"\`);`);
|
|
687
|
+
warnLines.push(` }`);
|
|
688
|
+
warnLines.push(` }`);
|
|
689
|
+
}
|
|
690
|
+
// Builds the result object literal. `directAssign` (strict mode) assigns each
|
|
691
|
+
// field straight from its cached read — the guard or the per-property
|
|
692
|
+
// assertions have already proven the type, so no coercion ternary is needed.
|
|
693
|
+
// Coerce mode keeps the type-checking-and-coercing expression. Refs, arrays of
|
|
694
|
+
// refs, records of refs and inline nested objects always delegate to their
|
|
695
|
+
// parser in both modes; the input spread is dropped whenever stripping.
|
|
696
|
+
const buildObjectLines = (directAssign) => {
|
|
697
|
+
const objectLines = [];
|
|
698
|
+
if (!stripKeys) {
|
|
699
|
+
objectLines.push(' ...input,');
|
|
661
700
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
objectLines.push(' ...input,');
|
|
671
|
-
}
|
|
672
|
-
// Spread allOf $ref parsers so their field coercions are applied before
|
|
673
|
-
// the explicit property validations below.
|
|
674
|
-
if (useRefImports && isSchemaObject(schema) && hasAllOf(schema)) {
|
|
675
|
-
for (const entry of schema.allOf) {
|
|
676
|
-
if (isSchemaObject(entry) && hasRef(entry)) {
|
|
677
|
-
const parserName = generateParserName(refToName(entry.$ref, suffix));
|
|
678
|
-
objectLines.push(` ...(${parserName}(input) as Record<string, unknown>),`);
|
|
701
|
+
// Spread allOf $ref parsers so their field coercions are applied before
|
|
702
|
+
// the explicit property validations below.
|
|
703
|
+
if (useRefImports && isSchemaObject(schema) && hasAllOf(schema)) {
|
|
704
|
+
for (const entry of schema.allOf) {
|
|
705
|
+
if (isSchemaObject(entry) && hasRef(entry)) {
|
|
706
|
+
const parserName = generateParserName(refToName(entry.$ref, suffix));
|
|
707
|
+
objectLines.push(` ...(${parserName}(input) as Record<string, unknown>),`);
|
|
708
|
+
}
|
|
679
709
|
}
|
|
680
710
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
711
|
+
for (const { key, varName, isRequired, propSchema } of propInfo) {
|
|
712
|
+
const shouldCache = shouldCacheVariable(propSchema, canFastPath, useRefImports);
|
|
713
|
+
const accessor = shouldCache ? varName : safeAccessor('input', key);
|
|
714
|
+
// Handle inline nested objects via their private sub-parser, mirroring
|
|
715
|
+
// how $ref properties delegate to the imported parser.
|
|
716
|
+
const subName = subTypeNames.get(key);
|
|
717
|
+
if (subName) {
|
|
718
|
+
const subParserName = generateParserName(subName);
|
|
719
|
+
if (isRequired) {
|
|
720
|
+
objectLines.push(` ${safeKey(key)}: ${subParserName}(${accessor}),`);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}: ${subParserName}(${accessor}) }),`);
|
|
724
|
+
}
|
|
725
|
+
continue;
|
|
692
726
|
}
|
|
693
|
-
|
|
694
|
-
|
|
727
|
+
// Handle direct $ref properties via imported parsers
|
|
728
|
+
if (shouldUseRefImport(propSchema, useRefImports)) {
|
|
729
|
+
const ref = propSchema.$ref;
|
|
730
|
+
const parserName = generateParserName(refToName(ref, suffix));
|
|
731
|
+
if (isRequired) {
|
|
732
|
+
objectLines.push(` ${safeKey(key)}: ${parserName}(${accessor}),`);
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}: ${parserName}(${accessor}) }),`);
|
|
736
|
+
}
|
|
737
|
+
continue;
|
|
695
738
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
739
|
+
// Handle array properties with $ref items
|
|
740
|
+
if (shouldUseArrayRefImport(propSchema, useRefImports)) {
|
|
741
|
+
const items = propSchema.items;
|
|
742
|
+
const ref = items.$ref;
|
|
743
|
+
const parserName = generateParserName(refToName(ref, suffix));
|
|
744
|
+
if (isRequired) {
|
|
745
|
+
objectLines.push(` ${safeKey(key)}: validateArray(${accessor}, ${parserName}),`);
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}: validateArray(${accessor}, ${parserName}) }),`);
|
|
749
|
+
}
|
|
750
|
+
continue;
|
|
704
751
|
}
|
|
705
|
-
|
|
706
|
-
|
|
752
|
+
// Handle object properties with additionalProperties $ref
|
|
753
|
+
if (shouldUseRecordRefImport(propSchema, useRefImports)) {
|
|
754
|
+
const additionalProps = propSchema.additionalProperties;
|
|
755
|
+
const ref = additionalProps.$ref;
|
|
756
|
+
const parserName = generateParserName(refToName(ref, suffix));
|
|
757
|
+
if (isRequired) {
|
|
758
|
+
objectLines.push(` ${safeKey(key)}: validateRecord(${accessor}, ${parserName}),`);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}: validateRecord(${accessor}, ${parserName}) }),`);
|
|
762
|
+
}
|
|
763
|
+
continue;
|
|
707
764
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
765
|
+
// Handle non-schema-object properties
|
|
766
|
+
if (!isSchemaObject(propSchema)) {
|
|
767
|
+
if (isRequired) {
|
|
768
|
+
objectLines.push(` ${safeKey(key)}: undefined,`);
|
|
769
|
+
}
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
// Strict mode has already proven the value's type (by guard or assertion),
|
|
773
|
+
// so the field is assigned straight from the cached read with no coercion.
|
|
774
|
+
let valueExpr;
|
|
775
|
+
if (directAssign) {
|
|
776
|
+
valueExpr = accessor;
|
|
717
777
|
}
|
|
718
778
|
else {
|
|
719
|
-
|
|
779
|
+
const defaultValue = getDefaultValue(propSchema);
|
|
780
|
+
// For optional properties we know the value is not undefined because
|
|
781
|
+
// we're inside the `...(accessor !== undefined && { ... })` check.
|
|
782
|
+
const knownNotUndefined = !isRequired;
|
|
783
|
+
valueExpr = generateValidationExpression(key, propSchema, defaultValue, true, undefined, undefined, shouldCache ? varName : undefined, knownNotUndefined);
|
|
720
784
|
}
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
// Handle object properties with additionalProperties $ref
|
|
724
|
-
if (shouldUseRecordRefImport(propSchema, useRefImports)) {
|
|
725
|
-
const additionalProps = propSchema.additionalProperties;
|
|
726
|
-
const ref = additionalProps.$ref;
|
|
727
|
-
const parserName = generateParserName(refToName(ref, suffix));
|
|
728
785
|
if (isRequired) {
|
|
729
|
-
objectLines.push(` ${safeKey(key)}:
|
|
786
|
+
objectLines.push(` ${safeKey(key)}: ${valueExpr},`);
|
|
730
787
|
}
|
|
731
788
|
else {
|
|
732
|
-
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}:
|
|
789
|
+
objectLines.push(` ...(${accessor} !== undefined && { ${safeKey(key)}: ${valueExpr} }),`);
|
|
733
790
|
}
|
|
734
|
-
continue;
|
|
735
791
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
792
|
+
return objectLines;
|
|
793
|
+
};
|
|
794
|
+
const emitReturn = (lines, objectLines) => {
|
|
795
|
+
lines.push(` return {`);
|
|
796
|
+
lines.push(objectLines.join('\n'));
|
|
797
|
+
lines.push(` } as unknown as ${typeName};`);
|
|
798
|
+
};
|
|
799
|
+
// The deep-guard fast path. `{ ...input }` is the only correct shape when the
|
|
800
|
+
// guard let undeclared keys through (no known-keys term) — they must survive.
|
|
801
|
+
// But when `stripKeys` is set the guard *also* proved `_hasOnlyKnownKeys`, so
|
|
802
|
+
// the input's keys are exactly the declared properties: an explicit literal of
|
|
803
|
+
// those keys is then equivalent to the spread, and faster — a fixed-shape
|
|
804
|
+
// literal beats a generic spread, yields a stable hidden class, and produces
|
|
805
|
+
// the same declared key order as the slow path (the spread used input order).
|
|
806
|
+
// The literal shares each value by reference, exactly like the spread did, so
|
|
807
|
+
// it never re-parses an already-validated nested object. allOf merges in
|
|
808
|
+
// properties this `propInfo` list doesn't carry, so it keeps the spread.
|
|
809
|
+
const emitDeepGuardReturn = (lines) => {
|
|
810
|
+
const canLiteral = stripKeys && !(isSchemaObject(schema) && hasAllOf(schema));
|
|
811
|
+
if (!canLiteral) {
|
|
812
|
+
lines.push(` if (${deepGuard}) return { ...input } as ${typeName};`);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const fields = [];
|
|
816
|
+
for (const { key, varName, isRequired, propSchema } of propInfo) {
|
|
817
|
+
if (!isSchemaObject(propSchema)) {
|
|
818
|
+
if (isRequired)
|
|
819
|
+
fields.push(` ${safeKey(key)}: undefined,`);
|
|
820
|
+
continue;
|
|
740
821
|
}
|
|
741
|
-
|
|
822
|
+
const accessor = shouldCacheVariable(propSchema, canFastPath, useRefImports)
|
|
823
|
+
? varName
|
|
824
|
+
: safeAccessor('input', key);
|
|
825
|
+
fields.push(isRequired
|
|
826
|
+
? ` ${safeKey(key)}: ${accessor},`
|
|
827
|
+
: ` ...(${accessor} !== undefined && { ${safeKey(key)}: ${accessor} }),`);
|
|
742
828
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
829
|
+
lines.push(` if (${deepGuard}) return {`);
|
|
830
|
+
lines.push(fields.join('\n'));
|
|
831
|
+
lines.push(` } as ${typeName};`);
|
|
832
|
+
};
|
|
833
|
+
const lines = [];
|
|
834
|
+
lines.push(`${exportPrefix}const ${functionName} = (input: unknown): ${typeName} => {`);
|
|
835
|
+
if (strict) {
|
|
836
|
+
// Guard first: a non-object throws straight away; a clean, well-typed input
|
|
837
|
+
// then short-circuits past the per-property assertions, which only run to
|
|
838
|
+
// pinpoint the failure when the guard rejects the input.
|
|
839
|
+
lines.push(` if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);`);
|
|
840
|
+
lines.push(...varDeclLines);
|
|
841
|
+
lines.push(...warnLines);
|
|
842
|
+
// The first assertion line is the `isObject` check, already done above.
|
|
843
|
+
const assertionLines = generateObjectStrictAssertion(schema, typeName).slice(1);
|
|
844
|
+
if (shallowGuard) {
|
|
845
|
+
// stripUnknown: a well-typed input skips the assertions and goes straight
|
|
846
|
+
// to the strip build (which removes extras and recurses into sub-parsers).
|
|
847
|
+
lines.push(` if (!(${shallowGuard})) {`);
|
|
848
|
+
for (const assertionLine of assertionLines) {
|
|
849
|
+
lines.push(` ${assertionLine}`);
|
|
850
|
+
}
|
|
851
|
+
lines.push(` }`);
|
|
852
|
+
emitReturn(lines, buildObjectLines(true));
|
|
751
853
|
}
|
|
752
854
|
else {
|
|
753
|
-
|
|
855
|
+
if (deepGuard) {
|
|
856
|
+
emitDeepGuardReturn(lines);
|
|
857
|
+
}
|
|
858
|
+
for (const assertionLine of assertionLines) {
|
|
859
|
+
lines.push(assertionLine);
|
|
860
|
+
}
|
|
861
|
+
if (strictKeys) {
|
|
862
|
+
lines.push(` for (const _k in input) {`);
|
|
863
|
+
lines.push(` if (${strictKeyCheck.isUnknown('_k')}) throw new Error(\`[${typeName}] unknown property "\${_k}"\`);`);
|
|
864
|
+
lines.push(` }`);
|
|
865
|
+
}
|
|
866
|
+
emitReturn(lines, buildObjectLines(true));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
lines.push(` if (!isObject(input)) return ${fallbackObject};`);
|
|
871
|
+
lines.push(...varDeclLines);
|
|
872
|
+
lines.push(...warnLines);
|
|
873
|
+
if (deepGuard) {
|
|
874
|
+
emitDeepGuardReturn(lines);
|
|
754
875
|
}
|
|
876
|
+
emitReturn(lines, buildObjectLines(false));
|
|
755
877
|
}
|
|
756
|
-
lines.push(` return {`);
|
|
757
|
-
lines.push(objectLines.join('\n'));
|
|
758
|
-
lines.push(` } as unknown as ${typeName};`);
|
|
759
878
|
lines.push(`}`);
|
|
760
879
|
const fn = lines.join('\n');
|
|
761
880
|
if (preamble.length === 0)
|