UNPKG

installed-check-core

Version:

Checks that all dependencies in your package.json have supported versions installed

101 lines (85 loc) 3.38 kB
import { explainVariable, typedObjectKeys } from '@voxpelli/typed-utils'; import isGlob from 'is-glob'; import { checkPackageVersions } from './check-package-versions.js'; import { checkVersions } from './check-versions.js'; /** * @typedef PerformInstalledCheckResult * @property {string[]} errors * @property {string[]} warnings * @property {string[]} suggestions * @property {import('./fix.js').Fix[]} fixes */ /** @typedef {'engine' | 'peer' | 'version'} InstalledChecks */ /** @type {Record<InstalledChecks, true>} */ const checkTypeMap = { 'engine': true, 'peer': true, 'version': true, }; const checkTypes = typedObjectKeys(checkTypeMap); /** * @typedef InstalledCheckOptions * @property {string[]|undefined} [ignore] * @property {boolean|undefined} [noDev] * @property {string|undefined} [prefix] * @property {boolean|undefined} [strict] */ /** * @param {InstalledChecks[]} checks * @param {import('./lookup-types.d.ts').PackageJsonLike} pkg * @param {import('./lookup-types.d.ts').InstalledDependencies} installed * @param {InstalledCheckOptions} [options] * @returns {Promise<PerformInstalledCheckResult>} */ export async function performInstalledCheck (checks, pkg, installed, options) { if (!checks || !Array.isArray(checks)) { throw new TypeError('Expected a "checks" array, got: ' + explainVariable(checks)); } if (!pkg || typeof pkg !== 'object') { throw new TypeError('Expected a "pkg" object, got: ' + explainVariable(pkg)); } if (!installed || typeof installed !== 'object') { throw new TypeError('Expected a "installed" object, got: ' + explainVariable(installed)); } const { ignore, prefix, ...passthroughOptions } = options || {}; const resolvedIgnores = ( ignore?.some(value => isGlob(value)) // eslint-disable-next-line unicorn/no-await-expression-member ? (await import('picomatch')).default(ignore) : ignore ); /** @type {import('./check-version-range.js').VersionRangeOptions} */ const checkOptions = { ignore: resolvedIgnores, ...passthroughOptions }; let hasCheck = false; /** @type {string[]} */ let errors = []; /** @type {string[]} */ let warnings = []; /** @type {string[]} */ let suggestions = []; /** @type {import('./fix.js').Fix[]} */ let fixes = []; const results = [ checks.includes('version') && checkPackageVersions(pkg, installed), checks.includes('engine') && checkVersions(pkg, 'engines', installed, { ...checkOptions, defaultKeys: ['node'], expectedInDependencies: true, ignoreDefinitelyTyped: true, }), checks.includes('peer') && checkVersions(pkg, 'peerDependencies', installed, checkOptions), ]; for (const result of results) { if (result) { hasCheck = true; errors = [...errors, ...(prefix ? result.errors.map(note => prefix + ': ' + note) : result.errors)]; warnings = [...warnings, ...(prefix ? result.warnings.map(note => prefix + ': ' + note) : result.warnings)]; suggestions = [...suggestions, ...(prefix ? result.suggestions.map(note => prefix + ': ' + note) : result.suggestions)]; fixes = [...fixes, ...result.fixes]; } } if (!hasCheck) { throw new Error('Expected to run at least one check. "checks" should include at least one of: ' + checkTypes.join(', ')); } return { errors, warnings, suggestions, fixes }; }