From a662d97aa0875a8330451cbd1c64afe0bfcaee29 Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Fri, 6 Nov 2026 08:55:26 -0800 Subject: [PATCH 1/2] [uplift] chore: add pack:check against the published 3.2.2 tarball --- .git-blame-ignore-revs | 3 + .github/workflows/ci.yml | 6 + .oxfmtrc.json | 1 + CONTRIBUTING.md | 10 ++ pack-snapshot.json | 102 ++++++++++++ package.json | 9 +- pnpm-lock.yaml | 346 +++++++++++++++++++++++++++++++++++++-- scripts/pack-check.mjs | 279 +++++++++++++++++++++++++++++++ 8 files changed, 740 insertions(+), 16 deletions(-) create mode 100644 pack-snapshot.json create mode 100644 scripts/pack-check.mjs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 83535ae..00bedab 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,3 +5,6 @@ # [uplift] chore: format with oxfmt (#143) 40505673987556571a90f975919ba7e318235660 + +# [uplift] chore: fix oxlint errors (#144) +9b6ffb1638bb1c15c79c3c8e7566b4bb2f81f288 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7490825..1d9d580 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,4 +38,10 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - name: Check + if: matrix.os == 'ubuntu-latest' run: pnpm check + # Format, lint and the packed tarball don't depend on the OS, so Windows + # only runs the tests. + - name: Test + if: matrix.os == 'windows-latest' + run: pnpm test diff --git a/.oxfmtrc.json b/.oxfmtrc.json index b07f626..a3719dd 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -8,6 +8,7 @@ "ignorePatterns": [ ".changeset", "CHANGELOG.md", + "pack-snapshot.json", "pnpm-lock.yaml", "test/fixtures/fast-deep-equal/" ] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63c8a3a..fe55caf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -128,6 +128,16 @@ $ pnpm run lint:fix `index.js` stays ES5 in 3.x, so don't apply ES2015+ fixes (`let`/`const`, arrow functions) to it. +### Published package + +`pnpm pack:check` (part of `pnpm check`) packs the package and checks what it publishes: + +- publint and [attw](https://github.com/arethetypeswrong/arethetypeswrong.github.io) find no problems. +- Installed in a clean directory, `require('react-fast-compare')` and `import isEqual from 'react-fast-compare'` give the same working function. +- The tarball matches `pack-snapshot.json`: manifest fields, file list, type resolution, `index.d.ts`, and `index.js` minified without comments. + +The snapshot was generated from the published 3.2.2 tarball. In 3.x, changes to `index.js` that only touch formatting or comments pass. Anything else fails until you run `pnpm pack:check --update` and commit the new snapshot, so every change to what users get shows up in review. To check another tarball, such as a published version, pass `--tarball ` (from `npm pack react-fast-compare@`). + ### Size You can check how we do with minification + compression with: diff --git a/pack-snapshot.json b/pack-snapshot.json new file mode 100644 index 0000000..fd75ee7 --- /dev/null +++ b/pack-snapshot.json @@ -0,0 +1,102 @@ +{ + "manifest": { + "name": "react-fast-compare", + "main": "index.js", + "types": "index.d.ts", + "typings": "index.d.ts", + "files": [ + "index.js", + "index.d.ts" + ] + }, + "files": [ + "LICENSE", + "README.md", + "index.d.ts", + "index.js", + "package.json" + ], + "resolutions": { + "node10": "types=index.d.ts js=index.js", + "node16-cjs": "types=index.d.ts js=index.js", + "node16-esm": "types=index.d.ts js=index.js", + "bundler": "types=index.d.ts js=index.js" + }, + "types": [ + "declare function isEqual(a: A, b: B): boolean;", + "export = isEqual;", + "" + ], + "code": [ + "var hasElementType = typeof Element !== \"undefined\";", + "", + "var hasMap = typeof Map === \"function\";", + "", + "var hasSet = typeof Set === \"function\";", + "", + "var hasArrayBuffer = typeof ArrayBuffer === \"function\" && !!ArrayBuffer.isView;", + "", + "function equal(a, b) {", + " if (a === b) return true;", + " if (a && b && typeof a == \"object\" && typeof b == \"object\") {", + " if (a.constructor !== b.constructor) return false;", + " var length, i, keys;", + " if (Array.isArray(a)) {", + " length = a.length;", + " if (length != b.length) return false;", + " for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false;", + " return true;", + " }", + " var it;", + " if (hasMap && a instanceof Map && b instanceof Map) {", + " if (a.size !== b.size) return false;", + " it = a.entries();", + " while (!(i = it.next()).done) if (!b.has(i.value[0])) return false;", + " it = a.entries();", + " while (!(i = it.next()).done) if (!equal(i.value[1], b.get(i.value[0]))) return false;", + " return true;", + " }", + " if (hasSet && a instanceof Set && b instanceof Set) {", + " if (a.size !== b.size) return false;", + " it = a.entries();", + " while (!(i = it.next()).done) if (!b.has(i.value[0])) return false;", + " return true;", + " }", + " if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {", + " length = a.length;", + " if (length != b.length) return false;", + " for (i = length; i-- !== 0; ) if (a[i] !== b[i]) return false;", + " return true;", + " }", + " if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;", + " if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === \"function\" && typeof b.valueOf === \"function\") return a.valueOf() === b.valueOf();", + " if (a.toString !== Object.prototype.toString && typeof a.toString === \"function\" && typeof b.toString === \"function\") return a.toString() === b.toString();", + " keys = Object.keys(a);", + " length = keys.length;", + " if (length !== Object.keys(b).length) return false;", + " for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;", + " if (hasElementType && a instanceof Element) return false;", + " for (i = length; i-- !== 0; ) {", + " if ((keys[i] === \"_owner\" || keys[i] === \"__v\" || keys[i] === \"__o\") && a.$$typeof) {", + " continue;", + " }", + " if (!equal(a[keys[i]], b[keys[i]])) return false;", + " }", + " return true;", + " }", + " return a !== a && b !== b;", + "}", + "", + "module.exports = function isEqual(a, b) {", + " try {", + " return equal(a, b);", + " } catch (error) {", + " if ((error.message || \"\").match(/stack|recursion/i)) {", + " console.warn(\"react-fast-compare cannot handle circular refs\");", + " return false;", + " }", + " throw error;", + " }", + "};" + ] +} diff --git a/package.json b/package.json index d8bfdd4..e5d9fcc 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "typings": "index.d.ts", "scripts": { "preversion": "pnpm check", - "check": "pnpm format && pnpm lint && pnpm test", + "check": "pnpm format && pnpm lint && pnpm test && pnpm pack:check", "benchmark": "node benchmark", "format": "oxfmt --check", "format:fix": "oxfmt", @@ -20,7 +20,8 @@ "test": "builder concurrent --buffer test-ts-usage test-ts-defs test-node-cov test-browser", "compress": "terser --compress --mangle=\"toplevel:true\" -- index.js", "size-min-gz": "pnpm -s compress | gzip -9 | wc -c", - "changeset": "changeset" + "changeset": "changeset", + "pack:check": "node scripts/pack-check.mjs" }, "repository": { "type": "git", @@ -42,6 +43,7 @@ "homepage": "https://github.com/FormidableLabs/react-fast-compare", "packageManager": "pnpm@12.16.0", "devDependencies": { + "@arethetypeswrong/cli": "0.18.5", "@babel/core": "^7.21.0", "@babel/preset-env": "^7.20.2", "@changesets/changelog-github": "^1.0.1", @@ -75,6 +77,7 @@ "oxlint": "1.90.0", "preact": "^10.13.1", "process": "^0.11.10", + "publint": "0.3.25", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.0.5", @@ -82,7 +85,7 @@ "redux": "^4.2.1", "shallow-equal-fuzzy": "0.0.2", "sinon": "^15.0.1", - "terser": "^5.16.6", + "terser": "5.51.2", "typescript": "^4.9.5", "webpack": "^5.76.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 104b71b..a667dca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,6 +166,9 @@ importers: .: devDependencies: + '@arethetypeswrong/cli': + specifier: 0.18.5 + version: 0.18.5 '@babel/core': specifier: ^7.21.0 version: 7.21.0(supports-color@8.1.1) @@ -265,6 +268,9 @@ importers: process: specifier: ^0.11.10 version: 0.11.10 + publint: + specifier: 0.3.25 + version: 0.3.25 react: specifier: ^18.2.0 version: 18.2.0 @@ -287,8 +293,8 @@ importers: specifier: ^15.0.1 version: 15.0.1 terser: - specifier: ^5.16.6 - version: 5.16.6 + specifier: 5.51.2 + version: 5.51.2 typescript: specifier: ^4.9.5 version: 4.9.5 @@ -302,6 +308,18 @@ packages: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} + '@andrewbranch/untar.js@1.0.4': + resolution: {integrity: sha512-pVXSwPsLuw8IGLo2Di0EaOfsk+ntVvpkk942J/sHYIkwvtKUakEcPh7HBgZ6tuimgzKSEHgCvO4XgQ05DEbwDw==} + + '@arethetypeswrong/cli@0.18.5': + resolution: {integrity: sha512-gM+8vRsQOD/Uc7EnBedUhkG5OCsDWE4uoak5QvomGpMpaky0Eh41p04nIMgrWb8EOmqZUJGc6zz9hsP6E56R7g==} + engines: {node: '>=20'} + hasBin: true + + '@arethetypeswrong/core@0.18.5': + resolution: {integrity: sha512-9ytjzGwxjm9Uz7I9avfbt5vlQt6uk9uRRESzJjqrznl6WKvI6dwYTo+vJ3U02Wrq/mR3iql/PzhvHhKdJIAjDQ==} + engines: {node: '>=20'} + '@babel/code-frame@7.21.4': resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} engines: {node: '>=6.9.0'} @@ -854,6 +872,9 @@ packages: resolution: {integrity: sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==} engines: {node: '>=6.9.0'} + '@braidai/lang@1.1.2': + resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} + '@changesets/apply-release-plan@8.1.1': resolution: {integrity: sha512-nk2Hbq3M9NeHMdaIRBDvawKrQJzXB9sGyBUE5yWnIKtvdcNCPj75zBekJYr0gTT2ecJH3eFeTrc8eisPImcv0Q==} engines: {node: ^22.11 || ^24 || >=26} @@ -951,6 +972,9 @@ packages: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.2': resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} @@ -963,15 +987,24 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.2': - resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} '@jridgewell/sourcemap-codec@1.4.14': resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + '@jridgewell/trace-mapping@0.3.17': resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@loaderkit/resolve@1.0.6': + resolution: {integrity: sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==} + '@manypkg/find-root@3.1.0': resolution: {integrity: sha512-BcSqCyKhBVZ5YkSzOiheMCV41kqAFptW6xGqYSTjkVTl9XQpr+pqHhwgGCOHQtjDCv7Is6EFyA14Sm5GVbVABA==} engines: {node: '>=20.0.0'} @@ -1236,6 +1269,14 @@ packages: resolution: {integrity: sha512-pOr5+q1fLYKwFN3LAJuGZEnfXDcQ73zqgDHMtGy+K+uIoUqyY+6MeDCWFwfu+4EFuq76I5EPFofoNAI+Bmmq4A==} engines: {node: '>=22.13'} + '@publint/pack@0.1.7': + resolution: {integrity: sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g==} + engines: {node: '>=18'} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + '@sinonjs/commons@2.0.0': resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} @@ -1392,6 +1433,11 @@ packages: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -1429,6 +1475,10 @@ packages: ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@3.0.0: resolution: {integrity: sha512-wFUFA5bg5dviipbQQ32yOQhl6gcJaJXiHE7dvR8VYPG97+J/GNC5FKGepKdEDUFeXRzDxPF1X/Btc8L+v7oqIQ==} engines: {node: '>=4'} @@ -1457,6 +1507,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} @@ -1590,6 +1643,14 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1602,10 +1663,22 @@ packages: resolution: {integrity: sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==} engines: {node: '>=6.0'} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -1633,6 +1706,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -1798,6 +1875,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -1821,6 +1901,10 @@ packages: resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} engines: {node: '>=0.12'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} @@ -1915,6 +1999,9 @@ packages: picomatch: optional: true + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -2062,6 +2149,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -2433,6 +2523,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -2444,6 +2538,17 @@ packages: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} + marked-terminal@7.3.1: + resolution: {integrity: sha512-B1eKs5mRiacjHHMlex1zn0zkVomz2/KWjD/dyA8WRQTXk2d15OzVjiK/iuPfvDFB27Gvr8p/u6MYgU0NY/O45w==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <19' + + marked@9.1.6: + resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} + engines: {node: '>= 16'} + hasBin: true + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -2487,6 +2592,10 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -2496,6 +2605,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nano-equal@2.0.2: resolution: {integrity: sha512-RtAioZtSSppEWRruYU8oz2AKPJWTW74TpzcqP79n7Kh4nHW+gmrJGcTuELmid9tvGR4Xp2cCoTtYIIDy9iWO4g==} @@ -2509,6 +2621,10 @@ packages: nise@5.1.4: resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==} + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + node-preload@0.2.1: resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} engines: {node: '>=8'} @@ -2637,6 +2753,15 @@ packages: package-manager-detector@1.9.0: resolution: {integrity: sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} @@ -2709,6 +2834,11 @@ packages: psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + publint@0.3.25: + resolution: {integrity: sha512-WMMbn/d7JqRlfXQL/JUI4n5skC8cJ5WVr8/wT5mmiYWkUdENkZr1I5rgs2+dQPVRgoJd+JRYtB46MTsuDylw9g==} + engines: {node: '>=18'} + hasBin: true + punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -2854,6 +2984,10 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -2932,6 +3066,10 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + socket.io-adapter@2.5.2: resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} @@ -3009,6 +3147,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -3036,8 +3178,8 @@ packages: uglify-js: optional: true - terser@5.16.6: - resolution: {integrity: sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==} + terser@5.51.2: + resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==} engines: {node: '>=10'} hasBin: true @@ -3045,6 +3187,13 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinyexec@1.3.1: resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} @@ -3112,6 +3261,11 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + typescript@5.6.1-rc: + resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + engines: {node: '>=14.17'} + hasBin: true + ua-parser-js@0.7.31: resolution: {integrity: sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==} deprecated: You are using an outdated version of ua-parser-js. Please update to ua-parser-js v0.7.33 / v1.0.33 / v2.0.0 (or later) to avoid ReDoS vulnerability [CVE-2022-25927](https://github.com/advisories/GHSA-fhg7-m89q-25r3) @@ -3120,6 +3274,10 @@ packages: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} @@ -3173,6 +3331,10 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3355,6 +3517,29 @@ snapshots: '@jridgewell/gen-mapping': 0.1.1 '@jridgewell/trace-mapping': 0.3.17 + '@andrewbranch/untar.js@1.0.4': {} + + '@arethetypeswrong/cli@0.18.5': + dependencies: + '@arethetypeswrong/core': 0.18.5 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.3.1(marked@9.1.6) + semver: 7.8.5 + + '@arethetypeswrong/core@0.18.5': + dependencies: + '@andrewbranch/untar.js': 1.0.4 + '@loaderkit/resolve': 1.0.6 + cjs-module-lexer: 1.4.3 + fflate: 0.8.3 + lru-cache: 11.5.3 + semver: 7.8.5 + typescript: 5.6.1-rc + validate-npm-package-name: 5.0.1 + '@babel/code-frame@7.21.4': dependencies: '@babel/highlight': 7.18.6 @@ -4066,6 +4251,8 @@ snapshots: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + '@braidai/lang@1.1.2': {} + '@changesets/apply-release-plan@8.1.1': dependencies: '@changesets/config': 4.0.1 @@ -4217,6 +4404,11 @@ snapshots: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping@0.3.2': dependencies: '@jridgewell/set-array': 1.1.2 @@ -4227,18 +4419,29 @@ snapshots: '@jridgewell/set-array@1.1.2': {} - '@jridgewell/source-map@0.3.2': + '@jridgewell/source-map@0.3.11': dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/sourcemap-codec@1.4.14': {} + '@jridgewell/sourcemap-codec@1.6.0': {} + '@jridgewell/trace-mapping@0.3.17': dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + + '@loaderkit/resolve@1.0.6': + dependencies: + '@braidai/lang': 1.1.2 + '@manypkg/find-root@3.1.0': dependencies: '@manypkg/tools': 2.1.2 @@ -4373,6 +4576,12 @@ snapshots: '@pnpm/deps.graph-sequencer@1100.0.1': {} + '@publint/pack@0.1.7': + dependencies: + tinyexec: 1.3.1 + + '@sindresorhus/is@4.6.0': {} + '@sinonjs/commons@2.0.0': dependencies: type-detect: 4.0.8 @@ -4569,6 +4778,8 @@ snapshots: acorn-walk@8.2.0: {} + acorn@8.19.0: {} + acorn@8.8.2: {} agent-base@6.0.0(supports-color@8.1.1): @@ -4609,6 +4820,10 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@3.0.0: {} ansi-regex@5.0.1: {} @@ -4628,6 +4843,8 @@ snapshots: ansi-styles@6.2.3: {} + any-promise@1.3.0: {} + anymatch@3.1.2: dependencies: normalize-path: 3.0.0 @@ -4785,6 +5002,10 @@ snapshots: ansi-styles: 4.2.1 supports-color: 7.2.0 + chalk@5.6.2: {} + + char-regex@1.0.2: {} + chokidar@3.5.3: dependencies: anymatch: 3.1.2 @@ -4805,8 +5026,25 @@ snapshots: dependencies: tslib: 1.13.0 + cjs-module-lexer@1.4.3: {} + clean-stack@2.2.0: {} + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -4841,6 +5079,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@10.0.1: {} + commander@2.20.3: {} commondir@1.0.1: {} @@ -4997,6 +5237,8 @@ snapshots: emoji-regex@9.2.2: {} + emojilib@2.4.0: {} + encodeurl@1.0.2: {} engine.io-parser@5.0.6: {} @@ -5027,6 +5269,8 @@ snapshots: entities@4.4.0: {} + environment@1.1.0: {} + es-get-iterator@1.1.3: dependencies: call-bind: 1.0.2 @@ -5105,6 +5349,8 @@ snapshots: optionalDependencies: picomatch: 4.0.7 + fflate@0.8.3: {} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 @@ -5253,6 +5499,8 @@ snapshots: he@1.2.0: {} + highlight.js@10.7.3: {} + hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -5687,6 +5935,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -5697,6 +5947,19 @@ snapshots: dependencies: semver: 6.3.0 + marked-terminal@7.3.1(marked@9.1.6): + dependencies: + ansi-escapes: 7.3.0 + ansi-regex: 6.5.0 + chalk: 5.6.2 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + + marked@9.1.6: {} + media-typer@0.3.0: {} merge-stream@2.0.0: {} @@ -5749,12 +6012,20 @@ snapshots: yargs-parser: 21.1.1 yargs-unparser: 2.0.0 + mri@1.2.0: {} + ms@2.0.0: {} ms@2.1.2: {} ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nano-equal@2.0.2: {} negotiator@0.6.2: {} @@ -5769,6 +6040,13 @@ snapshots: just-extend: 4.1.0 path-to-regexp: 1.8.0 + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + node-preload@0.2.1: dependencies: process-on-spawn: 1.0.0 @@ -5939,6 +6217,14 @@ snapshots: package-manager-detector@1.9.0: {} + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parse5@7.1.2: dependencies: entities: 4.4.0 @@ -5994,6 +6280,13 @@ snapshots: psl@1.9.0: {} + publint@0.3.25: + dependencies: + '@publint/pack': 0.1.7 + package-manager-detector: 1.9.0 + picocolors: 1.1.1 + sade: 1.8.1 + punycode@2.3.0: {} qjobs@1.2.0: {} @@ -6126,6 +6419,10 @@ snapshots: dependencies: glob: 7.2.3 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -6200,6 +6497,10 @@ snapshots: sisteransi@1.0.5: {} + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + socket.io-adapter@2.5.2: dependencies: ws: 8.11.0 @@ -6299,6 +6600,11 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} symbol-tree@3.2.4: {} @@ -6311,13 +6617,13 @@ snapshots: schema-utils: 3.1.1 serialize-javascript: 6.0.0 source-map: 0.6.1 - terser: 5.16.6 + terser: 5.51.2 webpack: 5.76.0 - terser@5.16.6: + terser@5.51.2: dependencies: - '@jridgewell/source-map': 0.3.2 - acorn: 8.8.2 + '@jridgewell/source-map': 0.3.11 + acorn: 8.19.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -6327,6 +6633,14 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tinyexec@1.3.1: {} tinyglobby@0.2.17: @@ -6382,10 +6696,14 @@ snapshots: typescript@4.9.5: {} + typescript@5.6.1-rc: {} + ua-parser-js@0.7.31: {} unicode-canonical-property-names-ecmascript@2.0.0: {} + unicode-emoji-modifier-base@1.0.0: {} + unicode-match-property-ecmascript@2.0.0: dependencies: unicode-canonical-property-names-ecmascript: 2.0.0 @@ -6433,6 +6751,8 @@ snapshots: uuid@8.3.2: {} + validate-npm-package-name@5.0.1: {} + vary@1.1.2: {} void-elements@2.0.1: {} diff --git a/scripts/pack-check.mjs b/scripts/pack-check.mjs new file mode 100644 index 0000000..cb69433 --- /dev/null +++ b/scripts/pack-check.mjs @@ -0,0 +1,279 @@ +// Checks what the package publishes (`pnpm pack:check`): +// +// 1. Packs the package with `pnpm pack`, or takes a tarball given with +// `--tarball ` (e.g. a published version from +// `npm pack react-fast-compare@3.2.2`). +// 2. Runs publint and attw (`@arethetypeswrong/cli`) on it. +// 3. Installs it outside the repo and loads it with `require()` and +// `import()`: both must give the same working `isEqual` function. +// 4. Compares it against `pack-snapshot.json`: manifest fields, file list, +// how attw resolves the types, `index.d.ts`, and `index.js` minified +// without comments. In 3.x only formatting and comments may change in +// `index.js` (see CONTRIBUTING). Pass `--update` to rewrite the snapshot +// after an intended change. +import { execFileSync } from 'node:child_process'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { publint } from 'publint'; +import { formatMessage } from 'publint/utils'; +import { minify } from 'terser'; + +const { log, error } = console; + +// Manifest fields that change how consumers resolve or install the package. +const SNAPSHOT_FIELDS = [ + 'name', + 'type', + 'main', + 'module', + 'types', + 'typings', + 'exports', + 'browser', + 'sideEffects', + 'files', + 'dependencies', + 'peerDependencies', +]; + +const args = process.argv.slice(2); +const update = args.includes('--update'); +const tarballArg = args.includes('--tarball') + ? args[args.indexOf('--tarball') + 1] + : null; +const rootDir = path.resolve(import.meta.dirname, '..'); +const workDir = path.join(rootDir, 'node_modules/.cache/pack-check'); +const snapshotPath = path.join(rootDir, 'pack-snapshot.json'); +const failures = []; + +const run = (cmd, cmdArgs, opts = {}) => + execFileSync(cmd, cmdArgs, { encoding: 'utf8', ...opts }); + +// Pack +fs.rmSync(workDir, { recursive: true, force: true }); +fs.mkdirSync(workDir, { recursive: true }); +let tarball; +if (tarballArg) { + tarball = path.resolve(tarballArg); +} else { + const { filename } = JSON.parse( + run('pnpm', ['pack', '--json', '--pack-destination', workDir], { + cwd: rootDir, + stdio: ['ignore', 'pipe', 'inherit'], + }) + ); + tarball = path.resolve(workDir, filename); +} +const files = run('tar', ['tzf', tarball]) + .split('\n') + .filter((f) => f && !f.endsWith('/')) + .map((f) => f.replace(/^package\//, '')) + .sort(); + +// Install outside the repo, so nothing resolves through the repo's +// `node_modules`. The package has no dependencies to link in. +const installRoot = fs.realpathSync( + fs.mkdtempSync(path.join(os.tmpdir(), 'pack-check-')) +); +for (let dir = path.dirname(installRoot); ; dir = path.dirname(dir)) { + if (fs.existsSync(path.join(dir, 'node_modules'))) + throw new Error(`${installRoot} isn't isolated: found ${dir}/node_modules`); + + if (dir === path.dirname(dir)) break; +} +const modulesDir = path.join(installRoot, 'node_modules'); +fs.mkdirSync(modulesDir); +run('tar', ['xzf', tarball, '-C', installRoot]); +const manifest = JSON.parse( + fs.readFileSync(path.join(installRoot, 'package/package.json'), 'utf8') +); +const installed = path.join(modulesDir, manifest.name); +fs.renameSync(path.join(installRoot, 'package'), installed); +const deps = Object.keys({ + ...manifest.dependencies, + ...manifest.peerDependencies, +}); +if (deps.length) failures.push(`Unexpected dependencies: ${deps.join(', ')}`); +const readPublished = (file) => + fs.readFileSync(path.join(installed, file), 'utf8'); + +try { + // publint + const { messages, pkg } = await publint({ + pkgDir: installed, + pack: false, + level: 'warning', + }); + for (const message of messages) { + failures.push( + `publint ${message.type} (${message.code}): ${formatMessage(message, pkg)}` + ); + } + + // attw. It exits before a piped stdout is flushed, so write to a file. + const attwJson = path.join(workDir, 'attw.json'); + const attwFd = fs.openSync(attwJson, 'w'); + try { + run('attw', [tarball, '--format', 'json'], { + stdio: ['ignore', attwFd, 'inherit'], + }); + } catch { + // Exits non-zero when it finds problems; they're read from the JSON. + } finally { + fs.closeSync(attwFd); + } + const { analysis } = JSON.parse(fs.readFileSync(attwJson, 'utf8')); + const stripPkg = (fileName) => + fileName?.replace(`/node_modules/${manifest.name}/`, ''); + for (const p of analysis.problems) { + failures.push( + `attw: ${[p.kind, p.entrypoint, p.resolutionKind, stripPkg(p.fileName)] + .filter(Boolean) + .join(' ')}` + ); + } + // Which types and JS file the package resolves to, per resolution mode. + const resolutions = Object.fromEntries( + Object.entries(analysis.entrypoints['.'].resolutions).map(([kind, r]) => [ + kind, + `types=${stripPkg(r.resolution?.fileName) ?? 'none'} js=${stripPkg(r.implementationResolution?.fileName) ?? 'none'}`, + ]) + ); + + // Load with `require()` and `import()`. + const loader = path.join(installRoot, 'load.mjs'); + fs.writeFileSync( + loader, + `import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); +const errors = []; +const spec = ${JSON.stringify(manifest.name)}; +const cjs = require(spec); +const esm = (await import(spec)).default; +if (typeof cjs !== 'function') errors.push('require(): not a function'); +if (esm !== cjs) errors.push('import(): default export is not module.exports'); +if (typeof cjs === 'function') { + if (cjs({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] }) !== true) { + errors.push('isEqual: equal objects compare false'); + } + if (cjs({ a: 1 }, { a: 2 }) !== false) { + errors.push('isEqual: different objects compare true'); + } +} +console.log(JSON.stringify(errors)); +` + ); + try { + const errors = JSON.parse( + run(process.execPath, [loader], { + cwd: installRoot, + stdio: ['ignore', 'pipe', 'pipe'], + }) + ); + failures.push(...errors.map((e) => `Loading ${manifest.name}: ${e}`)); + } catch (err) { + failures.push( + `Loading ${manifest.name} failed: ${(err.stderr || err.message).trim()}` + ); + } + + // Published code. Minified without comments, so formatting and comments + // don't count, and pretty-printed one statement per line, so a change shows + // up as a readable diff. Without `compress`, the output depends only on the + // code, not on the minifier's optimizations. + const { code } = await minify(readPublished(manifest.main), { + compress: false, + mangle: false, + format: { comments: false, beautify: true }, + }); + + // Snapshot + const snapshot = { + manifest: Object.fromEntries( + SNAPSHOT_FIELDS.filter((f) => f in manifest).map((f) => [f, manifest[f]]) + ), + files, + resolutions, + types: readPublished(manifest.types ?? manifest.typings).split('\n'), + code: code.split('\n'), + }; + if (update) { + fs.writeFileSync(snapshotPath, `${JSON.stringify(snapshot, null, 2)}\n`); + log(`Wrote ${path.relative(rootDir, snapshotPath)}`); + } else { + const expected = JSON.parse(fs.readFileSync(snapshotPath, 'utf8')); + const diffs = []; + for (const field of new Set([ + ...Object.keys(expected.manifest), + ...Object.keys(snapshot.manifest), + ])) { + const [a, b] = [expected.manifest[field], snapshot.manifest[field]].map( + (v) => JSON.stringify(v) + ); + if (a !== b) diffs.push(` manifest ${field}: ${a} -> ${b}`); + } + for (const kind of new Set([ + ...Object.keys(expected.resolutions), + ...Object.keys(resolutions), + ])) { + const a = expected.resolutions[kind] ?? 'missing'; + const b = resolutions[kind] ?? 'missing'; + if (a !== b) diffs.push(` resolution ${kind}: ${a} -> ${b}`); + } + diffs.push(...listDiff(expected.files, files, 'file ')); + diffs.push(...hunkDiff(expected.types, snapshot.types, 'types')); + diffs.push(...hunkDiff(expected.code, snapshot.code, 'code')); + if (diffs.length) { + failures.push( + `Published output differs from pack-snapshot.json (if intended, run \`pnpm pack:check --update\` and commit it):\n${diffs.join('\n')}` + ); + } + } +} finally { + fs.rmSync(installRoot, { recursive: true, force: true }); +} + +log(`${manifest.name}@${manifest.version}: ${files.length} files`); +if (failures.length) { + error(failures.join('\n\n')); + process.exit(1); +} + +// Entries removed and added (for unordered lists like the file list). +function listDiff(before, after, label) { + const [a, b] = [new Set(before), new Set(after)]; + return [ + ...before.filter((x) => !b.has(x)).map((x) => ` - ${label}${x}`), + ...after.filter((x) => !a.has(x)).map((x) => ` + ${label}${x}`), + ]; +} + +// The one hunk spanning every changed line, for ordered text (`index.d.ts`, +// `index.js`). Run `--update` and `git diff` for a finer diff. +function hunkDiff(before, after, label) { + let start = 0; + while ( + start < before.length && + start < after.length && + before[start] === after[start] + ) + start++; + + if (start === before.length && start === after.length) return []; + let endBefore = before.length; + let endAfter = after.length; + while ( + endBefore > start && + endAfter > start && + before[endBefore - 1] === after[endAfter - 1] + ) { + endBefore--; + endAfter--; + } + return [ + ` ${label}, line ${start + 1}:`, + ...before.slice(start, endBefore).map((x) => ` - ${x}`), + ...after.slice(start, endAfter).map((x) => ` + ${x}`), + ]; +} From 720f54a4099f1782d723dee76b0132cd0e2ae6cb Mon Sep 17 00:00:00 2001 From: Ryan Roemer Date: Fri, 6 Nov 2026 09:50:39 -0800 Subject: [PATCH 2/2] [uplift] chore: pack:check covers every dependency and install field --- scripts/pack-check.mjs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/scripts/pack-check.mjs b/scripts/pack-check.mjs index cb69433..91a0b3c 100644 --- a/scripts/pack-check.mjs +++ b/scripts/pack-check.mjs @@ -21,6 +21,16 @@ import { minify } from 'terser'; const { log, error } = console; +// Every field that makes consumers install another package. The package has +// none, and this check doesn't install any. +const DEPENDENCY_FIELDS = [ + 'dependencies', + 'peerDependencies', + 'optionalDependencies', + 'bundleDependencies', + 'bundledDependencies', +]; + // Manifest fields that change how consumers resolve or install the package. const SNAPSHOT_FIELDS = [ 'name', @@ -30,11 +40,16 @@ const SNAPSHOT_FIELDS = [ 'types', 'typings', 'exports', + 'imports', 'browser', 'sideEffects', 'files', - 'dependencies', - 'peerDependencies', + 'bin', + 'engines', + 'os', + 'cpu', + ...DEPENDENCY_FIELDS, + 'peerDependenciesMeta', ]; const args = process.argv.slice(2); @@ -90,11 +105,13 @@ const manifest = JSON.parse( ); const installed = path.join(modulesDir, manifest.name); fs.renameSync(path.join(installRoot, 'package'), installed); -const deps = Object.keys({ - ...manifest.dependencies, - ...manifest.peerDependencies, -}); -if (deps.length) failures.push(`Unexpected dependencies: ${deps.join(', ')}`); +for (const field of DEPENDENCY_FIELDS) { + const value = manifest[field]; + // `bundleDependencies` is a list of names, or `true` for all of them. + const names = Array.isArray(value) ? value : Object.keys(value ?? {}); + if (value === true || names.length) + failures.push(`Unexpected ${field}: ${JSON.stringify(value)}`); +} const readPublished = (file) => fs.readFileSync(path.join(installed, file), 'utf8'); @@ -123,7 +140,10 @@ try { } finally { fs.closeSync(attwFd); } - const { analysis } = JSON.parse(fs.readFileSync(attwJson, 'utf8')); + // No JSON means attw itself failed (its error is printed above). + const attwOutput = fs.readFileSync(attwJson, 'utf8'); + if (!attwOutput.trim()) throw new Error('attw failed; see its output above'); + const { analysis } = JSON.parse(attwOutput); const stripPkg = (fileName) => fileName?.replace(`/node_modules/${manifest.name}/`, ''); for (const p of analysis.problems) {