@arcteninc/core 0.0.51 → 0.0.53
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 +111 -61
package/package.json
CHANGED
|
@@ -692,6 +692,117 @@ function serializeTypeCustom(
|
|
|
692
692
|
}
|
|
693
693
|
|
|
694
694
|
const typeId = (type as any).id;
|
|
695
|
+
|
|
696
|
+
// Check for interfaces/type aliases FIRST (before general visited check)
|
|
697
|
+
// This allows us to handle recursive types properly with $defs
|
|
698
|
+
const symbol = type.getSymbol();
|
|
699
|
+
if (symbol) {
|
|
700
|
+
const declarations = symbol.getDeclarations();
|
|
701
|
+
if (declarations && declarations.length > 0) {
|
|
702
|
+
const firstDecl = declarations[0];
|
|
703
|
+
|
|
704
|
+
// Handle interfaces and type aliases (for recursive types)
|
|
705
|
+
if (ts.isInterfaceDeclaration(firstDecl) || ts.isTypeAliasDeclaration(firstDecl)) {
|
|
706
|
+
const typeName = symbol.getName();
|
|
707
|
+
if (typeName && defs) {
|
|
708
|
+
const defsKey = typeName; // Use the type name as key
|
|
709
|
+
|
|
710
|
+
// Check if already defined (from a previous call)
|
|
711
|
+
if (defs[defsKey]) {
|
|
712
|
+
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Check if we've visited this type before (circular/recursive reference)
|
|
716
|
+
// This happens when we encounter the same type while building its properties
|
|
717
|
+
if (typeId !== undefined && visited.has(typeId)) {
|
|
718
|
+
// Create a placeholder that will be filled in by the original call
|
|
719
|
+
if (!defs[defsKey]) {
|
|
720
|
+
defs[defsKey] = { type: 'object', properties: {} };
|
|
721
|
+
}
|
|
722
|
+
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Create placeholder first to handle recursion
|
|
726
|
+
defs[defsKey] = { type: 'object', properties: {} };
|
|
727
|
+
|
|
728
|
+
// Mark as visited BEFORE building properties (so recursion is detected)
|
|
729
|
+
if (typeId !== undefined) {
|
|
730
|
+
visited.add(typeId);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Build the schema for this type
|
|
734
|
+
// For interfaces, get properties from both the type and the declaration
|
|
735
|
+
const props = checker.getPropertiesOfType(type);
|
|
736
|
+
const properties: Record<string, JsonSchemaProperty> = {};
|
|
737
|
+
const required: string[] = [];
|
|
738
|
+
|
|
739
|
+
// Extract properties from the interface/type alias declaration
|
|
740
|
+
if (ts.isInterfaceDeclaration(firstDecl)) {
|
|
741
|
+
for (const member of firstDecl.members) {
|
|
742
|
+
if (ts.isPropertySignature(member) && ts.isIdentifier(member.name)) {
|
|
743
|
+
const propName = member.name.text;
|
|
744
|
+
const isOptional = member.questionToken !== undefined;
|
|
745
|
+
|
|
746
|
+
if (member.type) {
|
|
747
|
+
const propType = checker.getTypeFromTypeNode(member.type);
|
|
748
|
+
const propResult = serializeTypeCustom(propType, checker, defs, visited, depth + 1);
|
|
749
|
+
properties[propName] = propResult.schema;
|
|
750
|
+
|
|
751
|
+
if (!isOptional && !propResult.isOptional) {
|
|
752
|
+
required.push(propName);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
} else if (ts.isTypeAliasDeclaration(firstDecl) && firstDecl.type) {
|
|
758
|
+
// For type aliases, resolve the underlying type
|
|
759
|
+
const underlyingType = checker.getTypeFromTypeNode(firstDecl.type);
|
|
760
|
+
if (underlyingType.flags & ts.TypeFlags.Object) {
|
|
761
|
+
const aliasProps = checker.getPropertiesOfType(underlyingType);
|
|
762
|
+
for (const prop of aliasProps) {
|
|
763
|
+
const propName = prop.getName();
|
|
764
|
+
const propType = checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration || prop.declarations?.[0] || null as any);
|
|
765
|
+
const isOptional = (prop.flags & ts.SymbolFlags.Optional) !== 0;
|
|
766
|
+
|
|
767
|
+
const propResult = serializeTypeCustom(propType, checker, defs, visited, depth + 1);
|
|
768
|
+
properties[propName] = propResult.schema;
|
|
769
|
+
|
|
770
|
+
if (!isOptional && !propResult.isOptional) {
|
|
771
|
+
required.push(propName);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
} else if (props.length > 0) {
|
|
776
|
+
// Fallback: use getPropertiesOfType if declaration parsing didn't work
|
|
777
|
+
for (const prop of props) {
|
|
778
|
+
const propName = prop.getName();
|
|
779
|
+
const propType = checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration || prop.declarations?.[0] || null as any);
|
|
780
|
+
const isOptional = (prop.flags & ts.SymbolFlags.Optional) !== 0;
|
|
781
|
+
|
|
782
|
+
const propResult = serializeTypeCustom(propType, checker, defs, visited, depth + 1);
|
|
783
|
+
properties[propName] = propResult.schema;
|
|
784
|
+
|
|
785
|
+
if (!isOptional && !propResult.isOptional) {
|
|
786
|
+
required.push(propName);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Update the placeholder with the actual schema (even if empty, to avoid infinite loops)
|
|
792
|
+
defs[defsKey] = {
|
|
793
|
+
type: 'object',
|
|
794
|
+
properties,
|
|
795
|
+
...(required.length > 0 && { required })
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// Return reference
|
|
799
|
+
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// General recursion check for non-interface types
|
|
695
806
|
if (typeId !== undefined && visited.has(typeId)) {
|
|
696
807
|
return { isOptional: false, schema: {} };
|
|
697
808
|
}
|
|
@@ -725,7 +836,6 @@ function serializeTypeCustom(
|
|
|
725
836
|
}
|
|
726
837
|
|
|
727
838
|
// Handle enums (TypeScript enum types)
|
|
728
|
-
const symbol = type.getSymbol();
|
|
729
839
|
if (symbol) {
|
|
730
840
|
const declarations = symbol.getDeclarations();
|
|
731
841
|
if (declarations && declarations.length > 0) {
|
|
@@ -747,66 +857,6 @@ function serializeTypeCustom(
|
|
|
747
857
|
return { isOptional: false, schema: { enum: enumMembers } };
|
|
748
858
|
}
|
|
749
859
|
}
|
|
750
|
-
|
|
751
|
-
// Handle interfaces and type aliases (for recursive types)
|
|
752
|
-
if (ts.isInterfaceDeclaration(firstDecl) || ts.isTypeAliasDeclaration(firstDecl)) {
|
|
753
|
-
const typeName = symbol.getName();
|
|
754
|
-
if (typeName && defs) {
|
|
755
|
-
const defsKey = typeName; // Use the type name as key
|
|
756
|
-
|
|
757
|
-
// Check if we've visited this type before (circular/recursive reference)
|
|
758
|
-
if (visited.has(typeId)) {
|
|
759
|
-
// Create a reference to avoid infinite recursion
|
|
760
|
-
if (!defs[defsKey]) {
|
|
761
|
-
// Create placeholder - will be filled in below
|
|
762
|
-
defs[defsKey] = { type: 'object', properties: {} };
|
|
763
|
-
}
|
|
764
|
-
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
// Check if already defined (from a previous call)
|
|
768
|
-
if (defs[defsKey]) {
|
|
769
|
-
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// Mark as visited and build the definition
|
|
773
|
-
visited.add(typeId);
|
|
774
|
-
|
|
775
|
-
// Build the schema for this type
|
|
776
|
-
const props = checker.getPropertiesOfType(type);
|
|
777
|
-
if (props.length > 0) {
|
|
778
|
-
const properties: Record<string, JsonSchemaProperty> = {};
|
|
779
|
-
const required: string[] = [];
|
|
780
|
-
|
|
781
|
-
// Use the same visited set for properties to detect recursion
|
|
782
|
-
for (const prop of props) {
|
|
783
|
-
const propName = prop.getName();
|
|
784
|
-
const propType = checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration || prop.declarations?.[0] || checker.getDeclaredTypeOfSymbol(prop).symbol?.valueDeclaration || null as any);
|
|
785
|
-
const isOptional = (prop.flags & ts.SymbolFlags.Optional) !== 0;
|
|
786
|
-
|
|
787
|
-
// Recursively serialize the property type (will detect recursion via visited set)
|
|
788
|
-
const propResult = serializeTypeCustom(propType, checker, defs, visited, depth + 1);
|
|
789
|
-
properties[propName] = propResult.schema;
|
|
790
|
-
|
|
791
|
-
if (!isOptional && !propResult.isOptional) {
|
|
792
|
-
required.push(propName);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
const schema: JsonSchemaProperty = {
|
|
797
|
-
type: 'object',
|
|
798
|
-
properties,
|
|
799
|
-
...(required.length > 0 && { required })
|
|
800
|
-
};
|
|
801
|
-
|
|
802
|
-
// Store in defs
|
|
803
|
-
defs[defsKey] = schema;
|
|
804
|
-
|
|
805
|
-
// Return reference
|
|
806
|
-
return { isOptional: false, schema: { $ref: `#/$defs/${defsKey}` } };
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
860
|
}
|
|
811
861
|
}
|
|
812
862
|
|