diff --git a/package-lock.json b/package-lock.json index bfb46f03..9aad3d90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,8 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", "glob": "^10.3.10", + "minimatch": "^9.0.3", + "semver": "^7.6.0", "typescript": "^4.4.4" } }, @@ -100,6 +102,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "8.56.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", @@ -152,6 +176,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1026,13 +1072,12 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/builtin-modules": { @@ -1360,6 +1405,28 @@ "ignored": "bin/ignored" } }, + "node_modules/dotignore/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dotignore/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/dtrace-provider": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", @@ -1719,6 +1786,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -1740,6 +1817,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1777,6 +1866,28 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-plugin-n/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-n/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-prettier": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", @@ -1847,6 +1958,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2264,30 +2397,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -3038,15 +3147,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -3135,6 +3247,17 @@ "node": ">=0.8.0" } }, + "node_modules/mv/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/mv/node_modules/glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", @@ -3152,6 +3275,19 @@ "node": "*" } }, + "node_modules/mv/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/mv/node_modules/rimraf": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", @@ -3685,6 +3821,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3705,6 +3851,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4201,6 +4359,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tape/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/tape/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4221,6 +4389,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/tape/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/tape/node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -5496,6 +5676,27 @@ "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "@eslint/js": { @@ -5533,6 +5734,27 @@ "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "@humanwhocodes/module-importer": { @@ -6170,13 +6392,12 @@ } }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "builtin-modules": { @@ -6415,6 +6636,27 @@ "dev": true, "requires": { "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "dtrace-provider": { @@ -6615,6 +6857,27 @@ "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "eslint-compat-utils": { @@ -6709,6 +6972,16 @@ "tsconfig-paths": "^3.15.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -6727,6 +7000,15 @@ "esutils": "^2.0.2" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6752,6 +7034,27 @@ "minimatch": "^3.1.2", "resolve": "^1.22.2", "semver": "^7.5.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "eslint-plugin-prettier": { @@ -7104,26 +7407,6 @@ "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } } }, "glob-parent": { @@ -7661,12 +7944,12 @@ } }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, "minimist": { @@ -7734,6 +8017,17 @@ "rimraf": "~2.4.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", @@ -7748,6 +8042,16 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", @@ -8119,6 +8423,16 @@ "glob": "^7.1.3" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -8132,6 +8446,15 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -8480,6 +8803,16 @@ "string.prototype.trim": "^1.2.8" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -8494,6 +8827,15 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", diff --git a/package.json b/package.json index c1720570..ec3d0348 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", "glob": "^10.3.10", + "minimatch": "^9.0.3", + "semver": "^7.6.0", "typescript": "^4.4.4" } } diff --git a/scripts/update-otel-deps.js b/scripts/update-otel-deps.js index 7a329ebe..d2e3a073 100755 --- a/scripts/update-otel-deps.js +++ b/scripts/update-otel-deps.js @@ -4,62 +4,328 @@ * Update '@opentelemetry/*' deps in all workspaces. * * Usage: - * node scripts/update-otel-deps.js [WORKSPACES...] + * # You should do a clean 'npm ci' before running this. + * node scripts/update-otel-deps.js + * + * You can set the `DEBUG=1` envvar to get some debug output. */ +const assert = require('assert'); +const fs = require('fs'); const path = require('path'); -const {execFileSync, spawnSync} = require('child_process'); +const {spawnSync} = require('child_process'); const {globSync} = require('glob'); +const {minimatch} = require('minimatch'); +const semver = require('semver'); + +const TOP = process.cwd(); -const pj = require(path.resolve(__dirname, '../package.json')); +function debug(...args) { + if (process.env.DEBUG) { + console.log(...args); + } +} -function updateOTelDeps(workspace) { - // Only consider packages in this workspace's "package.json". - // A bare `npm outdated` will also include linked to workspaces in the - // same monorepo. - const pkg = require( - path.resolve(__dirname, '..', workspace, 'package.json') +function getAllWorkspaceDirs() { + const pj = JSON.parse( + fs.readFileSync(path.join(TOP, 'package.json'), 'utf8') ); - const otelDeps = Object.keys(pkg.dependencies || {}) - .concat(Object.keys(pkg.devDependencies || {})) - .filter((d) => d.startsWith('@opentelemetry/')); + const workspaceDirs = pj.workspaces + .map((wsGlob) => globSync(path.join(wsGlob, 'package.json'))) + .flat() + .map(path.dirname); + return workspaceDirs; +} - const p = spawnSync('npm', ['outdated', '--json'].concat(otelDeps), { - cwd: workspace, - encoding: 'utf8', - }); - const outdated = JSON.parse(p.stdout); +/** + * Update dependencies & devDependencies in npm workspaces defined by + * "./packages.json#packages". Use `patterns` to limit to a set of matching + * package names. + * + * Compare somewhat to dependabot group version updates: + * https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups + * However IME with opentelemetry-js-contrib.git, dependabot will variously + * timeout, not update all deps, or leave an unsync'd package-lock.json. + * + * See https://gist.github.com/trentm/e67fb941a4aca339c2911d873b2e8ab6 for + * notes on some perils with using 'npm outdated'. + * + * @param {object} opts + * @param {string[]} opts.patterns - An array of glob-like patterns to match + * against dependency names. E.g. `["@opentelemetry/*"]`. + * @param {boolean} [opts.allowRangeBumpFor0x] - By default this update only + * targets to latest available version that matches the current + * package.json range. Setting this to true allows any deps currently at an + * 0.x version to be bumped to the latest, even if the latest doesn't + * satisfy the current range. E.g. `^0.41.0` will be bumped to `0.42.0` or + * `1.2.3` or `2.3.4` if that is the latest published version. This means + * using `npm install ...` and changing the range in "package.json". + * @param {boolean} [opts.dryRun] - Note that a dry-run might not fully + * accurately represent the commands run, because the final 'npm update' + * args can depend on the results of earlier 'npm install' commands. + */ +function updateNpmWorkspacesDeps({patterns, allowRangeBumpFor0x, dryRun}) { + assert( + patterns && patterns.length > 0, + 'must provide one or more patterns' + ); + + let p; + + const wsDirs = getAllWorkspaceDirs(); + const matchStr = ` matching "${patterns.join('", "')}"`; + console.log(`Updating deps${matchStr} in ${wsDirs.length} workspace dirs`); - const npmArgs = []; - Object.keys(outdated).forEach((pkgName) => { - if (!pkgName.startsWith('@opentelemetry/')) { - return; + const depPatternFilter = (name) => { + if (!patterns) { + return true; } - npmArgs.push(`${pkgName}@${outdated[pkgName].latest}`); - }); - if (npmArgs.length > 0) { - console.log(`cd ${workspace} && npm install ${npmArgs.join(' ')}`); - npmArgs.unshift('install'); - execFileSync('npm', npmArgs, { - cwd: workspace, + for (let pat of patterns) { + if (minimatch(name, pat)) { + return true; + } + } + return false; + }; + + // Gather deps info from each of the workspace dirs. + const pkgInfoFromWsDir = {}; + const localPkgNames = new Set(); + for (let wsDir of wsDirs) { + const pj = JSON.parse( + fs.readFileSync(path.join(wsDir, 'package.json'), 'utf8') + ); + const deps = {}; + if (pj.dependencies) { + Object.keys(pj.dependencies) + .filter(depPatternFilter) + .forEach((d) => { + deps[d] = pj.dependencies[d]; + }); + } + if (pj.devDependencies) { + Object.keys(pj.devDependencies) + .filter(depPatternFilter) + .forEach((d) => { + deps[d] = pj.devDependencies[d]; + }); + } + localPkgNames.add(pj.name); + pkgInfoFromWsDir[wsDir] = { + name: pj.name, + deps, + }; + } + debug('pkgInfoFromWsDir: ', pkgInfoFromWsDir); + + console.log('\nGathering info on outdated deps in each workspace:'); + const summaryStrs = new Set(); + const npmInstallTasks = []; + const npmUpdatePkgNames = new Set(); + let i = 0; + for (let wsDir of wsDirs) { + i++; + console.log(` - ${wsDir} (${i} of ${wsDirs.length})`); + const info = pkgInfoFromWsDir[wsDir]; + const depNames = Object.keys(info.deps); + if (depNames.length === 0) { + continue; + } + // We use 'npm outdated -j ...' as a quick way to get the current + // installed version and latest published version of deps. The '-j' + // output shows a limited/random subset of data such that its `wanted` + // value cannot be used (see "npm outdated" perils above). + p = spawnSync('npm', ['outdated', '--json'].concat(depNames), { + cwd: wsDir, encoding: 'utf8', }); + const outdated = JSON.parse(p.stdout); + if (Object.keys(outdated).length === 0) { + continue; + } + + const npmInstallArgs = []; + for (let depName of depNames) { + if (!(depName in outdated)) { + continue; + } + const summaryNote = localPkgNames.has(depName) ? ' (local)' : ''; + const currVer = outdated[depName].current; + const latestVer = outdated[depName].latest; + if (semver.satisfies(latestVer, info.deps[depName])) { + // `npm update` should suffice. + npmUpdatePkgNames.add(depName); + summaryStrs.add( + `${currVer} -> ${latestVer} ${depName}${summaryNote}` + ); + } else if (semver.lt(currVer, '1.0.0')) { + if (allowRangeBumpFor0x) { + npmInstallArgs.push(`${depName}@${latestVer}`); + summaryStrs.add( + `${currVer} -> ${latestVer} ${depName} (range-bump)${summaryNote}` + ); + } else { + console.log( + `WARN: not updating dep "${depName}" in "${wsDir}" to latest: currVer=${currVer}, latestVer=${latestVer}, package.json dep range="${info.deps[depName]}" (use allowRangeBumpFor0x=true to supporting bumping 0.x deps out of package.json range)` + ); + } + } else { + // TODO: Add support for finding a release other than latest that satisfies the package.json range. + console.log( + `WARN: dep "${depName}" in "${wsDir}" cannot be updated to latest: currVer=${currVer}, latestVer=${latestVer}, package.json dep range="${info.deps[depName]}" (this script does not yet support finding a possible published ver to update to that does satisfy the package.json range)` + ); + } + } + if (npmInstallArgs.length > 0) { + npmInstallTasks.push({ + cwd: wsDir, + argv: ['npm', 'install'].concat(npmInstallArgs), + }); + } } -} -async function main() { - let allWorkspaces = pj.workspaces.map((w) => globSync(w)).flat(); - let workspaces = allWorkspaces; - if (process.argv.length > 2) { - workspaces = process.argv - .slice(2) - .map((s) => globSync(s)) - .flat() - .filter((s) => allWorkspaces.includes(s)); + console.log( + '\nPerforming updates (%d `npm install ...`s, %d `npm update ...`):', + npmInstallTasks.length, + npmUpdatePkgNames.size ? 1 : 0 + ); + debug('npmInstallTasks: ', npmInstallTasks); + debug('npmUpdatePkgNames: ', npmUpdatePkgNames); + for (let task of npmInstallTasks) { + console.log(` $ cd ${task.cwd} && ${task.argv.join(' ')}`); + if (!dryRun) { + p = spawnSync(task.argv[0], task.argv.slice(1), { + cwd: task.cwd, + encoding: 'utf8', + }); + if (p.error) { + throw p.error; + } else if (p.status !== 0) { + const err = Error(`'npm install' failed (status=${p.status})`); + err.cwd = task.cwd; + err.argv = task.argv; + err.process = p; + throw err; + } + // Note: As noted at https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1917#issue-2109198809 + // (see "... requires running npm install twice ...") in some cases this + // 'npm install' doesn't actually install the new version, but do not + // error out! + // TODO: guard against this with 'npm ls' or package.json check? + } + } + + // At this point we should just need a single `npm update ...` command + // to update the packages that have an available update matching the + // current package.json ranges. + // + // However, there might be transitive deps that prevent `npm update foo` + // updating to latest unless those transitive deps are included in the + // command. For example: + // - workspace "packages/foo" depends on: + // "@opentelemetry/host-metrics": "^0.34.1", + // "@opentelemetry/resources": "^1.20.0", + // - currently installed "@opentelemetry/host-metrics@0.34.1" depends on: + // "@opentelemetry/sdk-metrics": "^1.8.0" + // - currently installed "@opentelemetry/sdk-metrics@1.20.0" depends on: + // "@opentelemetry/resources": "1.20.0" (note the strict range) + // - When attempting to update `@opentelemetry/resources` to 1.21.0, it is + // implicitly pinned by the `@opentelemetry/sdk-metrics` dep unless the + // `npm update ...` command includes `@opentelemetry/sdk-metrics`. + // + // We will use `npm outdated ...` to gather all the "Depended by" entries + // for each `npmUpdatePkgNames` we want to update. + if (npmUpdatePkgNames.size > 0) { + const wsDirBasenames = new Set(wsDirs.map((d) => path.basename(d))); + p = spawnSync( + 'npm', + ['outdated', '-p'].concat(Array.from(npmUpdatePkgNames)), + {cwd: TOP, encoding: 'utf8'} + ); + // `npm outdated -p` output is: + // DIR:WANTED:CURRENT:LATEST:DEPENDED_BY + // e.g. + // % npm outdated @opentelemetry/resources -p + // /Users/trentm/src/a-project/node_modules/@opentelemetry/resources:@opentelemetry/resources@1.21.0:@opentelemetry/resources@1.20.0:@opentelemetry/resources@1.21.0:opentelemetry-node + // /Users/trentm/src/a-project/node_modules/@opentelemetry/resources:@opentelemetry/resources@1.20.0:@opentelemetry/resources@1.20.0:@opentelemetry/resources@1.21.0:@opentelemetry/sdk-metrics + // where that "opentelemetry-node" is a workspace dir *basename* (sigh). + p.stdout + .trim() + .split('\n') + .forEach((line) => { + const dependedBy = line.split(':')[4]; + if (wsDirBasenames.has(dependedBy)) { + return; + } + // TODO Do we want to guard this on `patterns`? + npmUpdatePkgNames.add(dependedBy); + }); + + console.log(` $ npm update ${Array.from(npmUpdatePkgNames).join(' ')}`); + if (!dryRun) { + p = spawnSync( + 'npm', + ['update'].concat(Array.from(npmUpdatePkgNames)), + { + cwd: TOP, + encoding: 'utf8', + } + ); + if (p.error) { + throw p.error; + } + } } - workspaces.forEach((w) => { - updateOTelDeps(w); + console.log('\nSanity check that all matching packages are up-to-date:'); + if (dryRun) { + console.log(' (Skipping sanity check for dry-run.)'); + } else { + const allDeps = new Set(); + Object.keys(pkgInfoFromWsDir).forEach((wsDir) => { + Object.keys(pkgInfoFromWsDir[wsDir].deps).forEach((dep) => { + allDeps.add(dep); + }); + }); + console.log(` $ npm outdated ${Array.from(allDeps).join(' ')}`); + p = spawnSync('npm', ['outdated'].concat(Array.from(allDeps)), { + cwd: TOP, + encoding: 'utf8', + }); + if (p.status !== 0) { + // Only *warning* here because the user might still want to commit + // what *was* updated. + console.log(`WARN: not all packages${matchStr} were fully updated: + *** 'npm outdated' exited non-zero, stdout: *** + ${p.stdout.trimEnd().split('\n').join('\n ')} + ***`); + } + } + + // Summary/commit message. + let commitMsg = `chore(deps): update deps${matchStr}\n\n`; + commitMsg += + ' ' + + Array.from(summaryStrs) + .sort((a, b) => { + const aParts = a.split(' '); + const bParts = b.split(' '); + return ( + semver.compare(aParts[0], bParts[0]) || + (aParts[3] > bParts[3] ? 1 : -1) + ); + }) + .join('\n '); + console.log( + `\nSummary of changes (possible commit message):\n--\n${commitMsg}\n--` + ); +} + +async function main() { + updateNpmWorkspacesDeps({ + patterns: ['@opentelemetry/*'], + allowRangeBumpFor0x: true, + dryRun: false, }); }