diff --git a/CHANGELOG.md b/CHANGELOG.md index f8baa1ddf..d160c3cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Changed + +- Upgraded to chokidar 4. This required a re-implementation of support for + watching globs, because chokidar 4 removed that feature. + ## [0.14.13] - 2026-06-23 ### Added diff --git a/package-lock.json b/package-lock.json index ef2511acb..ad1a6a559 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,11 @@ ], "dependencies": { "brace-expansion": "^5.0.6", - "chokidar": "^3.5.3", + "chokidar": "^4.0.3", "fast-glob": "^3.2.11", + "glob-parent": "^5.1.2", "jsonc-parser": "^3.0.0", + "picomatch": "^2.3.2", "proper-lockfile": "^4.1.2" }, "bin": { @@ -23,8 +25,10 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@types/glob-parent": "^5.1.3", "@types/node": "^18.19.130", "@types/node-forge": "^1.3.0", + "@types/picomatch": "^2.3.4", "@types/proper-lockfile": "^4.1.2", "@types/selfsigned": "^2.0.1", "@types/vscode": "^1.66.0", @@ -44,7 +48,7 @@ "vscode-languageclient": "^10.0.1", "vscode-languageserver": "^10.0.1", "vscode-languageserver-textdocument": "^1.0.4", - "wireit": "^0.14.12", + "wireit": "^0.14.13", "yarn": "^1.22.18" }, "engines": { @@ -82,90 +86,90 @@ } }, "node_modules/@azure/core-auth": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", - "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", + "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", "dev": true, "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-util": "^1.13.0", + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-client": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.2.tgz", - "integrity": "sha512-1D2LpsU7y9xrqKjdIbsB7PlrRePw0xsVV8p+AKTlzITrWmscajryfJCdDJB/oGwvDI5HmRo04eMMADB67uwAwQ==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.4.tgz", + "integrity": "sha512-f7IxTD15Qdux30s2qFARH+JxgwxWLG2Rlr4oSkPGuLWm+1p5y1+C04XGLA0vmX6EtqfutmjvpNmAfgwVIS5hpw==", "dev": true, "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.10.0", - "@azure/core-rest-pipeline": "^1.22.0", - "@azure/core-tracing": "^1.3.0", - "@azure/core-util": "^1.13.0", - "@azure/logger": "^1.3.0", + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.20.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.24.0.tgz", - "integrity": "sha512-PpLsoDQ3AMmKZ0VU+0GrmqMxgp/sExjlVm4R+nLWngeoEGAzOIPVifaxKGU5gMv+nWELUoHfvrolWD+ZS/nFJg==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.21.0.tgz", + "integrity": "sha512-a4MBwe/5WKbq9MIxikzgxLBbruC5qlkFYlBdI7Ev50Y7ib5Vo/Jvt5jnJo7NaWeJ908LCHL0S1Us4UMf1VoTfg==", "dev": true, "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-auth": "^1.10.0", - "@azure/core-tracing": "^1.3.0", - "@azure/core-util": "^1.13.0", - "@azure/logger": "^1.3.0", - "@typespec/ts-http-runtime": "^0.3.4", + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@typespec/ts-http-runtime": "^0.2.3", "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-tracing": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", - "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", + "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-util": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", - "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.12.0.tgz", + "integrity": "sha512-13IyjTQgABPARvG90+N2dXpC+hwp466XCdQXPCRlbWHgd3SJd5Q1VvaBGv6k1BIa4MQm6hAF1UBU1m8QUxV8sQ==", "dev": true, "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@typespec/ts-http-runtime": "^0.3.0", + "@azure/abort-controller": "^2.0.0", + "@typespec/ts-http-runtime": "^0.2.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/identity": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", - "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.10.1.tgz", + "integrity": "sha512-YM/z6RxRtFlXUH2egAYF/FDPes+MUE6ZoknjEdaq7ebJMMNUzn9zCJ3bd2ZZZlkP0r1xKa88kolhFH/FGV7JnA==", "dev": true, "license": "MIT", "dependencies": { @@ -176,46 +180,46 @@ "@azure/core-tracing": "^1.0.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^5.5.0", - "@azure/msal-node": "^5.1.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", "open": "^10.1.0", "tslib": "^2.2.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/logger": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", - "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.2.0.tgz", + "integrity": "sha512-0hKEzLhpw+ZTAfNJyRrn6s+V0nDWzXk9OjBr2TiGIu0OfMr5s2V4FpKLTAK3Ca5r5OKLbf4hkOGDPyiRjie/jA==", "dev": true, "license": "MIT", "dependencies": { - "@typespec/ts-http-runtime": "^0.3.0", + "@typespec/ts-http-runtime": "^0.2.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/msal-browser": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.14.0.tgz", - "integrity": "sha512-Dfl7hPZe9/JJwRhFFXHq2z1oHYBuGubmff3kWXOsd1AGgyXlqjNYAWuN/1JL/ZrcZBs8TKMjGSil6Rcc7E8VPQ==", + "version": "4.30.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.30.0.tgz", + "integrity": "sha512-HBBKfbZkMVzzF5bofvS1cXuNHFVc+gt4/HOnCmG/0hsHuZRJvJvDg/+7nTwIpoqvJc8BQp5o23rBUfisOLxR+w==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "16.9.0" + "@azure/msal-common": "15.17.0" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.9.0.tgz", - "integrity": "sha512-1MWGjqgUCRAYgLmVFZKp7fs3Rg1TFvIMgywY8ze2olNVvLlJoRThuoziWSDJuwwyJI5L4rnLb9Tyt5D9GvSLPw==", + "version": "15.17.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.17.0.tgz", + "integrity": "sha512-VQ5/gTLFADkwue+FohVuCqlzFPUq4xSrX8jeZe+iwZuY6moliNC8xt86qPVNYdtbQfELDf2Nu6LI+demFPHGgw==", "dev": true, "license": "MIT", "engines": { @@ -223,17 +227,18 @@ } }, "node_modules/@azure/msal-node": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.2.5.tgz", - "integrity": "sha512-RUuewWk9JvWJS5Yiy8/74Lm1rQAWlrU/qg/Bgtk1jIauVRtnb9XKwS5Xg0J+Whwjesq9EVrBIFgQEP8vHxgezA==", + "version": "3.8.10", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.10.tgz", + "integrity": "sha512-0Hz7Kx4hs70KZWep/Rd7aw/qOLUF92wUOhn7ZsOuB5xNR/06NL1E2RAI9+UKH1FtvN8nD6mFjH7UKSjv6vOWvQ==", "dev": true, "license": "MIT", "dependencies": { - "@azure/msal-common": "16.9.0", - "jsonwebtoken": "^9.0.0" + "@azure/msal-common": "15.17.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" }, "engines": { - "node": ">=20" + "node": ">=16" } }, "node_modules/@babel/code-frame": { @@ -1399,6 +1404,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/glob-parent": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@types/glob-parent/-/glob-parent-5.1.3.tgz", + "integrity": "sha512-p+NciRH8TRvrgISOCQ55CP+lktMmDpOXsp4spULIIz0L4aJ6G9zFX+N0UZ2xulmJRgaQLRxXIp4xHdL6YOQjDg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1433,6 +1445,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/picomatch": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.4.tgz", + "integrity": "sha512-0so8lU8O5zatZS/2Fi4zrwks+vZv7e0dygrgEZXljODXBig97l4cPQD+9LabXfGJOWwoRkTVz6Q4edZvD12UOA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/proper-lockfile": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/proper-lockfile/-/proper-lockfile-4.1.4.tgz", @@ -1458,15 +1477,11 @@ "license": "MIT" }, "node_modules/@types/selfsigned": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/selfsigned/-/selfsigned-2.1.0.tgz", - "integrity": "sha512-9IpB+OBu3QaMojPbLMg0PxMA85lOt7o53ycx2ds82CSFMyxlj0iZtAPVJ1m1qnzKTlznYqa6zNVaEWC7hk/E/w==", - "deprecated": "This is a stub types definition. selfsigned provides its own type definitions, so you do not need this installed.", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/selfsigned/-/selfsigned-2.0.4.tgz", + "integrity": "sha512-vNmPhMatNNp9iZ/Ri2w1fciqNcPA2edA58qhzi5F/qDO49Ap4GtEGytuiTX1pSO1HJr81VopC8/INylO9s0keQ==", "dev": true, - "license": "MIT", - "dependencies": { - "selfsigned": "*" - } + "license": "MIT" }, "node_modules/@types/vscode": { "version": "1.125.0", @@ -1706,9 +1721,9 @@ } }, "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.6.tgz", - "integrity": "sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.2.3.tgz", + "integrity": "sha512-oRhjSzcVjX8ExyaF8hC0zzTqxlVuRlgMHL/Bh4w3xB9+wjbm0FpXylVU/lBrn+kgphwYTrOk3tp+AVShGmlYCg==", "dev": true, "license": "MIT", "dependencies": { @@ -1717,7 +1732,7 @@ "tslib": "^2.6.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/@vscode/test-electron": { @@ -2032,6 +2047,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -2126,6 +2142,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2335,9 +2352,9 @@ } }, "node_modules/cheerio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", - "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.0.tgz", + "integrity": "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2345,16 +2362,16 @@ "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.1", - "htmlparser2": "^10.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", - "undici": "^7.19.0", + "undici": "^7.10.0", "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">=20.18.1" + "node": ">=18.17" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -2379,27 +2396,18 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, "node_modules/chownr": { @@ -3317,6 +3325,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3697,6 +3706,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -4446,9 +4456,9 @@ "optional": true }, "node_modules/node-sarif-builder": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", - "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.2.0.tgz", + "integrity": "sha512-kVIOdynrF2CRodHZeP/97Rh1syTUHBNiw17hUCIVhlhEsWlfJm19MuO56s4MdKbr22xWx6mzMnNAgXzVlIYM9Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4456,7 +4466,7 @@ "fs-extra": "^11.1.1" }, "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/normalize-package-data": { @@ -4498,6 +4508,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5057,13 +5068,14 @@ } }, "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -5122,17 +5134,6 @@ "require-from-string": "^2.0.2" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -5203,15 +5204,16 @@ "license": "MIT" }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/reflect-metadata": { @@ -5715,6 +5717,17 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/structured-source": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", @@ -6171,6 +6184,17 @@ "dev": true, "license": "MIT" }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "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).", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -6300,17 +6324,16 @@ } }, "node_modules/wireit": { - "version": "0.14.12", - "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.14.12.tgz", - "integrity": "sha512-gNSd+nZmMo6cuICezYXRIayu6TSOeCSCDzjSF0q6g8FKDsRbdqrONrSZYzdk/uBISmRcv4vZtsno6GyGvdXwGA==", + "version": "0.14.13", + "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.14.13.tgz", + "integrity": "sha512-Fo/VlEZKY4j53DQoW7Z/fWFrNGbnrfphgVDJdFoas5rVWUA9Z14/3AixEZcEfAuywympLCq49sTXVcD+sNtIxg==", "dev": true, "license": "Apache-2.0", "workspaces": [ - "vscode-extension", - "website" + "vscode-extension" ], "dependencies": { - "brace-expansion": "^4.0.0", + "brace-expansion": "^5.0.6", "chokidar": "^3.5.3", "fast-glob": "^3.2.11", "jsonc-parser": "^3.0.0", @@ -6323,27 +6346,42 @@ "node": ">=18.0.0" } }, - "node_modules/wireit/node_modules/balanced-match": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", - "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "node_modules/wireit/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">= 16" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/wireit/node_modules/brace-expansion": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz", - "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", + "node_modules/wireit/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^3.0.0" + "picomatch": "^2.2.1" }, "engines": { - "node": ">= 18" + "node": ">=8.10.0" } }, "node_modules/word-wrap": { diff --git a/package.json b/package.json index e5473234b..fe949e616 100644 --- a/package.json +++ b/package.json @@ -416,8 +416,10 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@types/glob-parent": "^5.1.3", "@types/node": "^18.19.130", "@types/node-forge": "^1.3.0", + "@types/picomatch": "^2.3.4", "@types/proper-lockfile": "^4.1.2", "@types/selfsigned": "^2.0.1", "@types/vscode": "^1.66.0", @@ -437,7 +439,7 @@ "vscode-languageclient": "^10.0.1", "vscode-languageserver": "^10.0.1", "vscode-languageserver-textdocument": "^1.0.4", - "wireit": "^0.14.12", + "wireit": "^0.14.13", "yarn": "^1.22.18" }, "prettier": { @@ -446,9 +448,11 @@ }, "dependencies": { "brace-expansion": "^5.0.6", - "chokidar": "^3.5.3", + "chokidar": "^4.0.3", "fast-glob": "^3.2.11", + "glob-parent": "^5.1.2", "jsonc-parser": "^3.0.0", + "picomatch": "^2.3.2", "proper-lockfile": "^4.1.2" }, "workspaces": [ diff --git a/src/test/glob.test.ts b/src/test/glob.test.ts index fdf86256c..f7a358c85 100644 --- a/src/test/glob.test.ts +++ b/src/test/glob.test.ts @@ -214,6 +214,16 @@ for (const mode of ['once', 'watch'] as const) { }); }); + void test(`[${mode}] ** glob with ! glob negation`, async () => { + await using ctx = await setup(); + await ctx.check({ + mode, + files: ['src/a.ts', 'src/b.js', 'src/sub/c.ts', 'src/sub/d.js'], + patterns: ['src/**/*', '!src/**/*.js'], + expected: ['src/a.ts', 'src/sub/c.ts'], + }); + }); + void test(`[${mode}] inclusion of directory with trailing slash`, async () => { await using ctx = await setup(); await ctx.check({ @@ -608,6 +618,20 @@ for (const mode of ['once', 'watch'] as const) { }, ); + void test( + `[${mode}] re-inclusion after negation`, + {skip: skipIfWatchOnWindows}, + async () => { + await using ctx = await setup(); + await ctx.check({ + mode, + files: ['foo/a.js', 'foo/bar.js', 'foo/c.js'], + patterns: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], + expected: ['foo/a.js', 'foo/bar.js', 'foo/c.js'], + }); + }, + ); + void test( `[${mode}] re-inclusion of directory`, {skip: skipIfWatch}, diff --git a/src/util/chokidar-with-globs.ts b/src/util/chokidar-with-globs.ts new file mode 100644 index 000000000..b9e859c7f --- /dev/null +++ b/src/util/chokidar-with-globs.ts @@ -0,0 +1,155 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import chokidar, { + type ChokidarOptions, + type FSWatcher as ChokidarFSWatcher, +} from 'chokidar'; +import picomatch from 'picomatch'; +import globParent from 'glob-parent'; +import * as pathlib from 'path'; + +/** + * Normalize a path to use forward slashes. Chokidar 4 normalizes all paths + * to forward slashes internally, so we must do the same when comparing paths + * in our `ignored` callback and emit filter. + */ +function toForwardSlashes(p: string): string { + return p.replace(/\\/g, '/'); +} + +/** + * Invoke Chokidar with additional support for glob patterns, emulating the + * behavior of chokidar 3. + * + * Chokidar 4 removed support for glob patterns. The original chokidar 3 + * implementation with glob support can be found at + * https://github.com/paulmillr/chokidar/blob/3.6.0/index.js. + * + * To support watching a glob pattern, we (1) extract the static directory + * portion of the glob and watch it recursively, and (2) filter down matching + * events to only those paths that matched the original glob pattern (because + * the directory watch is too coarse-grained). + * + * For example, given "a/b/*.js", we watch the folder "a/b" recursively, and + * then filter events so that "a/b/foo.js" matches but "a/b/foo.d.ts" does not. + */ +export function chokidarWatchWithGlobs( + patterns: string[], + // The `ignored` option is not supported here from callers because we override + // it internally for glob filtering and do not bother supporting also calling + // (polymorphic) caller-supplied one. + options?: Omit & {ignored?: never}, +): ChokidarFSWatcher { + const resolvedCwd = pathlib.resolve(options?.cwd ?? '.'); + const staticWatchPaths = new Set(); + const rules: { + ignore: boolean; + test: (path: string) => boolean; + }[] = []; + + for (const pattern of patterns) { + const isNegated = pattern.startsWith('!'); + const raw = isNegated ? pattern.slice(1) : pattern; + // Use path.join to resolve against cwd, matching chokidar 3's behavior + // (path.join treats '/bar' as a segment, correctly giving cwd/bar). + // Guard: if the path already has a drive-letter root (e.g. 'D:\...'), + // use it directly — path.join would incorrectly double the drive letter. + const absolute = + pathlib.parse(raw).root.length > 1 + ? pathlib.resolve(raw) + : pathlib.resolve(pathlib.join(resolvedCwd, raw)); + // Normalize to forward slashes for comparison with chokidar's paths. + // Chokidar 4 normalizes all paths to forward slashes internally. + const absoluteFwd = toForwardSlashes(absolute); + const isGlob = picomatch.scan(absoluteFwd).isGlob; + + if (isNegated) { + rules.push({ + ignore: true, + test: isGlob + ? picomatch(absoluteFwd, {dot: true}) + : (p) => { + const pFwd = toForwardSlashes(p); + return pFwd === absoluteFwd || pFwd.startsWith(absoluteFwd + '/'); + }, + }); + } else if (isGlob) { + staticWatchPaths.add(globParent(absoluteFwd)); + rules.push({ignore: false, test: picomatch(absoluteFwd, {dot: true})}); + } else { + staticWatchPaths.add(absoluteFwd); + rules.push({ + ignore: false, + test: (p) => { + const pFwd = toForwardSlashes(p); + return pFwd === absoluteFwd || pFwd.startsWith(absoluteFwd + '/'); + }, + }); + } + } + + const watcher = chokidar.watch( + staticWatchPaths.size > 0 ? [...staticWatchPaths] : [resolvedCwd], + { + ...options, + ignored: (path: string, stats) => { + // Chokidar calls `ignored` twice per path: first without stats + // (to decide whether to even stat the path), then with stats. We + // must return false here so chokidar proceeds to stat the path, + // since we need stats to distinguish files from directories. + if (!stats) { + return false; + } + // Never ignore directories, or chokidar won't recurse into them. + if (stats.isDirectory()) { + return false; + } + // Take the last matching rule because later rules shadow earlier ones + // (e.g. `foo/*.js` followed by `!foo/*.js`). + const lastMatchingRule = rules.findLast((r) => r.test(path)); + if (lastMatchingRule) { + return lastMatchingRule.ignore; + } + // No rule matched — this file is in a watched directory but doesn't + // match any pattern, so ignore it. + return true; + }, + }, + ); + + // Chokidar 4 only checks `ignored` during the initial directory scan, not + // on subsequent change events. Override `emit` to also filter those. + const originalEmit = watcher.emit.bind(watcher); + watcher.emit = ((event: string, ...args: unknown[]): boolean => { + // For individual events like 'add' or 'change', the path is args[0]. + // For the 'all' meta-event, the path is args[1] (args[0] is the event name). + const filePath = + event === 'all' + ? args[1] + : event === 'add' || + event === 'change' || + event === 'unlink' || + event === 'addDir' || + event === 'unlinkDir' + ? args[0] + : undefined; + if (typeof filePath === 'string') { + const absolutePath = toForwardSlashes( + pathlib.resolve(resolvedCwd, filePath), + ); + const lastMatchingRule = rules.findLast((r) => r.test(absolutePath)); + if (!lastMatchingRule || lastMatchingRule.ignore) { + return false; + } + } + return originalEmit.apply(watcher, [event, ...args] as Parameters< + typeof originalEmit + >); + }) as typeof watcher.emit; + + return watcher; +} diff --git a/src/watcher.ts b/src/watcher.ts index 79dbb3439..8961524eb 100644 --- a/src/watcher.ts +++ b/src/watcher.ts @@ -4,7 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import chokidar from 'chokidar'; +import type {FSWatcher} from 'chokidar'; +import {chokidarWatchWithGlobs} from './util/chokidar-with-globs.js'; import {Analyzer} from './analyzer.js'; import {Cache} from './caching/cache.js'; import { @@ -65,7 +66,7 @@ function unexpectedState(state: WatcherState) { */ interface FileWatcher extends AsyncDisposable { patterns: string[]; - watcher: chokidar.FSWatcher; + watcher: FSWatcher; } /** @@ -493,7 +494,7 @@ export const makeWatcher = ( // TODO(aomarks) chokidar doesn't work exactly like fast-glob, so there are // currently various differences in what gets watched vs what actually affects // the build. See https://github.com/google/wireit/issues/550. - const watcher = chokidar.watch( + const watcher = chokidarWatchWithGlobs( // Trim leading slashes from patterns, to "re-root" all paths to the package // directory, just as we do when globbing for script execution. patterns.map((pattern) => pattern.replace(/^\/+/, '')), diff --git a/tsconfig.json b/tsconfig.json index e7ff6f3a5..f9f154bfe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "module": "nodenext", "moduleResolution": "nodenext", "useDefineForClassFields": false, - "lib": ["es2022", "esnext.disposable"], + "lib": ["es2023", "esnext.disposable"], "rootDir": "src", "outDir": "lib", "strict": true,