nx
Version:
208 lines (207 loc) • 9.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNodesV2 = void 0;
exports.buildPackageJsonWorkspacesMatcher = buildPackageJsonWorkspacesMatcher;
exports.createNodeFromPackageJson = createNodeFromPackageJson;
exports.buildProjectConfigurationFromPackageJson = buildProjectConfigurationFromPackageJson;
exports.getGlobPatternsFromPackageManagerWorkspaces = getGlobPatternsFromPackageManagerWorkspaces;
const minimatch_1 = require("minimatch");
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const nx_json_1 = require("../../config/nx-json");
const to_project_name_1 = require("../../config/to-project-name");
const fileutils_1 = require("../../utils/fileutils");
const globs_1 = require("../../utils/globs");
const logger_1 = require("../../utils/logger");
const output_1 = require("../../utils/output");
const package_json_1 = require("../../utils/package-json");
const path_1 = require("../../utils/path");
const plugins_1 = require("../../project-graph/plugins");
const path_2 = require("path");
const file_hasher_1 = require("../../hasher/file-hasher");
const package_json_2 = require("../../../plugins/package-json");
exports.createNodesV2 = [
(0, globs_1.combineGlobPatterns)('package.json', '**/package.json', 'project.json', '**/project.json'),
(configFiles, _, context) => {
const { packageJsons, projectJsonRoots } = splitConfigFiles(configFiles);
const readJson = (f) => (0, fileutils_1.readJsonFile)((0, node_path_1.join)(context.workspaceRoot, f));
const isInPackageJsonWorkspaces = buildPackageJsonWorkspacesMatcher(context.workspaceRoot, readJson);
const isNextToProjectJson = (packageJsonPath) => {
return projectJsonRoots.has((0, node_path_1.dirname)(packageJsonPath));
};
const cache = (0, package_json_2.readPackageJsonConfigurationCache)();
return (0, plugins_1.createNodesFromFiles)((packageJsonPath, options, context) => {
const isInPackageManagerWorkspaces = isInPackageJsonWorkspaces(packageJsonPath);
if (!isInPackageManagerWorkspaces &&
!isNextToProjectJson(packageJsonPath)) {
// Skip if package.json is not part of the package.json workspaces and not next to a project.json.
return null;
}
return createNodeFromPackageJson(packageJsonPath, context.workspaceRoot, cache, isInPackageManagerWorkspaces);
}, packageJsons, _, context);
},
];
function splitConfigFiles(configFiles) {
const packageJsons = [];
const projectJsonRoots = new Set();
for (const configFile of configFiles) {
if ((0, path_2.basename)(configFile) === 'package.json') {
packageJsons.push(configFile);
}
else {
projectJsonRoots.add((0, node_path_1.dirname)(configFile));
}
}
return { packageJsons, projectJsonRoots };
}
function buildPackageJsonWorkspacesMatcher(workspaceRoot, readJson) {
const patterns = getGlobPatternsFromPackageManagerWorkspaces(workspaceRoot, readJson);
const negativePatterns = patterns.filter((p) => p.startsWith('!'));
const positivePatterns = patterns.filter((p) => !p.startsWith('!'));
if (
// There are some negative patterns
negativePatterns.length > 0 &&
// No positive patterns
(positivePatterns.length === 0 ||
// Or only a single positive pattern that is the default coming from root package
(positivePatterns.length === 1 && positivePatterns[0] === 'package.json'))) {
positivePatterns.push('**/package.json');
}
return (p) => positivePatterns.some((positive) => (0, minimatch_1.minimatch)(p, positive)) &&
/**
* minimatch will return true if the given p is NOT excluded by the negative pattern.
*
* For example if the negative pattern is "!packages/vite", then the given p "packages/vite" will return false,
* the given p "packages/something-else/package.json" will return true.
*
* Therefore, we need to ensure that every negative pattern returns true to validate that the given p is not
* excluded by any of the negative patterns.
*/
negativePatterns.every((negative) => (0, minimatch_1.minimatch)(p, negative));
}
function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackageManagerWorkspaces) {
const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, pkgJsonPath));
const projectRoot = (0, node_path_1.dirname)(pkgJsonPath);
const hash = (0, file_hasher_1.hashObject)({
...json,
root: projectRoot,
isInPackageManagerWorkspaces,
});
const cached = cache[hash];
if (cached) {
return {
projects: {
[cached.root]: cached,
},
};
}
const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, (0, nx_json_1.readNxJson)(workspaceRoot), isInPackageManagerWorkspaces);
cache[hash] = project;
return {
projects: {
[project.root]: project,
},
};
}
function buildProjectConfigurationFromPackageJson(packageJson, workspaceRoot, packageJsonPath, nxJson, isInPackageManagerWorkspaces) {
const normalizedPath = packageJsonPath.split('\\').join('/');
const projectRoot = (0, node_path_1.dirname)(normalizedPath);
const siblingProjectJson = tryReadJson((0, node_path_1.join)(workspaceRoot, projectRoot, 'project.json'));
if (siblingProjectJson) {
for (const target of Object.keys(siblingProjectJson?.targets ?? {})) {
const { executor, command, options } = siblingProjectJson.targets[target];
if (
// will use run-commands, different target
command ||
// Either uses a different executor or runs a different script
(executor &&
(executor !== 'nx:run-script' || options?.script !== target))) {
delete packageJson.scripts?.[target];
}
}
}
if (!packageJson.name && projectRoot === '.') {
throw new Error('Nx requires the root package.json to specify a name if it is being used as an Nx project.');
}
let name = packageJson.name ?? (0, to_project_name_1.toProjectName)(normalizedPath);
const projectConfiguration = {
root: projectRoot,
sourceRoot: projectRoot,
name,
...packageJson.nx,
targets: (0, package_json_1.readTargetsFromPackageJson)(packageJson, nxJson),
tags: (0, package_json_1.getTagsFromPackageJson)(packageJson),
metadata: (0, package_json_1.getMetadataFromPackageJson)(packageJson, isInPackageManagerWorkspaces),
};
if (nxJson?.workspaceLayout?.appsDir != nxJson?.workspaceLayout?.libsDir &&
nxJson?.workspaceLayout?.appsDir &&
projectRoot.startsWith(nxJson.workspaceLayout.appsDir)) {
projectConfiguration.projectType = 'application';
}
else if (typeof nxJson?.workspaceLayout?.libsDir !== 'undefined' &&
projectRoot.startsWith(nxJson.workspaceLayout.libsDir)) {
projectConfiguration.projectType = 'library';
}
return projectConfiguration;
}
/**
* Get the package.json globs from package manager workspaces
*/
function getGlobPatternsFromPackageManagerWorkspaces(root,
// allow overwriting these args so we can use them in devkit
readJson = (path) => (0, fileutils_1.readJsonFile)((0, node_path_1.join)(root, path)), readYaml = (path) => (0, fileutils_1.readYamlFile)((0, node_path_1.join)(root, path)), exists = (p) => (0, node_fs_1.existsSync)((0, node_path_1.join)(root, p))) {
try {
const patterns = [];
const packageJson = readJson('package.json');
patterns.push(...normalizePatterns(Array.isArray(packageJson.workspaces)
? packageJson.workspaces
: packageJson.workspaces?.packages ?? []));
if (exists('pnpm-workspace.yaml')) {
try {
const { packages } = readYaml('pnpm-workspace.yaml') ?? {};
patterns.push(...normalizePatterns(packages || []));
}
catch (e) {
output_1.output.warn({
title: `${logger_1.NX_PREFIX} Unable to parse pnpm-workspace.yaml`,
bodyLines: [e.toString()],
});
}
}
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(root, 'lerna.json'))) {
try {
const { packages } = readJson('lerna.json') ?? {};
patterns.push(...normalizePatterns(packages?.length > 0 ? packages : ['packages/*']));
}
catch (e) {
output_1.output.warn({
title: `${logger_1.NX_PREFIX} Unable to parse lerna.json`,
bodyLines: [e.toString()],
});
}
}
// Merge patterns from workspaces definitions
// TODO(@AgentEnder): update logic after better way to determine root project inclusion
// Include the root project
return packageJson.nx ? patterns.concat('package.json') : patterns;
}
catch {
return [];
}
}
function normalizePatterns(patterns) {
return patterns.map((pattern) => removeRelativePath(pattern.endsWith('/package.json')
? pattern
: (0, path_1.joinPathFragments)(pattern, 'package.json')));
}
function removeRelativePath(pattern) {
return pattern.startsWith('./') ? pattern.substring(2) : pattern;
}
function tryReadJson(path) {
try {
return (0, fileutils_1.readJsonFile)(path);
}
catch {
return null;
}
}