feat(core): change the signature of createNodes to return a project root map instead of project name map (#20102)

This commit is contained in:
Craigory Coppola 2023-11-08 13:20:53 -05:00 committed by GitHub
parent c7d0d21761
commit 08a4891494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 88 additions and 64 deletions

View File

@ -1,6 +1,6 @@
# Type alias: CreateNodesFunction<T\> # Type alias: CreateNodesFunction<T\>
Ƭ **CreateNodesFunction**<`T`\>: (`projectConfigurationFile`: `string`, `options`: `T` \| `undefined`, `context`: [`CreateNodesContext`](../../devkit/documents/CreateNodesContext)) => { `externalNodes?`: `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> ; `projects?`: `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> } Ƭ **CreateNodesFunction**<`T`\>: (`projectConfigurationFile`: `string`, `options`: `T` \| `undefined`, `context`: [`CreateNodesContext`](../../devkit/documents/CreateNodesContext)) => { `externalNodes?`: `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> ; `projects?`: `Record`<`string`, `Optional`<[`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration), `"root"`\>\> }
#### Type parameters #### Type parameters
@ -27,7 +27,7 @@ Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGra
`Object` `Object`
| Name | Type | | Name | Type | Description |
| :--------------- | :------------------------------------------------------------------------------------------------- | | :--------------- | :---------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
| `externalNodes?` | `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> | | `externalNodes?` | `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> | A map of external node name -> external node. External nodes do not have a root, so the key is their name. |
| `projects?` | `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> | | `projects?` | `Record`<`string`, `Optional`<[`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration), `"root"`\>\> | A map of project root -> project configuration |

View File

