diff --git a/package-lock.json b/package-lock.json index cebce07..13c32a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "deepmerge": "^4.3.1", "fs-extra": "^11.3.0", "glob": "^11.0.0", + "jsonc": "^2.0.0", "parse-imports": "^2.2.1", "smol-toml": "^1.3.1" }, @@ -4524,7 +4525,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -5358,6 +5358,12 @@ "fastest-levenshtein": "^1.0.7" } }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fast-xml-parser": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", @@ -6169,8 +6175,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { "version": "2.0.0", @@ -6769,8 +6774,7 @@ "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -6802,6 +6806,32 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jsonc/-/jsonc-2.0.0.tgz", + "integrity": "sha512-B281bLCT2TRMQa+AQUQY5AGcqSOXBOKaYGP4wDzoA/+QswUfN8sODektbPEs9Baq7LGKun5jQbNFpzwGuVYKhw==", + "license": "MIT", + "dependencies": { + "fast-safe-stringify": "^2.0.6", + "graceful-fs": "^4.1.15", + "mkdirp": "^0.5.1", + "parse-json": "^4.0.0", + "strip-bom": "^4.0.0", + "strip-json-comments": "^3.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jsonc/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -7025,7 +7055,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7038,6 +7067,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mocha": { "version": "10.8.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", @@ -10152,7 +10193,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -11418,7 +11458,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, diff --git a/package.json b/package.json index 4f0e5b6..cfd9fa5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "deepmerge": "^4.3.1", "fs-extra": "^11.3.0", "glob": "^11.0.0", + "jsonc": "^2.0.0", "parse-imports": "^2.2.1", "smol-toml": "^1.3.1" }, diff --git a/src/utilities/locales.ts b/src/utilities/locales.ts index b5f42bc..0ba530b 100644 --- a/src/utilities/locales.ts +++ b/src/utilities/locales.ts @@ -1,3 +1,4 @@ +import { jsonc } from 'jsonc' import fs, { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import path from 'node:path' @@ -10,6 +11,8 @@ import { CleanOptions, LocaleContent, LocaleDiff, LocaleOptions, SyncOptions, Tr const SCHEMA_DIRS = ['config', 'blocks', 'sections'] as const const STOREFRONT_DIRS = ['blocks', 'layout', 'sections', 'snippets', 'templates'] as const + + export async function getLocalesSource(source: string): Promise { if (isUrl(source)) { return fetchRemoteLocales(source) @@ -45,7 +48,8 @@ function loadLocalLocales(dir: string): LocaleContent { const filePath = path.join(dir, file) try { - content[file] = JSON.parse(fs.readFileSync(filePath, 'utf8')) + const fileContent = fs.readFileSync(filePath, 'utf8') + content[file] = jsonc.parse(fileContent, { stripComments: true }) as Record } catch (error) { throw new Error(`Failed to parse JSON file ${file}: ${error instanceof Error ? error.message : String(error)}`) } @@ -267,7 +271,8 @@ export async function removeUnreferencedStorefrontTranslations(themeDir: string, function removeUnreferencedKeysFromFile(filePath: string, usedKeys: Set, options?: LocaleOptions): void { if (!fs.existsSync(filePath)) return - const content = JSON.parse(fs.readFileSync(filePath, 'utf8')) + const fileContent = fs.readFileSync(filePath, 'utf8') + const content = jsonc.parse(fileContent, { stripComments: true }) as Record if (!content || typeof content !== 'object') return const flattenedContent = flattenObject(content) @@ -330,7 +335,8 @@ export async function mergeLocaleFiles( continue } - const targetContent = JSON.parse(fs.readFileSync(targetPath, 'utf8')) + const targetFileContent = fs.readFileSync(targetPath, 'utf8') + const targetContent = jsonc.parse(targetFileContent, { stripComments: true }) as Record const diff = compareLocales(sourceContent, targetContent) const mergedContent = mode === 'replace-existing' diff --git a/src/utilities/manifest.ts b/src/utilities/manifest.ts index 07e262e..c9bac25 100644 --- a/src/utilities/manifest.ts +++ b/src/utilities/manifest.ts @@ -1,3 +1,4 @@ +import { jsonc } from 'jsonc' import * as fs from 'node:fs' import logger from './logger.js' @@ -9,7 +10,7 @@ export function getManifest(path: string): Manifest { if (fs.existsSync(path)) { const manifestContent = fs.readFileSync(path, 'utf8') - const parsedContent = JSON.parse(manifestContent) + const parsedContent = jsonc.parse(manifestContent, { stripComments: true }) data.collections = parsedContent.collections || {} data.files.assets = parsedContent.files?.assets || {} data.files.snippets = parsedContent.files?.snippets || {} diff --git a/src/utilities/package-json.ts b/src/utilities/package-json.ts index 130a4d2..8375435 100644 --- a/src/utilities/package-json.ts +++ b/src/utilities/package-json.ts @@ -1,3 +1,4 @@ +import { jsonc } from 'jsonc' import fs from "node:fs"; import path from "node:path"; @@ -5,7 +6,7 @@ export function getNameFromPackageJson(dir: string): string|undefined { const pkgPath = path.join(dir, 'package.json'); let name; if (fs.existsSync(pkgPath)) { - const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const pkg = jsonc.parse(fs.readFileSync(pkgPath, 'utf8'), { stripComments: true }); name = pkg.name; } @@ -16,7 +17,7 @@ export function getVersionFromPackageJson(dir: string): string|undefined { const pkgPath = path.join(dir, 'package.json'); let version; if (fs.existsSync(pkgPath)) { - const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const pkg = jsonc.parse(fs.readFileSync(pkgPath, 'utf8'), { stripComments: true }); version = pkg.version; } diff --git a/src/utilities/setup.ts b/src/utilities/setup.ts index c80b9ae..8cdf38f 100644 --- a/src/utilities/setup.ts +++ b/src/utilities/setup.ts @@ -1,3 +1,4 @@ +import { jsonc } from 'jsonc' import path from 'node:path' import { copyFileIfChanged, writeFileIfChanged } from './files.js' @@ -57,7 +58,7 @@ export async function processSettingsSchema( } try { - const schema = JSON.parse(node.body) + const schema = jsonc.parse(node.body, { stripComments: true }) if (!Array.isArray(schema)) { logger.warn(`Invalid schema format in ${setupFile}: Expected an array`) return [] @@ -79,7 +80,7 @@ export async function processSettingsData( } try { - const data = JSON.parse(node.body) + const data = jsonc.parse(node.body, { stripComments: true }) if (typeof data !== 'object' || data === null) { logger.warn(`Invalid settings data format in ${setupFile}: Expected an object`) return {}