diff --git a/package-lock.json b/package-lock.json index d943de0c..ee86c676 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "lint-staged": "^17.0.8", "mocha": "^11.7.6", "mocha-snap": "^5.0.1", + "patch-package": "^8.0.1", "prettier": "^3.8.4", "prettier-plugin-packagejson": "^3.0.2", "tsx": "^4.22.4", @@ -2451,9 +2452,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2471,9 +2469,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2491,9 +2486,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2511,9 +2503,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3677,6 +3666,13 @@ "node": ">=8" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/acorn": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", @@ -4084,6 +4080,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -5808,6 +5823,16 @@ "node": ">=8" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -6926,6 +6951,26 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -6933,6 +6978,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6963,6 +7015,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", @@ -7045,6 +7107,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -7668,7 +7740,6 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", - "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8480,6 +8551,192 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/patch-package/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-package/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9214,6 +9471,24 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", diff --git a/package.json b/package.json index 539001a4..811b2696 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build:dev": "tsx ./packages/vscode/build.mts", "change": "changeset add", "format": "eslint --fix .; prettier . --write --log-level=warn", + "postinstall": "patch-package", "lint": "eslint . && prettier . --check --log-level=warn && cspell --quiet", "prepare": "husky & npm run --ws --if-present prepare", "test": "npm run build && npm run --ws --if-present test", @@ -38,6 +39,7 @@ "lint-staged": "^17.0.8", "mocha": "^11.7.6", "mocha-snap": "^5.0.1", + "patch-package": "^8.0.1", "prettier": "^3.8.4", "prettier-plugin-packagejson": "^3.0.2", "tsx": "^4.22.4", diff --git a/patches/css-tree+3.2.1.patch b/patches/css-tree+3.2.1.patch new file mode 100644 index 00000000..79a8e5c1 --- /dev/null +++ b/patches/css-tree+3.2.1.patch @@ -0,0 +1,42 @@ +diff --git a/node_modules/css-tree/lib/data-patch.js b/node_modules/css-tree/lib/data-patch.js +index cd49cbe..386e2d6 100644 +--- a/node_modules/css-tree/lib/data-patch.js ++++ b/node_modules/css-tree/lib/data-patch.js +@@ -1,6 +1,3 @@ +-import { createRequire } from 'module'; +- +-const require = createRequire(import.meta.url); +-const patch = require('../data/patch.json'); ++import patch from '../data/patch.json' with { type: 'json' }; + + export default patch; +diff --git a/node_modules/css-tree/lib/data.js b/node_modules/css-tree/lib/data.js +index 162fa20..247ecc5 100755 +--- a/node_modules/css-tree/lib/data.js ++++ b/node_modules/css-tree/lib/data.js +@@ -1,10 +1,7 @@ +-import { createRequire } from 'module'; + import patch from './data-patch.js'; +- +-const require = createRequire(import.meta.url); +-const mdnAtrules = require('mdn-data/css/at-rules.json'); +-const mdnProperties = require('mdn-data/css/properties.json'); +-const mdnSyntaxes = require('mdn-data/css/syntaxes.json'); ++import mdnAtrules from 'mdn-data/css/at-rules.json' with { type: 'json' }; ++import mdnProperties from 'mdn-data/css/properties.json' with { type: 'json' }; ++import mdnSyntaxes from 'mdn-data/css/syntaxes.json' with { type: 'json' }; + + const hasOwn = Object.hasOwn || ((object, property) => Object.prototype.hasOwnProperty.call(object, property)); + const extendSyntax = /^\s*\|\s*/; +diff --git a/node_modules/css-tree/lib/version.js b/node_modules/css-tree/lib/version.js +index dde3a83..6426ea1 100644 +--- a/node_modules/css-tree/lib/version.js ++++ b/node_modules/css-tree/lib/version.js +@@ -1,5 +1,3 @@ +-import { createRequire } from 'module'; ++import pkg from '../package.json' with { type: 'json' }; + +-const require = createRequire(import.meta.url); +- +-export const { version } = require('../package.json'); ++export const { version } = pkg; diff --git a/patches/jsdom+29.1.1.patch b/patches/jsdom+29.1.1.patch new file mode 100644 index 00000000..4adfe045 --- /dev/null +++ b/patches/jsdom+29.1.1.patch @@ -0,0 +1,31 @@ +diff --git a/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js b/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js +index cbf82b1..bda2edb 100644 +--- a/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js ++++ b/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js +@@ -28,8 +28,6 @@ const { parseJSONFromBytes } = require("../helpers/json"); + const { asciiCaseInsensitiveMatch } = require("../helpers/strings"); + const { serializeEntryList } = require("./multipart-form-data"); + +-const syncWorkerFile = require.resolve("./xhr-sync-worker.js"); +- + // TODO: simplify after dropping Node.js v20 support + function trimUint8Array(arr, newSize) { + if (arr.buffer.transfer) { +@@ -41,14 +39,9 @@ function trimUint8Array(arr, newSize) { + let syncWorker = null; + + function getSyncWorker() { +- if (!syncWorker) { +- syncWorker = new Worker(syncWorkerFile); +- syncWorker.unref(); +- syncWorker.on("exit", () => { +- syncWorker = null; +- }); +- } +- return syncWorker; ++ // Synchronous XHR relies on a bundled worker asset and is unused by the Marko ++ // language server; remove it so the module bundles without that asset. ++ throw new Error("jsdom: synchronous XMLHttpRequest is not supported."); + } + + const SYNC_WORKER_TIMEOUT_MS = 2 * 60 * 1000; diff --git a/scripts/marko-esbuild.mts b/scripts/marko-esbuild.mts index c09dc666..f1e0684a 100644 --- a/scripts/marko-esbuild.mts +++ b/scripts/marko-esbuild.mts @@ -71,17 +71,44 @@ export const markoBundlePlugins: Plugin[] = [ }, }, { - name: "jsdom-fix", + name: "jsdom-default-stylesheet-inline", setup(build) { + // jsdom reads its default UA stylesheet from a sibling .css asset via + // `fs.readFileSync(path.resolve(__dirname, ...))` when computed-style.js + // loads. esbuild bundles only JS, so that asset is missing next to the + // output bundle and the read throws, crashing the server on startup. The + // stylesheet is load-bearing (axe relies on computed styles), so inline + // its contents at build time rather than dropping it. + // + // jsdom's other bundling hazards (the sync-XHR worker and css-tree's + // createRequire JSON loads) are removed/rewritten in patches/ instead. build.onLoad( - { filter: /\/jsdom\/.*\/XMLHttpRequest-impl\.js$/ }, - async (args) => ({ - loader: "js", - contents: (await fs.readFile(args.path, "utf8")).replace( - 'require.resolve ? require.resolve("./xhr-sync-worker.js") :', - "", - ), - }), + { filter: /\/jsdom\/.*\/css\/helpers\/computed-style\.js$/ }, + async (args) => { + const source = await fs.readFile(args.path, "utf8"); + const css = await fs.readFile( + path.resolve( + path.dirname(args.path), + "../../../browser/default-stylesheet.css", + ), + "utf8", + ); + const readCall = + /fs\.readFileSync\(\s*path\.resolve\(__dirname,[^)]*\),\s*\{[^}]*\}\s*\)/; + if (!readCall.test(source)) { + // Fail loudly rather than silently shipping a bundle that crashes at + // runtime, e.g. if a jsdom upgrade changes how the stylesheet loads. + throw new Error( + `jsdom-default-stylesheet-inline: stylesheet read not found in ${args.path}; the jsdom internals changed and this workaround is stale.`, + ); + } + return { + loader: "js", + // a function replacement avoids `$`-token interpretation in the + // injected JSON string (e.g. if the stylesheet contains `$&`). + contents: source.replace(readCall, () => JSON.stringify(css)), + }; + }, ); }, },