diff --git a/package-lock.json b/package-lock.json index 134ade1..b737376 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,9 +64,9 @@ "dev": true }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.4.0.tgz", - "integrity": "sha512-/PPLr2g5PAUCKAPEbfyk6/baZA+WJHQtUhPkoCQMpyRE8I0lXrG1QFRN8e5s3ZYxM8d/g5BZc6lH3s8Op7/VEg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz", + "integrity": "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==", "dev": true, "funding": [ { @@ -82,13 +82,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.2" + "@csstools/css-tokenizer": "^2.2.3" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.2.tgz", - "integrity": "sha512-wCDUe/MAw7npAHFLyW3QjSyLA66S5QFaV1jIXlNQvdJ8RzXDSgALa49eWcUO6P55ARQaz0TsDdAgdRgkXFYY8g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz", + "integrity": "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==", "dev": true, "funding": [ { @@ -105,9 +105,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.6.tgz", - "integrity": "sha512-R6AKl9vaU0It7D7TR2lQn0pre5aQfdeqHRePlaRCY8rHL3l9eVlNRpsEVDKFi/zAjzv68CxH2M5kqbhPFPKjvw==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.7.tgz", + "integrity": "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==", "dev": true, "funding": [ { @@ -123,8 +123,8 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.4.0", - "@csstools/css-tokenizer": "^2.2.2" + "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-tokenizer": "^2.2.3" } }, "node_modules/@csstools/selector-specificity": { @@ -166,18 +166,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -201,23 +189,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -320,9 +291,9 @@ "dev": true }, "node_modules/@webref/css": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/@webref/css/-/css-6.10.1.tgz", - "integrity": "sha512-ZxCgURpBTiZ+YjHT1BSPWjfI6nJJIGLH5876TLZ4LGq2KEBbWUymZ3cZVXjXZTjLqO3BzQE4mnKP/C9ADCBviA==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/@webref/css/-/css-6.10.2.tgz", + "integrity": "sha512-BQepib8uNtlsxZbeVBHk1xdKDQRKFn4Gz73zy/zgRP+0we2v+LT2e8nOqt2KCGfUjSoNkSDS0Wc8z003qJXqFQ==", "dev": true, "peerDependencies": { "css-tree": "^2.3.1" @@ -403,21 +374,26 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, + "node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -522,6 +498,39 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -534,6 +543,23 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -811,70 +837,6 @@ "node": ">=16" } }, - "node_modules/flat-cache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/flatted": { "version": "3.2.9", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", @@ -913,20 +875,22 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1355,9 +1319,9 @@ "dev": true }, "node_modules/meow": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.0.0.tgz", - "integrity": "sha512-4Hu+75Vo7EOR+8C9RmkabfLijuwd9SrzQ8f0SyC4qZZwU6BlxeOt5ulF3PGCpcMJX4hI+ktpJhea0P6PN1RiWw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.1.0.tgz", + "integrity": "sha512-o5R/R3Tzxq0PJ3v3qcQJtSvSE9nKOLSAaDuuoMzDVuGTwHdccMWcYomh9Xolng2tjT6O/Y83d+0coVGof6tqmA==", "dev": true, "engines": { "node": ">=18" @@ -1389,15 +1353,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { @@ -1591,9 +1558,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "dev": true, "funding": [ { @@ -1734,6 +1701,24 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2053,12 +2038,6 @@ "stylelint": "^16.0.1" } }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2151,6 +2130,54 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2207,17 +2234,17 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -2295,58 +2322,39 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrappy": { @@ -2424,7 +2432,7 @@ }, "packages/attribute-selector-no-unknown": { "name": "@mrhenry/stylelint-mrhenry-attribute-selector-no-unknown", - "version": "2.0.1", + "version": "2.1.0", "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.15" diff --git a/packages/attribute-selector-no-unknown/CHANGELOG.md b/packages/attribute-selector-no-unknown/CHANGELOG.md index 65c34e5..6c1df59 100644 --- a/packages/attribute-selector-no-unknown/CHANGELOG.md +++ b/packages/attribute-selector-no-unknown/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 2.1.0 + +- Add `globalAttributes` secondary option +- Add `attributesByTagName` secondary option + +```js +{ + globalAttributes: ['attr-foo'], + attributesByTagName: { + 'elem-foo': ['attr-bar', 'attr-baz'] + } +} +``` + ## 2.0.1 - Add type annotations diff --git a/packages/attribute-selector-no-unknown/index.mjs b/packages/attribute-selector-no-unknown/index.mjs index 7045e77..c144219 100644 --- a/packages/attribute-selector-no-unknown/index.mjs +++ b/packages/attribute-selector-no-unknown/index.mjs @@ -1,6 +1,7 @@ import stylelint from 'stylelint'; import selectorParser from 'postcss-selector-parser'; import { data } from './data.mjs'; +import { isRecordOfStringArrays, isString } from './validate-options.mjs'; const ruleName = "@mrhenry/stylelint-mrhenry-attribute-selector-no-unknown"; const messages = stylelint.utils.ruleMessages(ruleName, { @@ -27,7 +28,34 @@ const ruleFunction = (primaryOption, secondaryOption, context) => { /* c8 ignore next */ if (!validPrimary) return; - + + const validSecondary = stylelint.utils.validateOptions(postcssResult, ruleName, { + actual: secondaryOption, + possible: { + globalAttributes: [isString], + attributesByTagName: isRecordOfStringArrays, + }, + optional: true, + }); + + /* c8 ignore next */ + if (!validSecondary) return; + + const userData = { + /** @type {Set} */ + globalAttributes: new Set(secondaryOption?.globalAttributes ?? []), + /** @type {Map} */ + attributesByTagName: new Map(Object.entries(secondaryOption?.attributesByTagName ?? {})), + /** @type {Set} */ + allAttributes: new Set(secondaryOption?.globalAttributes ?? []), + } + + for (const attributes of userData.attributesByTagName.values()) { + for (const attribute of attributes) { + userData.allAttributes.add(attribute); + } + } + postcssRoot.walkRules((rule) => { if (!rule.selector.includes('[')) { return; @@ -46,8 +74,12 @@ const ruleFunction = (primaryOption, secondaryOption, context) => { // Global attributes are always allowed. if (data.globalAttributes.has(attribute)) return; + if (userData.globalAttributes.has(attribute)) return; - if (!data.allAttributes.has(attribute)) { + if ( + !data.allAttributes.has(attribute) && + !userData.allAttributes.has(attribute) + ) { // An unknown attribute that doesn't start with "data-" is always invalid. stylelint.utils.report({ message: messages.expected, @@ -64,13 +96,16 @@ const ruleFunction = (primaryOption, secondaryOption, context) => { const tagName = findTagNameInCompound(node); if (!tagName) { - // Without a tagname we assime that any attribute is allowed. + // Without a tagname we assume that any attribute is allowed. return; } const attributesByTagName = data.attributesByTagName.get(tagName); if (attributesByTagName && attributesByTagName.includes(attribute)) return; + const userAttributesByTagName = userData.attributesByTagName.get(tagName); + if (userAttributesByTagName && userAttributesByTagName.includes(attribute)) return; + // If the tag name is a standard element // we assume that only attributes that are valid for that tag are allowed. stylelint.utils.report({ diff --git a/packages/attribute-selector-no-unknown/index.test.mjs b/packages/attribute-selector-no-unknown/index.test.mjs index dd903c1..6cecf72 100644 --- a/packages/attribute-selector-no-unknown/index.test.mjs +++ b/packages/attribute-selector-no-unknown/index.test.mjs @@ -147,6 +147,63 @@ testRule({ ] }); +testRule({ + plugins: ["./index.mjs"], + ruleName: rule.ruleName, + config: [true, { + globalAttributes: ['attr-foo'], + attributesByTagName: { + 'elem-foo': ['attr-bar', 'attr-baz'], + 'elem-bar': ['attr-bar-2'], + } + }], + + accept: [ + { + code: '[attr-foo] {}', + }, + { + code: 'div[attr-foo] {}', + }, + { + code: 'summary[attr-foo] {}', + }, + { + code: 'elem-foo[attr-bar] {}', + }, + { + code: 'elem-foo[attr-baz] {}', + }, + { + code: '[attr-bar] {}', + }, + { + code: 'elem-bar[attr-bar-2] {}', + }, + ], + + reject: [ + { + code: "div[attr-bar] {}", + description: "Non-global attribute selector with an unexpected tag name", + message: rule.messages.expected('attr-bar', 'div'), + line: 1, + column: 4, + endLine: 1, + endColumn: 12 + }, + { + code: "elem-bar[attr-bar] {}", + description: "Non-global attribute selector with an unexpected tag name", + message: rule.messages.expected('attr-bar', 'elem-bar'), + line: 1, + column: 9, + endLine: 1, + endColumn: 17 + }, + ] +}); + testRule({ plugins: ["./index.mjs"], ruleName: rule.ruleName, diff --git a/packages/attribute-selector-no-unknown/package.json b/packages/attribute-selector-no-unknown/package.json index 206beb4..a0b38a6 100644 --- a/packages/attribute-selector-no-unknown/package.json +++ b/packages/attribute-selector-no-unknown/package.json @@ -1,6 +1,6 @@ { "name": "@mrhenry/stylelint-mrhenry-attribute-selector-no-unknown", - "version": "2.0.1", + "version": "2.1.0", "description": "Warn when unknown attribute selectors are used", "type": "module", "main": "index.mjs", @@ -18,6 +18,7 @@ "files": [ "index.mjs", "data.mjs", + "validate-options.mjs", "LICENSE", "README.md" ], diff --git a/packages/attribute-selector-no-unknown/validate-options.mjs b/packages/attribute-selector-no-unknown/validate-options.mjs new file mode 100644 index 0000000..040c7ce --- /dev/null +++ b/packages/attribute-selector-no-unknown/validate-options.mjs @@ -0,0 +1,25 @@ +export function isString(value) { + return typeof value === 'string' || value instanceof String; +} + +export function isRecordOfStringArrays(value) { + if (!value) return false; + if (typeof value !== 'object') return false; + if (Array.isArray(value)) return false; + + for (const key in value) { + if (Object.hasOwnProperty.call(value, key)) { + /* c8 ignore next */ + if (!isString(key)) return false; + + if (!value[key]) return false; + if (!Array.isArray(value[key])) return false; + + for (const attr of value[key]) { + if (!isString(attr)) return false; + } + } + } + + return true; +} diff --git a/packages/attribute-selector-no-unknown/validate-options.test.mjs b/packages/attribute-selector-no-unknown/validate-options.test.mjs new file mode 100644 index 0000000..e9292ad --- /dev/null +++ b/packages/attribute-selector-no-unknown/validate-options.test.mjs @@ -0,0 +1,116 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { isRecordOfStringArrays } from "./validate-options.mjs"; + +test("isRecordOfStringArrays", async (t) => { + await t.test("`null` is not a valid option", () => { + assert.ok(!isRecordOfStringArrays(null)); + }); + + await t.test("`undefined` is not a valid option", () => { + assert.ok(!isRecordOfStringArrays(undefined)); + }); + + await t.test("`true` is not a valid option", () => { + assert.ok(!isRecordOfStringArrays(true)); + }); + + await t.test("`false` is not a valid option", () => { + assert.ok(!isRecordOfStringArrays(true)); + }); + + await t.test("A string is not a valid option", () => { + assert.ok(!isRecordOfStringArrays('foo')); + }); + + await t.test("An array is not a valid option", () => { + assert.ok(!isRecordOfStringArrays([])); + }); + + await t.test("An empty object is a valid option", () => { + assert.ok(isRecordOfStringArrays({})); + }); + + await t.test("Element value of `false` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + 'x-foo': false, + })); + }); + + await t.test("Element value of `true` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + 'x-foo': true, + })); + }); + + await t.test("Element value of `null` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + 'x-foo': null, + })); + }); + + await t.test("Element value of `{}` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + 'x-foo': {}, + })); + }); + + await t.test("Element key of `false` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + [false]: {}, + })); + }); + + await t.test("Element key of `true` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + [true]: {}, + })); + }); + + await t.test("Element key of `null` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + [null]: {}, + })); + }); + + await t.test("Element key of `{}` is invalid", () => { + assert.ok(!isRecordOfStringArrays({ + [{}]: {}, + })); + }); + + await t.test("An object with an empty array is valid", () => { + assert.ok(isRecordOfStringArrays({ + 'x-foo': [], + })); + }); + + await t.test("false", () => { + assert.ok(!isRecordOfStringArrays({ + 'x-foo': [ + false, + ], + })); + }); + + await t.test("string / string", () => { + assert.ok(isRecordOfStringArrays({ + 'x-foo': [ + 'attr-bar' + ], + })); + }); + + await t.test("mixed", () => { + assert.ok(isRecordOfStringArrays({ + 'x-foo': [ + 'attr-bar', + new String('attr-bar'), + ], + [new String('x-foo')]: [ + 'attr-bar', + new String('attr-bar'), + ], + })); + }); +});