mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 07:12:18 +10:00
refactor(import): add v4section/v4url aliases, inline clamp wrappers, replace classes with fns
Finding 5: Introduce V4Url + V4Section<T> type aliases in reactive-resume-v4-json.tsx; collapse
310-line V4ResumeData type (13x 5-field section header, 11x {label,href}) into typed aliases.
Inferred shape is structurally identical.
Finding 6: Remove 9 single-caller clamp/pxToPt wrappers; replace compile-time constants
(rotation=0, sidebarWidth=35, shadowWidth=0, gapX=4, gapY=6) with literals; inline dynamic
calls (clamp(x, 32, 512) etc.) at the two body/heading typography call sites.
Finding 7: Convert three stateless single-method importer classes to plain functions.
Extract shared rethrowAsImportError() to error.ts, replacing triplicated ZodError catch blocks.
Update web import dialog + all in-package test files to use function API.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
This commit is contained in:
@@ -1,22 +1,20 @@
|
||||
// biome-ignore-all lint/style/noNonNullAssertion: These tests assert imported section lengths before inspecting the first item.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { JSONResumeImporter } from "./json-resume";
|
||||
import { parseJSONResume } from "./json-resume";
|
||||
|
||||
const importer = new JSONResumeImporter();
|
||||
|
||||
describe("JSONResumeImporter.parse", () => {
|
||||
describe("parseJSONResume", () => {
|
||||
it("throws when input is not valid JSON", () => {
|
||||
expect(() => importer.parse("not json")).toThrow();
|
||||
expect(() => parseJSONResume("not json")).toThrow();
|
||||
});
|
||||
|
||||
it("throws a serialized validation error for an obviously invalid shape", () => {
|
||||
// Email field is validated; a non-email string should fail the loose schema.
|
||||
const invalid = JSON.stringify({ basics: { email: "not-an-email" } });
|
||||
expect(() => importer.parse(invalid)).toThrow();
|
||||
expect(() => parseJSONResume(invalid)).toThrow();
|
||||
});
|
||||
|
||||
it("imports an empty JSON Resume into a baseline ResumeData", () => {
|
||||
const result = importer.parse("{}");
|
||||
const result = parseJSONResume("{}");
|
||||
// Defaults preserve a name field even when unset by input.
|
||||
expect(typeof result.basics.name).toBe("string");
|
||||
});
|
||||
@@ -34,7 +32,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.basics.name).toBe("Jane Doe");
|
||||
expect(result.basics.headline).toBe("Engineer");
|
||||
expect(result.basics.email).toBe("jane@example.com");
|
||||
@@ -62,7 +60,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
],
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.sections.experience.items).toHaveLength(1);
|
||||
|
||||
const item = result.sections.experience.items[0]!;
|
||||
@@ -89,7 +87,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
],
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.sections.education.items).toHaveLength(1);
|
||||
|
||||
const edu = result.sections.education.items[0]!;
|
||||
@@ -103,7 +101,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
skills: [{ name: "TypeScript", level: "Master", keywords: ["node", "react"] }],
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
const skill = result.sections.skills.items[0]!;
|
||||
|
||||
expect(skill.name).toBe("TypeScript");
|
||||
@@ -121,7 +119,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.sections.profiles.items).toHaveLength(1);
|
||||
|
||||
const profile = result.sections.profiles.items[0]!;
|
||||
@@ -134,13 +132,13 @@ describe("JSONResumeImporter.parse", () => {
|
||||
basics: { image: "https://example.com/pic.jpg" },
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.picture.url).toBe("https://example.com/pic.jpg");
|
||||
expect(result.picture.hidden).toBe(false);
|
||||
});
|
||||
|
||||
it("leaves the summary content empty when basics.summary is absent", () => {
|
||||
const result = importer.parse(JSON.stringify({ basics: { name: "Jane" } }));
|
||||
const result = parseJSONResume(JSON.stringify({ basics: { name: "Jane" } }));
|
||||
expect(result.summary.content).toBe("");
|
||||
});
|
||||
|
||||
@@ -159,7 +157,7 @@ describe("JSONResumeImporter.parse", () => {
|
||||
],
|
||||
});
|
||||
|
||||
const result = importer.parse(json);
|
||||
const result = parseJSONResume(json);
|
||||
expect(result.sections.projects.items).toHaveLength(1);
|
||||
|
||||
const project = result.sections.projects.items[0]!;
|
||||
|
||||
Reference in New Issue
Block a user