fix(core): change graph node type and name to string (#29610)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Emily Xiong 2025-03-04 16:41:11 -05:00 committed by GitHub
parent 437bad4aac
commit 04cf098d59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 74 additions and 52 deletions

View File

@ -14,8 +14,8 @@ while allowing tracking of the full tree of different nested versions
### Properties
- [data](../../devkit/documents/ProjectGraphExternalNode#data): Object
- [name](../../devkit/documents/ProjectGraphExternalNode#name): `npm:${string}`
- [type](../../devkit/documents/ProjectGraphExternalNode#type): "npm"
- [name](../../devkit/documents/ProjectGraphExternalNode#name): string
- [type](../../devkit/documents/ProjectGraphExternalNode#type): string
## Properties
@ -35,10 +35,10 @@ while allowing tracking of the full tree of different nested versions
### name
**name**: \`npm:$\{string}\`
**name**: `string`
---
### type
**type**: `"npm"`
**type**: `string`

View File

@ -50,6 +50,7 @@ import {
matchImportWithWildcard,
stringifyTags,
} from '../utils/runtime-lint-utils';
import { isProjectGraphProjectNode } from 'nx/src/config/project-graph';
export type Options = [
{
@ -525,6 +526,11 @@ export default ESLintUtils.RuleCreator(
return;
}
if (!isProjectGraphProjectNode(targetProject)) {
return;
}
targetProject = targetProject as ProjectGraphProjectNode;
// check constraints between libs and apps
// check for circular dependency
const circularPath = checkCircularPath(

View File

@ -14,7 +14,7 @@ describe('updatePaths', () => {
const deps: DependentBuildableProjectNode[] = [
{
name: '@proj/lib',
node: { data: { root: 'libs/lib' } } as any,
node: { type: 'lib', data: { root: 'libs/lib' } } as any,
outputs: ['dist/libs/lib'],
},
];

View File

@ -9,7 +9,6 @@ import {
parseTargetString,
readJsonFile,
stripIndents,
workspaceRoot,
writeJsonFile,
} from '@nx/devkit';
import { unlinkSync } from 'fs';
@ -20,6 +19,10 @@ import { dirname, join, relative, extname, resolve } from 'path';
import type * as ts from 'typescript';
import { readTsConfigPaths } from './typescript/ts-config';
import { randomUUID } from 'crypto';
import {
isProjectGraphExternalNode,
isProjectGraphProjectNode,
} from 'nx/src/config/project-graph';
function isBuildable(target: string, node: ProjectGraphProjectNode): boolean {
return (
@ -112,7 +115,7 @@ export function calculateProjectDependencies(
.map(({ name: dep, isTopLevel }) => {
let project: DependentBuildableProjectNode = null;
const depNode = projGraph.nodes[dep] || projGraph.externalNodes[dep];
if (depNode.type === 'lib') {
if (isProjectGraphProjectNode(depNode) && depNode.type === 'lib') {
if (isBuildable(targetName, depNode)) {
const libPackageJsonPath = join(
root,
@ -138,7 +141,7 @@ export function calculateProjectDependencies(
} else {
nonBuildableDependencies.push(dep);
}
} else if (depNode.type === 'npm') {
} else if (isProjectGraphExternalNode(depNode)) {
project = {
name: depNode.data.packageName,
outputs: [],
@ -530,54 +533,52 @@ export function updatePaths(
) {
const pathsKeys = Object.keys(paths);
// For each registered dependency
dependencies.forEach((dep) => {
if (dep.node.type === 'npm') {
return;
}
dependencies
.filter((dep) => isProjectGraphProjectNode(dep.node))
.forEach((dep) => {
// If there are outputs
if (dep.outputs && dep.outputs.length > 0) {
// Directly map the dependency name to the output paths (dist/packages/..., etc.)
paths[dep.name] = dep.outputs;
// If there are outputs
if (dep.outputs && dep.outputs.length > 0) {
// Directly map the dependency name to the output paths (dist/packages/..., etc.)
paths[dep.name] = dep.outputs;
// check for secondary entrypoints
// For each registered path
for (const path of pathsKeys) {
const nestedName = `${dep.name}/`;
// check for secondary entrypoints
// For each registered path
for (const path of pathsKeys) {
const nestedName = `${dep.name}/`;
// If the path points to the current dependency and is nested (/)
if (path.startsWith(nestedName)) {
const nestedPart = path.slice(nestedName.length);
// If the path points to the current dependency and is nested (/)
if (path.startsWith(nestedName)) {
const nestedPart = path.slice(nestedName.length);
// Bind potential secondary endpoints for ng-packagr projects
let mappedPaths = dep.outputs.map(
(output) => `${output}/${nestedPart}`
);
// Bind potential secondary endpoints for ng-packagr projects
let mappedPaths = dep.outputs.map(
(output) => `${output}/${nestedPart}`
);
const { root } = (dep.node as ProjectGraphProjectNode).data;
// Update nested mappings to point to the dependency's output paths
mappedPaths = mappedPaths.concat(
paths[path].flatMap((p) =>
dep.outputs.flatMap((output) => {
const basePath = p.replace(root, output);
return [
// extension-less path to support compiled output
basePath.replace(
new RegExp(`${extname(basePath)}$`, 'gi'),
''
),
// original path with the root re-mapped to the output path
basePath,
];
})
)
);
const { root } = dep.node.data;
// Update nested mappings to point to the dependency's output paths
mappedPaths = mappedPaths.concat(
paths[path].flatMap((p) =>
dep.outputs.flatMap((output) => {
const basePath = p.replace(root, output);
return [
// extension-less path to support compiled output
basePath.replace(
new RegExp(`${extname(basePath)}$`, 'gi'),
''
),
// original path with the root re-mapped to the output path
basePath,
];
})
)
);
paths[path] = mappedPaths;
paths[path] = mappedPaths;
}
}
}
}
});
});
}
/**
@ -630,7 +631,10 @@ export function updateBuildableProjectPackageJsonDependencies(
) {
try {
let depVersion;
if (entry.node.type === 'lib') {
if (
isProjectGraphProjectNode(entry.node) &&
entry.node.type === 'lib'
) {
const outputs = getOutputsForTargetAndConfiguration(
{
project: projectName,

View File

@ -103,6 +103,12 @@ export interface ProjectGraphProjectNode {
};
}
export function isProjectGraphProjectNode(
node: ProjectGraphProjectNode | ProjectGraphExternalNode
): node is ProjectGraphProjectNode {
return node.type === 'app' || node.type === 'e2e' || node.type === 'lib';
}
/**
* A node describing an external dependency
* `name` has as form of:
@ -114,8 +120,8 @@ export interface ProjectGraphProjectNode {
*
*/
export interface ProjectGraphExternalNode {
type: 'npm';
name: `npm:${string}`;
type: string; // not app, e2e, or lib
name: string;
data: {
version: string;
packageName: string;
@ -123,6 +129,12 @@ export interface ProjectGraphExternalNode {
};
}
export function isProjectGraphExternalNode(
node: ProjectGraphProjectNode | ProjectGraphExternalNode
): node is ProjectGraphExternalNode {
return isProjectGraphProjectNode(node) === false;
}
/**
* A dependency between two projects
*/