UNPKG

@o3r/schematics

Version:

Schematics module of the Otter framework

204 lines • 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.enforceTildeRange = void 0; exports.getExternalDependenciesVersionRange = getExternalDependenciesVersionRange; exports.isRangeGreater = isRangeGreater; exports.getDependencyMaximumVersionRange = getDependencyMaximumVersionRange; exports.getVersionToInstallFromPackageJson = getVersionToInstallFromPackageJson; exports.isDependencyAlreadyInstalled = isDependencyAlreadyInstalled; exports.getNodeDependencyList = getNodeDependencyList; exports.getExternalDependenciesInfo = getExternalDependenciesInfo; const tslib_1 = require("tslib"); const fs = tslib_1.__importStar(require("node:fs")); const dependencies_1 = require("@schematics/angular/utility/dependencies"); const semver_1 = require("semver"); const error_1 = require("./error"); /** * Method to extract the provided package version range from a package.json file * Look for the range based on this order of priority: * - generatorDependencies * - peerDependencies * - dependencies * - devDependencies * @param packageNames list of package we want to retrieve the version * @param packageJsonPath Path to the package.json to refer to * @param logger logger * @returns The version range value retrieved from the provided package.json file */ function getExternalDependenciesVersionRange(packageNames, packageJsonPath, logger) { const packageJsonContent = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' })); return packageNames.reduce((acc, packageName) => { acc[packageName] = packageJsonContent.generatorDependencies?.[packageName] || packageJsonContent.peerDependencies?.[packageName] || packageJsonContent.dependencies?.[packageName] || packageJsonContent.devDependencies?.[packageName]; if (!acc[packageName]) { logger.warn(`Unable to retrieve version for ${packageName} in ${packageJsonPath}. Version set to "latest".`); acc[packageName] = 'latest'; } return acc; }, {}); } /** * Replace the caret ranges by tilde ranges * @param range Range to replace */ const enforceTildeRange = (range) => range === 'latest' ? range : range?.replace(/\^/g, '~'); exports.enforceTildeRange = enforceTildeRange; /** * Return true if B is a subset of A or if minVersion of A is greater than minVersion of B * @param rangeA * @param rangeB */ function isRangeGreater(rangeA, rangeB) { if (rangeA === 'latest' && rangeB !== 'latest') { return true; } if (rangeB === 'latest') { return false; } const minVersionA = (0, semver_1.minVersion)(rangeA); const minVersionB = (0, semver_1.minVersion)(rangeB); const isBPreleaseOfVersionA = minVersionB.prerelease?.length > 0 && (0, semver_1.subset)(`${minVersionB.major}.${minVersionB.minor}.${minVersionB.patch}`, rangeA); return (0, semver_1.subset)(rangeB, rangeA) || isBPreleaseOfVersionA || ((0, semver_1.gt)(minVersionA, minVersionB) && !(0, semver_1.subset)(rangeA, rangeB)); } /** * Compute the version range for a package based on the less restrictive version declared in the package.json. * If the versions declared in the package.json do not intersect, take the highest version. * @param packageName * @param packageJsonContent * @param isTildeEnforced */ function getDependencyMaximumVersionRange(packageName, packageJsonContent, isTildeEnforced) { const rangeSortedByHighestMinimum = [ packageJsonContent.peerDependencies?.[packageName], packageJsonContent.dependencies?.[packageName], packageJsonContent.devDependencies?.[packageName] ] .map((packageVersion) => isTildeEnforced && packageVersion ? (0, exports.enforceTildeRange)(packageVersion) : packageVersion) .filter((packageVersion) => { return (0, semver_1.valid)(packageVersion) !== null || (0, semver_1.validRange)(packageVersion) !== null; }) .toSorted((rangeA, rangeB) => isRangeGreater(rangeB, rangeA) ? 1 : (isRangeGreater(rangeA, rangeB) ? -1 : 0)); return rangeSortedByHighestMinimum[0]; } /** * Find the range for this package based on the generatorDependency object of the package.json * If there are no specified generator dependency, look for the range with the highest minimum or the widest range * @param packageName * @param packageJsonPath * @param isTildeEnforced */ function getVersionToInstallFromPackageJson(packageName, packageJsonPath, isTildeEnforced) { const packageJsonContent = (JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' }))); return packageJsonContent.generatorDependencies?.[packageName] ?? getDependencyMaximumVersionRange(packageName, packageJsonContent, isTildeEnforced); } /** * Check if a dependency has already been installed for the requested range * @param depName * @param packageJson * @param root0 * @param root0.range * @param root0.types */ function isDependencyAlreadyInstalled(depName, packageJson, { range, types }) { const packageJsonDepVersions = types?.map((type) => (packageJson[type] || {})[depName]); return packageJsonDepVersions.some((version) => !!version && ((0, semver_1.satisfies)(version, range, { includePrerelease: true }) || (0, semver_1.subset)(version, range, { includePrerelease: true }))); } /** * Method used to build the list of node dependencies to be installed * @param dependenciesVersions map of dependency and its associated required version * @param type node type of the dependency * @returns the list of node dependencies to be installed */ function getNodeDependencyList(dependenciesVersions, type) { return Object.entries(dependenciesVersions).map(([name, version]) => ({ name, version, type, overwrite: true })); } /** * Retrieves information about external dependencies (peer and dev) for a given project. * @template T - Type of the dependency names. * @template U - Type of the dev dependency names. * @param params - The parameters object. * @param params.dependenciesToInstall - Array of external peer dependency names. * @param params.devDependenciesToInstall - Array of external dev dependency names. * @param params.o3rPackageJsonPath - The path to the o3r `package.json` file. * @param params.projectPackageJson - The path to the package json of the project where the dependencies will be installed. * @param params.projectType - The angular type of the project, either 'application' or 'library'. * @param params.rootPackageJsonPath - Path to the root of the repository where the dependency will be installed * @param logger - The logger instance for logging information. * @param isInstallRequired - Whether the package should be installed or not. By default, return true. */ function getExternalDependenciesInfo({ dependenciesToInstall, devDependenciesToInstall, o3rPackageJsonPath, projectPackageJson, projectType, rootPackageJsonPath }, logger, isInstallRequired = (_) => undefined) { if (!projectPackageJson) { throw new error_1.O3rCliError(`Cannot install a dependency as there is no package.json in the project. ${JSON.stringify(dependenciesToInstall)} - Cannot install a dependency as there is no package.json in the project. ${JSON.stringify(devDependenciesToInstall)}`); } const rootPath = rootPackageJsonPath || 'package.json'; const peerDependenciesInfo = dependenciesToInstall.reduce((acc, name) => { const rootVersion = [ name, ...name.startsWith('@angular/') && !['@angular/cdk', '@angular/material'].includes(name) ? ['@angular/core'] : [], ...name.startsWith('@angular-devkit/') && name !== '@angular-devkit/architect' ? ['@angular-devkit/core'] : [], ...name.startsWith('@ngrx/') ? ['@ngrx/store'] : [] ] .map((packageName) => getVersionToInstallFromPackageJson(packageName, rootPath, false)) .find((version) => typeof version === 'string'); let range = rootVersion || getVersionToInstallFromPackageJson(name, o3rPackageJsonPath, true); if (typeof range !== 'string') { logger?.warn(`Unable to retrieve version for ${name} in ${o3rPackageJsonPath}. Version set to "latest".`); range = 'latest'; } const inManifest = { range, types: projectType === 'application' ? [dependencies_1.NodeDependencyType.Default] : [dependencies_1.NodeDependencyType.Peer, dependencies_1.NodeDependencyType.Dev] }; if (isDependencyAlreadyInstalled(name, projectPackageJson, inManifest)) { return acc; } acc[name] = { // Tilde is handled in the range returned by getDependencyMaximumVersionRange enforceTildeRange: false, inManifest: [inManifest], requireInstall: isInstallRequired(name) }; return acc; }, {}); const devDependenciesInfo = devDependenciesToInstall.reduce((acc, name) => { const rootVersion = [ name, ...name.startsWith('@angular/') ? ['@angular/core'] : [], ...name.startsWith('@angular-devkit/') && name !== '@angular-devkit/architect' ? ['@angular-devkit/core'] : [], ...name.startsWith('@ngrx/') ? ['@ngrx/store'] : [] ] .map((packageName) => getVersionToInstallFromPackageJson(packageName, rootPath, false)) .find((version) => typeof version === 'string'); let range = rootVersion || getVersionToInstallFromPackageJson(name, o3rPackageJsonPath, true); if (typeof range !== 'string') { logger?.warn(`Unable to retrieve version for ${name} in ${o3rPackageJsonPath}. Version set to "latest".`); range = 'latest'; } const inManifest = { range, types: [dependencies_1.NodeDependencyType.Dev] }; if (isDependencyAlreadyInstalled(name, projectPackageJson, inManifest)) { return acc; } acc[name] = { // Tilde is handled in the range returned by getDependencyMaximumVersionRange enforceTildeRange: false, inManifest: [inManifest], requireInstall: isInstallRequired(name) }; return acc; }, {}); return { ...peerDependenciesInfo, ...devDependenciesInfo }; } //# sourceMappingURL=dependencies.js.map