mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-22 06:12:17 +10:00
* fix(import): auto-detect JSON format and show readable errors (#1) Readable import errors, a fail-soft v4 parser, and auto-detect of the JSON format so uploads just work. The format dropdown becomes an optional override. PDF and DOCX (AI) paths are untouched. * fix(import): address review feedback on the v4 guard and error message - reactive-resume-v4-json.tsx: reject arrays in isRecord so array-valued basics, sections, or metadata no longer pass the v4 shape guard. - reactive-resume-v4-json.tsx: reuse the guard's error instance in the catch arm instead of allocating a duplicate NOT_V4_MESSAGE. - error.ts: use a singular "Problem" label for root-level Zod issues so the message stays grammatical. - add a regression test for array-valued v4 branches. * fix(import): preserve selected JSON format * test(import): cover selected JSON parser --------- Co-authored-by: MrTig-afk <MrTig-afk@users.noreply.github.com> Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
This commit is contained in:
co-authored by
MrTig-afk
Amruth Pillai
parent
9f13638eab
commit
bad431b2fc
@@ -19,6 +19,7 @@ describe("detectJsonImportType", () => {
|
||||
});
|
||||
|
||||
it("returns an empty string for unrecognized shapes", () => {
|
||||
expect(detectJsonImportType({})).toBe("");
|
||||
expect(detectJsonImportType({ foo: "bar" })).toBe("");
|
||||
expect(detectJsonImportType(null)).toBe("");
|
||||
expect(detectJsonImportType("nope")).toBe("");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ResumeData } from "@reactive-resume/schema/resume/data";
|
||||
import type { DialogProps } from "../store";
|
||||
import type { ImportType } from "./import.utils";
|
||||
import type { ResumeJsonFormat } from "./parse-json";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { DownloadSimpleIcon, FileIcon, UploadSimpleIcon } from "@phosphor-icons/react";
|
||||
@@ -10,9 +11,6 @@ import { Link, useNavigate } from "@tanstack/react-router";
|
||||
import { useRef, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import z from "zod";
|
||||
import { parseJSONResume } from "@reactive-resume/import/json-resume";
|
||||
import { parseReactiveResumeJSON } from "@reactive-resume/import/reactive-resume-json";
|
||||
import { parseReactiveResumeV4JSON } from "@reactive-resume/import/reactive-resume-v4-json";
|
||||
import { Badge } from "@reactive-resume/ui/components/badge";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import {
|
||||
@@ -34,6 +32,7 @@ import { client, orpc } from "@/libs/orpc/client";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { useDialogStore } from "../store";
|
||||
import { detectJsonImportType } from "./import.utils";
|
||||
import { parseResumeJson } from "./parse-json";
|
||||
|
||||
const formSchema = z.discriminatedUnion("type", [
|
||||
z.object({
|
||||
@@ -149,16 +148,12 @@ export function ImportResumeDialog(_: DialogProps<"resume.import">) {
|
||||
try {
|
||||
let data: ResumeData | undefined;
|
||||
|
||||
if (value.type === "json-resume-json") {
|
||||
data = parseJSONResume(await value.file.text());
|
||||
}
|
||||
|
||||
if (value.type === "reactive-resume-json") {
|
||||
data = parseReactiveResumeJSON(await value.file.text());
|
||||
}
|
||||
|
||||
if (value.type === "reactive-resume-v4-json") {
|
||||
data = parseReactiveResumeV4JSON(await value.file.text());
|
||||
if (
|
||||
value.type === "json-resume-json" ||
|
||||
value.type === "reactive-resume-json" ||
|
||||
value.type === "reactive-resume-v4-json"
|
||||
) {
|
||||
data = parseResumeJson(await value.file.text(), value.type as ResumeJsonFormat);
|
||||
}
|
||||
|
||||
if (value.type === "pdf") {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseResumeJson } from "./parse-json";
|
||||
|
||||
describe("parseResumeJson", () => {
|
||||
it("keeps a selected v4 import from falling back to JSON Resume", () => {
|
||||
expect(() => parseResumeJson("{}", "reactive-resume-v4-json")).toThrow(/v4/i);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { ResumeData } from "@reactive-resume/schema/resume/data";
|
||||
import { parseJSONResume } from "@reactive-resume/import/json-resume";
|
||||
import { parseReactiveResumeJSON } from "@reactive-resume/import/reactive-resume-json";
|
||||
import { parseReactiveResumeV4JSON } from "@reactive-resume/import/reactive-resume-v4-json";
|
||||
|
||||
export type ResumeJsonFormat = "reactive-resume-json" | "reactive-resume-v4-json" | "json-resume-json";
|
||||
|
||||
export function parseResumeJson(text: string, format: ResumeJsonFormat): ResumeData {
|
||||
if (format === "reactive-resume-json") return parseReactiveResumeJSON(text);
|
||||
if (format === "reactive-resume-v4-json") return parseReactiveResumeV4JSON(text);
|
||||
return parseJSONResume(text);
|
||||
}
|
||||
Reference in New Issue
Block a user