support regex for include/exclude and merge cli/config options
Fixes: https://github.com/silverwind/updates/issues/57 Fixes: https://github.com/silverwind/updates/issues/66
This commit is contained in:
parent
ae3b22a400
commit
de94050877
@ -34,14 +34,15 @@ Put a `updates.config.js` or `updates.config.mjs` in the root of your project, u
|
||||
export default {
|
||||
exclude: [
|
||||
"semver",
|
||||
/^react/,
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Config File Options
|
||||
|
||||
- `include` *Array[String]*: Array of dependencies to include
|
||||
- `exclude` *Array[String]*: Array of dependencies to exclude
|
||||
- `include` *Array[String|Regexp]*: Array of dependencies to include
|
||||
- `exclude` *Array[String|Regexp]*: Array of dependencies to exclude
|
||||
- `types` *Array[String]*: Array of dependency types
|
||||
- `registry` *String*: URL to npm registry
|
||||
|
||||
|
24
package-lock.json
generated
24
package-lock.json
generated
@ -1477,18 +1477,6 @@
|
||||
"@esbuild/win32-x64": "0.18.19"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.46.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
|
||||
@ -1814,6 +1802,18 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`exclude version deps 1`] = `
|
||||
exports[`exclude 1`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
"updates": {
|
||||
@ -12,6 +12,18 @@ exports[`exclude version deps 1`] = `
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`exclude 2`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
"react": {
|
||||
"info": "https://github.com/facebook/react/tree/HEAD/packages/react",
|
||||
"new": "18.2.0",
|
||||
"old": "18.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`greatest 1`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
@ -78,7 +90,7 @@ exports[`greatest 1`] = `
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`include version deps #2 1`] = `
|
||||
exports[`include 1`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
"noty": {
|
||||
@ -90,7 +102,19 @@ exports[`include version deps #2 1`] = `
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`include version deps 1`] = `
|
||||
exports[`include 2 1`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
"noty": {
|
||||
"info": "https://github.com/needim/noty",
|
||||
"new": "3.2.0-beta",
|
||||
"old": "3.1.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`include 3 1`] = `
|
||||
{
|
||||
"dependencies": {
|
||||
"noty": {
|
||||
|
50
updates.js
50
updates.js
@ -611,6 +611,18 @@ async function getCerts(extra = []) {
|
||||
return [...(await import("node:tls")).rootCertificates, ...extra];
|
||||
}
|
||||
|
||||
// parse include/exclude into a Set of regexes
|
||||
function matchersToRegexSet(cliArgs, configArgs) {
|
||||
const ret = new Set();
|
||||
for (const arg of cliArgs || []) {
|
||||
ret.add(new RegExp(/\/.+\//.test(arg) ? arg.slice(1, -1) : `^${esc(arg)}$`));
|
||||
}
|
||||
for (const arg of configArgs || []) {
|
||||
ret.add(arg instanceof RegExp ? arg : new RegExp(`^${esc(arg)}$`));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
for (const stream of [process.stdout, process.stderr]) {
|
||||
stream?._handle?.setBlocking?.(true);
|
||||
@ -622,13 +634,13 @@ async function main() {
|
||||
stdout.write(`usage: updates [options]
|
||||
|
||||
Options:
|
||||
-l, --language <lang> Language to check, either 'js' or 'py'
|
||||
-u, --update Update versions and write package file
|
||||
-f, --file <path> Use given package file or module directory
|
||||
-i, --include <pkg,...> Include only given packages, supports '/regex/' syntax
|
||||
-e, --exclude <pkg,...> Exclude given packages, supports '/regex/' syntax
|
||||
-p, --prerelease [<pkg,...>] Consider prerelease versions
|
||||
-R, --release [<pkg,...>] Only use release versions, may downgrade
|
||||
-g, --greatest [<pkg,...>] Prefer greatest over latest version
|
||||
-i, --include <pkg,...> Include only given packages
|
||||
-e, --exclude <pkg,...> Exclude given packages
|
||||
-t, --types <type,...> Check only given dependency types
|
||||
-P, --patch [<pkg,...>] Consider only up to semver-patch
|
||||
-m, --minor [<pkg,...>] Consider only up to semver-minor
|
||||
@ -636,7 +648,7 @@ async function main() {
|
||||
-E, --error-on-outdated Exit with code 2 when updates are available and 0 when not
|
||||
-U, --error-on-unchanged Exit with code 0 when updates are available and 2 when not
|
||||
-r, --registry <url> Override npm registry URL
|
||||
-f, --file <path> Use given package file or module directory
|
||||
-l, --language <lang> Language to check, either 'js' or 'py'
|
||||
-S, --sockets <num> Maximum number of parallel HTTP sockets opened. Default: ${MAX_SOCKETS}
|
||||
-j, --json Output a JSON object
|
||||
-n, --no-color Disable color output
|
||||
@ -646,7 +658,10 @@ async function main() {
|
||||
|
||||
Examples:
|
||||
$ updates
|
||||
$ updates -u && npm i
|
||||
$ updates -u
|
||||
$ updates -e '/^react-(dom)?/'
|
||||
$ updates -f package.json
|
||||
$ updates -f pyproject.toml
|
||||
`);
|
||||
exit(0);
|
||||
}
|
||||
@ -763,22 +778,25 @@ async function main() {
|
||||
finish(new Error(`Error parsing ${packageFile}: ${err.message}`));
|
||||
}
|
||||
|
||||
let include, exclude;
|
||||
if (args.include && args.include !== true) {
|
||||
include = new Set(((Array.isArray(args.include) ? args.include : [args.include]).flatMap(item => item.split(","))));
|
||||
} else if ("include" in config && Array.isArray(config.include)) {
|
||||
include = new Set(config.include);
|
||||
let includeCli, excludeCli;
|
||||
if (args.include && args.include !== true) { // cli
|
||||
includeCli = (Array.isArray(args.include) ? args.include : [args.include]).flatMap(item => item.split(","));
|
||||
}
|
||||
if (args.exclude && args.exclude !== true) {
|
||||
exclude = new Set(((Array.isArray(args.exclude) ? args.exclude : [args.exclude]).flatMap(item => item.split(","))));
|
||||
} else if ("exclude" in config && Array.isArray(config.exclude)) {
|
||||
exclude = new Set(config.exclude);
|
||||
excludeCli = (Array.isArray(args.exclude) ? args.exclude : [args.exclude]).flatMap(item => item.split(","));
|
||||
}
|
||||
|
||||
const include = matchersToRegexSet(includeCli, config?.include);
|
||||
const exclude = matchersToRegexSet(excludeCli, config?.exclude);
|
||||
|
||||
function canInclude(name, language) {
|
||||
if (language === "py" && name === "python") return false;
|
||||
if (exclude?.has?.(name) === true) return false;
|
||||
if (include?.has?.(name) === false) return false;
|
||||
for (const re of exclude) {
|
||||
if (re.test(name)) return false;
|
||||
}
|
||||
for (const re of include) {
|
||||
if (!re.test(name)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -806,7 +824,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (!Object.keys(deps).length && !Object.keys(maybeUrlDeps).length) {
|
||||
if (include || exclude) {
|
||||
if (include.size || exclude.size) {
|
||||
finish(new Error(`No dependencies match the given include/exclude filters`));
|
||||
} else {
|
||||
finish("No dependencies present, nothing to do");
|
||||
|
@ -167,9 +167,11 @@ test("greatest", makeTest("-j -g"));
|
||||
test("prerelease", makeTest("-j -g -p"));
|
||||
test("release", makeTest("-j -R"));
|
||||
test("patch", makeTest("-j -P"));
|
||||
test("include version deps", makeTest("-j -i noty"));
|
||||
test("include version deps #2", makeTest("-j -i noty -i noty,noty"));
|
||||
test("exclude version deps", makeTest("-j -e gulp-sourcemaps,prismjs,svgstore,html-webpack-plugin,noty,jpeg-buffer-orientation,styled-components,@babel/preset-env,versions/updates,react"));
|
||||
test("include", makeTest("-j -i noty"));
|
||||
test("include 2", makeTest("-j -i noty -i noty,noty"));
|
||||
test("include 3", makeTest("-j -i /^noty/"));
|
||||
test("exclude", makeTest("-j -e gulp-sourcemaps,prismjs,svgstore,html-webpack-plugin,noty,jpeg-buffer-orientation,styled-components,@babel/preset-env,versions/updates,react"));
|
||||
test("exclude", makeTest("-j -e gulp-sourcemaps -i /react/"));
|
||||
|
||||
test("pypi", makeTest(
|
||||
`-j -f ${fileURLToPath(new URL("fixtures/pyproject.toml", import.meta.url))}`,
|
||||
|
Loading…
Reference in New Issue
Block a user