From 14be75f6a8497ae1416188e21b2b0f818443cc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 4 Dec 2023 17:51:40 +0900 Subject: [PATCH] fix: json error with position (#15225) --- .../__snapshots__/fixture.spec.ts.snap | 4 +-- .../src/node/__tests__/plugins/json.spec.ts | 26 +++++++++++++++++++ packages/vite/src/node/plugins/json.ts | 21 ++++++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 packages/vite/src/node/__tests__/plugins/json.spec.ts diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap index c1f028dd30df29..cb45d521897491 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap +++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap @@ -39,7 +39,7 @@ export const customQueryObject = /* #__PURE__ */ Object.assign({"./sibling.ts": export const parent = /* #__PURE__ */ Object.assign({ }); -export const rootMixedRelative = /* #__PURE__ */ Object.assign({"/css.spec.ts": () => import("../../css.spec.ts?url").then(m => m["default"]),"/define.spec.ts": () => import("../../define.spec.ts?url").then(m => m["default"]),"/esbuild.spec.ts": () => import("../../esbuild.spec.ts?url").then(m => m["default"]),"/import.spec.ts": () => import("../../import.spec.ts?url").then(m => m["default"]),"/importGlob/fixture-b/a.ts": () => import("../fixture-b/a.ts?url").then(m => m["default"]),"/importGlob/fixture-b/b.ts": () => import("../fixture-b/b.ts?url").then(m => m["default"]),"/importGlob/fixture-b/index.ts": () => import("../fixture-b/index.ts?url").then(m => m["default"]) +export const rootMixedRelative = /* #__PURE__ */ Object.assign({"/css.spec.ts": () => import("../../css.spec.ts?url").then(m => m["default"]),"/define.spec.ts": () => import("../../define.spec.ts?url").then(m => m["default"]),"/esbuild.spec.ts": () => import("../../esbuild.spec.ts?url").then(m => m["default"]),"/import.spec.ts": () => import("../../import.spec.ts?url").then(m => m["default"]),"/importGlob/fixture-b/a.ts": () => import("../fixture-b/a.ts?url").then(m => m["default"]),"/importGlob/fixture-b/b.ts": () => import("../fixture-b/b.ts?url").then(m => m["default"]),"/importGlob/fixture-b/index.ts": () => import("../fixture-b/index.ts?url").then(m => m["default"]),"/json.spec.ts": () => import("../../json.spec.ts?url").then(m => m["default"]) }); @@ -93,7 +93,7 @@ export const customQueryObject = /* #__PURE__ */ Object.assign({"./sibling.ts": export const parent = /* #__PURE__ */ Object.assign({ }); -export const rootMixedRelative = /* #__PURE__ */ Object.assign({"/css.spec.ts": () => import("../../css.spec.ts?url&lang.ts").then(m => m["default"]),"/define.spec.ts": () => import("../../define.spec.ts?url&lang.ts").then(m => m["default"]),"/esbuild.spec.ts": () => import("../../esbuild.spec.ts?url&lang.ts").then(m => m["default"]),"/import.spec.ts": () => import("../../import.spec.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/a.ts": () => import("../fixture-b/a.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/b.ts": () => import("../fixture-b/b.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/index.ts": () => import("../fixture-b/index.ts?url&lang.ts").then(m => m["default"]) +export const rootMixedRelative = /* #__PURE__ */ Object.assign({"/css.spec.ts": () => import("../../css.spec.ts?url&lang.ts").then(m => m["default"]),"/define.spec.ts": () => import("../../define.spec.ts?url&lang.ts").then(m => m["default"]),"/esbuild.spec.ts": () => import("../../esbuild.spec.ts?url&lang.ts").then(m => m["default"]),"/import.spec.ts": () => import("../../import.spec.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/a.ts": () => import("../fixture-b/a.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/b.ts": () => import("../fixture-b/b.ts?url&lang.ts").then(m => m["default"]),"/importGlob/fixture-b/index.ts": () => import("../fixture-b/index.ts?url&lang.ts").then(m => m["default"]),"/json.spec.ts": () => import("../../json.spec.ts?url&lang.ts").then(m => m["default"]) }); diff --git a/packages/vite/src/node/__tests__/plugins/json.spec.ts b/packages/vite/src/node/__tests__/plugins/json.spec.ts new file mode 100644 index 00000000000000..b95d31eefa4942 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/json.spec.ts @@ -0,0 +1,26 @@ +import { expect, test } from 'vitest' +import { extractJsonErrorPosition } from '../../plugins/json' + +const getErrorMessage = (input: string) => { + try { + JSON.parse(input) + throw new Error('No error happened') + } catch (e) { + return e.message + } +} + +test('can extract json error position', () => { + const cases = [ + { input: '{', expectedPosition: 0 }, + { input: '{},', expectedPosition: 1 }, + { input: '"f', expectedPosition: 1 }, + { input: '[', expectedPosition: 0 }, + ] + + for (const { input, expectedPosition } of cases) { + expect(extractJsonErrorPosition(getErrorMessage(input), input.length)).toBe( + expectedPosition, + ) + } +}) diff --git a/packages/vite/src/node/plugins/json.ts b/packages/vite/src/node/plugins/json.ts index dbda0ded60e018..5de486cf59cbcd 100644 --- a/packages/vite/src/node/plugins/json.ts +++ b/packages/vite/src/node/plugins/json.ts @@ -71,13 +71,26 @@ export function jsonPlugin( map: { mappings: '' }, } } catch (e) { - const errorMessageList = /\d+/.exec(e.message) - const position = errorMessageList && parseInt(errorMessageList[0], 10) + const position = extractJsonErrorPosition(e.message, json.length) const msg = position - ? `, invalid JSON syntax found at line ${position}` + ? `, invalid JSON syntax found at position ${position}` : `.` - this.error(`Failed to parse JSON file` + msg, e.idx) + this.error(`Failed to parse JSON file` + msg, position) } }, } } + +export function extractJsonErrorPosition( + errorMessage: string, + inputLength: number, +): number | undefined { + if (errorMessage.startsWith('Unexpected end of JSON input')) { + return inputLength - 1 + } + + const errorMessageList = /at position (\d+)/.exec(errorMessage) + return errorMessageList + ? Math.max(parseInt(errorMessageList[1], 10) - 1, 0) + : undefined +}