mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-15 01:01:43 +10:00
refactor(v4.0.0-alpha): beginning of a new era
This commit is contained in:
248
libs/parser/src/reactive-resume-v3/index.ts
Normal file
248
libs/parser/src/reactive-resume-v3/index.ts
Normal file
@ -0,0 +1,248 @@
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import {
|
||||
defaultAward,
|
||||
defaultCertification,
|
||||
defaultEducation,
|
||||
defaultExperience,
|
||||
defaultInterest,
|
||||
defaultLanguage,
|
||||
defaultProfile,
|
||||
defaultProject,
|
||||
defaultPublication,
|
||||
defaultReference,
|
||||
defaultResumeData,
|
||||
defaultSkill,
|
||||
defaultVolunteer,
|
||||
ResumeData,
|
||||
} from "@reactive-resume/schema";
|
||||
import { isUrl, Json } from "@reactive-resume/utils";
|
||||
import { Schema } from "zod";
|
||||
|
||||
import { Parser } from "../interfaces/parser";
|
||||
import { ReactiveResumeV3, reactiveResumeV3Schema } from "./schema";
|
||||
|
||||
export * from "./schema";
|
||||
|
||||
export class ReactiveResumeV3Parser implements Parser<Json, ReactiveResumeV3> {
|
||||
schema: Schema;
|
||||
|
||||
constructor() {
|
||||
this.schema = reactiveResumeV3Schema;
|
||||
}
|
||||
|
||||
readFile(file: File): Promise<Json> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = () => {
|
||||
try {
|
||||
const result = JSON.parse(reader.result as string) as Json;
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
reject(new Error("Failed to parse JSON"));
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = () => {
|
||||
reject(new Error("Failed to read the file"));
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
}
|
||||
|
||||
validate(data: Json) {
|
||||
return this.schema.parse(data) as ReactiveResumeV3;
|
||||
}
|
||||
|
||||
convert(data: ReactiveResumeV3) {
|
||||
const result = JSON.parse(JSON.stringify(defaultResumeData)) as ResumeData;
|
||||
|
||||
// Basics
|
||||
result.basics.name = data.basics.name;
|
||||
result.basics.email = data.basics.email;
|
||||
result.basics.phone = data.basics.phone;
|
||||
result.basics.headline = data.basics.headline;
|
||||
result.basics.location = data.basics.location.address;
|
||||
result.sections.summary.content = data.basics.summary;
|
||||
result.basics.picture.url = isUrl(data.basics.photo.url) ? data.basics.photo.url : "";
|
||||
|
||||
// Profiles
|
||||
if (data.basics.profiles) {
|
||||
for (const profile of data.basics.profiles) {
|
||||
result.sections.profiles.items.push({
|
||||
...defaultProfile,
|
||||
id: createId(),
|
||||
network: profile.network,
|
||||
username: profile.username,
|
||||
icon: profile.network.toLocaleLowerCase(),
|
||||
url: { ...defaultProfile.url, href: isUrl(profile.url) ? profile.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Work
|
||||
if (data.sections.work.items) {
|
||||
for (const work of data.sections.work.items) {
|
||||
result.sections.experience.items.push({
|
||||
...defaultExperience,
|
||||
id: createId(),
|
||||
company: work.name,
|
||||
position: work.position,
|
||||
summary: work.summary,
|
||||
date: `${work.date.start} - ${work.date.end}`,
|
||||
url: { ...defaultExperience.url, href: isUrl(work.url) ? work.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Awards
|
||||
if (data.sections.awards.items) {
|
||||
for (const award of data.sections.awards.items) {
|
||||
result.sections.awards.items.push({
|
||||
...defaultAward,
|
||||
id: createId(),
|
||||
title: award.title,
|
||||
awarder: award.awarder,
|
||||
date: award.date,
|
||||
summary: award.summary,
|
||||
url: { ...defaultAward.url, href: isUrl(award.url) ? award.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Skills
|
||||
if (data.sections.skills.items) {
|
||||
for (const skill of data.sections.skills.items) {
|
||||
result.sections.skills.items.push({
|
||||
...defaultSkill,
|
||||
id: createId(),
|
||||
name: skill.name,
|
||||
level: Math.floor(skill.levelNum / 2),
|
||||
description: skill.level,
|
||||
keywords: skill.keywords,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Projects
|
||||
if (data.sections.projects.items) {
|
||||
for (const project of data.sections.projects.items) {
|
||||
result.sections.projects.items.push({
|
||||
...defaultProject,
|
||||
id: createId(),
|
||||
name: project.name,
|
||||
summary: project.summary,
|
||||
description: project.description,
|
||||
date: `${project.date.start} - ${project.date.end}`,
|
||||
keywords: project.keywords,
|
||||
url: { ...defaultProject.url, href: isUrl(project.url) ? project.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Education
|
||||
if (data.sections.education.items) {
|
||||
for (const education of data.sections.education.items) {
|
||||
result.sections.education.items.push({
|
||||
...defaultEducation,
|
||||
id: createId(),
|
||||
institution: education.institution,
|
||||
studyType: education.degree,
|
||||
area: education.area,
|
||||
score: education.score,
|
||||
summary: education.summary,
|
||||
date: `${education.date.start} - ${education.date.end}`,
|
||||
url: { ...defaultEducation.url, href: isUrl(education.url) ? education.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Interests
|
||||
if (data.sections.interests.items) {
|
||||
for (const interest of data.sections.interests.items) {
|
||||
result.sections.interests.items.push({
|
||||
...defaultInterest,
|
||||
id: createId(),
|
||||
name: interest.name,
|
||||
keywords: interest.keywords,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Languages
|
||||
if (data.sections.languages.items) {
|
||||
for (const language of data.sections.languages.items) {
|
||||
result.sections.languages.items.push({
|
||||
...defaultLanguage,
|
||||
id: createId(),
|
||||
name: language.name,
|
||||
fluency: language.level,
|
||||
fluencyLevel: Math.floor(language.levelNum / 2),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Volunteer
|
||||
if (data.sections.volunteer.items) {
|
||||
for (const volunteer of data.sections.volunteer.items) {
|
||||
result.sections.volunteer.items.push({
|
||||
...defaultVolunteer,
|
||||
id: createId(),
|
||||
organization: volunteer.organization,
|
||||
position: volunteer.position,
|
||||
summary: volunteer.summary,
|
||||
date: `${volunteer.date.start} - ${volunteer.date.end}`,
|
||||
url: { ...defaultVolunteer.url, href: isUrl(volunteer.url) ? volunteer.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// References
|
||||
if (data.sections.references.items) {
|
||||
for (const reference of data.sections.references.items) {
|
||||
result.sections.references.items.push({
|
||||
...defaultReference,
|
||||
id: createId(),
|
||||
name: reference.name,
|
||||
summary: reference.summary,
|
||||
description: reference.relationship,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Publications
|
||||
if (data.sections.publications.items) {
|
||||
for (const publication of data.sections.publications.items) {
|
||||
result.sections.publications.items.push({
|
||||
...defaultPublication,
|
||||
id: createId(),
|
||||
name: publication.name,
|
||||
summary: publication.summary,
|
||||
date: publication.date,
|
||||
url: { ...defaultPublication.url, href: isUrl(publication.url) ? publication.url : "" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Certifications
|
||||
if (data.sections.certifications.items) {
|
||||
for (const certification of data.sections.certifications.items) {
|
||||
result.sections.certifications.items.push({
|
||||
...defaultCertification,
|
||||
id: createId(),
|
||||
name: certification.name,
|
||||
issuer: certification.issuer,
|
||||
summary: certification.summary,
|
||||
date: certification.date,
|
||||
url: {
|
||||
...defaultCertification.url,
|
||||
href: isUrl(certification.url) ? certification.url : "",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
179
libs/parser/src/reactive-resume-v3/schema.ts
Normal file
179
libs/parser/src/reactive-resume-v3/schema.ts
Normal file
@ -0,0 +1,179 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const dateSchema = z.object({ start: z.string(), end: z.string() });
|
||||
|
||||
const profileSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
network: z.string(),
|
||||
username: z.string(),
|
||||
});
|
||||
|
||||
const basicsSchema = z.object({
|
||||
name: z.string(),
|
||||
email: z.literal("").or(z.string().email()),
|
||||
phone: z.string(),
|
||||
headline: z.string(),
|
||||
summary: z.string(),
|
||||
birthdate: z.string(),
|
||||
website: z.string(),
|
||||
profiles: z.array(profileSchema),
|
||||
location: z.object({
|
||||
address: z.string(),
|
||||
postalCode: z.string(),
|
||||
city: z.string(),
|
||||
country: z.string(),
|
||||
region: z.string(),
|
||||
}),
|
||||
photo: z.object({
|
||||
visible: z.boolean(),
|
||||
url: z.string(),
|
||||
filters: z.object({
|
||||
shape: z.string(),
|
||||
size: z.number(),
|
||||
border: z.boolean(),
|
||||
grayscale: z.boolean(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const sectionSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.enum(["basic", "custom"]),
|
||||
columns: z.number(),
|
||||
visible: z.boolean(),
|
||||
});
|
||||
|
||||
const workSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
date: dateSchema,
|
||||
name: z.string(),
|
||||
position: z.string(),
|
||||
summary: z.string(),
|
||||
});
|
||||
|
||||
const awardSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
date: z.string(),
|
||||
title: z.string(),
|
||||
awarder: z.string(),
|
||||
summary: z.string(),
|
||||
});
|
||||
|
||||
const skillSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
level: z.string(),
|
||||
keywords: z.array(z.string()),
|
||||
levelNum: z.number(),
|
||||
});
|
||||
|
||||
const projectSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
date: dateSchema,
|
||||
name: z.string(),
|
||||
summary: z.string(),
|
||||
keywords: z.array(z.string()),
|
||||
description: z.string(),
|
||||
});
|
||||
|
||||
const educationSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
area: z.string(),
|
||||
date: dateSchema,
|
||||
score: z.string(),
|
||||
degree: z.string(),
|
||||
courses: z.array(z.string()),
|
||||
summary: z.string(),
|
||||
institution: z.string(),
|
||||
});
|
||||
|
||||
const interestSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
keywords: z.array(z.string()),
|
||||
});
|
||||
|
||||
const languageSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
level: z.string(),
|
||||
levelNum: z.number(),
|
||||
});
|
||||
|
||||
const volunteerSchema = z.object({
|
||||
id: z.string(),
|
||||
organization: z.string(),
|
||||
position: z.string(),
|
||||
date: dateSchema,
|
||||
url: z.string(),
|
||||
summary: z.string(),
|
||||
});
|
||||
|
||||
const referenceSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
summary: z.string(),
|
||||
relationship: z.string(),
|
||||
});
|
||||
|
||||
const publicationSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
date: z.string(),
|
||||
name: z.string(),
|
||||
publisher: z.string(),
|
||||
summary: z.string(),
|
||||
});
|
||||
|
||||
const certificationSchema = z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
date: z.string(),
|
||||
name: z.string(),
|
||||
issuer: z.string(),
|
||||
summary: z.string(),
|
||||
});
|
||||
|
||||
const metadataSchema = z.object({
|
||||
css: z.object({ value: z.string(), visible: z.boolean() }),
|
||||
date: z.object({ format: z.string() }),
|
||||
theme: z.object({ text: z.string(), primary: z.string(), background: z.string() }),
|
||||
layout: z.array(z.array(z.array(z.string()))),
|
||||
locale: z.string(),
|
||||
template: z.string(),
|
||||
typography: z.object({
|
||||
size: z.object({ body: z.number(), heading: z.number() }),
|
||||
family: z.object({ body: z.string(), heading: z.string() }),
|
||||
}),
|
||||
});
|
||||
|
||||
export const reactiveResumeV3Schema = z.object({
|
||||
public: z.boolean(),
|
||||
basics: basicsSchema,
|
||||
sections: z.object({
|
||||
work: sectionSchema.extend({ items: z.array(workSchema) }),
|
||||
awards: sectionSchema.extend({ items: z.array(awardSchema) }),
|
||||
skills: sectionSchema.extend({ items: z.array(skillSchema) }),
|
||||
projects: sectionSchema.extend({ items: z.array(projectSchema) }),
|
||||
education: sectionSchema.extend({ items: z.array(educationSchema) }),
|
||||
interests: sectionSchema.extend({ items: z.array(interestSchema) }),
|
||||
languages: sectionSchema.extend({ items: z.array(languageSchema) }),
|
||||
volunteer: sectionSchema.extend({ items: z.array(volunteerSchema) }),
|
||||
references: sectionSchema.extend({ items: z.array(referenceSchema) }),
|
||||
publications: sectionSchema.extend({ items: z.array(publicationSchema) }),
|
||||
certifications: sectionSchema.extend({
|
||||
items: z.array(certificationSchema),
|
||||
}),
|
||||
}),
|
||||
metadata: metadataSchema,
|
||||
});
|
||||
|
||||
export type ReactiveResumeV3 = z.infer<typeof reactiveResumeV3Schema>;
|
||||
Reference in New Issue
Block a user