@o3r/schematics
Version:
Schematics module of the Otter framework
204 lines • 10.4 kB
JavaScript
;
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