@o3r/schematics
Version:
Schematics module of the Otter framework
137 lines • 7.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ngAddPackages = ngAddPackages;
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 index_1 = require("../../utility/index");
const getNgAddSchema = (packageName, context) => {
try {
const collection = context.engine.createCollection(packageName);
return collection.createSchematic('ng-add');
}
catch {
context.logger.warn(`No ng-add found for ${packageName}`);
return undefined;
}
};
const sortDependencies = (packageJson, depType) => {
packageJson[depType] = packageJson[depType]
? Object.fromEntries(Object.entries(packageJson[depType] || {}).sort(([key1, _val1], [key2, _val2]) => key1.localeCompare(key2)))
: undefined;
};
/**
* Install via `ng add` a list of npm packages.
* @param packages List of packages to be installed via `ng add`
* @param options install options
* @param packageJsonPath path of the package json of the project where they will be installed
*/
function ngAddPackages(packages, options, packageJsonPath = '/package.json') {
if (packages.length === 0) {
return schematics_1.noop;
}
const cwd = process.cwd().replace(/[/\\]+/g, '/');
// FileSystem working directory might be different from Tree working directory (when using `yarn workspace` for example)
const fsWorkingDirectory = (options?.workingDirectory && !cwd.endsWith(options.workingDirectory)) ? options.workingDirectory : '.';
const versions = Object.fromEntries(packages.map((packageName, index) => [packageName, typeof options?.version === 'object' ? options.version[index] : options?.version]));
if (options?.workingDirectory && !packageJsonPath.startsWith(options.workingDirectory)) {
packageJsonPath = path.join(options.workingDirectory, packageJsonPath);
}
const getInstalledVersion = (packageName) => {
let versionFound;
for (const workingDirectory of new Set([fsWorkingDirectory, '.'])) {
try {
const fileSystemPackageJson = JSON.parse((0, node_fs_1.readFileSync)(path.join(workingDirectory, 'package.json'), { encoding: 'utf8' }));
let version;
if (options?.dependencyType === dependencies_1.NodeDependencyType.Dev) {
version = fileSystemPackageJson.devDependencies[packageName];
}
else if (options?.dependencyType === dependencies_1.NodeDependencyType.Peer) {
version = fileSystemPackageJson.peerDependencies[packageName];
}
else {
version = fileSystemPackageJson.dependencies[packageName];
}
if (versionFound && version !== versionFound) {
// In case of conflict between package.json files, we consider the package as not installed to force its update
return;
}
versionFound = version;
}
catch {
return;
}
}
return versionFound;
};
const getOptions = (schema) => {
const schemaOptions = schema.description.schemaJson?.properties || {};
return Object.entries(options || {}).reduce((accOptions, [key, value]) => {
if (schemaOptions[key]) {
accOptions[key] = value;
}
return accOptions;
}, {});
};
const installedVersions = packages.map((packageName) => getInstalledVersion(packageName));
const packageManager = (0, index_1.getPackageManager)();
const packagesToInstall = packages.filter((packageName, index) => !installedVersions[index] || installedVersions[index] !== versions[packageName]);
if (packagesToInstall.length === 0) {
return schematics_1.noop;
}
return (0, schematics_1.chain)([
// Update package.json in tree
(tree) => {
for (const filePath of new Set([packageJsonPath, './package.json'])) {
const packageJson = tree.readJson(filePath);
packages.forEach((packageName) => {
const version = versions[packageName] || 'latest';
if (options?.dependencyType === dependencies_1.NodeDependencyType.Dev) {
packageJson.devDependencies = { ...packageJson.devDependencies, [packageName]: version };
}
else if (options?.dependencyType === dependencies_1.NodeDependencyType.Peer) {
packageJson.peerDependencies = { ...packageJson.peerDependencies, [packageName]: version };
}
else {
packageJson.dependencies = { ...packageJson.dependencies, [packageName]: version };
}
});
['dependencies', 'devDependencies', 'peerDependencies'].forEach((depType) => {
sortDependencies(packageJson, depType);
});
tree.overwrite(filePath, JSON.stringify(packageJson, null, 2));
}
},
// Run ng-adds
async (tree, context) => {
if (options?.skipNgAddSchematicRun) {
context.logger.info(`Package(s) '${packagesToInstall.join(', ')}' was(were) installed.
The run of 'ng-add' schematics for the package(s) is intentionally skipped. You can do the run standalone, later.`);
return schematics_1.noop;
}
new Set([packageJsonPath, './package.json']).forEach((filePath) => {
(0, node_fs_1.mkdirSync)(path.join(process.cwd(), path.dirname(filePath)), { recursive: true });
(0, node_fs_1.writeFileSync)(path.join(process.cwd(), filePath), tree.readText(filePath));
});
context.addTask(new tasks_1.NodePackageInstallTask({
packageManager: packageManager,
hideOutput: false,
quiet: false
}));
await new Promise((resolve, reject) => context.engine.executePostTasks().subscribe({ next: () => { }, complete: () => resolve(), error: (errors) => reject(errors) }));
const ngAddsToApply = packagesToInstall
.map((packageName) => ({ packageName, ngAddCollection: getNgAddSchema(packageName, context) }))
.filter(({ packageName, ngAddCollection }) => {
if (!ngAddCollection) {
context.logger.info(`No ng-add schematic found for: '${packageName}'. Skipping ng add for: ${packageName}${versions[packageName] ? ' with version: ' + versions[packageName] : ''}`);
}
return !!ngAddCollection;
})
.map(({ packageName, ngAddCollection }) => (0, schematics_1.externalSchematic)(packageName, 'ng-add', getOptions(ngAddCollection)));
return (0, schematics_1.chain)(ngAddsToApply);
}
]);
}
//# sourceMappingURL=ng-add.helpers.js.map