UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

125 lines (124 loc) • 5.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTouchedNpmPackages = void 0; const file_utils_1 = require("../../../../project-graph/file-utils"); const json_diff_1 = require("../../../../utils/json-diff"); const logger_1 = require("../../../../utils/logger"); const get_package_name_from_import_path_1 = require("../../../../utils/get-package-name-from-import-path"); const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGraph) => { const packageJsonChange = touchedFiles.find((f) => f.file === 'package.json'); if (!packageJsonChange) return []; const globalPackages = new Set(getGlobalPackages(nxJson.plugins)); let touched = []; const changes = packageJsonChange.getChanges(); const npmPackages = Object.values(projectGraph.externalNodes); let packagesByName; const missingTouchedNpmPackages = []; for (const c of changes) { if ((0, json_diff_1.isJsonChange)(c) && (c.path[0] === 'dependencies' || c.path[0] === 'devDependencies') && c.path.length === 2) { // A package was deleted so mark all workspace projects as touched. if (c.type === json_diff_1.JsonDiffType.Deleted) { touched = Object.keys(projectGraph.nodes); break; } else { let npmPackage = npmPackages.find((pkg) => pkg.data.packageName === c.path[1]); if (!npmPackage) { // dependency can also point to a workspace project const nodes = Object.values(projectGraph.nodes); npmPackage = nodes.find((n) => n.name === c.path[1]); } if (!npmPackage) { missingTouchedNpmPackages.push(c.path[1]); continue; } touched.push(npmPackage.name); // If it was a type declarations package then also mark its corresponding implementation package as affected if (npmPackage.name.startsWith('npm:@types/')) { const implementationNpmPackage = npmPackages.find((pkg) => pkg.data.packageName === c.path[1].substring(7)); if (implementationNpmPackage) { touched.push(implementationNpmPackage.name); } } if ('packageName' in npmPackage.data) { if (globalPackages.has(npmPackage.data.packageName)) { return Object.keys(projectGraph.nodes); } } } } else if ((0, json_diff_1.isJsonChange)(c) && (c.path[0] === 'overrides' || c.path[0] === 'resolutions' || (c.path[0] === 'pnpm' && c.path[1] === 'overrides'))) { const packageSelector = getPackageSelector(c); if (!packageSelector) continue; packagesByName ??= groupPackagesByName(npmPackages); const matchingNpmPackages = findPackagesForSelector(packageSelector, packagesByName, c.path[0] === 'pnpm'); // An unresolved selector can still target a transitive dependency, // so fall back to marking every project affected. if (!matchingNpmPackages.length) { return Object.keys(projectGraph.nodes); } if (matchingNpmPackages.some((pkg) => globalPackages.has(pkg.data.packageName))) { return Object.keys(projectGraph.nodes); } touched.push(...matchingNpmPackages.map((pkg) => pkg.name)); } else if ((0, file_utils_1.isWholeFileChange)(c)) { // Whole file was touched, so all npm packages are touched. touched = npmPackages.map((pkg) => pkg.name); break; } } if (missingTouchedNpmPackages.length) { logger_1.logger.warn(`The affected projects might have not been identified properly. The package(s) ${missingTouchedNpmPackages.join(', ')} were not found. Please open an issue in GitHub including the package.json file.`); } return [...new Set(touched)]; }; exports.getTouchedNpmPackages = getTouchedNpmPackages; function getPackageSelector(change) { if (typeof change.value.lhs !== 'string' && typeof change.value.rhs !== 'string') { return; } const selectorIndex = change.path[0] === 'pnpm' ? 2 : change.path.length - 1; const selector = change.path[selectorIndex]; return selector === '.' ? change.path[selectorIndex - 1] : selector; } function groupPackagesByName(npmPackages) { const packagesByName = new Map(); for (const pkg of npmPackages) { const packageName = pkg.data.packageName; if (!packageName) continue; const packages = packagesByName.get(packageName); if (packages) { packages.push(pkg); } else { packagesByName.set(packageName, [pkg]); } } return packagesByName; } function findPackagesForSelector(selector, packagesByName, isPnpmOverride) { if (isPnpmOverride) { // Pnpm does not treat `>` as a parent delimiter when it starts a range. const parentDelimiterIndex = selector.search(/[^ |@]>/); if (parentDelimiterIndex !== -1) { selector = selector.slice(parentDelimiterIndex + 2); } } const packageName = selector.match(/(?:^|\/)(@[^/@>\s]+\/[^/@>\s]+|[^/@>\s]+)(?:@[^/]*)?$/)?.[1]; return packageName ? (packagesByName.get(packageName) ?? []) : []; } function getGlobalPackages(plugins) { return (plugins ?? []) .map((p) => (0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(typeof p === 'string' ? p : p.plugin)) .concat('nx'); }