Added recursive pydantic model converter

This commit is contained in:
James Ketr 2025-06-09 19:56:55 -07:00
parent 1531a05de0
commit 9edf5a5b23
2 changed files with 488 additions and 135 deletions

View File

@ -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':

View File

@ -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