From 87bfca1579d51aa03b1d4508555522dfce83dccc Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 24 Jun 2024 18:35:16 -0500 Subject: [PATCH 01/16] Install AJV validator --- package-lock.json | 26 +++++++++++++++++++++----- package.json | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7520faf..ccd514c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "license": "GPL-2.0", "devDependencies": { + "ajv": "^8.16.0", + "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "inquirer": "^9.1.4", "parse5-html-rewriting-stream": "^7.0.0", @@ -21,21 +23,35 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", diff --git a/package.json b/package.json index d906da2..e3d8b80 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "patterns:escape": "node ./theme-utils.mjs escape-patterns" }, "devDependencies": { + "ajv": "^8.16.0", + "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "inquirer": "^9.1.4", "parse5-html-rewriting-stream": "^7.0.0", From f380375458903948f4eb89f57502e58aa5048739 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 24 Jun 2024 18:34:25 -0500 Subject: [PATCH 02/16] Add validate script --- theme-utils.mjs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/theme-utils.mjs b/theme-utils.mjs index 9f4f3aa..5d5d909 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -1,14 +1,20 @@ import { spawn } from 'child_process'; import fs from 'fs'; +import process from 'process'; import inquirer from 'inquirer'; import { RewritingStream } from 'parse5-html-rewriting-stream'; import { table } from 'table'; import progressbar from 'string-progressbar'; +import Ajv from 'ajv-draft-04'; const isWin = process.platform === 'win32'; const commands = { + validate: { + helpText: 'Validates the theme.json file(s) against the JSON Schema.', + run: (args) => validate(args?.slice(1)), + }, "escape-patterns": { helpText: 'Escapes block patterns for pattern files that have changes (staged or unstaged).', run: () => escapePatterns() @@ -253,6 +259,49 @@ async function escapePatterns() { } } +async function validate(files) { + const ajv = new Ajv({ + allowMatchingProperties: true, + allErrors: true, + }); + const errors = []; + for (let i = 0; i < files.length; i++) { + const filename = files[i]; + try { + const file = await fs.promises + .readFile(filename, 'utf-8') + .then(JSON.parse); + const schemaURL = file['$schema']; + const schema = !schemaURL + ? { + type: 'object', + required: ['$schema'], + } + : schemaURL.startsWith('http') + ? await fetch(schemaURL).then((res) => res.json()) + : await fs.promises + .readFile( + path.join(path.dirname(filename), schemaURL), + 'utf-8' + ) + .then(JSON.parse); + if (!ajv.validate(schema, file)) { + throw ajv.errors; + } + } catch (error) { + errors.push({ filename, error }); + } finally { + const bar = progressbar.filledBar(files.length, i + 1)[0]; + process.stdout.write(`${bar} ${i + 1}/${files.length}\r`, 'utf-8'); + } + } + if (errors.length) { + console.log(); + console.error(JSON.stringify(errors, null, 2)); + process.exit(1); + } +} + function startProgress(length) { let current = 0; function render() { From 8417ca3abb9c56bf9e988693e3fe50b58866ae77 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 00:17:49 -0500 Subject: [PATCH 03/16] Update validateSchema --- theme-utils.mjs | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index 5d5d909..b9f7f03 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -1,6 +1,7 @@ import { spawn } from 'child_process'; import fs from 'fs'; +import path from 'path'; import process from 'process'; import inquirer from 'inquirer'; import { RewritingStream } from 'parse5-html-rewriting-stream'; @@ -11,9 +12,9 @@ import Ajv from 'ajv-draft-04'; const isWin = process.platform === 'win32'; const commands = { - validate: { + 'validate-schema': { helpText: 'Validates the theme.json file(s) against the JSON Schema.', - run: (args) => validate(args?.slice(1)), + run: (args) => validateSchema(args?.slice(1)), }, "escape-patterns": { helpText: 'Escapes block patterns for pattern files that have changes (staged or unstaged).', @@ -259,45 +260,49 @@ async function escapePatterns() { } } -async function validate(files) { +async function validateSchema(files) { const ajv = new Ajv({ allowMatchingProperties: true, allErrors: true, }); const errors = []; + let progress = progressbar.filledBar(files.length, 0)[0]; + process.stdout.write(`${progress} 0/${files.length}`, 'utf-8'); for (let i = 0; i < files.length; i++) { const filename = files[i]; try { const file = await fs.promises .readFile(filename, 'utf-8') .then(JSON.parse); - const schemaURL = file['$schema']; - const schema = !schemaURL - ? { - type: 'object', - required: ['$schema'], - } - : schemaURL.startsWith('http') - ? await fetch(schemaURL).then((res) => res.json()) - : await fs.promises - .readFile( - path.join(path.dirname(filename), schemaURL), - 'utf-8' - ) - .then(JSON.parse); + const schemaURL = file.$schema; + let schema; + if (!schemaURL) { + schema = { + type: 'object', + required: ['$schema'], + }; + } else if (schemaURL.startsWith('http')) { + schema = await fetch(schemaURL).then((res) => res.json()); + } else { + schema = await fs.promises + .readFile( + path.join(path.dirname(filename), schemaURL), + 'utf-8' + ) + .then(JSON.parse); + } if (!ajv.validate(schema, file)) { throw ajv.errors; } } catch (error) { errors.push({ filename, error }); - } finally { - const bar = progressbar.filledBar(files.length, i + 1)[0]; - process.stdout.write(`${bar} ${i + 1}/${files.length}\r`, 'utf-8'); } + progress = progressbar.filledBar(files.length, i + 1)[0]; + process.stdout.write(`\r${progress} ${i + 1}/${files.length}`, 'utf-8'); } + console.log(); if (errors.length) { - console.log(); - console.error(JSON.stringify(errors, null, 2)); + console.log(JSON.stringify(errors, null, 2)); process.exit(1); } } From e2b92d3b6c915c61428f1a5c90359503d1997795 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 00:27:49 -0500 Subject: [PATCH 04/16] Add lint-staged for theme.json schemas --- .lintstagedrc.json | 3 + package-lock.json | 657 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 +- 3 files changed, 639 insertions(+), 25 deletions(-) create mode 100644 .lintstagedrc.json diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..b63933b --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,3 @@ +{ + "theme.json": "node ./theme-utils.mjs validate" +} diff --git a/package-lock.json b/package-lock.json index ccd514c..8c4adbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "inquirer": "^9.1.4", + "lint-staged": "^15.2.7", "parse5-html-rewriting-stream": "^7.0.0", "string-progressbar": "^1.0.4", "table": "^6.8.1" @@ -53,13 +54,10 @@ } }, "node_modules/ansi-escapes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", - "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "dependencies": { - "type-fest": "^3.0.0" - }, "engines": { "node": ">=14.16" }, @@ -131,6 +129,18 @@ "readable-stream": "^3.4.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -156,9 +166,9 @@ } }, "node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -200,6 +210,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-width": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", @@ -236,6 +313,52 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -284,6 +407,74 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -320,6 +511,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs-extra": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", @@ -334,12 +537,45 @@ "node": ">=14.14" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -425,6 +661,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -437,6 +694,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -455,6 +718,102 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", + "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -483,6 +842,115 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -492,12 +960,45 @@ "node": ">=6" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -583,6 +1084,39 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -631,6 +1165,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -675,6 +1215,27 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -722,6 +1283,15 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-progressbar": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/string-progressbar/-/string-progressbar-1.0.4.tgz", @@ -746,9 +1316,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { "ansi-regex": "^6.0.1" @@ -760,6 +1330,18 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", @@ -835,24 +1417,24 @@ "node": ">=0.6.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "dev": true }, - "node_modules/type-fest": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.6.1.tgz", - "integrity": "sha512-htXWckxlT6U4+ilVgweNliPqlsVSSucbxVexRYllyMVJDtf5rTjv6kF/s+qAd4QSL1BZcnJPEJavYBPQiWuZDA==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -886,6 +1468,21 @@ "defaults": "^1.0.3" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -902,6 +1499,18 @@ "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } } } } diff --git a/package.json b/package.json index e3d8b80..38d8748 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,15 @@ "npm": ">=10.2.3" }, "scripts": { - "patterns:escape": "node ./theme-utils.mjs escape-patterns" + "patterns:escape": "node ./theme-utils.mjs escape-patterns", + "schema:validate": "node ./theme-utils.mjs validate-schema" }, "devDependencies": { "ajv": "^8.16.0", "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "inquirer": "^9.1.4", + "lint-staged": "^15.2.7", "parse5-html-rewriting-stream": "^7.0.0", "string-progressbar": "^1.0.4", "table": "^6.8.1" From 3ba70b55cedbca9e37ff2e3a4aebb5da1a7b1ce0 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 01:06:45 -0500 Subject: [PATCH 05/16] Update filename to file --- theme-utils.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index b9f7f03..c3d864b 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -295,7 +295,7 @@ async function validateSchema(files) { throw ajv.errors; } } catch (error) { - errors.push({ filename, error }); + errors.push({ file: filename, error }); } progress = progressbar.filledBar(files.length, i + 1)[0]; process.stdout.write(`\r${progress} ${i + 1}/${files.length}`, 'utf-8'); From 9b54d8c1c48ec60276c4d4d4c72b12312c57e13c Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 01:10:35 -0500 Subject: [PATCH 06/16] Add pre-commit hook --- .husky/pre-commit | 4 ++++ package-lock.json | 16 ++++++++++++++++ package.json | 6 ++++-- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d24fdfc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/package-lock.json b/package-lock.json index 8c4adbc..03e653b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "ajv": "^8.16.0", "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", + "husky": "^8.0.0", "inquirer": "^9.1.4", "lint-staged": "^15.2.7", "parse5-html-rewriting-stream": "^7.0.0", @@ -576,6 +577,21 @@ "node": ">=16.17.0" } }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index 38d8748..0e63ab8 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ }, "scripts": { "patterns:escape": "node ./theme-utils.mjs escape-patterns", - "schema:validate": "node ./theme-utils.mjs validate-schema" + "schema:validate": "node ./theme-utils.mjs validate-schema", + "prepare": "husky install" }, "devDependencies": { "ajv": "^8.16.0", @@ -20,6 +21,7 @@ "lint-staged": "^15.2.7", "parse5-html-rewriting-stream": "^7.0.0", "string-progressbar": "^1.0.4", - "table": "^6.8.1" + "table": "^6.8.1", + "husky": "^8.0.0" } } From 8fb8156ffc15b77314b71a5646a0611f75e9f1f1 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 08:56:28 -0500 Subject: [PATCH 07/16] Fix lint-staged --- .lintstagedrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index b63933b..6ace39e 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,3 +1,3 @@ { - "theme.json": "node ./theme-utils.mjs validate" + "theme.json": "node ./theme-utils.mjs validate-schema" } From e76b51ea4c1a84bca4bce0577155b2b81de0c059 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 09:36:24 -0500 Subject: [PATCH 08/16] Add schema url to the error output --- theme-utils.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index c3d864b..f4fdbfb 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -270,11 +270,12 @@ async function validateSchema(files) { process.stdout.write(`${progress} 0/${files.length}`, 'utf-8'); for (let i = 0; i < files.length; i++) { const filename = files[i]; + let schemaURL; try { const file = await fs.promises .readFile(filename, 'utf-8') .then(JSON.parse); - const schemaURL = file.$schema; + schemaURL = file.$schema; let schema; if (!schemaURL) { schema = { @@ -295,7 +296,7 @@ async function validateSchema(files) { throw ajv.errors; } } catch (error) { - errors.push({ file: filename, error }); + errors.push({ file: filename, schema: schemaURL ?? 'missing schema', error }); } progress = progressbar.filledBar(files.length, i + 1)[0]; process.stdout.write(`\r${progress} ${i + 1}/${files.length}`, 'utf-8'); From 4e95fa1d006f07a99925f46855ea16232d1565f1 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 10:16:25 -0500 Subject: [PATCH 09/16] Leave error schema as undefined when missing --- theme-utils.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index f4fdbfb..d71480b 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -296,7 +296,7 @@ async function validateSchema(files) { throw ajv.errors; } } catch (error) { - errors.push({ file: filename, schema: schemaURL ?? 'missing schema', error }); + errors.push({ file: filename, schema: schemaURL, error }); } progress = progressbar.filledBar(files.length, i + 1)[0]; process.stdout.write(`\r${progress} ${i + 1}/${files.length}`, 'utf-8'); From 3ba9b5a660c9748035627903b7fa5ff52e44de69 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 10:19:19 -0500 Subject: [PATCH 10/16] Add error exit code for invalid commands --- theme-utils.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index d71480b..1154e8d 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -31,7 +31,8 @@ const commands = { let command = args?.[0]; if (!commands[command]) { - return showHelp(); + showHelp(); + process.exit(1); } commands[command].run(args); From b8caa5d296bf0a921bbcec1a8dec7bf246cd0a6e Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 13:52:41 -0500 Subject: [PATCH 11/16] Rewrite for latest ajv --- json-schema-draft-04.json | 216 ++++++++++++++++++++++++++++++++++++++ package-lock.json | 15 --- package.json | 5 +- theme-utils.mjs | 81 +++++++------- 4 files changed, 261 insertions(+), 56 deletions(-) create mode 100644 json-schema-draft-04.json diff --git a/json-schema-draft-04.json b/json-schema-draft-04.json new file mode 100644 index 0000000..2ac6430 --- /dev/null +++ b/json-schema-draft-04.json @@ -0,0 +1,216 @@ +{ + "$id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#" + } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ + { + "$ref": "#/definitions/positiveInteger" + }, + { + "default": 0 + } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "multipleOf": { + "type": "number" + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { + "$ref": "#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#" + } + ], + "default": {} + }, + "items": { + "anyOf": [ + { + "$ref": "#" + }, + { + "$ref": "#/definitions/schemaArray" + } + ], + "default": {} + }, + "maxItems": { + "$ref": "#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { + "$ref": "#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "#/definitions/stringArray" + }, + "additionalProperties": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#" + } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "$ref": "#" + }, + { + "$ref": "#/definitions/stringArray" + } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { + "$ref": "#/definitions/simpleTypes" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/simpleTypes" + }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { + "type": "string" + }, + "allOf": { + "$ref": "#/definitions/schemaArray" + }, + "anyOf": { + "$ref": "#/definitions/schemaArray" + }, + "oneOf": { + "$ref": "#/definitions/schemaArray" + }, + "not": { + "$ref": "#" + } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/package-lock.json b/package-lock.json index 03e653b..a9e0784 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "GPL-2.0", "devDependencies": { "ajv": "^8.16.0", - "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "husky": "^8.0.0", "inquirer": "^9.1.4", @@ -40,20 +39,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ansi-escapes": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", diff --git a/package.json b/package.json index 0e63ab8..d274b13 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,12 @@ }, "devDependencies": { "ajv": "^8.16.0", - "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", + "husky": "^8.0.0", "inquirer": "^9.1.4", "lint-staged": "^15.2.7", "parse5-html-rewriting-stream": "^7.0.0", "string-progressbar": "^1.0.4", - "table": "^6.8.1", - "husky": "^8.0.0" + "table": "^6.8.1" } } diff --git a/theme-utils.mjs b/theme-utils.mjs index 1154e8d..8219180 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -7,7 +7,7 @@ import inquirer from 'inquirer'; import { RewritingStream } from 'parse5-html-rewriting-stream'; import { table } from 'table'; import progressbar from 'string-progressbar'; -import Ajv from 'ajv-draft-04'; +import Ajv from 'ajv'; const isWin = process.platform === 'win32'; @@ -261,51 +261,56 @@ async function escapePatterns() { } } -async function validateSchema(files) { - const ajv = new Ajv({ +async function validateSchema( files ) { + const ajv = new Ajv( { allowMatchingProperties: true, allErrors: true, - }); + loadSchema: async ( uri ) => { + if ( uri.startsWith( 'http' ) ) { + return fetch( uri ).then( ( res ) => res.json() ); + } + return fs.promises.readFile( uri, 'utf-8' ).then( JSON.parse ); + }, + } ); + ajv.addMetaSchema( + await fs.promises + .readFile( './json-schema-draft-04.json', 'utf-8' ) + .then( JSON.parse ) + ); const errors = []; - let progress = progressbar.filledBar(files.length, 0)[0]; - process.stdout.write(`${progress} 0/${files.length}`, 'utf-8'); - for (let i = 0; i < files.length; i++) { - const filename = files[i]; - let schemaURL; + let progress = progressbar.filledBar( files.length, 0 )[ 0 ]; + process.stdout.write( `${ progress } 0/${ files.length }`, 'utf-8' ); + for ( const [ i, file ] of files.entries() ) { + let schemaUri; try { - const file = await fs.promises - .readFile(filename, 'utf-8') - .then(JSON.parse); - schemaURL = file.$schema; - let schema; - if (!schemaURL) { - schema = { - type: 'object', - required: ['$schema'], - }; - } else if (schemaURL.startsWith('http')) { - schema = await fetch(schemaURL).then((res) => res.json()); - } else { - schema = await fs.promises - .readFile( - path.join(path.dirname(filename), schemaURL), - 'utf-8' - ) - .then(JSON.parse); - } - if (!ajv.validate(schema, file)) { - throw ajv.errors; + const data = await fs.promises + .readFile( file, 'utf-8' ) + .then( JSON.parse ); + schemaUri = + typeof data?.$schema === 'string' && + ! data.$schema.startsWith( 'http' ) + ? path.resolve( path.dirname( file ), data.$schema ) + : data?.$schema; + const schema = schemaUri + ? { $ref: schemaUri } + : { type: 'object', required: [ '$schema' ] }; + const validate = await ajv.compileAsync( schema ); + if ( ! validate( data ) ) { + throw validate.errors; } - } catch (error) { - errors.push({ file: filename, schema: schemaURL, error }); + } catch ( error ) { + errors.push( { file, schema: schemaUri, error } ); } - progress = progressbar.filledBar(files.length, i + 1)[0]; - process.stdout.write(`\r${progress} ${i + 1}/${files.length}`, 'utf-8'); + progress = progressbar.filledBar( files.length, i + 1 )[ 0 ]; + process.stdout.write( + `\r${ progress } ${ i + 1 }/${ files.length }`, + 'utf-8' + ); } console.log(); - if (errors.length) { - console.log(JSON.stringify(errors, null, 2)); - process.exit(1); + if ( errors.length ) { + console.log( JSON.stringify( errors, null, 2 ) ); + process.exit( 1 ); } } From 585d2b5345e5cf53e66e5f864c9d81c7624d5bcb Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 13:56:02 -0500 Subject: [PATCH 12/16] Revert to ajv@6 --- json-schema-draft-04.json | 216 -------------------------------------- package-lock.json | 50 +++++++-- package.json | 2 +- theme-utils.mjs | 6 +- 4 files changed, 45 insertions(+), 229 deletions(-) delete mode 100644 json-schema-draft-04.json diff --git a/json-schema-draft-04.json b/json-schema-draft-04.json deleted file mode 100644 index 2ac6430..0000000 --- a/json-schema-draft-04.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "$id": "http://json-schema.org/draft-04/schema#", - "$schema": "http://json-schema.org/draft-07/schema#", - "description": "Core schema meta-schema", - "definitions": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#" - } - }, - "positiveInteger": { - "type": "integer", - "minimum": 0 - }, - "positiveIntegerDefault0": { - "allOf": [ - { - "$ref": "#/definitions/positiveInteger" - }, - { - "default": 0 - } - ] - }, - "simpleTypes": { - "enum": [ - "array", - "boolean", - "integer", - "null", - "number", - "object", - "string" - ] - }, - "stringArray": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - } - }, - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "$schema": { - "type": "string" - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": true, - "multipleOf": { - "type": "number" - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "boolean", - "default": false - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "boolean", - "default": false - }, - "maxLength": { - "$ref": "#/definitions/positiveInteger" - }, - "minLength": { - "$ref": "#/definitions/positiveIntegerDefault0" - }, - "pattern": { - "type": "string", - "format": "regex" - }, - "additionalItems": { - "anyOf": [ - { - "type": "boolean" - }, - { - "$ref": "#" - } - ], - "default": {} - }, - "items": { - "anyOf": [ - { - "$ref": "#" - }, - { - "$ref": "#/definitions/schemaArray" - } - ], - "default": {} - }, - "maxItems": { - "$ref": "#/definitions/positiveInteger" - }, - "minItems": { - "$ref": "#/definitions/positiveIntegerDefault0" - }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxProperties": { - "$ref": "#/definitions/positiveInteger" - }, - "minProperties": { - "$ref": "#/definitions/positiveIntegerDefault0" - }, - "required": { - "$ref": "#/definitions/stringArray" - }, - "additionalProperties": { - "anyOf": [ - { - "type": "boolean" - }, - { - "$ref": "#" - } - ], - "default": {} - }, - "definitions": { - "type": "object", - "additionalProperties": { - "$ref": "#" - }, - "default": {} - }, - "properties": { - "type": "object", - "additionalProperties": { - "$ref": "#" - }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { - "$ref": "#" - }, - "default": {} - }, - "dependencies": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "$ref": "#" - }, - { - "$ref": "#/definitions/stringArray" - } - ] - } - }, - "enum": { - "type": "array", - "minItems": 1, - "uniqueItems": true - }, - "type": { - "anyOf": [ - { - "$ref": "#/definitions/simpleTypes" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/simpleTypes" - }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "format": { - "type": "string" - }, - "allOf": { - "$ref": "#/definitions/schemaArray" - }, - "anyOf": { - "$ref": "#/definitions/schemaArray" - }, - "oneOf": { - "$ref": "#/definitions/schemaArray" - }, - "not": { - "$ref": "#" - } - }, - "dependencies": { - "exclusiveMaximum": [ "maximum" ], - "exclusiveMinimum": [ "minimum" ] - }, - "default": {} -} diff --git a/package-lock.json b/package-lock.json index a9e0784..b1a085d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "GPL-2.0", "devDependencies": { - "ajv": "^8.16.0", + "ajv": "^6.12.6", "fs-extra": "^11.1.0", "husky": "^8.0.0", "inquirer": "^9.1.4", @@ -24,15 +24,15 @@ } }, "node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { "type": "github", @@ -481,6 +481,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, "node_modules/figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -702,9 +708,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "node_modules/jsonfile": { @@ -1359,6 +1365,22 @@ "node": ">=10.0.0" } }, + "node_modules/table/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/table/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1374,6 +1396,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/table/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/package.json b/package.json index d274b13..ab8e969 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "prepare": "husky install" }, "devDependencies": { - "ajv": "^8.16.0", + "ajv": "^6.12.6", "fs-extra": "^11.1.0", "husky": "^8.0.0", "inquirer": "^9.1.4", diff --git a/theme-utils.mjs b/theme-utils.mjs index 8219180..cadea0b 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -265,6 +265,7 @@ async function validateSchema( files ) { const ajv = new Ajv( { allowMatchingProperties: true, allErrors: true, + schemaId: 'auto', loadSchema: async ( uri ) => { if ( uri.startsWith( 'http' ) ) { return fetch( uri ).then( ( res ) => res.json() ); @@ -274,7 +275,10 @@ async function validateSchema( files ) { } ); ajv.addMetaSchema( await fs.promises - .readFile( './json-schema-draft-04.json', 'utf-8' ) + .readFile( + './node_modules/ajv/lib/refs/json-schema-draft-04.json', + 'utf-8' + ) .then( JSON.parse ) ); const errors = []; From 42cad57cc61f03564ee77ef60897931047a5ca1e Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 15:55:34 -0500 Subject: [PATCH 13/16] Support both draft-04 and draft-07 --- package-lock.json | 65 +++++++++++++++++++---------------------------- package.json | 3 ++- theme-utils.mjs | 64 +++++++++++++++++++++++++--------------------- 3 files changed, 63 insertions(+), 69 deletions(-) diff --git a/package-lock.json b/package-lock.json index b1a085d..03e653b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "GPL-2.0", "devDependencies": { - "ajv": "^6.12.6", + "ajv": "^8.16.0", + "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "husky": "^8.0.0", "inquirer": "^9.1.4", @@ -24,21 +25,35 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", @@ -481,12 +496,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, "node_modules/figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -708,9 +717,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/jsonfile": { @@ -1365,22 +1374,6 @@ "node": ">=10.0.0" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/table/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1396,12 +1389,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/table/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/package.json b/package.json index ab8e969..5f62d8b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "prepare": "husky install" }, "devDependencies": { - "ajv": "^6.12.6", + "ajv": "^8.16.0", + "ajv-draft-04": "^1.0.0", "fs-extra": "^11.1.0", "husky": "^8.0.0", "inquirer": "^9.1.4", diff --git a/theme-utils.mjs b/theme-utils.mjs index cadea0b..47c024f 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -8,6 +8,7 @@ import { RewritingStream } from 'parse5-html-rewriting-stream'; import { table } from 'table'; import progressbar from 'string-progressbar'; import Ajv from 'ajv'; +import AjvDraft04 from 'ajv-draft-04'; const isWin = process.platform === 'win32'; @@ -262,43 +263,48 @@ async function escapePatterns() { } async function validateSchema( files ) { - const ajv = new Ajv( { + function readJson( file ) { + return fs.promises.readFile( file, 'utf-8' ).then( JSON.parse ); + } + async function loadSchema( uri, dirname = '' ) { + if ( ! uri ) { + return { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + required: [ '$schema' ], + }; + } + if ( ! URL.canParse( uri ) ) { + return readJson( path.resolve( dirname, uri ) ); + } + const url = new URL( uri ); + if ( url.protocol === 'http:' || url.protocol === 'https:' ) { + return fetch( url ).then( ( res ) => res.json() ); + } + if ( url.protocol === 'file:' ) { + return readJson( path.resolve( dirname, url.href.slice( 7 ) ) ); + } + throw new Error( `Unsupported schema protocol: ${ url.protocol }` ); + } + const ajvOptions = { allowMatchingProperties: true, allErrors: true, - schemaId: 'auto', - loadSchema: async ( uri ) => { - if ( uri.startsWith( 'http' ) ) { - return fetch( uri ).then( ( res ) => res.json() ); - } - return fs.promises.readFile( uri, 'utf-8' ).then( JSON.parse ); - }, - } ); - ajv.addMetaSchema( - await fs.promises - .readFile( - './node_modules/ajv/lib/refs/json-schema-draft-04.json', - 'utf-8' - ) - .then( JSON.parse ) - ); + loadSchema, + }; + const ajv = { + 'http://json-schema.org/draft-07/schema#': new Ajv( ajvOptions ), + 'http://json-schema.org/draft-04/schema#': new AjvDraft04( ajvOptions ), + }; const errors = []; let progress = progressbar.filledBar( files.length, 0 )[ 0 ]; process.stdout.write( `${ progress } 0/${ files.length }`, 'utf-8' ); for ( const [ i, file ] of files.entries() ) { let schemaUri; try { - const data = await fs.promises - .readFile( file, 'utf-8' ) - .then( JSON.parse ); - schemaUri = - typeof data?.$schema === 'string' && - ! data.$schema.startsWith( 'http' ) - ? path.resolve( path.dirname( file ), data.$schema ) - : data?.$schema; - const schema = schemaUri - ? { $ref: schemaUri } - : { type: 'object', required: [ '$schema' ] }; - const validate = await ajv.compileAsync( schema ); + const data = await readJson( file ); + schemaUri = data.$schema; + const schema = await loadSchema( schemaUri, path.dirname( file ) ); + const validate = await ajv[ schema.$schema ].compileAsync( schema ); if ( ! validate( data ) ) { throw validate.errors; } From 432d2aa77b786a326b7fa15ae7442eabc8deee7a Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 25 Jun 2024 15:56:00 -0500 Subject: [PATCH 14/16] Add colored JSON output --- theme-utils.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme-utils.mjs b/theme-utils.mjs index 47c024f..847bdd9 100644 --- a/theme-utils.mjs +++ b/theme-utils.mjs @@ -319,7 +319,7 @@ async function validateSchema( files ) { } console.log(); if ( errors.length ) { - console.log( JSON.stringify( errors, null, 2 ) ); + console.dir( errors, { depth: null } ); process.exit( 1 ); } } From d5749dbfeed0ba5d4ce16bd76bbc64bea0c8be78 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Wed, 26 Jun 2024 01:05:26 -0500 Subject: [PATCH 15/16] Add variations and font collection validation --- .lintstagedrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 6ace39e..3b2fb79 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,3 +1,3 @@ { - "theme.json": "node ./theme-utils.mjs validate-schema" + "{theme.json,styles/*.json,assets/fonts/*.json}": "node ./theme-utils.mjs validate-schema" } From 97e93d435aabda9eaad7f31a32a6524226875290 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Wed, 26 Jun 2024 12:34:24 -0500 Subject: [PATCH 16/16] Fix glob for running validation in lint-staged --- .lintstagedrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 3b2fb79..bffe1ad 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,3 +1,3 @@ { - "{theme.json,styles/*.json,assets/fonts/*.json}": "node ./theme-utils.mjs validate-schema" + "{**/theme.json,**/styles/*.json,**/assets/fonts/*.json}": "node ./theme-utils.mjs validate-schema" }