@o3r/schematics
Version:
Schematics module of the Otter framework
191 lines • 11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupDependencies = exports.enforceTildeRange = exports.getPackageInstallConfig = exports.hasSetupInformation = void 0;
const node_fs_1 = require("node:fs");
const path = require("node:path");
const schematics_1 = require("@angular-devkit/schematics");
const tasks_1 = require("@angular-devkit/schematics/tasks");
const dependencies_1 = require("@schematics/angular/utility/dependencies");
const semver = require("semver");
const loaders_1 = require("../../utility/loaders");
const package_manager_runner_1 = require("../../utility/package-manager-runner");
const editor_config_1 = require("../editor-config");
/**
* Determine if the context has information regarding the setup dependencies process
* @param context Schematic context
*/
const hasSetupInformation = (context) => {
return !!context.setupDependencies;
};
exports.hasSetupInformation = hasSetupInformation;
/**
* Retrieve the package install configuration
* This is a workaround to ng-add to add the dependency to the sub-package
* @param packageJsonPath Path to the module package.json file
* @param tree Tree to read the file
* @param projectName Name of the project
* @param devDependencyOnly If true, the dependency will be added as devDependency
* @param exactO3rVersion Use a pinned version of the o3r package
*/
const getPackageInstallConfig = (packageJsonPath, tree, projectName, devDependencyOnly, exactO3rVersion) => {
if (!projectName) {
return {};
}
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, { encoding: 'utf8' }));
const workspaceProject = projectName ? (0, loaders_1.getWorkspaceConfig)(tree)?.projects[projectName] : undefined;
return {
[packageJson.name]: {
inManifest: [{
range: `${exactO3rVersion ? '' : '~'}${packageJson.version}`,
types: devDependencyOnly ? [dependencies_1.NodeDependencyType.Dev] : (0, loaders_1.getProjectNewDependenciesTypes)(workspaceProject)
}],
requireInstall: true,
ngAddOptions: { exactO3rVersion: exactO3rVersion }
}
};
};
exports.getPackageInstallConfig = getPackageInstallConfig;
/**
* Replace the caret ranges by tilde ranges
* @param range Range to replace
*/
const enforceTildeRange = (range) => {
return range?.replace(/\^/g, '~');
};
exports.enforceTildeRange = enforceTildeRange;
/**
* Setup dependency to a repository.
* Will run manually the ngAdd schematics according to the parameters and install the packages if required
* @param options
*/
const setupDependencies = (options) => {
return () => {
const ngAddToRun = new Set(Object.keys(options.dependencies)
.filter((dep) => options.ngAddToRun?.some((pattern) => typeof pattern === 'string' ? pattern === dep : pattern.test(dep))));
const isInstallRequired = Object.values(options.dependencies).some(({ requireInstall }) => requireInstall);
const isInstallNeeded = () => {
const needsInstall = Array.from(ngAddToRun).some((packageName) => !(0, package_manager_runner_1.isPackageInstalled)(packageName));
return needsInstall || (options.skipInstall === undefined ? (ngAddToRun.size > 0 || isInstallRequired) : !options.skipInstall);
};
const editPackageJson = (packageJsonPath, packageToInstall, dependency, updateLists) => {
return (tree, context) => {
if (!tree.exists(packageJsonPath)) {
context.logger.warn(`The file ${packageJsonPath} does not exist, the dependency ${packageToInstall} will not be added`);
return tree;
}
const packageJsonContent = tree.readJson(packageJsonPath);
dependency.inManifest.forEach(({ range, types }) => {
const isTildeRangeEnforced = dependency.enforceTildeRange === undefined ? (options.enforceTildeRange === undefined || options.enforceTildeRange) : dependency.enforceTildeRange;
if (isTildeRangeEnforced) {
range = (0, exports.enforceTildeRange)(range);
}
(types || [dependencies_1.NodeDependencyType.Default]).forEach((depType) => {
if (packageJsonContent[depType]?.[packageToInstall]) {
if (range && semver.validRange(range)) {
const currentMinimalVersion = semver.minVersion(packageJsonContent[depType]?.[packageToInstall]);
const myRangeMinimalVersion = semver.minVersion(range);
if (currentMinimalVersion && myRangeMinimalVersion && semver.gt(myRangeMinimalVersion, currentMinimalVersion)) {
context.logger.debug(`The dependency ${packageToInstall} (${depType}@${range}) will be added in ${packageJsonPath}`);
packageJsonContent[depType][packageToInstall] = range;
}
else {
if (updateLists) {
ngAddToRun.delete(packageToInstall);
}
context.logger.debug(`The dependency ${packageToInstall} (${depType}) is already in ${packageJsonPath}, it will not be added.`);
context.logger.debug(`Because its range is inferior or included to the current one (${range} < ${packageJsonContent[depType][packageToInstall]}) in targeted ${packageJsonPath}`);
}
}
else {
if (updateLists) {
ngAddToRun.delete(packageToInstall);
}
context.logger.warn(`The dependency ${packageToInstall} (${depType}) will not added `
+ `because there is already this dependency with a defined range (${packageJsonContent[depType][packageToInstall]}) in targeted ${packageJsonPath}`);
}
}
else {
packageJsonContent[depType] ||= {};
packageJsonContent[depType][packageToInstall] = range;
context.logger.debug(`The dependency ${packageToInstall} (${depType}@${range}) will be added in ${packageJsonPath}`);
}
packageJsonContent[depType] = Object.keys(packageJsonContent[depType])
.sort()
.reduce((acc, key) => {
acc[key] = packageJsonContent[depType][key];
return acc;
}, {});
});
});
const content = JSON.stringify(packageJsonContent, null, 2);
tree.overwrite(packageJsonPath, content);
};
};
const addDependencies = (tree) => {
const workspaceConfig = (0, loaders_1.getWorkspaceConfig)(tree);
const workspaceProject = (options.projectName && workspaceConfig?.projects?.[options.projectName]) || undefined;
const projectDirectory = workspaceProject?.root;
return (0, schematics_1.chain)(Object.entries(options.dependencies)
.map(([packageName, dependencyDetails]) => {
const shouldRunInSubPackage = projectDirectory && !dependencyDetails.toWorkspaceOnly;
const rootPackageRule = editPackageJson('package.json', packageName, dependencyDetails, !shouldRunInSubPackage);
if (shouldRunInSubPackage) {
return (0, schematics_1.chain)([
rootPackageRule,
editPackageJson(path.posix.join(projectDirectory, 'package.json'), packageName, dependencyDetails, true)
]);
}
return rootPackageRule;
}));
};
const runNgAddSchematics = (_, context) => {
const packageManager = options.packageManager || (0, package_manager_runner_1.getPackageManager)();
const installId = isInstallNeeded()
? [
context.addTask(new tasks_1.NodePackageInstallTask({ packageManager, quiet: true, workingDirectory: options.workingDirectory }), options.runAfterTasks)
]
: undefined;
if (installId !== undefined) {
context.logger.debug(`Schedule the installation of the workspace (${ngAddToRun.size > 0 ? 'for: ' + [...ngAddToRun].join(', ') : (options.skipInstall ? 'skipped' : 'forced')})`);
}
const getOptions = (packageName, schema) => {
const schemaOptions = schema?.description.schemaJson?.properties;
return Object.fromEntries(Object.entries({ projectName: options.projectName, ...options.ngAddOptions, ...options.dependencies[packageName].ngAddOptions })
.filter(([key]) => !schemaOptions || !!schemaOptions[key]));
};
const finalTaskIds = [...ngAddToRun]
.map((packageName) => {
let schematic;
try {
const collection = context.engine.createCollection(packageName);
schematic = collection.createSchematic('ng-add');
}
catch (e) {
context.logger.warn(`The package ${packageName} was not installed, the options check will be skipped`, e);
}
const schematicOptions = getOptions(packageName, schematic);
return { packageName, schematicOptions };
})
.reduce((ids, { packageName, schematicOptions }) => {
context.logger.debug(`Schedule the schematic ng-add for ${packageName}`);
return [...ids, context.addTask(new tasks_1.RunSchematicTask(packageName, 'ng-add', schematicOptions), ids)];
}, [...(installId || []), ...(options.runAfterTasks || [])]);
if ((0, exports.hasSetupInformation)(context)) {
context.setupDependencies.taskIds.push(...finalTaskIds);
}
else {
context.setupDependencies = { taskIds: finalTaskIds };
}
if (options.scheduleTaskCallback) {
options.scheduleTaskCallback(finalTaskIds);
}
};
return (0, schematics_1.chain)([
addDependencies,
runNgAddSchematics,
(0, editor_config_1.applyEditorConfig)(['json'])
]);
};
};
exports.setupDependencies = setupDependencies;
//# sourceMappingURL=dependencies.js.map