fix(import): auto-detect JSON format and show readable errors (#1) (#3296)

* 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:
Kaushik N
2026-08-13 23:01:06 +02:00
committed by GitHub
co-authored by MrTig-afk Amruth Pillai
parent 9f13638eab
commit bad431b2fc
8 changed files with 139 additions and 18 deletions
@@ -394,3 +394,33 @@ describe("parseReactiveResumeV4JSON language level scaling (v4: 0-10 → v5:
expect(result.sections.languages.items[0]?.level).toBe(3);
});
});
// ─── Guard: non-v4 JSON must fail with a readable error, not a raw TypeError ───
describe("parseReactiveResumeV4JSON rejects non-v4 input gracefully", () => {
it("throws a readable error (not a TypeError) for an empty object", () => {
expect(() => parseReactiveResumeV4JSON("{}")).toThrow(/v4/i);
});
it("throws for a JSON Resume shaped file (basics but no sections/metadata)", () => {
expect(() => parseReactiveResumeV4JSON(JSON.stringify({ basics: { name: "Jane" } }))).toThrow(/v4/i);
});
it("throws for a top-level JSON array", () => {
expect(() => parseReactiveResumeV4JSON("[]")).toThrow(/v4/i);
});
it("throws for a current-format export whose metadata.layout is not a v4 array", () => {
const currentFormat = {
basics: { name: "Jane" },
sections: {},
metadata: { layout: { sidebarWidth: 35, pages: [] } },
};
expect(() => parseReactiveResumeV4JSON(JSON.stringify(currentFormat))).toThrow(/v4/i);
});
it("throws when basics, sections, or metadata are arrays rather than objects", () => {
const arrayBranches = JSON.stringify({ basics: [], sections: [], metadata: [] });
expect(() => parseReactiveResumeV4JSON(arrayBranches)).toThrow(/v4/i);
});
});