Skip to content

Commit

Permalink
support regex for include/exclude and merge cli/config options
Browse files Browse the repository at this point in the history
Fixes: #57
Fixes: #66
  • Loading branch information
silverwind committed Aug 25, 2023
1 parent ae3b22a commit 62a2b32
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 36 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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|Regex]*: Array of dependencies to include
- `exclude` *Array[String|Regex]*: Array of dependencies to exclude
- `types` *Array[String]*: Array of dependency types
- `registry` *String*: URL to npm registry

Expand Down
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 27 additions & 3 deletions snapshots/updates.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`exclude version deps 1`] = `
exports[`exclude 1`] = `
{
"dependencies": {
"updates": {
Expand All @@ -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": {
Expand Down Expand Up @@ -78,7 +90,19 @@ exports[`greatest 1`] = `
}
`;

exports[`include version deps #2 1`] = `
exports[`include 1`] = `
{
"dependencies": {
"noty": {
"info": "https://github.com/needim/noty",
"new": "3.2.0-beta",
"old": "3.1.0",
},
},
}
`;

exports[`include 2 1`] = `
{
"dependencies": {
"noty": {
Expand All @@ -90,7 +114,7 @@ exports[`include version deps #2 1`] = `
}
`;

exports[`include version deps 1`] = `
exports[`include 3 1`] = `
{
"dependencies": {
"noty": {
Expand Down
3 changes: 3 additions & 0 deletions updates.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ export default {
"registry-auth-token",
"semver",
],
include: [
/foo/,
],
};
51 changes: 35 additions & 16 deletions updates.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,19 @@ 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 || []) {
console.log({arg});
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);
Expand All @@ -622,21 +635,21 @@ 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
-d, --allow-downgrade [<pkg,...>] Allow version downgrades when using latest version
-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
Expand All @@ -646,7 +659,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);
}
Expand Down Expand Up @@ -763,22 +779,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;
}

Expand Down Expand Up @@ -806,7 +825,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");
Expand Down
8 changes: 5 additions & 3 deletions updates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))}`,
Expand Down

0 comments on commit 62a2b32

Please sign in to comment.