Added recursive pydantic model converter
This commit is contained in:
parent
1531a05de0
commit
9edf5a5b23
@ -1,6 +1,6 @@
|
||||
// Generated TypeScript types from Pydantic models
|
||||
// Source: src/backend/models.py
|
||||
// Generated on: 2025-06-09T20:36:06.432367
|
||||
// Generated on: 2025-06-10T02:48:12.087485
|
||||
// DO NOT EDIT MANUALLY - This file is auto-generated
|
||||
|
||||
// ============================
|
||||
@ -161,8 +161,8 @@ export interface BaseUser {
|
||||
fullName: string;
|
||||
phone?: string;
|
||||
location?: Location;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
lastLogin?: Date;
|
||||
profileImage?: string;
|
||||
status: "active" | "inactive" | "pending" | "banned";
|
||||
@ -185,8 +185,8 @@ export interface Candidate {
|
||||
fullName: string;
|
||||
phone?: string;
|
||||
location?: Location;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
lastLogin?: Date;
|
||||
profileImage?: string;
|
||||
status: "active" | "inactive" | "pending" | "banned";
|
||||
@ -219,8 +219,8 @@ export interface CandidateAI {
|
||||
fullName: string;
|
||||
phone?: string;
|
||||
location?: Location;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
lastLogin?: Date;
|
||||
profileImage?: string;
|
||||
status: "active" | "inactive" | "pending" | "banned";
|
||||
@ -353,6 +353,8 @@ export interface ChatMessageResume {
|
||||
tunables?: Tunables;
|
||||
metadata: ChatMessageMetaData;
|
||||
resume: string;
|
||||
systemPrompt?: string;
|
||||
prompt?: string;
|
||||
}
|
||||
|
||||
export interface ChatMessageSkillAssessment {
|
||||
@ -567,8 +569,8 @@ export interface Employer {
|
||||
fullName: string;
|
||||
phone?: string;
|
||||
location?: Location;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
lastLogin?: Date;
|
||||
profileImage?: string;
|
||||
status: "active" | "inactive" | "pending" | "banned";
|
||||
@ -620,8 +622,8 @@ export interface Guest {
|
||||
fullName: string;
|
||||
phone?: string;
|
||||
location?: Location;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
lastLogin?: Date;
|
||||
profileImage?: string;
|
||||
status: "active" | "inactive" | "pending" | "banned";
|
||||
@ -682,8 +684,8 @@ export interface InterviewFeedback {
|
||||
weaknesses: Array<string>;
|
||||
recommendation: "strong_hire" | "hire" | "no_hire" | "strong_no_hire";
|
||||
comments: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
isVisible: boolean;
|
||||
skillAssessments?: Array<SkillAssessment>;
|
||||
}
|
||||
@ -712,8 +714,8 @@ export interface Job {
|
||||
company?: string;
|
||||
description: string;
|
||||
requirements?: JobRequirements;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
}
|
||||
|
||||
export interface JobApplication {
|
||||
@ -742,12 +744,12 @@ export interface JobFull {
|
||||
company?: string;
|
||||
description: string;
|
||||
requirements?: JobRequirements;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
location: Location;
|
||||
salaryRange?: SalaryRange;
|
||||
employmentType: "full-time" | "part-time" | "contract" | "internship" | "freelance";
|
||||
datePosted: Date;
|
||||
datePosted?: Date;
|
||||
applicationDeadline?: Date;
|
||||
isActive: boolean;
|
||||
applicants?: Array<JobApplication>;
|
||||
@ -784,11 +786,7 @@ export interface JobRequirementsMessage {
|
||||
status: "streaming" | "status" | "done" | "error";
|
||||
type: "binary" | "text" | "json";
|
||||
timestamp?: Date;
|
||||
title?: string;
|
||||
summary?: string;
|
||||
company?: string;
|
||||
description: string;
|
||||
requirements?: JobRequirements;
|
||||
job: Job;
|
||||
}
|
||||
|
||||
export interface JobResponse {
|
||||
@ -901,8 +899,8 @@ export interface RAGConfiguration {
|
||||
embeddingModel: string;
|
||||
vectorStoreType: "chroma";
|
||||
retrievalParameters: RetrievalParameters;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
version: number;
|
||||
isActive: boolean;
|
||||
}
|
||||
@ -1078,14 +1076,14 @@ export interface WorkExperience {
|
||||
}
|
||||
|
||||
// ============================
|
||||
// Date Conversion Functions
|
||||
// Date and Nested Model Conversion Functions
|
||||
// ============================
|
||||
|
||||
// These functions convert API responses to properly typed objects
|
||||
// with Date objects instead of ISO date strings
|
||||
// with Date objects instead of ISO date strings and nested model conversions
|
||||
|
||||
/**
|
||||
* Convert Analytics from API response, parsing date fields
|
||||
* Convert Analytics from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertAnalyticsFromApi(data: any): Analytics {
|
||||
@ -1098,7 +1096,7 @@ export function convertAnalyticsFromApi(data: any): Analytics {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ApiMessage from API response, parsing date fields
|
||||
* Convert ApiMessage from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertApiMessageFromApi(data: any): ApiMessage {
|
||||
@ -1111,7 +1109,7 @@ export function convertApiMessageFromApi(data: any): ApiMessage {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ApplicationDecision from API response, parsing date fields
|
||||
* Convert ApplicationDecision from API response
|
||||
* Date fields: date
|
||||
*/
|
||||
export function convertApplicationDecisionFromApi(data: any): ApplicationDecision {
|
||||
@ -1124,7 +1122,7 @@ export function convertApplicationDecisionFromApi(data: any): ApplicationDecisio
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Attachment from API response, parsing date fields
|
||||
* Convert Attachment from API response
|
||||
* Date fields: uploadedAt
|
||||
*/
|
||||
export function convertAttachmentFromApi(data: any): Attachment {
|
||||
@ -1137,8 +1135,22 @@ export function convertAttachmentFromApi(data: any): Attachment {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Authentication from API response, parsing date fields
|
||||
* Convert AuthResponse from API response
|
||||
* Nested models: user (Candidate)
|
||||
*/
|
||||
export function convertAuthResponseFromApi(data: any): AuthResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Candidate model
|
||||
user: convertCandidateFromApi(data.user),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Authentication from API response
|
||||
* Date fields: resetPasswordExpiry, lastPasswordChange, lockedUntil
|
||||
* Nested models: refreshTokens (RefreshToken)
|
||||
*/
|
||||
export function convertAuthenticationFromApi(data: any): Authentication {
|
||||
if (!data) return data;
|
||||
@ -1151,10 +1163,12 @@ export function convertAuthenticationFromApi(data: any): Authentication {
|
||||
lastPasswordChange: new Date(data.lastPasswordChange),
|
||||
// Convert lockedUntil from ISO string to Date
|
||||
lockedUntil: data.lockedUntil ? new Date(data.lockedUntil) : undefined,
|
||||
// Convert nested RefreshToken model
|
||||
refreshTokens: data.refreshTokens.map((item: any) => convertRefreshTokenFromApi(item)),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert BaseUser from API response, parsing date fields
|
||||
* Convert BaseUser from API response
|
||||
* Date fields: lastActivity, createdAt, updatedAt, lastLogin
|
||||
*/
|
||||
export function convertBaseUserFromApi(data: any): BaseUser {
|
||||
@ -1165,15 +1179,15 @@ export function convertBaseUserFromApi(data: any): BaseUser {
|
||||
// Convert lastActivity from ISO string to Date
|
||||
lastActivity: data.lastActivity ? new Date(data.lastActivity) : undefined,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert lastLogin from ISO string to Date
|
||||
lastLogin: data.lastLogin ? new Date(data.lastLogin) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert BaseUserWithType from API response, parsing date fields
|
||||
* Convert BaseUserWithType from API response
|
||||
* Date fields: lastActivity
|
||||
*/
|
||||
export function convertBaseUserWithTypeFromApi(data: any): BaseUserWithType {
|
||||
@ -1186,8 +1200,9 @@ export function convertBaseUserWithTypeFromApi(data: any): BaseUserWithType {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Candidate from API response, parsing date fields
|
||||
* Convert Candidate from API response
|
||||
* Date fields: lastActivity, createdAt, updatedAt, lastLogin, availabilityDate
|
||||
* Nested models: experience (WorkExperience), education (Education), certifications (Certification), jobApplications (JobApplication)
|
||||
*/
|
||||
export function convertCandidateFromApi(data: any): Candidate {
|
||||
if (!data) return data;
|
||||
@ -1197,18 +1212,27 @@ export function convertCandidateFromApi(data: any): Candidate {
|
||||
// Convert lastActivity from ISO string to Date
|
||||
lastActivity: data.lastActivity ? new Date(data.lastActivity) : undefined,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert lastLogin from ISO string to Date
|
||||
lastLogin: data.lastLogin ? new Date(data.lastLogin) : undefined,
|
||||
// Convert availabilityDate from ISO string to Date
|
||||
availabilityDate: data.availabilityDate ? new Date(data.availabilityDate) : undefined,
|
||||
// Convert nested WorkExperience model
|
||||
experience: data.experience ? convertWorkExperienceFromApi(data.experience) : undefined,
|
||||
// Convert nested Education model
|
||||
education: data.education ? convertEducationFromApi(data.education) : undefined,
|
||||
// Convert nested Certification model
|
||||
certifications: data.certifications ? convertCertificationFromApi(data.certifications) : undefined,
|
||||
// Convert nested JobApplication model
|
||||
jobApplications: data.jobApplications ? convertJobApplicationFromApi(data.jobApplications) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert CandidateAI from API response, parsing date fields
|
||||
* Convert CandidateAI from API response
|
||||
* Date fields: lastActivity, createdAt, updatedAt, lastLogin, availabilityDate
|
||||
* Nested models: experience (WorkExperience), education (Education), certifications (Certification)
|
||||
*/
|
||||
export function convertCandidateAIFromApi(data: any): CandidateAI {
|
||||
if (!data) return data;
|
||||
@ -1218,17 +1242,49 @@ export function convertCandidateAIFromApi(data: any): CandidateAI {
|
||||
// Convert lastActivity from ISO string to Date
|
||||
lastActivity: data.lastActivity ? new Date(data.lastActivity) : undefined,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert lastLogin from ISO string to Date
|
||||
lastLogin: data.lastLogin ? new Date(data.lastLogin) : undefined,
|
||||
// Convert availabilityDate from ISO string to Date
|
||||
availabilityDate: data.availabilityDate ? new Date(data.availabilityDate) : undefined,
|
||||
// Convert nested WorkExperience model
|
||||
experience: data.experience ? convertWorkExperienceFromApi(data.experience) : undefined,
|
||||
// Convert nested Education model
|
||||
education: data.education ? convertEducationFromApi(data.education) : undefined,
|
||||
// Convert nested Certification model
|
||||
certifications: data.certifications ? convertCertificationFromApi(data.certifications) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Certification from API response, parsing date fields
|
||||
* Convert CandidateListResponse from API response
|
||||
* Nested models: data (Candidate)
|
||||
*/
|
||||
export function convertCandidateListResponseFromApi(data: any): CandidateListResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Candidate model
|
||||
data: data.data ? convertCandidateFromApi(data.data) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert CandidateResponse from API response
|
||||
* Nested models: data (Candidate)
|
||||
*/
|
||||
export function convertCandidateResponseFromApi(data: any): CandidateResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Candidate model
|
||||
data: data.data ? convertCandidateFromApi(data.data) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Certification from API response
|
||||
* Date fields: issueDate, expirationDate
|
||||
*/
|
||||
export function convertCertificationFromApi(data: any): Certification {
|
||||
@ -1243,7 +1299,7 @@ export function convertCertificationFromApi(data: any): Certification {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessage from API response, parsing date fields
|
||||
* Convert ChatMessage from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageFromApi(data: any): ChatMessage {
|
||||
@ -1256,7 +1312,7 @@ export function convertChatMessageFromApi(data: any): ChatMessage {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageError from API response, parsing date fields
|
||||
* Convert ChatMessageError from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageErrorFromApi(data: any): ChatMessageError {
|
||||
@ -1269,7 +1325,7 @@ export function convertChatMessageErrorFromApi(data: any): ChatMessageError {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageRagSearch from API response, parsing date fields
|
||||
* Convert ChatMessageRagSearch from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageRagSearchFromApi(data: any): ChatMessageRagSearch {
|
||||
@ -1282,7 +1338,7 @@ export function convertChatMessageRagSearchFromApi(data: any): ChatMessageRagSea
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageResume from API response, parsing date fields
|
||||
* Convert ChatMessageResume from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageResumeFromApi(data: any): ChatMessageResume {
|
||||
@ -1295,8 +1351,9 @@ export function convertChatMessageResumeFromApi(data: any): ChatMessageResume {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageSkillAssessment from API response, parsing date fields
|
||||
* Convert ChatMessageSkillAssessment from API response
|
||||
* Date fields: timestamp
|
||||
* Nested models: skillAssessment (SkillAssessment)
|
||||
*/
|
||||
export function convertChatMessageSkillAssessmentFromApi(data: any): ChatMessageSkillAssessment {
|
||||
if (!data) return data;
|
||||
@ -1305,10 +1362,12 @@ export function convertChatMessageSkillAssessmentFromApi(data: any): ChatMessage
|
||||
...data,
|
||||
// Convert timestamp from ISO string to Date
|
||||
timestamp: data.timestamp ? new Date(data.timestamp) : undefined,
|
||||
// Convert nested SkillAssessment model
|
||||
skillAssessment: convertSkillAssessmentFromApi(data.skillAssessment),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageStatus from API response, parsing date fields
|
||||
* Convert ChatMessageStatus from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageStatusFromApi(data: any): ChatMessageStatus {
|
||||
@ -1321,7 +1380,7 @@ export function convertChatMessageStatusFromApi(data: any): ChatMessageStatus {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageStreaming from API response, parsing date fields
|
||||
* Convert ChatMessageStreaming from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageStreamingFromApi(data: any): ChatMessageStreaming {
|
||||
@ -1334,7 +1393,7 @@ export function convertChatMessageStreamingFromApi(data: any): ChatMessageStream
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatMessageUser from API response, parsing date fields
|
||||
* Convert ChatMessageUser from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertChatMessageUserFromApi(data: any): ChatMessageUser {
|
||||
@ -1347,7 +1406,7 @@ export function convertChatMessageUserFromApi(data: any): ChatMessageUser {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert ChatSession from API response, parsing date fields
|
||||
* Convert ChatSession from API response
|
||||
* Date fields: createdAt, lastActivity
|
||||
*/
|
||||
export function convertChatSessionFromApi(data: any): ChatSession {
|
||||
@ -1362,7 +1421,7 @@ export function convertChatSessionFromApi(data: any): ChatSession {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert DataSourceConfiguration from API response, parsing date fields
|
||||
* Convert DataSourceConfiguration from API response
|
||||
* Date fields: lastRefreshed
|
||||
*/
|
||||
export function convertDataSourceConfigurationFromApi(data: any): DataSourceConfiguration {
|
||||
@ -1375,7 +1434,7 @@ export function convertDataSourceConfigurationFromApi(data: any): DataSourceConf
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Document from API response, parsing date fields
|
||||
* Convert Document from API response
|
||||
* Date fields: uploadDate
|
||||
*/
|
||||
export function convertDocumentFromApi(data: any): Document {
|
||||
@ -1388,8 +1447,22 @@ export function convertDocumentFromApi(data: any): Document {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert DocumentMessage from API response, parsing date fields
|
||||
* Convert DocumentListResponse from API response
|
||||
* Nested models: documents (Document)
|
||||
*/
|
||||
export function convertDocumentListResponseFromApi(data: any): DocumentListResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Document model
|
||||
documents: data.documents.map((item: any) => convertDocumentFromApi(item)),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert DocumentMessage from API response
|
||||
* Date fields: timestamp
|
||||
* Nested models: document (Document)
|
||||
*/
|
||||
export function convertDocumentMessageFromApi(data: any): DocumentMessage {
|
||||
if (!data) return data;
|
||||
@ -1398,10 +1471,12 @@ export function convertDocumentMessageFromApi(data: any): DocumentMessage {
|
||||
...data,
|
||||
// Convert timestamp from ISO string to Date
|
||||
timestamp: data.timestamp ? new Date(data.timestamp) : undefined,
|
||||
// Convert nested Document model
|
||||
document: convertDocumentFromApi(data.document),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert EditHistory from API response, parsing date fields
|
||||
* Convert EditHistory from API response
|
||||
* Date fields: editedAt
|
||||
*/
|
||||
export function convertEditHistoryFromApi(data: any): EditHistory {
|
||||
@ -1414,7 +1489,7 @@ export function convertEditHistoryFromApi(data: any): EditHistory {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Education from API response, parsing date fields
|
||||
* Convert Education from API response
|
||||
* Date fields: startDate, endDate
|
||||
*/
|
||||
export function convertEducationFromApi(data: any): Education {
|
||||
@ -1429,8 +1504,9 @@ export function convertEducationFromApi(data: any): Education {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Employer from API response, parsing date fields
|
||||
* Convert Employer from API response
|
||||
* Date fields: lastActivity, createdAt, updatedAt, lastLogin
|
||||
* Nested models: jobs (Job)
|
||||
*/
|
||||
export function convertEmployerFromApi(data: any): Employer {
|
||||
if (!data) return data;
|
||||
@ -1440,15 +1516,30 @@ export function convertEmployerFromApi(data: any): Employer {
|
||||
// Convert lastActivity from ISO string to Date
|
||||
lastActivity: data.lastActivity ? new Date(data.lastActivity) : undefined,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert lastLogin from ISO string to Date
|
||||
lastLogin: data.lastLogin ? new Date(data.lastLogin) : undefined,
|
||||
// Convert nested Job model
|
||||
jobs: data.jobs ? convertJobFromApi(data.jobs) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Guest from API response, parsing date fields
|
||||
* Convert EmployerResponse from API response
|
||||
* Nested models: data (Employer)
|
||||
*/
|
||||
export function convertEmployerResponseFromApi(data: any): EmployerResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Employer model
|
||||
data: data.data ? convertEmployerFromApi(data.data) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Guest from API response
|
||||
* Date fields: lastActivity, createdAt, updatedAt, lastLogin
|
||||
*/
|
||||
export function convertGuestFromApi(data: any): Guest {
|
||||
@ -1459,16 +1550,30 @@ export function convertGuestFromApi(data: any): Guest {
|
||||
// Convert lastActivity from ISO string to Date
|
||||
lastActivity: data.lastActivity ? new Date(data.lastActivity) : undefined,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert lastLogin from ISO string to Date
|
||||
lastLogin: data.lastLogin ? new Date(data.lastLogin) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert InterviewFeedback from API response, parsing date fields
|
||||
* Convert GuestSessionResponse from API response
|
||||
* Nested models: user (Guest)
|
||||
*/
|
||||
export function convertGuestSessionResponseFromApi(data: any): GuestSessionResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Guest model
|
||||
user: convertGuestFromApi(data.user),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert InterviewFeedback from API response
|
||||
* Date fields: createdAt, updatedAt
|
||||
* Nested models: skillAssessments (SkillAssessment)
|
||||
*/
|
||||
export function convertInterviewFeedbackFromApi(data: any): InterviewFeedback {
|
||||
if (!data) return data;
|
||||
@ -1476,14 +1581,17 @@ export function convertInterviewFeedbackFromApi(data: any): InterviewFeedback {
|
||||
return {
|
||||
...data,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert nested SkillAssessment model
|
||||
skillAssessments: data.skillAssessments ? convertSkillAssessmentFromApi(data.skillAssessments) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert InterviewSchedule from API response, parsing date fields
|
||||
* Convert InterviewSchedule from API response
|
||||
* Date fields: scheduledDate, endDate
|
||||
* Nested models: feedback (InterviewFeedback)
|
||||
*/
|
||||
export function convertInterviewScheduleFromApi(data: any): InterviewSchedule {
|
||||
if (!data) return data;
|
||||
@ -1494,11 +1602,14 @@ export function convertInterviewScheduleFromApi(data: any): InterviewSchedule {
|
||||
scheduledDate: new Date(data.scheduledDate),
|
||||
// Convert endDate from ISO string to Date
|
||||
endDate: new Date(data.endDate),
|
||||
// Convert nested InterviewFeedback model
|
||||
feedback: data.feedback ? convertInterviewFeedbackFromApi(data.feedback) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert Job from API response, parsing date fields
|
||||
* Convert Job from API response
|
||||
* Date fields: createdAt, updatedAt
|
||||
* Nested models: owner (BaseUser)
|
||||
*/
|
||||
export function convertJobFromApi(data: any): Job {
|
||||
if (!data) return data;
|
||||
@ -1506,14 +1617,17 @@ export function convertJobFromApi(data: any): Job {
|
||||
return {
|
||||
...data,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert nested BaseUser model
|
||||
owner: data.owner ? convertBaseUserFromApi(data.owner) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert JobApplication from API response, parsing date fields
|
||||
* Convert JobApplication from API response
|
||||
* Date fields: appliedDate, updatedDate
|
||||
* Nested models: interviewSchedules (InterviewSchedule), decision (ApplicationDecision)
|
||||
*/
|
||||
export function convertJobApplicationFromApi(data: any): JobApplication {
|
||||
if (!data) return data;
|
||||
@ -1524,11 +1638,16 @@ export function convertJobApplicationFromApi(data: any): JobApplication {
|
||||
appliedDate: new Date(data.appliedDate),
|
||||
// Convert updatedDate from ISO string to Date
|
||||
updatedDate: new Date(data.updatedDate),
|
||||
// Convert nested InterviewSchedule model
|
||||
interviewSchedules: data.interviewSchedules ? convertInterviewScheduleFromApi(data.interviewSchedules) : undefined,
|
||||
// Convert nested ApplicationDecision model
|
||||
decision: data.decision ? convertApplicationDecisionFromApi(data.decision) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert JobFull from API response, parsing date fields
|
||||
* Convert JobFull from API response
|
||||
* Date fields: createdAt, updatedAt, datePosted, applicationDeadline, featuredUntil
|
||||
* Nested models: owner (BaseUser), applicants (JobApplication)
|
||||
*/
|
||||
export function convertJobFullFromApi(data: any): JobFull {
|
||||
if (!data) return data;
|
||||
@ -1536,20 +1655,38 @@ export function convertJobFullFromApi(data: any): JobFull {
|
||||
return {
|
||||
...data,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert datePosted from ISO string to Date
|
||||
datePosted: new Date(data.datePosted),
|
||||
datePosted: data.datePosted ? new Date(data.datePosted) : undefined,
|
||||
// Convert applicationDeadline from ISO string to Date
|
||||
applicationDeadline: data.applicationDeadline ? new Date(data.applicationDeadline) : undefined,
|
||||
// Convert featuredUntil from ISO string to Date
|
||||
featuredUntil: data.featuredUntil ? new Date(data.featuredUntil) : undefined,
|
||||
// Convert nested BaseUser model
|
||||
owner: data.owner ? convertBaseUserFromApi(data.owner) : undefined,
|
||||
// Convert nested JobApplication model
|
||||
applicants: data.applicants ? convertJobApplicationFromApi(data.applicants) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert JobRequirementsMessage from API response, parsing date fields
|
||||
* Convert JobListResponse from API response
|
||||
* Nested models: data (Job)
|
||||
*/
|
||||
export function convertJobListResponseFromApi(data: any): JobListResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Job model
|
||||
data: data.data ? convertJobFromApi(data.data) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert JobRequirementsMessage from API response
|
||||
* Date fields: timestamp
|
||||
* Nested models: job (Job)
|
||||
*/
|
||||
export function convertJobRequirementsMessageFromApi(data: any): JobRequirementsMessage {
|
||||
if (!data) return data;
|
||||
@ -1558,10 +1695,25 @@ export function convertJobRequirementsMessageFromApi(data: any): JobRequirements
|
||||
...data,
|
||||
// Convert timestamp from ISO string to Date
|
||||
timestamp: data.timestamp ? new Date(data.timestamp) : undefined,
|
||||
// Convert nested Job model
|
||||
job: convertJobFromApi(data.job),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert MessageReaction from API response, parsing date fields
|
||||
* Convert JobResponse from API response
|
||||
* Nested models: data (Job)
|
||||
*/
|
||||
export function convertJobResponseFromApi(data: any): JobResponse {
|
||||
if (!data) return data;
|
||||
|
||||
return {
|
||||
...data,
|
||||
// Convert nested Job model
|
||||
data: data.data ? convertJobFromApi(data.data) : undefined,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert MessageReaction from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertMessageReactionFromApi(data: any): MessageReaction {
|
||||
@ -1574,8 +1726,9 @@ export function convertMessageReactionFromApi(data: any): MessageReaction {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert RAGConfiguration from API response, parsing date fields
|
||||
* Convert RAGConfiguration from API response
|
||||
* Date fields: createdAt, updatedAt
|
||||
* Nested models: dataSourceConfigurations (DataSourceConfiguration)
|
||||
*/
|
||||
export function convertRAGConfigurationFromApi(data: any): RAGConfiguration {
|
||||
if (!data) return data;
|
||||
@ -1583,13 +1736,15 @@ export function convertRAGConfigurationFromApi(data: any): RAGConfiguration {
|
||||
return {
|
||||
...data,
|
||||
// Convert createdAt from ISO string to Date
|
||||
createdAt: new Date(data.createdAt),
|
||||
createdAt: data.createdAt ? new Date(data.createdAt) : undefined,
|
||||
// Convert updatedAt from ISO string to Date
|
||||
updatedAt: new Date(data.updatedAt),
|
||||
updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
|
||||
// Convert nested DataSourceConfiguration model
|
||||
dataSourceConfigurations: data.dataSourceConfigurations.map((item: any) => convertDataSourceConfigurationFromApi(item)),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert RateLimitResult from API response, parsing date fields
|
||||
* Convert RateLimitResult from API response
|
||||
* Date fields: resetTimes
|
||||
*/
|
||||
export function convertRateLimitResultFromApi(data: any): RateLimitResult {
|
||||
@ -1602,7 +1757,7 @@ export function convertRateLimitResultFromApi(data: any): RateLimitResult {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert RateLimitStatus from API response, parsing date fields
|
||||
* Convert RateLimitStatus from API response
|
||||
* Date fields: resetTimes
|
||||
*/
|
||||
export function convertRateLimitStatusFromApi(data: any): RateLimitStatus {
|
||||
@ -1615,7 +1770,7 @@ export function convertRateLimitStatusFromApi(data: any): RateLimitStatus {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert RefreshToken from API response, parsing date fields
|
||||
* Convert RefreshToken from API response
|
||||
* Date fields: expiresAt
|
||||
*/
|
||||
export function convertRefreshTokenFromApi(data: any): RefreshToken {
|
||||
@ -1628,7 +1783,7 @@ export function convertRefreshTokenFromApi(data: any): RefreshToken {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert SkillAssessment from API response, parsing date fields
|
||||
* Convert SkillAssessment from API response
|
||||
* Date fields: createdAt, updatedAt
|
||||
*/
|
||||
export function convertSkillAssessmentFromApi(data: any): SkillAssessment {
|
||||
@ -1643,7 +1798,7 @@ export function convertSkillAssessmentFromApi(data: any): SkillAssessment {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert UserActivity from API response, parsing date fields
|
||||
* Convert UserActivity from API response
|
||||
* Date fields: timestamp
|
||||
*/
|
||||
export function convertUserActivityFromApi(data: any): UserActivity {
|
||||
@ -1656,7 +1811,7 @@ export function convertUserActivityFromApi(data: any): UserActivity {
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert WorkExperience from API response, parsing date fields
|
||||
* Convert WorkExperience from API response
|
||||
* Date fields: startDate, endDate
|
||||
*/
|
||||
export function convertWorkExperienceFromApi(data: any): WorkExperience {
|
||||
@ -1687,6 +1842,8 @@ export function convertFromApi<T>(data: any, modelType: string): T {
|
||||
return convertApplicationDecisionFromApi(data) as T;
|
||||
case 'Attachment':
|
||||
return convertAttachmentFromApi(data) as T;
|
||||
case 'AuthResponse':
|
||||
return convertAuthResponseFromApi(data) as T;
|
||||
case 'Authentication':
|
||||
return convertAuthenticationFromApi(data) as T;
|
||||
case 'BaseUser':
|
||||
@ -1697,6 +1854,10 @@ export function convertFromApi<T>(data: any, modelType: string): T {
|
||||
return convertCandidateFromApi(data) as T;
|
||||
case 'CandidateAI':
|
||||
return convertCandidateAIFromApi(data) as T;
|
||||
case 'CandidateListResponse':
|
||||
return convertCandidateListResponseFromApi(data) as T;
|
||||
case 'CandidateResponse':
|
||||
return convertCandidateResponseFromApi(data) as T;
|
||||
case 'Certification':
|
||||
return convertCertificationFromApi(data) as T;
|
||||
case 'ChatMessage':
|
||||
@ -1721,6 +1882,8 @@ export function convertFromApi<T>(data: any, modelType: string): T {
|
||||
return convertDataSourceConfigurationFromApi(data) as T;
|
||||
case 'Document':
|
||||
return convertDocumentFromApi(data) as T;
|
||||
case 'DocumentListResponse':
|
||||
return convertDocumentListResponseFromApi(data) as T;
|
||||
case 'DocumentMessage':
|
||||
return convertDocumentMessageFromApi(data) as T;
|
||||
case 'EditHistory':
|
||||
@ -1729,8 +1892,12 @@ export function convertFromApi<T>(data: any, modelType: string): T {
|
||||
return convertEducationFromApi(data) as T;
|
||||
case 'Employer':
|
||||
return convertEmployerFromApi(data) as T;
|
||||
case 'EmployerResponse':
|
||||
return convertEmployerResponseFromApi(data) as T;
|
||||
case 'Guest':
|
||||
return convertGuestFromApi(data) as T;
|
||||
case 'GuestSessionResponse':
|
||||
return convertGuestSessionResponseFromApi(data) as T;
|
||||
case 'InterviewFeedback':
|
||||
return convertInterviewFeedbackFromApi(data) as T;
|
||||
case 'InterviewSchedule':
|
||||
@ -1741,8 +1908,12 @@ export function convertFromApi<T>(data: any, modelType: string): T {
|
||||
return convertJobApplicationFromApi(data) as T;
|
||||
case 'JobFull':
|
||||
return convertJobFullFromApi(data) as T;
|
||||
case 'JobListResponse':
|
||||
return convertJobListResponseFromApi(data) as T;
|
||||
case 'JobRequirementsMessage':
|
||||
return convertJobRequirementsMessageFromApi(data) as T;
|
||||
case 'JobResponse':
|
||||
return convertJobResponseFromApi(data) as T;
|
||||
case 'MessageReaction':
|
||||
return convertMessageReactionFromApi(data) as T;
|
||||
case 'RAGConfiguration':
|
||||
|
@ -2,14 +2,15 @@
|
||||
"""
|
||||
Enhanced Type Generator - Generate TypeScript types from Pydantic models
|
||||
Now with command line parameters, pre-test validation, TypeScript compilation,
|
||||
automatic date field conversion functions, and proper enum default handling
|
||||
automatic date field conversion functions, proper enum default handling,
|
||||
and NESTED MODEL CONVERSION SUPPORT
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import subprocess
|
||||
from typing import Any, Dict, List, Optional, Union, get_origin, get_args
|
||||
from typing import Any, Dict, List, Optional, Union, get_origin, get_args, Set
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
@ -64,7 +65,7 @@ current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, current_dir)
|
||||
|
||||
try:
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel # type: ignore
|
||||
except ImportError as e:
|
||||
print(f"Error importing pydantic: {e}")
|
||||
print("Make sure pydantic is installed: pip install pydantic")
|
||||
@ -138,6 +139,61 @@ def is_date_type(python_type: Any) -> bool:
|
||||
|
||||
return False
|
||||
|
||||
def is_pydantic_model_type(python_type: Any) -> bool:
|
||||
"""Check if a Python type is a Pydantic model"""
|
||||
# Unwrap any annotations first
|
||||
python_type = unwrap_annotated_type(python_type)
|
||||
|
||||
# Handle Union types (like Optional[SomeModel])
|
||||
origin = get_origin(python_type)
|
||||
if origin is Union:
|
||||
args = get_args(python_type)
|
||||
# Check if any of the union args is a Pydantic model (excluding None)
|
||||
return any(is_pydantic_model_type(arg) for arg in args if arg is not type(None))
|
||||
|
||||
# Handle List types (like List[SomeModel])
|
||||
if origin is list or origin is List:
|
||||
args = get_args(python_type)
|
||||
if args:
|
||||
return is_pydantic_model_type(args[0])
|
||||
|
||||
# Check if it's a Pydantic model
|
||||
try:
|
||||
if isinstance(python_type, type) and issubclass(python_type, BaseModel):
|
||||
return python_type != BaseModel
|
||||
except:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def get_model_name_from_type(python_type: Any) -> Optional[str]:
|
||||
"""Extract the model name from a type"""
|
||||
# Unwrap any annotations first
|
||||
python_type = unwrap_annotated_type(python_type)
|
||||
|
||||
# Handle Union types
|
||||
origin = get_origin(python_type)
|
||||
if origin is Union:
|
||||
args = get_args(python_type)
|
||||
# Find the first Pydantic model in the union
|
||||
for arg in args:
|
||||
if arg is not type(None):
|
||||
model_name = get_model_name_from_type(arg)
|
||||
if model_name:
|
||||
return model_name
|
||||
|
||||
# Handle List types
|
||||
if origin is list or origin is List:
|
||||
args = get_args(python_type)
|
||||
if args:
|
||||
return get_model_name_from_type(args[0])
|
||||
|
||||
# Direct model check
|
||||
if isinstance(python_type, type) and issubclass(python_type, BaseModel):
|
||||
return python_type.__name__
|
||||
|
||||
return None
|
||||
|
||||
def get_default_enum_value(field_info: Any, debug: bool = False) -> Optional[Any]:
|
||||
"""Extract the specific enum value from a field's default, if it exists"""
|
||||
if not hasattr(field_info, 'default'):
|
||||
@ -416,11 +472,12 @@ def is_field_optional(field_info: Any, field_type: Any, debug: bool = False) ->
|
||||
print(f" └─ RESULT: Required (fallback - no Optional type, no default)")
|
||||
return False
|
||||
|
||||
def process_pydantic_model(model_class, debug: bool = False) -> Dict[str, Any]:
|
||||
def process_pydantic_model(model_class, all_models: Set[str], debug: bool = False) -> Dict[str, Any]:
|
||||
"""Process a Pydantic model and return TypeScript interface definition"""
|
||||
interface_name = model_class.__name__
|
||||
properties = []
|
||||
date_fields = [] # Track date fields for conversion functions
|
||||
model_fields = [] # Track fields that are Pydantic models
|
||||
|
||||
if debug:
|
||||
print(f" 🔍 Processing model: {interface_name}")
|
||||
@ -462,6 +519,21 @@ def process_pydantic_model(model_class, debug: bool = False) -> Dict[str, Any]:
|
||||
elif debug and ('date' in str(field_type).lower() or 'time' in str(field_type).lower()):
|
||||
print(f" ⚠️ Field {ts_name} contains 'date'/'time' but not detected as date type: {field_type}")
|
||||
|
||||
# Check if this is a Pydantic model field
|
||||
if is_pydantic_model_type(field_type):
|
||||
model_name = get_model_name_from_type(field_type)
|
||||
if model_name and model_name in all_models:
|
||||
is_optional = is_field_optional(field_info, field_type, debug)
|
||||
is_list = get_origin(unwrap_annotated_type(field_type)) in (list, List)
|
||||
model_fields.append({
|
||||
'name': ts_name,
|
||||
'model': model_name,
|
||||
'optional': is_optional,
|
||||
'is_list': is_list
|
||||
})
|
||||
if debug:
|
||||
print(f" 🔗 Model field detected: {ts_name} -> {model_name} (optional: {is_optional}, list: {is_list})")
|
||||
|
||||
# Pass field_info to the type converter for default enum handling
|
||||
ts_type = python_type_to_typescript(field_type, field_info, debug)
|
||||
|
||||
@ -514,6 +586,21 @@ def process_pydantic_model(model_class, debug: bool = False) -> Dict[str, Any]:
|
||||
elif debug and ('date' in str(field_type).lower() or 'time' in str(field_type).lower()):
|
||||
print(f" ⚠️ Field {ts_name} contains 'date'/'time' but not detected as date type: {field_type}")
|
||||
|
||||
# Check if this is a Pydantic model field
|
||||
if is_pydantic_model_type(field_type):
|
||||
model_name = get_model_name_from_type(field_type)
|
||||
if model_name and model_name in all_models:
|
||||
is_optional = is_field_optional(field_info, field_type)
|
||||
is_list = get_origin(unwrap_annotated_type(field_type)) in (list, List)
|
||||
model_fields.append({
|
||||
'name': ts_name,
|
||||
'model': model_name,
|
||||
'optional': is_optional,
|
||||
'is_list': is_list
|
||||
})
|
||||
if debug:
|
||||
print(f" 🔗 Model field detected: {ts_name} -> {model_name} (optional: {is_optional}, list: {is_list})")
|
||||
|
||||
# Pass field_info to the type converter for default enum handling
|
||||
ts_type = python_type_to_typescript(field_type, field_info, debug)
|
||||
|
||||
@ -535,7 +622,8 @@ def process_pydantic_model(model_class, debug: bool = False) -> Dict[str, Any]:
|
||||
return {
|
||||
'name': interface_name,
|
||||
'properties': properties,
|
||||
'date_fields': date_fields
|
||||
'date_fields': date_fields,
|
||||
'model_fields': model_fields
|
||||
}
|
||||
|
||||
def process_enum(enum_class) -> Dict[str, Any]:
|
||||
@ -549,38 +637,87 @@ def process_enum(enum_class) -> Dict[str, Any]:
|
||||
'values': " | ".join(values)
|
||||
}
|
||||
|
||||
def build_conversion_dependency_graph(interfaces: List[Dict[str, Any]]) -> Dict[str, Set[str]]:
|
||||
"""Build a graph of which models depend on which other models for conversion"""
|
||||
dependencies = {}
|
||||
|
||||
# First pass: identify which models have conversions
|
||||
models_with_conversions = set()
|
||||
for interface in interfaces:
|
||||
if interface.get('date_fields') or interface.get('model_fields'):
|
||||
models_with_conversions.add(interface['name'])
|
||||
|
||||
# Second pass: build dependency graph
|
||||
for interface in interfaces:
|
||||
interface_name = interface['name']
|
||||
deps = set()
|
||||
|
||||
# Add dependencies for nested models
|
||||
for model_field in interface.get('model_fields', []):
|
||||
model_name = model_field['model']
|
||||
if model_name in models_with_conversions:
|
||||
deps.add(model_name)
|
||||
|
||||
if deps or interface.get('date_fields'):
|
||||
dependencies[interface_name] = deps
|
||||
|
||||
return dependencies
|
||||
|
||||
def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
|
||||
"""Generate TypeScript conversion functions for models with date fields"""
|
||||
"""Generate TypeScript conversion functions for models with date fields or nested models"""
|
||||
# Build dependency graph
|
||||
dependencies = build_conversion_dependency_graph(interfaces)
|
||||
|
||||
if not dependencies:
|
||||
return ""
|
||||
|
||||
conversion_functions = []
|
||||
|
||||
for interface in interfaces:
|
||||
interface_name = interface['name']
|
||||
date_fields = interface.get('date_fields', [])
|
||||
model_fields = interface.get('model_fields', [])
|
||||
|
||||
if not date_fields:
|
||||
continue # Skip interfaces without date fields
|
||||
# Skip if no conversion needed
|
||||
if not date_fields and not model_fields:
|
||||
continue
|
||||
|
||||
# Check if any model fields need conversion
|
||||
model_fields_needing_conversion = [
|
||||
mf for mf in model_fields
|
||||
if mf['model'] in dependencies
|
||||
]
|
||||
|
||||
if not date_fields and not model_fields_needing_conversion:
|
||||
continue
|
||||
|
||||
function_name = f"convert{interface_name}FromApi"
|
||||
|
||||
# Generate function
|
||||
func_lines = [
|
||||
f"/**",
|
||||
f" * Convert {interface_name} from API response, parsing date fields",
|
||||
f" * Date fields: {', '.join([f['name'] for f in date_fields])}",
|
||||
f" * Convert {interface_name} from API response",
|
||||
]
|
||||
|
||||
if date_fields:
|
||||
func_lines.append(f" * Date fields: {', '.join([f['name'] for f in date_fields])}")
|
||||
if model_fields_needing_conversion:
|
||||
func_lines.append(f" * Nested models: {', '.join([f'{mf['name']} ({mf['model']})' for mf in model_fields_needing_conversion])}")
|
||||
|
||||
func_lines.extend([
|
||||
f" */",
|
||||
f"export function {function_name}(data: any): {interface_name} {{",
|
||||
f" if (!data) return data;",
|
||||
f" ",
|
||||
f" return {{",
|
||||
f" ...data,"
|
||||
]
|
||||
])
|
||||
|
||||
# Add date field conversions with validation
|
||||
# Add date field conversions
|
||||
for date_field in date_fields:
|
||||
field_name = date_field['name']
|
||||
is_optional = date_field['optional']
|
||||
|
||||
# Add a comment for clarity
|
||||
func_lines.append(f" // Convert {field_name} from ISO string to Date")
|
||||
|
||||
if is_optional:
|
||||
@ -588,6 +725,26 @@ def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
|
||||
else:
|
||||
func_lines.append(f" {field_name}: new Date(data.{field_name}),")
|
||||
|
||||
# Add nested model conversions
|
||||
for model_field in model_fields_needing_conversion:
|
||||
field_name = model_field['name']
|
||||
model_name = model_field['model']
|
||||
is_optional = model_field['optional']
|
||||
is_list = model_field['is_list']
|
||||
|
||||
func_lines.append(f" // Convert nested {model_name} model")
|
||||
|
||||
if is_list:
|
||||
if is_optional:
|
||||
func_lines.append(f" {field_name}: data.{field_name} ? data.{field_name}.map((item: any) => convert{model_name}FromApi(item)) : undefined,")
|
||||
else:
|
||||
func_lines.append(f" {field_name}: data.{field_name}.map((item: any) => convert{model_name}FromApi(item)),")
|
||||
else:
|
||||
if is_optional:
|
||||
func_lines.append(f" {field_name}: data.{field_name} ? convert{model_name}FromApi(data.{field_name}) : undefined,")
|
||||
else:
|
||||
func_lines.append(f" {field_name}: convert{model_name}FromApi(data.{field_name}),")
|
||||
|
||||
func_lines.extend([
|
||||
f" }};",
|
||||
f"}}"
|
||||
@ -601,11 +758,11 @@ def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
|
||||
# Generate the conversion functions section
|
||||
result = [
|
||||
"// ============================",
|
||||
"// Date Conversion Functions",
|
||||
"// Date and Nested Model Conversion Functions",
|
||||
"// ============================",
|
||||
"",
|
||||
"// These functions convert API responses to properly typed objects",
|
||||
"// with Date objects instead of ISO date strings",
|
||||
"// with Date objects instead of ISO date strings and nested model conversions",
|
||||
"",
|
||||
]
|
||||
|
||||
@ -613,9 +770,9 @@ def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
|
||||
result.append("")
|
||||
|
||||
# Generate a generic converter function
|
||||
models_with_dates = [interface['name'] for interface in interfaces if interface.get('date_fields')]
|
||||
models_with_conversions = list(dependencies.keys())
|
||||
|
||||
if models_with_dates:
|
||||
if models_with_conversions:
|
||||
result.extend([
|
||||
"/**",
|
||||
" * Generic converter that automatically selects the right conversion function",
|
||||
@ -627,7 +784,7 @@ def generate_conversion_functions(interfaces: List[Dict[str, Any]]) -> str:
|
||||
" switch (modelType) {"
|
||||
])
|
||||
|
||||
for model_name in models_with_dates:
|
||||
for model_name in sorted(models_with_conversions):
|
||||
result.append(f" case '{model_name}':")
|
||||
result.append(f" return convert{model_name}FromApi(data) as T;")
|
||||
|
||||
@ -671,8 +828,17 @@ def generate_typescript_interfaces(source_file: str, debug: bool = False):
|
||||
|
||||
interfaces = []
|
||||
enums = []
|
||||
all_models = set()
|
||||
|
||||
# Scan the models module
|
||||
# First pass: collect all model names
|
||||
for name in dir(models_module):
|
||||
obj = getattr(models_module, name)
|
||||
if (isinstance(obj, type) and
|
||||
issubclass(obj, BaseModel) and
|
||||
obj != BaseModel):
|
||||
all_models.add(name)
|
||||
|
||||
# Second pass: process models with knowledge of all models
|
||||
for name in dir(models_module):
|
||||
obj = getattr(models_module, name)
|
||||
|
||||
@ -686,10 +852,17 @@ def generate_typescript_interfaces(source_file: str, debug: bool = False):
|
||||
issubclass(obj, BaseModel) and
|
||||
obj != BaseModel):
|
||||
|
||||
interface = process_pydantic_model(obj, debug)
|
||||
interface = process_pydantic_model(obj, all_models, debug)
|
||||
interfaces.append(interface)
|
||||
date_count = len(interface.get('date_fields', []))
|
||||
print(f" ✅ Found Pydantic model: {name}" + (f" ({date_count} date fields)" if date_count > 0 else ""))
|
||||
nested_count = len(interface.get('model_fields', []))
|
||||
status_parts = []
|
||||
if date_count > 0:
|
||||
status_parts.append(f"{date_count} date fields")
|
||||
if nested_count > 0:
|
||||
status_parts.append(f"{nested_count} nested models")
|
||||
status = f" ({', '.join(status_parts)})" if status_parts else ""
|
||||
print(f" ✅ Found Pydantic model: {name}{status}")
|
||||
|
||||
# Check if it's an Enum
|
||||
elif (isinstance(obj, type) and
|
||||
@ -707,8 +880,10 @@ def generate_typescript_interfaces(source_file: str, debug: bool = False):
|
||||
continue
|
||||
|
||||
total_date_fields = sum(len(interface.get('date_fields', [])) for interface in interfaces)
|
||||
total_nested_models = sum(len(interface.get('model_fields', [])) for interface in interfaces)
|
||||
print(f"\n📊 Found {len(interfaces)} interfaces and {len(enums)} enums")
|
||||
print(f"🗓️ Found {total_date_fields} date fields across all models")
|
||||
print(f"🔗 Found {total_nested_models} nested model fields requiring conversion")
|
||||
|
||||
# Generate TypeScript content
|
||||
ts_content = f"""// Generated TypeScript types from Pydantic models
|
||||
@ -781,7 +956,7 @@ def compile_typescript(ts_file: str) -> bool:
|
||||
def main():
|
||||
"""Main function with command line argument parsing"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate TypeScript types from Pydantic models with date conversion functions and proper enum handling',
|
||||
description='Generate TypeScript types from Pydantic models with nested model conversion support',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
@ -792,12 +967,19 @@ Examples:
|
||||
python generate_types.py --debug # Enable debug output
|
||||
python generate_types.py --source models.py --output types.ts --skip-test --skip-compile --debug
|
||||
|
||||
Generated conversion functions can be used like:
|
||||
const candidate = convertCandidateFromApi(apiResponse);
|
||||
const jobs = convertArrayFromApi<Job>(apiResponse, 'Job');
|
||||
Generated conversion functions now support nested models:
|
||||
// If JobRequirementsMessage has a 'job' field of type Job
|
||||
const message = convertJobRequirementsMessageFromApi(apiResponse);
|
||||
// The nested job field will also be converted automatically
|
||||
|
||||
Enum types are now properly handled:
|
||||
status: ApiStatusType = ApiStatusType.DONE -> status: ApiStatusType (not locked to "done")
|
||||
// Arrays of models are also supported
|
||||
const messages = convertArrayFromApi<JobRequirementsMessage>(apiResponse, 'JobRequirementsMessage');
|
||||
|
||||
The conversion functions handle:
|
||||
- Date field conversion (ISO strings to Date objects)
|
||||
- Nested model conversion (recursive conversion of Pydantic model fields)
|
||||
- Arrays of models
|
||||
- Optional fields
|
||||
"""
|
||||
)
|
||||
|
||||
@ -834,12 +1016,12 @@ Enum types are now properly handled:
|
||||
parser.add_argument(
|
||||
'--version', '-v',
|
||||
action='version',
|
||||
version='TypeScript Generator 3.2 (Fixed Enum Default Handling)'
|
||||
version='TypeScript Generator 4.0 (With Nested Model Conversion Support)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("🚀 Enhanced TypeScript Type Generator with Fixed Enum Handling")
|
||||
print("🚀 Enhanced TypeScript Type Generator with Nested Model Conversion")
|
||||
print("=" * 60)
|
||||
print(f"📁 Source file: {args.source}")
|
||||
print(f"📁 Output file: {args.output}")
|
||||
@ -885,29 +1067,24 @@ Enum types are now properly handled:
|
||||
# Count conversion functions and provide detailed feedback
|
||||
conversion_count = ts_content.count('export function convert') - ts_content.count('convertFromApi') - ts_content.count('convertArrayFromApi')
|
||||
enum_type_count = ts_content.count('export type')
|
||||
nested_conversion_count = ts_content.count('// Convert nested')
|
||||
|
||||
if conversion_count > 0:
|
||||
print(f"🗓️ Generated {conversion_count} date conversion functions")
|
||||
print(f"🗓️ Generated {conversion_count} conversion functions")
|
||||
if nested_conversion_count > 0:
|
||||
print(f"🔗 Including {nested_conversion_count} nested model conversions")
|
||||
if enum_type_count > 0:
|
||||
print(f"🎯 Generated {enum_type_count} enum types (properly allowing all values)")
|
||||
print(f"🎯 Generated {enum_type_count} enum types")
|
||||
|
||||
if args.debug:
|
||||
# Show which models have date conversion
|
||||
models_with_dates = []
|
||||
# Show which models have conversions
|
||||
models_with_conversions = []
|
||||
for line in ts_content.split('\n'):
|
||||
if line.startswith('export function convert') and 'FromApi' in line and 'convertFromApi' not in line:
|
||||
model_name = line.split('convert')[1].split('FromApi')[0]
|
||||
models_with_dates.append(model_name)
|
||||
if models_with_dates:
|
||||
print(f" Models with date conversion: {', '.join(models_with_dates)}")
|
||||
|
||||
# Provide troubleshooting info if debug mode
|
||||
if args.debug:
|
||||
print(f"\n🐛 Debug mode was enabled. If you see incorrect type conversions:")
|
||||
print(f" 1. Check the debug output above for enum default handling")
|
||||
print(f" 2. Look for '📅 Date type check' lines for date handling")
|
||||
print(f" 3. Look for '⚠️' warnings about fallback types")
|
||||
print(f" 4. Verify your Pydantic model field types and defaults are correct")
|
||||
models_with_conversions.append(model_name)
|
||||
if models_with_conversions:
|
||||
print(f" Models with conversions: {', '.join(models_with_conversions)}")
|
||||
|
||||
# Step 5: Compile TypeScript (unless skipped)
|
||||
if not args.skip_compile:
|
||||
@ -924,19 +1101,24 @@ Enum types are now properly handled:
|
||||
print(f"✅ Generated {args.output} from {args.source}")
|
||||
print(f"✅ File size: {file_size} characters")
|
||||
if conversion_count > 0:
|
||||
print(f"✅ Date conversion functions: {conversion_count}")
|
||||
print(f"✅ Conversion functions: {conversion_count}")
|
||||
if nested_conversion_count > 0:
|
||||
print(f"✅ Nested model conversions: {nested_conversion_count}")
|
||||
if enum_type_count > 0:
|
||||
print(f"✅ Enum types (with full value range): {enum_type_count}")
|
||||
print(f"✅ Enum types: {enum_type_count}")
|
||||
if not args.skip_test:
|
||||
print("✅ Model validation passed")
|
||||
if not args.skip_compile:
|
||||
print("✅ TypeScript syntax validated")
|
||||
|
||||
print(f"\n💡 Usage in your TypeScript project:")
|
||||
print(f" import {{ Candidate, Employer, Job, convertCandidateFromApi }} from './{Path(args.output).stem}';")
|
||||
print(f" import {{ Candidate, Job, convertJobRequirementsMessageFromApi }} from './{Path(args.output).stem}';")
|
||||
if conversion_count > 0:
|
||||
print(f" const candidate = convertCandidateFromApi(apiResponse);")
|
||||
print(f" const jobs = convertArrayFromApi<Job>(apiResponse, 'Job');")
|
||||
print(f"\n // Example with nested model conversion:")
|
||||
print(f" const message = convertJobRequirementsMessageFromApi(apiResponse);")
|
||||
print(f" // The nested 'job' field is automatically converted too!")
|
||||
print(f"\n // For arrays:")
|
||||
print(f" const messages = convertArrayFromApi<JobRequirementsMessage>(apiResponse, 'JobRequirementsMessage');")
|
||||
|
||||
return True
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user