Comparing version 0.0.8 to 0.0.9
180
dist/cli.js
@@ -260,16 +260,27 @@ 'use strict'; | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
}); | ||
function getVersionRangePrefix(v) { | ||
const leadings = ['>=', '<=', '>', '<', '~', '^']; | ||
const ver = v.trim(); | ||
if (ver === '*') | ||
return '*'; | ||
if (ver[0] === '~' || ver[0] === '^') | ||
return ver[0]; | ||
for (const leading of leadings) { | ||
if (ver.startsWith(leading)) | ||
return leading; | ||
} | ||
if (ver.includes('x')) { | ||
const parts = ver.split('.'); | ||
if (parts[0] === 'x') | ||
return '*'; | ||
if (parts[1] === 'x') | ||
return '^'; | ||
if (parts[2] === 'x') | ||
return '~'; | ||
} | ||
if (+ver[0] < 10) | ||
return ''; | ||
return null; | ||
} | ||
function resetRange(version, mode) { | ||
function changeVersionRange(version, mode) { | ||
if (mode === 'newest') | ||
@@ -290,2 +301,42 @@ return '*'; | ||
} | ||
function applyVersionRangePrefix(version, prefix) { | ||
if (version == null || prefix == null) | ||
return null; | ||
if (prefix === '*') | ||
return '*'; | ||
return prefix + version; | ||
} | ||
function getMaxSatisfying(versions, current, mode) { | ||
const range = changeVersionRange(current, mode); | ||
if (!range) | ||
return null; | ||
const prefix = getVersionRangePrefix(current); | ||
if (range === '*') | ||
return '*'; | ||
return applyVersionRangePrefix(semver.maxSatisfying(versions, range), prefix); | ||
} | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
try { | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
} | ||
catch (e) { | ||
versionCache[name] = { | ||
tags: {}, | ||
versions: [], | ||
error: e.statusCode || e, | ||
}; | ||
return versionCache[name]; | ||
} | ||
}); | ||
} | ||
function resolveDependency(raw, mode, filter = () => true) { | ||
@@ -297,11 +348,16 @@ return __awaiter(this, void 0, void 0, function* () { | ||
const dep = Object.assign({}, raw); | ||
const { versions, tags } = yield getLatestVersions(dep.name); | ||
const range = mode === 'latest' ? tags.latest : resetRange(dep.currentVersion, mode); | ||
if (range) { | ||
const max = semver.maxSatisfying(versions, range); | ||
// TODO: align the range | ||
dep.latestVersion = max ? `^${max}` : dep.currentVersion; | ||
dep.diff = semver.diff(semver.minVersion(dep.currentVersion), semver.minVersion(dep.latestVersion)); | ||
dep.update = dep.diff !== null; | ||
const { versions, tags, error } = yield getLatestVersions(dep.name); | ||
let max = null; | ||
if (!error) { | ||
max = mode === 'latest' | ||
? tags.latest | ||
: getMaxSatisfying(versions, dep.currentVersion, mode); | ||
} | ||
if (!error && max) { | ||
dep.latestVersion = max; | ||
const current = semver.minVersion(dep.currentVersion); | ||
const latest = semver.minVersion(dep.latestVersion); | ||
dep.diff = semver.diff(current, latest); | ||
dep.update = dep.diff !== null && semver.lt(current, latest); | ||
} | ||
else { | ||
@@ -311,2 +367,3 @@ dep.latestVersion = dep.currentVersion; | ||
dep.update = false; | ||
dep.resolveError = error !== null && error !== void 0 ? error : 'invalid_range'; | ||
} | ||
@@ -338,2 +395,28 @@ return dep; | ||
const createFilterAction = (filterOptions) => { | ||
if (!filterOptions || !filterOptions.length) | ||
return () => true; | ||
if (filterOptions.length === 1) { | ||
const filter = filterOptions[0]; | ||
const separator = filter.includes(',') ? ',' : null; | ||
if (separator !== null) { | ||
const filterArray = filter.split(separator); | ||
return (depName) => filterArray.includes(depName); | ||
} | ||
let regex = null; | ||
try { | ||
const endIndex = filter.lastIndexOf('/'); | ||
const regexp = filter.substring(1, endIndex); | ||
const flags = filter.substring(endIndex + 1, filter.length); | ||
regex = new RegExp(regexp, flags); | ||
} | ||
catch (e) { | ||
regex = null; | ||
} | ||
if (regex) | ||
return (depName) => regex.test(depName); | ||
} | ||
return (depName) => filterOptions.includes(depName); | ||
}; | ||
function check(options) { | ||
@@ -346,2 +429,3 @@ return __awaiter(this, void 0, void 0, function* () { | ||
}); | ||
// packages loading | ||
const packages = yield loadPackages(options); | ||
@@ -352,6 +436,6 @@ const privatePackageNames = packages | ||
.filter(i => i); | ||
const filter = (dep) => { | ||
// to filter out private dependency in monorepo | ||
return !privatePackageNames.includes(dep.name); | ||
}; | ||
const filterAction = createFilterAction(options.filter); | ||
// to filter out private dependency in monorepo | ||
const filter = (dep) => filterAction(dep.name) && !privatePackageNames.includes(dep.name); | ||
// progress bar | ||
console.log(); | ||
@@ -361,19 +445,21 @@ const bars = new cliProgress.MultiBar({ | ||
hideCursor: true, | ||
format: `${chalk.cyan('{type}')} {bar} {value}/{total} ${chalk.gray('{name}')}`, | ||
format: `{type} {bar} {value}/{total} ${chalk.gray('{name}')}`, | ||
linewrap: false, | ||
barsize: 40, | ||
}, cliProgress.Presets.shades_grey); | ||
const packagesBar = options.recursive ? bars.create(packages.length, 0, { type: 'pkg' }) : null; | ||
const depBar = bars.create(1, 0, { type: 'dep' }); | ||
const packagesBar = options.recursive ? bars.create(packages.length, 0, { type: chalk.cyan('pkg') }) : null; | ||
const depBar = bars.create(1, 0); | ||
for (const pkg of packages) { | ||
packagesBar === null || packagesBar === void 0 ? void 0 : packagesBar.increment(0, { name: pkg.name }); | ||
yield checkProject(pkg, options, filter, logger, depBar); | ||
packagesBar === null || packagesBar === void 0 ? void 0 : packagesBar.increment(0, { name: chalk.cyan(pkg.name) }); | ||
yield checkProject(pkg, options, filter, privatePackageNames, logger, depBar); | ||
packagesBar === null || packagesBar === void 0 ? void 0 : packagesBar.increment(1); | ||
} | ||
bars.stop(); | ||
// TODO: summary | ||
// tips | ||
if (!options.write) { | ||
logger.log(); | ||
if (options.mode === 'default') | ||
logger.log(`Run ${chalk.yellow('taze major')} to check major updates`); | ||
logger.log(`Run ${chalk.cyan('taze -w')} to write package.json`); | ||
logger.log(`Run ${chalk.cyan('taze major')} to check major updates`); | ||
logger.log(`Run ${chalk.green('taze -w')} to write package.json`); | ||
logger.log(); | ||
@@ -384,5 +470,5 @@ } | ||
} | ||
function checkProject(pkg, options, filter, logger, bar) { | ||
function checkProject(pkg, options, filter, privatePackageNames, logger, bar) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
bar.start(pkg.deps.length, 0, { type: 'dep' }); | ||
bar.start(pkg.deps.length, 0, { type: chalk.green('dep') }); | ||
yield resolvePackage(pkg, options.mode, filter, (c, _, name) => { | ||
@@ -400,2 +486,3 @@ bar.update(c, { name }); | ||
} | ||
return pkg; | ||
}); | ||
@@ -426,4 +513,24 @@ } | ||
} | ||
const errors = pkg.resolved.filter(i => i.resolveError != null); | ||
if (errors.length) { | ||
logger.log(); | ||
for (const dep of errors) | ||
printResolveError(dep, logger); | ||
} | ||
logger.log(); | ||
} | ||
function printResolveError(dep, logger) { | ||
if (dep.resolveError == null) | ||
return; | ||
if (dep.resolveError === 404) { | ||
logger.log(chalk.redBright(`> ${chalk.underline(dep.name)} not found`)); | ||
} | ||
else if (dep.resolveError === 'invalid_range') { | ||
logger.log(chalk.yellowBright(`> ${chalk.underline(dep.name)} has an unresolvable version range: ${chalk.underline(dep.currentVersion)}`)); | ||
} | ||
else { | ||
logger.log(chalk.redBright(`> ${chalk.underline(dep.name)} unknown error`)); | ||
logger.log(chalk.redBright(dep.resolveError.toString())); | ||
} | ||
} | ||
@@ -462,7 +569,8 @@ // eslint-disable-next-line no-unused-expressions | ||
type: 'string', | ||
describe: 'filter rules to restrict a subsets of dependencies for updates', | ||
describe: 'filter rules to restrict dependencies to check updates', | ||
array: true, | ||
}) | ||
.option('ignore', { | ||
type: 'string', | ||
describe: 'ignore rules to restrict a subsets of dependencies for updates', | ||
describe: 'ignore rules to restrict dependencies to not check updates', | ||
}) | ||
@@ -469,0 +577,0 @@ // TODO: |
@@ -24,2 +24,3 @@ import semver from 'semver'; | ||
update: boolean; | ||
resolveError?: number | string | Error; | ||
} | ||
@@ -31,2 +32,3 @@ interface CheckOptions { | ||
write: boolean; | ||
filter: string[]; | ||
} | ||
@@ -33,0 +35,0 @@ interface PackageMeta { |
@@ -64,16 +64,27 @@ import pacote from 'pacote'; | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
}); | ||
function getVersionRangePrefix(v) { | ||
const leadings = ['>=', '<=', '>', '<', '~', '^']; | ||
const ver = v.trim(); | ||
if (ver === '*') | ||
return '*'; | ||
if (ver[0] === '~' || ver[0] === '^') | ||
return ver[0]; | ||
for (const leading of leadings) { | ||
if (ver.startsWith(leading)) | ||
return leading; | ||
} | ||
if (ver.includes('x')) { | ||
const parts = ver.split('.'); | ||
if (parts[0] === 'x') | ||
return '*'; | ||
if (parts[1] === 'x') | ||
return '^'; | ||
if (parts[2] === 'x') | ||
return '~'; | ||
} | ||
if (+ver[0] < 10) | ||
return ''; | ||
return null; | ||
} | ||
function resetRange(version, mode) { | ||
function changeVersionRange(version, mode) { | ||
if (mode === 'newest') | ||
@@ -94,2 +105,42 @@ return '*'; | ||
} | ||
function applyVersionRangePrefix(version, prefix) { | ||
if (version == null || prefix == null) | ||
return null; | ||
if (prefix === '*') | ||
return '*'; | ||
return prefix + version; | ||
} | ||
function getMaxSatisfying(versions, current, mode) { | ||
const range = changeVersionRange(current, mode); | ||
if (!range) | ||
return null; | ||
const prefix = getVersionRangePrefix(current); | ||
if (range === '*') | ||
return '*'; | ||
return applyVersionRangePrefix(semver.maxSatisfying(versions, range), prefix); | ||
} | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
try { | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
} | ||
catch (e) { | ||
versionCache[name] = { | ||
tags: {}, | ||
versions: [], | ||
error: e.statusCode || e, | ||
}; | ||
return versionCache[name]; | ||
} | ||
}); | ||
} | ||
function resolveDependency(raw, mode, filter = () => true) { | ||
@@ -101,11 +152,16 @@ return __awaiter(this, void 0, void 0, function* () { | ||
const dep = Object.assign({}, raw); | ||
const { versions, tags } = yield getLatestVersions(dep.name); | ||
const range = mode === 'latest' ? tags.latest : resetRange(dep.currentVersion, mode); | ||
if (range) { | ||
const max = semver.maxSatisfying(versions, range); | ||
// TODO: align the range | ||
dep.latestVersion = max ? `^${max}` : dep.currentVersion; | ||
dep.diff = semver.diff(semver.minVersion(dep.currentVersion), semver.minVersion(dep.latestVersion)); | ||
dep.update = dep.diff !== null; | ||
const { versions, tags, error } = yield getLatestVersions(dep.name); | ||
let max = null; | ||
if (!error) { | ||
max = mode === 'latest' | ||
? tags.latest | ||
: getMaxSatisfying(versions, dep.currentVersion, mode); | ||
} | ||
if (!error && max) { | ||
dep.latestVersion = max; | ||
const current = semver.minVersion(dep.currentVersion); | ||
const latest = semver.minVersion(dep.latestVersion); | ||
dep.diff = semver.diff(current, latest); | ||
dep.update = dep.diff !== null && semver.lt(current, latest); | ||
} | ||
else { | ||
@@ -115,2 +171,3 @@ dep.latestVersion = dep.currentVersion; | ||
dep.update = false; | ||
dep.resolveError = error !== null && error !== void 0 ? error : 'invalid_range'; | ||
} | ||
@@ -117,0 +174,0 @@ return dep; |
@@ -70,16 +70,27 @@ 'use strict'; | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
}); | ||
function getVersionRangePrefix(v) { | ||
const leadings = ['>=', '<=', '>', '<', '~', '^']; | ||
const ver = v.trim(); | ||
if (ver === '*') | ||
return '*'; | ||
if (ver[0] === '~' || ver[0] === '^') | ||
return ver[0]; | ||
for (const leading of leadings) { | ||
if (ver.startsWith(leading)) | ||
return leading; | ||
} | ||
if (ver.includes('x')) { | ||
const parts = ver.split('.'); | ||
if (parts[0] === 'x') | ||
return '*'; | ||
if (parts[1] === 'x') | ||
return '^'; | ||
if (parts[2] === 'x') | ||
return '~'; | ||
} | ||
if (+ver[0] < 10) | ||
return ''; | ||
return null; | ||
} | ||
function resetRange(version, mode) { | ||
function changeVersionRange(version, mode) { | ||
if (mode === 'newest') | ||
@@ -100,2 +111,42 @@ return '*'; | ||
} | ||
function applyVersionRangePrefix(version, prefix) { | ||
if (version == null || prefix == null) | ||
return null; | ||
if (prefix === '*') | ||
return '*'; | ||
return prefix + version; | ||
} | ||
function getMaxSatisfying(versions, current, mode) { | ||
const range = changeVersionRange(current, mode); | ||
if (!range) | ||
return null; | ||
const prefix = getVersionRangePrefix(current); | ||
if (range === '*') | ||
return '*'; | ||
return applyVersionRangePrefix(semver.maxSatisfying(versions, range), prefix); | ||
} | ||
const versionCache = {}; | ||
function getLatestVersions(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (versionCache[name]) | ||
return versionCache[name]; | ||
try { | ||
const data = yield pacote.packument(name, Object.assign({}, npmConfig)); | ||
versionCache[name] = { | ||
tags: data['dist-tags'], | ||
versions: Object.keys(data.versions || {}), | ||
}; | ||
return versionCache[name]; | ||
} | ||
catch (e) { | ||
versionCache[name] = { | ||
tags: {}, | ||
versions: [], | ||
error: e.statusCode || e, | ||
}; | ||
return versionCache[name]; | ||
} | ||
}); | ||
} | ||
function resolveDependency(raw, mode, filter = () => true) { | ||
@@ -107,11 +158,16 @@ return __awaiter(this, void 0, void 0, function* () { | ||
const dep = Object.assign({}, raw); | ||
const { versions, tags } = yield getLatestVersions(dep.name); | ||
const range = mode === 'latest' ? tags.latest : resetRange(dep.currentVersion, mode); | ||
if (range) { | ||
const max = semver.maxSatisfying(versions, range); | ||
// TODO: align the range | ||
dep.latestVersion = max ? `^${max}` : dep.currentVersion; | ||
dep.diff = semver.diff(semver.minVersion(dep.currentVersion), semver.minVersion(dep.latestVersion)); | ||
dep.update = dep.diff !== null; | ||
const { versions, tags, error } = yield getLatestVersions(dep.name); | ||
let max = null; | ||
if (!error) { | ||
max = mode === 'latest' | ||
? tags.latest | ||
: getMaxSatisfying(versions, dep.currentVersion, mode); | ||
} | ||
if (!error && max) { | ||
dep.latestVersion = max; | ||
const current = semver.minVersion(dep.currentVersion); | ||
const latest = semver.minVersion(dep.latestVersion); | ||
dep.diff = semver.diff(current, latest); | ||
dep.update = dep.diff !== null && semver.lt(current, latest); | ||
} | ||
else { | ||
@@ -121,2 +177,3 @@ dep.latestVersion = dep.currentVersion; | ||
dep.update = false; | ||
dep.resolveError = error !== null && error !== void 0 ? error : 'invalid_range'; | ||
} | ||
@@ -123,0 +180,0 @@ return dep; |
{ | ||
"name": "taze", | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"license": "MIT", | ||
@@ -9,5 +9,6 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"dev": "ts-node -O '{\"module\":\"commonjs\"}' ./src/cli.ts", | ||
"dev": "ts-node ./src/cli.ts", | ||
"build": "rollup -c", | ||
"release": "pnpx bumpp --commit --tag && pnpm build && pnpm publish && git push" | ||
"release": "pnpx bumpp --commit --tag && pnpm build && pnpm publish && git push", | ||
"test": "ava" | ||
}, | ||
@@ -38,2 +39,3 @@ "files": [ | ||
"@typescript-eslint/eslint-plugin": "^3.7.0", | ||
"ava": "^3.10.1", | ||
"eslint": "^7.5.0", | ||
@@ -49,3 +51,11 @@ "rollup": "^2.22.2", | ||
"extends": "@antfu/eslint-config-ts" | ||
}, | ||
"ava": { | ||
"extensions": [ | ||
"ts" | ||
], | ||
"require": [ | ||
"ts-node/register" | ||
] | ||
} | ||
} |
@@ -7,4 +7,19 @@ <h1 align="center">🥦 Taze<sup>𝛼</sup></h1> | ||
<p align="center">or recursive for monorepos</p> | ||
<p align="center">or recursively for <b>monorepos</b></p> | ||
<pre align="center">npx taze <b>-r</b></pre> | ||
<pre align="center">npx taze <b>-r</b></pre> | ||
## Usage | ||
## Features | ||
- Built-in support for monorepos | ||
- Update in the version range your defined by default | ||
## Alternatives | ||
`taze` is great inspired from the following tools. They work well but have different feature sets and focuses, try them out as well! | ||
- [npm-check-updates](https://github.com/raineorshine/npm-check-updates) | ||
- [npm-check](https://github.com/dylang/npm-check) |
47111
1217
24
16