From 93ff15df79e796426849e7678142bcc9fd723997 Mon Sep 17 00:00:00 2001 From: AgentEnder Date: Tue, 7 Nov 2023 10:50:37 -0500 Subject: [PATCH] feat(core): change the signature of createNodes to return a project root map instead of project name map --- docs/generated/devkit/CreateNodesFunction.md | 10 ++-- .../recipes/plugins/project-graph-plugins.md | 12 ++--- e2e/plugin/src/nx-plugin.fixtures.ts | 3 +- .../plugins/package-json-workspaces.spec.ts | 6 +-- .../nx/plugins/package-json-workspaces.ts | 11 ++-- packages/nx/src/adapter/angular-json.ts | 53 ++++++++++++------- .../build-nodes/project-json.spec.ts | 4 +- .../project-json/build-nodes/project-json.ts | 9 ++-- .../utils/project-configuration-utils.ts | 18 +++++-- packages/nx/src/utils/nx-plugin.ts | 20 ++++--- .../__snapshots__/generator.spec.ts.snap | 3 +- .../files/src/plugins/plugin.ts.template | 3 +- 12 files changed, 88 insertions(+), 64 deletions(-) diff --git a/docs/generated/devkit/CreateNodesFunction.md b/docs/generated/devkit/CreateNodesFunction.md index 85a1a8a912d59..2d47929e9fd51 100644 --- a/docs/generated/devkit/CreateNodesFunction.md +++ b/docs/generated/devkit/CreateNodesFunction.md @@ -1,6 +1,6 @@ # Type alias: CreateNodesFunction -Ƭ **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 @@ -27,7 +27,7 @@ Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGra `Object` -| Name | Type | -| :--------------- | :------------------------------------------------------------------------------------------------- | -| `externalNodes?` | `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> | -| `projects?` | `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> | +| Name | Type | Description | +| :--------------- | :---------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | +| `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`, `Optional`<[`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration), `"root"`\>\> | A map of project root -> project configuration | diff --git a/docs/shared/recipes/plugins/project-graph-plugins.md b/docs/shared/recipes/plugins/project-graph-plugins.md index d3888c90e7184..a0c8788f48965 100644 --- a/docs/shared/recipes/plugins/project-graph-plugins.md +++ b/docs/shared/recipes/plugins/project-graph-plugins.md @@ -60,15 +60,11 @@ export const createNodes: CreateNodes = [ '**/project.json', (projectConfigurationFile: string, opts, context: CreateNodesContext) => { const projectConfiguration = readJson(projectConfigurationFile); - const projectRoot = dirname(projectConfigurationFile); - const projectName = projectConfiguration.name; + const root = dirname(projectConfigurationFile); return { projects: { - [projectName]: { - ...projectConfiguration, - root: projectRoot, - }, + [root]: projectConfiguration, }, }; }, @@ -244,12 +240,10 @@ export const createNodes: CreateNodes = [ '**/project.json', (fileName, opts, ctx) => { const root = dirname(fileName); - const name = basename(fileName); return { projects: { - [name]: { - root, + [root]: { tags: opts.tagName ? [opts.tagName] : [], }, }, diff --git a/e2e/plugin/src/nx-plugin.fixtures.ts b/e2e/plugin/src/nx-plugin.fixtures.ts index 0bf42cc2708de..95d05b3e9eaa1 100644 --- a/e2e/plugin/src/nx-plugin.fixtures.ts +++ b/e2e/plugin/src/nx-plugin.fixtures.ts @@ -37,8 +37,9 @@ export const createNodes: CreateNodes = [ return { projects: { - [name]: { + [root]: { root, + name, targets: { build: { executor: "nx:run-commands", diff --git a/packages/nx/plugins/package-json-workspaces.spec.ts b/packages/nx/plugins/package-json-workspaces.spec.ts index 99ee379093ca2..8fa06b6a3fbd1 100644 --- a/packages/nx/plugins/package-json-workspaces.spec.ts +++ b/packages/nx/plugins/package-json-workspaces.spec.ts @@ -40,7 +40,7 @@ describe('nx package.json workspaces plugin', () => { .toMatchInlineSnapshot(` { "projects": { - "root": { + ".": { "name": "root", "projectType": "library", "root": ".", @@ -68,7 +68,7 @@ describe('nx package.json workspaces plugin', () => { .toMatchInlineSnapshot(` { "projects": { - "lib-a": { + "packages/lib-a": { "name": "lib-a", "projectType": "library", "root": "packages/lib-a", @@ -96,7 +96,7 @@ describe('nx package.json workspaces plugin', () => { .toMatchInlineSnapshot(` { "projects": { - "lib-b": { + "packages/lib-b": { "implicitDependencies": [ "lib-a", ], diff --git a/packages/nx/plugins/package-json-workspaces.ts b/packages/nx/plugins/package-json-workspaces.ts index 6cf5e16c4feb1..e94c3fb3bf7f4 100644 --- a/packages/nx/plugins/package-json-workspaces.ts +++ b/packages/nx/plugins/package-json-workspaces.ts @@ -30,13 +30,14 @@ export function getNxPackageJsonWorkspacesPlugin(root: string): NxPluginV2 { export function createNodeFromPackageJson(pkgJsonPath: string, root: string) { const json: PackageJson = readJsonFile(join(root, pkgJsonPath)); + const project = buildProjectConfigurationFromPackageJson( + json, + pkgJsonPath, + readNxJson(root) + ); return { projects: { - [json.name]: buildProjectConfigurationFromPackageJson( - json, - pkgJsonPath, - readNxJson(root) - ), + [project.root]: project, }, }; } diff --git a/packages/nx/src/adapter/angular-json.ts b/packages/nx/src/adapter/angular-json.ts index 64a158441adec..b509554da8874 100644 --- a/packages/nx/src/adapter/angular-json.ts +++ b/packages/nx/src/adapter/angular-json.ts @@ -56,48 +56,61 @@ function readAngularJson(angularCliWorkspaceRoot: string) { } 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) { renamePropertyWithStableKeys(projectConfig, 'architect', 'targets'); } if (projectConfig.schematics) { renamePropertyWithStableKeys(projectConfig, 'schematics', 'generators'); } + if (!projectConfig.name) { + projectConfig.name = name; + } + Object.values(projectConfig.targets || {}).forEach((target: any) => { if (target.builder !== undefined) { renamePropertyWithStableKeys(target, 'builder', 'executor'); } }); - }); + } + if (w.schematics) { renamePropertyWithStableKeys(w, 'schematics', 'generators'); } if (w.version !== 2) { w.version = 2; } + return w; } export function toOldFormat(w: any) { - Object.values(w.projects || {}).forEach((projectConfig: any) => { - if (typeof projectConfig === 'string') { - throw new Error( - "'project.json' files are incompatible with version 1 workspace schemas." - ); - } - if (projectConfig.targets) { - renamePropertyWithStableKeys(projectConfig, 'targets', 'architect'); - } - if (projectConfig.generators) { - renamePropertyWithStableKeys(projectConfig, 'generators', 'schematics'); - } - delete projectConfig.name; - Object.values(projectConfig.architect || {}).forEach((target: any) => { - if (target.executor !== undefined) { - renamePropertyWithStableKeys(target, 'executor', 'builder'); + if (w.projects) { + for (const name in w.projects) { + const projectConfig = w.projects[name]; + if (typeof projectConfig === 'string') { + throw new Error( + "'project.json' files are incompatible with version 1 workspace schemas." + ); } - }); - }); + if (projectConfig.targets) { + renamePropertyWithStableKeys(projectConfig, 'targets', 'architect'); + } + if (projectConfig.generators) { + renamePropertyWithStableKeys(projectConfig, 'generators', 'schematics'); + } + delete projectConfig.name; + Object.values(projectConfig.architect || {}).forEach((target: any) => { + if (target.executor !== undefined) { + renamePropertyWithStableKeys(target, 'executor', 'builder'); + } + }); + } + } if (w.generators) { renamePropertyWithStableKeys(w, 'generators', 'schematics'); diff --git a/packages/nx/src/plugins/project-json/build-nodes/project-json.spec.ts b/packages/nx/src/plugins/project-json/build-nodes/project-json.spec.ts index 378f7e4558f7d..f4bbe1d6934d2 100644 --- a/packages/nx/src/plugins/project-json/build-nodes/project-json.spec.ts +++ b/packages/nx/src/plugins/project-json/build-nodes/project-json.spec.ts @@ -39,7 +39,7 @@ describe('nx project.json plugin', () => { .toMatchInlineSnapshot(` { "projects": { - "root": { + ".": { "name": "root", "root": ".", "targets": { @@ -53,7 +53,7 @@ describe('nx project.json plugin', () => { .toMatchInlineSnapshot(` { "projects": { - "lib-a": { + "packages/lib-a": { "name": "lib-a", "root": "packages/lib-a", "targets": { diff --git a/packages/nx/src/plugins/project-json/build-nodes/project-json.ts b/packages/nx/src/plugins/project-json/build-nodes/project-json.ts index 513bb9380a8d3..bfaa8d03fe056 100644 --- a/packages/nx/src/plugins/project-json/build-nodes/project-json.ts +++ b/packages/nx/src/plugins/project-json/build-nodes/project-json.ts @@ -9,13 +9,14 @@ export const CreateProjectJsonProjectsPlugin: NxPluginV2 = { name: 'nx-core-build-project-json-nodes', createNodes: [ '{project.json,**/project.json}', - (file, _, context) => { - const root = context.workspaceRoot; - const json = readJsonFile(join(root, file)); + (file, _, { workspaceRoot }) => { + const json = readJsonFile( + join(workspaceRoot, file) + ); const project = buildProjectFromProjectJson(json, file); return { projects: { - [project.name]: project, + [project.root]: project, }, }; }, diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.ts index dc2919beba08d..d821ec0ac9ff1 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.ts @@ -114,11 +114,19 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins( workspaceRoot: root, }); for (const node in projectNodes) { - projectNodes[node].name ??= node; - mergeProjectConfigurationIntoRootMap( - projectRootMap, - projectNodes[node] - ); + mergeProjectConfigurationIntoRootMap(projectRootMap, { + // If root is specified in config, that will overwrite this. + // Specifying it here though allows plugins to return something like + // { + // 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); } diff --git a/packages/nx/src/utils/nx-plugin.ts b/packages/nx/src/utils/nx-plugin.ts index 6b00524979086..b890afac47c86 100644 --- a/packages/nx/src/utils/nx-plugin.ts +++ b/packages/nx/src/utils/nx-plugin.ts @@ -40,7 +40,6 @@ import { } from '../adapter/angular-json'; import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces'; 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'; /** @@ -60,7 +59,14 @@ export type CreateNodesFunction = ( options: T | undefined, context: CreateNodesContext ) => { - projects?: Record; + /** + * A map of project root -> project configuration + */ + projects?: Record>; + + /** + * A map of external node name -> external node. External nodes do not have a root, so the key is their name. + */ externalNodes?: Record; }; @@ -311,12 +317,12 @@ function ensurePluginIsV2(plugin: NxPlugin): NxPluginV2 { createNodes: [ `*/**/${combineGlobPatterns(plugin.projectFilePatterns)}`, (configFilePath) => { - const name = toProjectName(configFilePath); + const root = dirname(configFilePath); return { projects: { - [name]: { - name, - root: dirname(configFilePath), + [root]: { + name: toProjectName(configFilePath), + root, targets: plugin.registerProjectTargets?.(configFilePath), }, }, @@ -535,3 +541,5 @@ function getDefaultPluginsSync(root: string): LoadedNxPlugin[] { plugin: p, })); } + +type Optional = Omit & Partial>; diff --git a/tools/workspace-plugin/src/generators/create-nodes-plugin/__snapshots__/generator.spec.ts.snap b/tools/workspace-plugin/src/generators/create-nodes-plugin/__snapshots__/generator.spec.ts.snap index d345e64ccb22b..bf06487e4c81d 100644 --- a/tools/workspace-plugin/src/generators/create-nodes-plugin/__snapshots__/generator.spec.ts.snap +++ b/tools/workspace-plugin/src/generators/create-nodes-plugin/__snapshots__/generator.spec.ts.snap @@ -88,11 +88,10 @@ export const createNodes: CreateNodes = [ } options = normalizeOptions(options); - const projectName = basename(projectRoot); return { projects: { - [projectName]: { + [projectRoot]: { root: projectRoot, projectType: 'library', targets: buildEslintTargets( diff --git a/tools/workspace-plugin/src/generators/create-nodes-plugin/files/src/plugins/plugin.ts.template b/tools/workspace-plugin/src/generators/create-nodes-plugin/files/src/plugins/plugin.ts.template index 3a7fa16c73185..8dbcfa926f667 100644 --- a/tools/workspace-plugin/src/generators/create-nodes-plugin/files/src/plugins/plugin.ts.template +++ b/tools/workspace-plugin/src/generators/create-nodes-plugin/files/src/plugins/plugin.ts.template @@ -31,11 +31,10 @@ export const createNodes: CreateNodes<<%= className %>PluginOptions> = [ } options = normalizeOptions(options); - const projectName = basename(projectRoot); return { projects: { - [projectName]: { + [projectRoot]: { root: projectRoot, projectType: 'library', targets: build<%= className %>Targets(