@ -60,15 +60,11 @@ export const createNodes: CreateNodes = [
'**/project.json', '**/project.json',
(projectConfigurationFile: string, opts, context: CreateNodesContext) => { (projectConfigurationFile: string, opts, context: CreateNodesContext) => {
const projectConfiguration = readJson(projectConfigurationFile); const projectConfiguration = readJson(projectConfigurationFile);
const projectRoot = dirname(projectConfigurationFile); const root = dirname(projectConfigurationFile);
const projectName = projectConfiguration.name;
return { return {
projects: { projects: {
[projectName]: { [root]: projectConfiguration,
...projectConfiguration,
root: projectRoot,
},
}, },
}; };
}, },
@ -244,12 +240,10 @@ export const createNodes: CreateNodes<MyPluginOptions> = [
'**/project.json', '**/project.json',
(fileName, opts, ctx) => { (fileName, opts, ctx) => {
const root = dirname(fileName); const root = dirname(fileName);
const name = basename(fileName);
return { return {
projects: { projects: {
[name]: { [root]: {
root,
tags: opts.tagName ? [opts.tagName] : [], tags: opts.tagName ? [opts.tagName] : [],
}, },
}, },

View File

@ -37,8 +37,9 @@ export const createNodes: CreateNodes<PluginOptions> = [
return { return {
projects: { projects: {
[name]: { [root]: {
root, root,
name,
targets: { targets: {
build: { build: {
executor: "nx:run-commands", executor: "nx:run-commands",

View File

@ -40,7 +40,7 @@ describe('nx package.json workspaces plugin', () => {
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"root": { ".": {
"name": "root", "name": "root",
"projectType": "library", "projectType": "library",
"root": ".", "root": ".",
@ -68,7 +68,7 @@ describe('nx package.json workspaces plugin', () => {
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"lib-a": { "packages/lib-a": {
"name": "lib-a", "name": "lib-a",
"projectType": "library", "projectType": "library",
"root": "packages/lib-a", "root": "packages/lib-a",
@ -96,7 +96,7 @@ describe('nx package.json workspaces plugin', () => {
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"lib-b": { "packages/lib-b": {
"implicitDependencies": [ "implicitDependencies": [
"lib-a", "lib-a",
], ],

View File

@ -30,13 +30,14 @@ export function getNxPackageJsonWorkspacesPlugin(root: string): NxPluginV2 {
export function createNodeFromPackageJson(pkgJsonPath: string, root: string) { export function createNodeFromPackageJson(pkgJsonPath: string, root: string) {
const json: PackageJson = readJsonFile(join(root, pkgJsonPath)); const json: PackageJson = readJsonFile(join(root, pkgJsonPath));
return { const project = buildProjectConfigurationFromPackageJson(
projects: {
[json.name]: buildProjectConfigurationFromPackageJson(
json, json,
pkgJsonPath, pkgJsonPath,
readNxJson(root) readNxJson(root)
), );
return {
projects: {
[project.root]: project,
}, },
}; };
} }

View File

@ -56,30 +56,42 @@ function readAngularJson(angularCliWorkspaceRoot: string) {
} }
export function toNewFormat(w: any): ProjectsConfigurations { export function toNewFormat(w: any): ProjectsConfigurations {
Object.values(w.projects || {}).forEach((projectConfig: any) => { if (!w.projects) {
return w;
}
for (const name in w.projects ?? {}) {
const projectConfig = w.projects[name];
if (projectConfig.architect) { if (projectConfig.architect) {
renamePropertyWithStableKeys(projectConfig, 'architect', 'targets'); renamePropertyWithStableKeys(projectConfig, 'architect', 'targets');
} }
if (projectConfig.schematics) { if (projectConfig.schematics) {
renamePropertyWithStableKeys(projectConfig, 'schematics', 'generators'); renamePropertyWithStableKeys(projectConfig, 'schematics', 'generators');
} }
if (!projectConfig.name) {
projectConfig.name = name;
}
Object.values(projectConfig.targets || {}).forEach((target: any) => { Object.values(projectConfig.targets || {}).forEach((target: any) => {
if (target.builder !== undefined) { if (target.builder !== undefined) {
renamePropertyWithStableKeys(target, 'builder', 'executor'); renamePropertyWithStableKeys(target, 'builder', 'executor');
} }
}); });
}); }
if (w.schematics) { if (w.schematics) {
renamePropertyWithStableKeys(w, 'schematics', 'generators'); renamePropertyWithStableKeys(w, 'schematics', 'generators');
} }
if (w.version !== 2) { if (w.version !== 2) {
w.version = 2; w.version = 2;
} }
return w; return w;
} }
export function toOldFormat(w: any) { export function toOldFormat(w: any) {
Object.values(w.projects || {}).forEach((projectConfig: any) => { if (w.projects) {
for (const name in w.projects) {
const projectConfig = w.projects[name];
if (typeof projectConfig === 'string') { if (typeof projectConfig === 'string') {
throw new Error( throw new Error(
"'project.json' files are incompatible with version 1 workspace schemas." "'project.json' files are incompatible with version 1 workspace schemas."
@ -97,7 +109,8 @@ export function toOldFormat(w: any) {
renamePropertyWithStableKeys(target, 'executor', 'builder'); renamePropertyWithStableKeys(target, 'executor', 'builder');
} }
}); });
}); }
}
if (w.generators) { if (w.generators) {
renamePropertyWithStableKeys(w, 'generators', 'schematics'); renamePropertyWithStableKeys(w, 'generators', 'schematics');

View File

@ -39,7 +39,7 @@ describe('nx project.json plugin', () => {
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"root": { ".": {
"name": "root", "name": "root",
"root": ".", "root": ".",
"targets": { "targets": {
@ -53,7 +53,7 @@ describe('nx project.json plugin', () => {
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"lib-a": { "packages/lib-a": {
"name": "lib-a", "name": "lib-a",
"root": "packages/lib-a", "root": "packages/lib-a",
"targets": { "targets": {

View File

@ -9,13 +9,14 @@ export const CreateProjectJsonProjectsPlugin: NxPluginV2 = {
name: 'nx-core-build-project-json-nodes', name: 'nx-core-build-project-json-nodes',
createNodes: [ createNodes: [
'{project.json,**/project.json}', '{project.json,**/project.json}',
(file, _, context) => { (file, _, { workspaceRoot }) => {
const root = context.workspaceRoot; const json = readJsonFile<ProjectConfiguration>(
const json = readJsonFile<ProjectConfiguration>(join(root, file)); join(workspaceRoot, file)
);
const project = buildProjectFromProjectJson(json, file); const project = buildProjectFromProjectJson(json, file);
return { return {
projects: { projects: {
[project.name]: project, [project.root]: project,
}, },
}; };
}, },

View File

@ -114,11 +114,19 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
workspaceRoot: root, workspaceRoot: root,
}); });
for (const node in projectNodes) { for (const node in projectNodes) {
projectNodes[node].name ??= node; mergeProjectConfigurationIntoRootMap(projectRootMap, {
mergeProjectConfigurationIntoRootMap( // If root is specified in config, that will overwrite this.
projectRootMap, // Specifying it here though allows plugins to return something like
projectNodes[node] // {
); // projects: {
// [root]: { targets: buildTargetsFromFile(f) }
// }
// }
// Otherwise, the root would have to be specified in the config as well
// which would be a bit redundant.
root: node,
...projectNodes[node],
});
} }
Object.assign(externalNodes, pluginExternalNodes); Object.assign(externalNodes, pluginExternalNodes);
} }

View File

@ -40,7 +40,6 @@ import {
} from '../adapter/angular-json'; } from '../adapter/angular-json';
import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces'; import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces';
import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json'; import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json';
import { FileMapCache } from '../project-graph/nx-deps-cache';
import { CreatePackageJsonProjectsNextToProjectJson } from '../plugins/project-json/build-nodes/package-json-next-to-project-json'; import { CreatePackageJsonProjectsNextToProjectJson } from '../plugins/project-json/build-nodes/package-json-next-to-project-json';
/** /**
@ -60,7 +59,14 @@ export type CreateNodesFunction<T = unknown> = (
options: T | undefined, options: T | undefined,
context: CreateNodesContext context: CreateNodesContext
) => { ) => {
projects?: Record<string, ProjectConfiguration>; /**
* A map of project root -> project configuration
*/
projects?: Record<string, Optional<ProjectConfiguration, 'root'>>;
/**
* A map of external node name -> external node. External nodes do not have a root, so the key is their name.
*/
externalNodes?: Record<string, ProjectGraphExternalNode>; externalNodes?: Record<string, ProjectGraphExternalNode>;
}; };
@ -311,12 +317,12 @@ function ensurePluginIsV2(plugin: NxPlugin): NxPluginV2 {
createNodes: [ createNodes: [
`*/**/${combineGlobPatterns(plugin.projectFilePatterns)}`, `*/**/${combineGlobPatterns(plugin.projectFilePatterns)}`,
(configFilePath) => { (configFilePath) => {
const name = toProjectName(configFilePath); const root = dirname(configFilePath);
return { return {
projects: { projects: {
[name]: { [root]: {
name, name: toProjectName(configFilePath),
root: dirname(configFilePath), root,
targets: plugin.registerProjectTargets?.(configFilePath), targets: plugin.registerProjectTargets?.(configFilePath),
}, },
}, },
@ -535,3 +541,5 @@ function getDefaultPluginsSync(root: string): LoadedNxPlugin[] {
plugin: p, plugin: p,
})); }));
} }
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

View File

@ -88,11 +88,10 @@ export const createNodes: CreateNodes<EslintPluginOptions> = [
} }
options = normalizeOptions(options); options = normalizeOptions(options);
const projectName = basename(projectRoot);
return { return {
projects: { projects: {
[projectName]: { [projectRoot]: {
root: projectRoot, root: projectRoot,
projectType: 'library', projectType: 'library',
targets: buildEslintTargets( targets: buildEslintTargets(

View File

@ -31,11 +31,10 @@ export const createNodes: CreateNodes<<%= className %>PluginOptions> = [
} }
options = normalizeOptions(options); options = normalizeOptions(options);
const projectName = basename(projectRoot);
return { return {
projects: { projects: {
[projectName]: { [projectRoot]: {
root: projectRoot, root: projectRoot,
projectType: 'library', projectType: 'library',
targets: build<%= className %>Targets( targets: build<%= className %>Targets(