@arcteninc/core 0.0.48 → 0.0.49
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/package.json +1 -1
- package/scripts/cli-extract-types-auto.ts +260 -127
package/package.json
CHANGED
|
@@ -21,9 +21,11 @@ async function ensureGeneratorLoaded(): Promise<boolean> {
|
|
|
21
21
|
// @ts-ignore - ts-json-schema-generator is optional
|
|
22
22
|
tsJsonSchemaGeneratorModule = await import('ts-json-schema-generator');
|
|
23
23
|
generatorAvailable = true;
|
|
24
|
+
console.log('✓ ts-json-schema-generator loaded successfully');
|
|
24
25
|
return true;
|
|
25
26
|
} catch (error) {
|
|
26
27
|
tsJsonSchemaGeneratorModule = false; // Mark as failed
|
|
28
|
+
console.warn('⚠️ ts-json-schema-generator not available:', error);
|
|
27
29
|
return false;
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -572,108 +574,41 @@ function resolveImportPath(
|
|
|
572
574
|
return null;
|
|
573
575
|
}
|
|
574
576
|
|
|
575
|
-
/**
|
|
576
|
-
* Try to resolve an anonymous type to a named type by checking structural compatibility
|
|
577
|
-
* This helps when function parameters use anonymous types that match existing interfaces
|
|
578
|
-
*/
|
|
579
|
-
function tryResolveToNamedType(
|
|
580
|
-
type: ts.Type,
|
|
581
|
-
checker: ts.TypeChecker,
|
|
582
|
-
sourceFile: ts.SourceFile
|
|
583
|
-
): { typeName: string; sourceFile: string } | null {
|
|
584
|
-
// Only try for object types
|
|
585
|
-
if (!(type.flags & ts.TypeFlags.Object)) return null;
|
|
586
|
-
|
|
587
|
-
const props = checker.getPropertiesOfType(type);
|
|
588
|
-
if (props.length === 0) return null;
|
|
589
|
-
|
|
590
|
-
// Get all exported interfaces/types from the same file
|
|
591
|
-
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
592
|
-
if (!moduleSymbol) return null;
|
|
593
|
-
|
|
594
|
-
const fileSymbols = checker.getExportsOfModule(moduleSymbol);
|
|
595
|
-
if (!fileSymbols || fileSymbols.length === 0) return null;
|
|
596
|
-
|
|
597
|
-
// Check each exported type/interface to see if it matches structurally
|
|
598
|
-
for (const symbol of fileSymbols) {
|
|
599
|
-
if (!symbol) continue;
|
|
600
|
-
|
|
601
|
-
const name = symbol.getName();
|
|
602
|
-
if (!name || name.length === 0) continue;
|
|
603
|
-
|
|
604
|
-
const declarations = symbol.getDeclarations();
|
|
605
|
-
if (!declarations || declarations.length === 0) continue;
|
|
606
|
-
|
|
607
|
-
for (const decl of declarations) {
|
|
608
|
-
if (ts.isInterfaceDeclaration(decl) || ts.isTypeAliasDeclaration(decl)) {
|
|
609
|
-
// Get the type from the declaration
|
|
610
|
-
const declaredType = checker.getTypeAtLocation(decl);
|
|
611
|
-
|
|
612
|
-
// Check if properties match (simple structural check)
|
|
613
|
-
const declaredProps = checker.getPropertiesOfType(declaredType);
|
|
614
|
-
if (declaredProps.length === props.length) {
|
|
615
|
-
// Check if all property names match
|
|
616
|
-
const propNames = new Set(props.map(p => p.getName()));
|
|
617
|
-
const declaredPropNames = new Set(declaredProps.map(p => p.getName()));
|
|
618
|
-
|
|
619
|
-
if (propNames.size === declaredPropNames.size &&
|
|
620
|
-
[...propNames].every(n => declaredPropNames.has(n))) {
|
|
621
|
-
// Properties match - this might be the same type
|
|
622
|
-
return {
|
|
623
|
-
typeName: name,
|
|
624
|
-
sourceFile: sourceFile.fileName,
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
577
|
/**
|
|
636
578
|
* Try to get type name and source file for use with ts-json-schema-generator
|
|
579
|
+
* Handles interfaces, type aliases, classes, and enums
|
|
637
580
|
*/
|
|
638
581
|
function getTypeInfoForGenerator(
|
|
639
582
|
type: ts.Type,
|
|
640
|
-
checker: ts.TypeChecker
|
|
641
|
-
paramSourceFile?: ts.SourceFile
|
|
583
|
+
checker: ts.TypeChecker
|
|
642
584
|
): { typeName: string; sourceFile: string } | null {
|
|
643
585
|
const symbol = type.getSymbol();
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}
|
|
586
|
+
if (!symbol) return null;
|
|
587
|
+
|
|
588
|
+
const name = symbol.getName();
|
|
589
|
+
if (!name || name.length === 0) return null;
|
|
590
|
+
|
|
591
|
+
const declarations = symbol.getDeclarations();
|
|
592
|
+
if (!declarations || declarations.length === 0) return null;
|
|
593
|
+
|
|
594
|
+
// Find the first declaration that's a type alias, interface, class, or enum
|
|
595
|
+
for (const decl of declarations) {
|
|
596
|
+
if (
|
|
597
|
+
ts.isTypeAliasDeclaration(decl) ||
|
|
598
|
+
ts.isInterfaceDeclaration(decl) ||
|
|
599
|
+
ts.isClassDeclaration(decl) ||
|
|
600
|
+
ts.isEnumDeclaration(decl)
|
|
601
|
+
) {
|
|
602
|
+
const sourceFile = decl.getSourceFile();
|
|
603
|
+
if (sourceFile) {
|
|
604
|
+
return {
|
|
605
|
+
typeName: name,
|
|
606
|
+
sourceFile: sourceFile.fileName,
|
|
607
|
+
};
|
|
667
608
|
}
|
|
668
609
|
}
|
|
669
610
|
}
|
|
670
|
-
|
|
671
|
-
// If it's an anonymous type, try to resolve it to a named type
|
|
672
|
-
if (paramSourceFile) {
|
|
673
|
-
const resolved = tryResolveToNamedType(type, checker, paramSourceFile);
|
|
674
|
-
if (resolved) return resolved;
|
|
675
|
-
}
|
|
676
|
-
|
|
611
|
+
|
|
677
612
|
return null;
|
|
678
613
|
}
|
|
679
614
|
|
|
@@ -695,17 +630,7 @@ async function serializeTypeWithGenerator(
|
|
|
695
630
|
return null;
|
|
696
631
|
}
|
|
697
632
|
|
|
698
|
-
|
|
699
|
-
let sourceFileForLookup: ts.SourceFile | undefined;
|
|
700
|
-
const symbol = type.getSymbol();
|
|
701
|
-
if (symbol) {
|
|
702
|
-
const declarations = symbol.getDeclarations();
|
|
703
|
-
if (declarations && declarations.length > 0) {
|
|
704
|
-
sourceFileForLookup = declarations[0].getSourceFile();
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
const typeInfo = getTypeInfoForGenerator(type, checker, sourceFileForLookup);
|
|
633
|
+
const typeInfo = getTypeInfoForGenerator(type, checker);
|
|
709
634
|
if (!typeInfo) return null;
|
|
710
635
|
|
|
711
636
|
try {
|
|
@@ -741,7 +666,8 @@ async function serializeTypeWithGenerator(
|
|
|
741
666
|
schema: schemaWithoutDefs as JsonSchemaProperty,
|
|
742
667
|
};
|
|
743
668
|
} catch (error) {
|
|
744
|
-
// If generator fails,
|
|
669
|
+
// If generator fails, log the error for debugging
|
|
670
|
+
console.warn(`⚠️ ts-json-schema-generator failed for type "${typeInfo.typeName}" from ${typeInfo.sourceFile}:`, error);
|
|
745
671
|
return null;
|
|
746
672
|
}
|
|
747
673
|
}
|
|
@@ -749,39 +675,246 @@ async function serializeTypeWithGenerator(
|
|
|
749
675
|
// Cache for generator results to avoid repeated calls
|
|
750
676
|
const generatorCache = new Map<string, { isOptional: boolean; schema: JsonSchemaProperty }>();
|
|
751
677
|
|
|
678
|
+
/**
|
|
679
|
+
* Custom serializer for anonymous types, enums, and object types
|
|
680
|
+
* This is a fallback when ts-json-schema-generator can't handle the type
|
|
681
|
+
*/
|
|
682
|
+
function serializeTypeCustom(
|
|
683
|
+
type: ts.Type,
|
|
684
|
+
checker: ts.TypeChecker,
|
|
685
|
+
defs?: Record<string, JsonSchemaProperty>,
|
|
686
|
+
visited = new Set<number>(),
|
|
687
|
+
depth = 0
|
|
688
|
+
): { isOptional: boolean; schema: JsonSchemaProperty } {
|
|
689
|
+
// Prevent infinite recursion
|
|
690
|
+
if (depth > 10) {
|
|
691
|
+
return { isOptional: false, schema: {} };
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const typeId = (type as any).id;
|
|
695
|
+
if (typeId !== undefined && visited.has(typeId)) {
|
|
696
|
+
return { isOptional: false, schema: {} };
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if (typeId !== undefined) {
|
|
700
|
+
visited.add(typeId);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Handle primitives first (safety net in case serializeType didn't catch them)
|
|
704
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
705
|
+
return { isOptional: false, schema: { type: 'string' } };
|
|
706
|
+
}
|
|
707
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
708
|
+
return { isOptional: false, schema: { type: 'number' } };
|
|
709
|
+
}
|
|
710
|
+
if (type.flags & ts.TypeFlags.Boolean) {
|
|
711
|
+
return { isOptional: false, schema: { type: 'boolean' } };
|
|
712
|
+
}
|
|
713
|
+
if (type.flags & ts.TypeFlags.Null) {
|
|
714
|
+
return { isOptional: false, schema: { type: 'null' } };
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Handle string/number literals (enum values are often represented as literals)
|
|
718
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
719
|
+
const literalType = type as ts.StringLiteralType;
|
|
720
|
+
return { isOptional: false, schema: { type: 'string', const: literalType.value } };
|
|
721
|
+
}
|
|
722
|
+
if (type.flags & ts.TypeFlags.NumberLiteral) {
|
|
723
|
+
const literalType = type as ts.NumberLiteralType;
|
|
724
|
+
return { isOptional: false, schema: { type: 'number', const: literalType.value } };
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Handle enums (TypeScript enum types)
|
|
728
|
+
const symbol = type.getSymbol();
|
|
729
|
+
if (symbol) {
|
|
730
|
+
const declarations = symbol.getDeclarations();
|
|
731
|
+
if (declarations && declarations.length > 0) {
|
|
732
|
+
const firstDecl = declarations[0];
|
|
733
|
+
if (ts.isEnumDeclaration(firstDecl)) {
|
|
734
|
+
const enumMembers = firstDecl.members.map(m => {
|
|
735
|
+
if (m.initializer && ts.isStringLiteral(m.initializer)) {
|
|
736
|
+
return m.initializer.text;
|
|
737
|
+
} else if (m.initializer && ts.isNumericLiteral(m.initializer)) {
|
|
738
|
+
return Number(m.initializer.text);
|
|
739
|
+
} else if (m.name && ts.isIdentifier(m.name)) {
|
|
740
|
+
// For enum members without initializers, use the name
|
|
741
|
+
return m.name.text;
|
|
742
|
+
}
|
|
743
|
+
return null;
|
|
744
|
+
}).filter((v): v is string | number => v !== null);
|
|
745
|
+
|
|
746
|
+
if (enumMembers.length > 0) {
|
|
747
|
+
return { isOptional: false, schema: { enum: enumMembers } };
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Handle object types with properties
|
|
754
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
755
|
+
const props = checker.getPropertiesOfType(type);
|
|
756
|
+
if (props.length > 0) {
|
|
757
|
+
const properties: Record<string, JsonSchemaProperty> = {};
|
|
758
|
+
const required: string[] = [];
|
|
759
|
+
|
|
760
|
+
for (const prop of props) {
|
|
761
|
+
const propName = prop.getName();
|
|
762
|
+
const propType = checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration || prop.declarations?.[0] || checker.getDeclaredTypeOfSymbol(prop).symbol?.valueDeclaration || null as any);
|
|
763
|
+
const isOptional = (prop.flags & ts.SymbolFlags.Optional) !== 0;
|
|
764
|
+
|
|
765
|
+
// Recursively serialize the property type
|
|
766
|
+
const propResult = serializeTypeCustom(propType, checker, defs, new Set(visited), depth + 1);
|
|
767
|
+
properties[propName] = propResult.schema;
|
|
768
|
+
|
|
769
|
+
if (!isOptional && !propResult.isOptional) {
|
|
770
|
+
required.push(propName);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
isOptional: false,
|
|
776
|
+
schema: {
|
|
777
|
+
type: 'object',
|
|
778
|
+
properties,
|
|
779
|
+
...(required.length > 0 && { required })
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Fallback to empty schema
|
|
786
|
+
return { isOptional: false, schema: {} };
|
|
787
|
+
}
|
|
788
|
+
|
|
752
789
|
/**
|
|
753
790
|
* Serialize a TypeScript type to JSON Schema format using ts-json-schema-generator
|
|
754
|
-
*
|
|
755
|
-
* Returns empty schema for anonymous types
|
|
791
|
+
* Handles primitives, arrays, and named types (interfaces, type aliases, classes, enums)
|
|
756
792
|
*/
|
|
757
793
|
async function serializeType(
|
|
758
794
|
type: ts.Type,
|
|
759
795
|
checker: ts.TypeChecker,
|
|
760
796
|
program: ts.Program | undefined,
|
|
761
797
|
configPath: string | undefined,
|
|
762
|
-
defs?: Record<string, JsonSchemaProperty
|
|
763
|
-
sourceFileForLookup?: ts.SourceFile
|
|
798
|
+
defs?: Record<string, JsonSchemaProperty>
|
|
764
799
|
): Promise<{ isOptional: boolean; schema: JsonSchemaProperty }> {
|
|
765
|
-
|
|
766
|
-
|
|
800
|
+
// Handle primitives first (these don't need the generator)
|
|
801
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
802
|
+
return { isOptional: false, schema: { type: 'string' } };
|
|
803
|
+
}
|
|
804
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
805
|
+
return { isOptional: false, schema: { type: 'number' } };
|
|
806
|
+
}
|
|
807
|
+
if (type.flags & ts.TypeFlags.Boolean) {
|
|
808
|
+
return { isOptional: false, schema: { type: 'boolean' } };
|
|
809
|
+
}
|
|
810
|
+
if (type.flags & ts.TypeFlags.Null) {
|
|
811
|
+
return { isOptional: false, schema: { type: 'null' } };
|
|
812
|
+
}
|
|
813
|
+
if (type.flags & ts.TypeFlags.Undefined || type.flags & ts.TypeFlags.Void) {
|
|
814
|
+
return { isOptional: true, schema: { type: 'null' } };
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Handle string/number literals (enum values are often represented as literals)
|
|
818
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
819
|
+
const literalType = type as ts.StringLiteralType;
|
|
820
|
+
return { isOptional: false, schema: { type: 'string', const: literalType.value } };
|
|
821
|
+
}
|
|
822
|
+
if (type.flags & ts.TypeFlags.NumberLiteral) {
|
|
823
|
+
const literalType = type as ts.NumberLiteralType;
|
|
824
|
+
return { isOptional: false, schema: { type: 'number', const: literalType.value } };
|
|
767
825
|
}
|
|
768
826
|
|
|
769
|
-
//
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
827
|
+
// Handle arrays
|
|
828
|
+
if (checker.isArrayType(type)) {
|
|
829
|
+
const typeArgs = (type as ts.TypeReference).typeArguments;
|
|
830
|
+
if (typeArgs && typeArgs.length > 0) {
|
|
831
|
+
const itemResult = await serializeType(typeArgs[0], checker, program, configPath, defs);
|
|
832
|
+
return {
|
|
833
|
+
isOptional: false,
|
|
834
|
+
schema: { type: 'array', items: itemResult.schema }
|
|
835
|
+
};
|
|
778
836
|
}
|
|
837
|
+
return { isOptional: false, schema: { type: 'array' } };
|
|
779
838
|
}
|
|
780
|
-
|
|
781
|
-
|
|
839
|
+
|
|
840
|
+
// Handle union types (like string | null)
|
|
841
|
+
if (type.isUnion()) {
|
|
842
|
+
const types = type.types;
|
|
843
|
+
const hasNull = types.some(t => t.flags & ts.TypeFlags.Null);
|
|
844
|
+
const hasUndefined = types.some(t => t.flags & ts.TypeFlags.Undefined);
|
|
845
|
+
const nonNullUndefinedTypes = types.filter(
|
|
846
|
+
t => !(t.flags & ts.TypeFlags.Null) && !(t.flags & ts.TypeFlags.Undefined)
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
// If it's just T | undefined, make it optional
|
|
850
|
+
if (hasUndefined && nonNullUndefinedTypes.length === 1 && !hasNull) {
|
|
851
|
+
const result = await serializeType(nonNullUndefinedTypes[0], checker, program, configPath, defs);
|
|
852
|
+
return { isOptional: true, schema: result.schema };
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Check if union is all string/number literals (enum-like union)
|
|
856
|
+
// This handles cases where TypeScript represents enums as unions of literals
|
|
857
|
+
const allStringLiterals = nonNullUndefinedTypes.every(t => t.flags & ts.TypeFlags.StringLiteral);
|
|
858
|
+
const allNumberLiterals = nonNullUndefinedTypes.every(t => t.flags & ts.TypeFlags.NumberLiteral);
|
|
859
|
+
|
|
860
|
+
if (allStringLiterals && nonNullUndefinedTypes.length > 0) {
|
|
861
|
+
const enumValues = nonNullUndefinedTypes.map(t => {
|
|
862
|
+
const literalType = t as ts.StringLiteralType;
|
|
863
|
+
return literalType.value;
|
|
864
|
+
});
|
|
865
|
+
const schema: JsonSchemaProperty = { enum: enumValues };
|
|
866
|
+
return { isOptional: hasNull || hasUndefined, schema };
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (allNumberLiterals && nonNullUndefinedTypes.length > 0) {
|
|
870
|
+
const enumValues = nonNullUndefinedTypes.map(t => {
|
|
871
|
+
const literalType = t as ts.NumberLiteralType;
|
|
872
|
+
return literalType.value;
|
|
873
|
+
});
|
|
874
|
+
const schema: JsonSchemaProperty = { enum: enumValues };
|
|
875
|
+
return { isOptional: hasNull || hasUndefined, schema };
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Build anyOf for unions
|
|
879
|
+
if (nonNullUndefinedTypes.length > 0 || hasNull) {
|
|
880
|
+
const anyOf: JsonSchemaProperty[] = [];
|
|
881
|
+
if (hasNull || hasUndefined) {
|
|
882
|
+
anyOf.push({ type: 'null' });
|
|
883
|
+
}
|
|
884
|
+
for (const unionType of nonNullUndefinedTypes) {
|
|
885
|
+
const result = await serializeType(unionType, checker, program, configPath, defs);
|
|
886
|
+
anyOf.push(result.schema);
|
|
887
|
+
}
|
|
888
|
+
if (anyOf.length === 1) {
|
|
889
|
+
return { isOptional: hasNull || hasUndefined, schema: anyOf[0] };
|
|
890
|
+
}
|
|
891
|
+
return { isOptional: false, schema: { anyOf } };
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Check if it's an enum - handle with custom serializer first
|
|
896
|
+
const symbol = type.getSymbol();
|
|
897
|
+
if (symbol) {
|
|
898
|
+
const declarations = symbol.getDeclarations();
|
|
899
|
+
if (declarations && declarations.length > 0) {
|
|
900
|
+
const firstDecl = declarations[0];
|
|
901
|
+
if (ts.isEnumDeclaration(firstDecl)) {
|
|
902
|
+
// Use custom serializer for enums (more reliable)
|
|
903
|
+
return serializeTypeCustom(type, checker, defs);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// For named types (interfaces, type aliases, classes), try generator first
|
|
909
|
+
if (!program || !configPath) {
|
|
910
|
+
// No program/config - use custom serializer
|
|
911
|
+
return serializeTypeCustom(type, checker, defs);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const typeInfo = getTypeInfoForGenerator(type, checker);
|
|
782
915
|
if (!typeInfo) {
|
|
783
|
-
// Anonymous/inline type -
|
|
784
|
-
return
|
|
916
|
+
// Anonymous/inline type - use custom serializer
|
|
917
|
+
return serializeTypeCustom(type, checker, defs);
|
|
785
918
|
}
|
|
786
919
|
|
|
787
920
|
// Check cache first
|
|
@@ -790,14 +923,15 @@ async function serializeType(
|
|
|
790
923
|
return generatorCache.get(cacheKey)!;
|
|
791
924
|
}
|
|
792
925
|
|
|
793
|
-
// Use generator
|
|
926
|
+
// Use generator for named types
|
|
794
927
|
const result = await serializeTypeWithGenerator(type, checker, program, configPath, defs);
|
|
795
928
|
if (result) {
|
|
796
929
|
generatorCache.set(cacheKey, result);
|
|
797
930
|
return result;
|
|
798
931
|
}
|
|
799
932
|
|
|
800
|
-
// Generator failed - return empty schema
|
|
933
|
+
// Generator failed - log and return empty schema
|
|
934
|
+
console.warn(`⚠️ Failed to generate schema for type "${typeInfo.typeName}" from ${typeInfo.sourceFile}. Using empty schema.`);
|
|
801
935
|
return { isOptional: false, schema: {} }; // Empty schema = any value
|
|
802
936
|
}
|
|
803
937
|
|
|
@@ -999,8 +1133,7 @@ async function extractFunctionMetadata(
|
|
|
999
1133
|
|
|
1000
1134
|
// Use ts-json-schema-generator for named types only
|
|
1001
1135
|
// Anonymous types are not supported - agents can't use them anyway
|
|
1002
|
-
|
|
1003
|
-
const result = await serializeType(type, checker, program, configPath, defs, sourceFile);
|
|
1136
|
+
const result = await serializeType(type, checker, program, configPath, defs);
|
|
1004
1137
|
propSchema = result.schema;
|
|
1005
1138
|
isOptional = result.isOptional;
|
|
1006
1139
|
} else {
|