UNPKG

@o3r/schematics

Version:

Schematics module of the Otter framework

185 lines • 9.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ngAddPackages = ngAddPackages; exports.ngAddDependenciesRule = ngAddDependenciesRule; const tslib_1 = require("tslib"); const node_fs_1 = require("node:fs"); const path = tslib_1.__importStar(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 dependencies_2 = require("./dependencies"); 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] || {}).toSorted(([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); } ]); } /** * Add dependencies to the project during ng add process * @param options * @param packageJsonPath * @param deps */ function ngAddDependenciesRule(options, packageJsonPath, deps) { return async (tree, context) => { const { dependenciesToInstall = [], devDependenciesToInstall = [], additionalNgAddToRun = [] } = await (typeof deps === 'function' ? deps(options, tree, context) : deps); const depsInfo = (0, index_1.getO3rPeerDeps)(packageJsonPath); const workspaceProject = options.projectName ? (0, index_1.getWorkspaceConfig)(tree)?.projects[options.projectName] : undefined; const projectDirectory = workspaceProject?.root || '.'; const projectPackageJson = tree.readJson(path.posix.join(projectDirectory, 'package.json')); depsInfo.o3rPeerDeps.push(...additionalNgAddToRun.filter((dep) => !depsInfo.o3rPeerDeps.includes(dep))); const internalDependencies = depsInfo.o3rPeerDeps.reduce((acc, dep) => { acc[dep] = { inManifest: [{ range: `${options.exactO3rVersion ? '' : '~'}${depsInfo.packageVersion}`, types: (0, index_1.getProjectNewDependenciesTypes)(workspaceProject) }], ngAddOptions: { exactO3rVersion: options.exactO3rVersion } }; return acc; }, (0, dependencies_2.getPackageInstallConfig)(packageJsonPath, tree, options.projectName, false, !!options.exactO3rVersion)); const externalDependenciesInfo = (0, index_1.getExternalDependenciesInfo)({ devDependenciesToInstall, dependenciesToInstall, o3rPackageJsonPath: packageJsonPath, projectType: workspaceProject?.projectType, projectPackageJson }, context.logger); const dependencies = { ...internalDependencies, ...externalDependenciesInfo }; return (0, schematics_1.chain)([ (0, dependencies_2.setupDependencies)({ projectName: options.projectName, skipInstall: options.skipInstall, dependencies, ngAddToRun: depsInfo.o3rPeerDeps }) ]); }; } //# sourceMappingURL=ng-add-helpers.js.map