diff --git a/packages/devkit/src/utils/add-plugin.spec.ts b/packages/devkit/src/utils/add-plugin.spec.ts index 10fad482fc358..6a8135d929330 100644 --- a/packages/devkit/src/utils/add-plugin.spec.ts +++ b/packages/devkit/src/utils/add-plugin.spec.ts @@ -10,7 +10,7 @@ import { addPlugin, generateCombinations } from './add-plugin'; describe('addPlugin', () => { let tree: Tree; - let createNodes: CreateNodes; + let createNodes: CreateNodes<{ targetName: string }>; let graph: ProjectGraph; let fs: TempFs; @@ -30,9 +30,27 @@ describe('addPlugin', () => { targets: {}, }, }, + app2: { + name: 'app2', + type: 'app', + data: { + root: 'app2', + targets: {}, + }, + }, + app3: { + name: 'app3', + type: 'app', + data: { + root: 'app3', + targets: {}, + }, + }, }, dependencies: { app1: [], + app2: [], + app3: [], }, }; createNodes = [ @@ -45,12 +63,19 @@ describe('addPlugin', () => { [targetName]: { command: 'next build' }, }, }, + app2: { + name: 'app2', + targets: { + [targetName]: { command: 'next build' }, + }, + }, }, }), ]; await fs.createFiles({ 'app1/next.config.js': '', + 'app2/next.config.js': '', }); }); @@ -61,6 +86,10 @@ describe('addPlugin', () => { describe('adding the plugin', () => { it('should not conflicting with the existing graph', async () => { graph.nodes.app1.data.targets.build = {}; + graph.nodes.app2.data.targets.build1 = {}; + // app 3 doesn't have a next config, so it having this + // target should not affect the plugin options + graph.nodes.app3.data.targets.build2 = {}; await addPlugin( tree, @@ -69,7 +98,7 @@ describe('addPlugin', () => { createNodes, { - targetName: ['build', '_build'], + targetName: ['build', 'build1', 'build2'], }, true ); @@ -77,7 +106,7 @@ describe('addPlugin', () => { expect(readJson(tree, 'nx.json').plugins).toContainEqual({ plugin: '@nx/next/plugin', options: { - targetName: '_build', + targetName: 'build2', }, }); }); @@ -372,6 +401,7 @@ describe('addPlugin', () => { }); }); }); + describe('generateCombinations', () => { it('should return all combinations for a 2x2 array of strings', () => { const input = { diff --git a/packages/devkit/src/utils/convert-nx-executor.ts b/packages/devkit/src/utils/convert-nx-executor.ts index 3fcfd6bdc8b48..242cdef0e00a4 100644 --- a/packages/devkit/src/utils/convert-nx-executor.ts +++ b/packages/devkit/src/utils/convert-nx-executor.ts @@ -3,11 +3,14 @@ import type { Executor, ExecutorContext } from 'nx/src/config/misc-interfaces'; import type { ProjectsConfigurations } from 'nx/src/devkit-exports'; import { requireNx } from '../../nx'; +import { NX_VERSION } from './package-json'; +import { lt } from 'semver'; const { Workspaces, readNxJsonFromDisk, retrieveProjectConfigurationsWithAngularProjects, + readProjectConfigurationsFromRootMap, } = requireNx(); /** @@ -32,7 +35,24 @@ export function convertNxExecutor(executor: Executor) { projects: await retrieveProjectConfigurationsWithAngularProjects( builderContext.workspaceRoot, nxJsonConfiguration - ).then((p) => (p as any).projectNodes ?? p.projects), + ).then((p) => { + if ((p as any).projectNodes) { + return (p as any).projectNodes; + } + // v18.3.4 changed projects to be keyed by root + // rather than project name + if (lt(NX_VERSION, '18.3.4')) { + return p.projects; + } + + if (readProjectConfigurationsFromRootMap) { + return readProjectConfigurationsFromRootMap(p.projects); + } + + throw new Error( + 'Unable to successfully map Nx executor -> Angular Builder' + ); + }), } : // TODO(v19): remove retrieveProjectConfigurations. This is to be backwards compatible with Nx 16.5 and below. (workspaces as any).readProjectsConfigurations({ diff --git a/packages/nx/src/config/workspaces.spec.ts b/packages/nx/src/config/workspaces.spec.ts index f7145e5fc5b60..99d55af978040 100644 --- a/packages/nx/src/config/workspaces.spec.ts +++ b/packages/nx/src/config/workspaces.spec.ts @@ -52,7 +52,7 @@ describe('Workspaces', () => { } ); console.log(projects); - expect(projects['my-package']).toEqual({ + expect(projects['packages/my-package']).toEqual({ name: 'my-package', root: 'packages/my-package', sourceRoot: 'packages/my-package', diff --git a/packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts b/packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts index 3d09d9ff0a5ef..8616b1eff8ac1 100644 --- a/packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts +++ b/packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts @@ -234,29 +234,29 @@ async function processFilesAndCreateAndSerializeProjectGraph( const nxJson = readNxJson(workspaceRoot); global.NX_GRAPH_CREATION = true; - let graphNodes: ConfigurationResult; + let projectConfigurationsResult: ConfigurationResult; let projectConfigurationsError; try { - graphNodes = await retrieveProjectConfigurations( + projectConfigurationsResult = await retrieveProjectConfigurations( plugins, workspaceRoot, nxJson ); } catch (e) { if (e instanceof ProjectConfigurationsError) { - graphNodes = e.partialProjectConfigurationsResult; + projectConfigurationsResult = e.partialProjectConfigurationsResult; projectConfigurationsError = e; } else { throw e; } } await processCollectedUpdatedAndDeletedFiles( - graphNodes, + projectConfigurationsResult, updatedFileHashes, deletedFiles ); - const g = await createAndSerializeProjectGraph(graphNodes); + const g = await createAndSerializeProjectGraph(projectConfigurationsResult); delete global.NX_GRAPH_CREATION; @@ -284,7 +284,7 @@ async function processFilesAndCreateAndSerializeProjectGraph( error: new DaemonProjectGraphError( errors, g.projectGraph, - graphNodes.sourceMaps + projectConfigurationsResult.sourceMaps ), projectGraph: null, projectFileMapCache: null, diff --git a/packages/nx/src/devkit-internals.ts b/packages/nx/src/devkit-internals.ts index 7e50804f08874..2c9565d9adfb4 100644 --- a/packages/nx/src/devkit-internals.ts +++ b/packages/nx/src/devkit-internals.ts @@ -8,6 +8,7 @@ export { getExecutorInformation } from './command-line/run/executor-utils'; export { readNxJson as readNxJsonFromDisk } from './config/nx-json'; export { calculateDefaultProjectName } from './config/calculate-default-project-name'; export { retrieveProjectConfigurationsWithAngularProjects } from './project-graph/utils/retrieve-workspace-files'; +export { readProjectConfigurationsFromRootMap } from './project-graph/utils/project-configuration-utils'; export { splitTarget } from './utils/split-target'; export { combineOptionsForExecutor } from './utils/params'; export { sortObjectByKeys } from './utils/object-sort'; diff --git a/packages/nx/src/executors/utils/convert-nx-executor.ts b/packages/nx/src/executors/utils/convert-nx-executor.ts index 7b7d618f4c76a..afeb41e277816 100644 --- a/packages/nx/src/executors/utils/convert-nx-executor.ts +++ b/packages/nx/src/executors/utils/convert-nx-executor.ts @@ -6,6 +6,7 @@ import type { Observable } from 'rxjs'; import { readNxJson } from '../../config/nx-json'; import { Executor, ExecutorContext } from '../../config/misc-interfaces'; import { retrieveProjectConfigurations } from '../../project-graph/utils/retrieve-workspace-files'; +import { readProjectConfigurationsFromRootMap } from '../../project-graph/utils/project-configuration-utils'; import { ProjectsConfigurations } from '../../config/workspace-json-project-json'; import { loadNxPlugins } from '../../project-graph/plugins/internal-api'; @@ -25,13 +26,15 @@ export function convertNxExecutor(executor: Executor) { ); const projectsConfigurations: ProjectsConfigurations = { version: 2, - projects: ( - await retrieveProjectConfigurations( - plugins, - builderContext.workspaceRoot, - nxJsonConfiguration - ) - ).projects, + projects: readProjectConfigurationsFromRootMap( + ( + await retrieveProjectConfigurations( + plugins, + builderContext.workspaceRoot, + nxJsonConfiguration + ) + ).projects + ), }; cleanup(); const context: ExecutorContext = { diff --git a/packages/nx/src/generators/utils/project-configuration.ts b/packages/nx/src/generators/utils/project-configuration.ts index 8cb7b51fa6f29..03000a95bb0ef 100644 --- a/packages/nx/src/generators/utils/project-configuration.ts +++ b/packages/nx/src/generators/utils/project-configuration.ts @@ -211,7 +211,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): { (r) => deletedFiles.indexOf(r) === -1 ); - const rootMap: Map = new Map(); + const rootMap: Record = {}; for (const projectFile of projectFiles) { if (basename(projectFile) === 'project.json') { const json = readJson(tree, projectFile); @@ -230,7 +230,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): { projectFile, readNxJson(tree) ); - if (!rootMap.has(config.root)) { + if (!rootMap[config.root]) { mergeProjectConfigurationIntoRootMap( rootMap, // Inferred targets, tags, etc don't show up when running generators diff --git a/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts b/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts index bd253f3c7ce91..ae1005569ebc3 100644 --- a/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts +++ b/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts @@ -18,15 +18,19 @@ describe('explicit package json dependencies', () => { projects: { proj: { root: 'libs/proj', + name: 'proj', }, proj2: { root: 'libs/proj2', + name: 'proj2', }, proj3: { root: 'libs/proj3', + name: 'proj3', }, proj4: { root: 'libs/proj4', + name: 'proj4', }, }, }; diff --git a/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.spec.ts b/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.spec.ts index d6b5e5a0f77d5..49155a2899bc6 100644 --- a/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.spec.ts +++ b/packages/nx/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.spec.ts @@ -580,7 +580,9 @@ async function createContext( return { externalNodes: builder.getUpdatedProjectGraph().externalNodes, - projects: projects, + projects: Object.fromEntries( + Object.entries(projects).map(([root, config]) => [config.name, config]) + ), nxJsonConfiguration: nxJson, filesToProcess: fileMap, fileMap: fileMap, diff --git a/packages/nx/src/project-graph/build-project-graph.ts b/packages/nx/src/project-graph/build-project-graph.ts index 841226a26d189..0c15bdeb1b8e2 100644 --- a/packages/nx/src/project-graph/build-project-graph.ts +++ b/packages/nx/src/project-graph/build-project-graph.ts @@ -60,7 +60,7 @@ export function getFileMap(): { } export async function buildProjectGraphUsingProjectFileMap( - projects: Record, + projectRootMap: Record, externalNodes: Record, fileMap: FileMap, allWorkspaceFiles: FileData[], @@ -75,6 +75,12 @@ export async function buildProjectGraphUsingProjectFileMap( storedAllWorkspaceFiles = allWorkspaceFiles; storedRustReferences = rustReferences; + const projects: Record = {}; + for (const root in projectRootMap) { + const project = projectRootMap[root]; + projects[project.name] = project; + } + const nxJson = readNxJson(); const projectGraphVersion = '6.0'; assertWorkspaceValidity(projects, nxJson); @@ -233,15 +239,9 @@ function createContext( fileMap: FileMap, filesToProcess: FileMap ): CreateDependenciesContext { - const clonedProjects = Object.keys(projects).reduce((map, projectName) => { - map[projectName] = { - ...projects[projectName], - }; - return map; - }, {} as Record); return { nxJsonConfiguration: nxJson, - projects: clonedProjects, + projects, externalNodes, workspaceRoot, fileMap, diff --git a/packages/nx/src/project-graph/file-map-utils.spec.ts b/packages/nx/src/project-graph/file-map-utils.spec.ts index 5017d24fca67d..cb3285430ecd3 100644 --- a/packages/nx/src/project-graph/file-map-utils.spec.ts +++ b/packages/nx/src/project-graph/file-map-utils.spec.ts @@ -8,16 +8,19 @@ describe('fileMapUtils', () => { version: 2, projects: { demo: { + name: 'demo', root: 'apps/demo', sourceRoot: 'apps/demo/src', projectType: 'application' as ProjectType, }, 'demo-e2e': { + name: 'demo-e2e', root: 'apps/demo-e2e', sourceRoot: 'apps/demo-e2e/src', projectType: 'application' as ProjectType, }, ui: { + name: 'ui', root: 'libs/ui', sourceRoot: 'libs/ui/src', projectType: 'library' as ProjectType, diff --git a/packages/nx/src/project-graph/file-utils.ts b/packages/nx/src/project-graph/file-utils.ts index cffed56f53b35..cd99d0b5cd279 100644 --- a/packages/nx/src/project-graph/file-utils.ts +++ b/packages/nx/src/project-graph/file-utils.ts @@ -192,7 +192,7 @@ function getProjectsSyncNoInference(root: string, nxJson: NxJsonConfiguration) { ...getDefaultPluginsSync(root), ]; - const projectRootMap: Map = new Map(); + const projectRootMap: Record = {}; // We iterate over plugins first - this ensures that plugins specified first take precedence. for (const plugin of plugins) { diff --git a/packages/nx/src/project-graph/plugins/loader.ts b/packages/nx/src/project-graph/plugins/loader.ts index 6ba9c14d3b7ca..b91003b719fa3 100644 --- a/packages/nx/src/project-graph/plugins/loader.ts +++ b/packages/nx/src/project-graph/plugins/loader.ts @@ -17,6 +17,7 @@ import { registerTsConfigPaths, } from '../../plugins/js/utils/register'; import { + ProjectRootMappings, createProjectRootMappingsFromProjectConfigurations, findProjectForPath, } from '../utils/find-project-for-path'; @@ -111,12 +112,11 @@ function lookupLocalPlugin( projects: Record, root = workspaceRoot ) { - const plugin = findNxProjectForImportPath(importPath, projects, root); - if (!plugin) { + const projectConfig = findNxProjectForImportPath(importPath, projects, root); + if (!projectConfig) { return null; } - const projectConfig: ProjectConfiguration = projects[plugin]; return { path: path.join(root, projectConfig.root), projectConfig }; } @@ -124,18 +124,23 @@ function findNxProjectForImportPath( importPath: string, projects: Record, root = workspaceRoot -): string | null { +): ProjectConfiguration | null { const tsConfigPaths: Record = readTsConfigPaths(root); const possiblePaths = tsConfigPaths[importPath]?.map((p) => normalizePath(path.relative(root, path.join(root, p))) ); if (possiblePaths?.length) { - const projectRootMappings = - createProjectRootMappingsFromProjectConfigurations(projects); + const projectRootMappings: ProjectRootMappings = new Map(); + const projectNameMap = new Map(); + for (const projectRoot in projects) { + const project = projects[projectRoot]; + projectRootMappings.set(project.root, project.name); + projectNameMap.set(project.name, project); + } for (const tsConfigPath of possiblePaths) { const nxProject = findProjectForPath(tsConfigPath, projectRootMappings); if (nxProject) { - return nxProject; + return projectNameMap.get(nxProject); } } logger.verbose( diff --git a/packages/nx/src/project-graph/utils/find-project-for-path.ts b/packages/nx/src/project-graph/utils/find-project-for-path.ts index 6522b7be64f1c..de7dcadd68f7e 100644 --- a/packages/nx/src/project-graph/utils/find-project-for-path.ts +++ b/packages/nx/src/project-graph/utils/find-project-for-path.ts @@ -13,9 +13,8 @@ export function createProjectRootMappingsFromProjectConfigurations( projects: Record ) { const projectRootMappings: ProjectRootMappings = new Map(); - for (const projectName of Object.keys(projects)) { - const root = projects[projectName].root; - projectRootMappings.set(normalizeProjectRoot(root), projectName); + for (const { name, root } of Object.values(projects)) { + projectRootMappings.set(normalizeProjectRoot(root), name); } return projectRootMappings; } diff --git a/packages/nx/src/project-graph/utils/normalize-project-nodes.ts b/packages/nx/src/project-graph/utils/normalize-project-nodes.ts index 4493df96640d5..f01ff9768dcbb 100644 --- a/packages/nx/src/project-graph/utils/normalize-project-nodes.ts +++ b/packages/nx/src/project-graph/utils/normalize-project-nodes.ts @@ -5,34 +5,41 @@ import { TargetConfiguration, } from '../../config/workspace-json-project-json'; import { findMatchingProjects } from '../../utils/find-matching-projects'; -import { resolveNxTokensInOptions } from '../utils/project-configuration-utils'; +import { + readProjectConfigurationsFromRootMap, + resolveNxTokensInOptions, +} from '../utils/project-configuration-utils'; import { CreateDependenciesContext } from '../plugins'; export async function normalizeProjectNodes( - ctx: CreateDependenciesContext, + { projects }: CreateDependenciesContext, builder: ProjectGraphBuilder ) { - const toAdd = []; // Sorting projects by name to make sure that the order of projects in the graph is deterministic. // This is important to ensure that expanded properties referencing projects (e.g. implicit dependencies) // are also deterministic, and thus don't cause the calculated project configuration hash to shift. - const projects = Object.keys(ctx.projects).sort(); + const sortedProjectNames = Object.keys(projects).sort(); // Used for expanding implicit dependencies (e.g. `@proj/*` or `tag:foo`) - const partialProjectGraphNodes = projects.reduce((graph, project) => { - const projectConfiguration = ctx.projects[project]; - graph[project] = { - name: project, - type: projectConfiguration.projectType === 'library' ? 'lib' : 'app', // missing fallback to `e2e` - data: { - ...projectConfiguration, - }, - }; - return graph; - }, {} as Record); + const partialProjectGraphNodes = sortedProjectNames.reduce( + (graph, project) => { + const projectConfiguration = projects[project]; + graph[project] = { + name: project, + type: projectConfiguration.projectType === 'library' ? 'lib' : 'app', // missing fallback to `e2e` + data: { + ...projectConfiguration, + }, + }; + return graph; + }, + {} as Record + ); + + const toAdd = []; - for (const key of projects) { - const p = ctx.projects[key]; + for (const key of sortedProjectNames) { + const p = projects[key]; p.implicitDependencies = normalizeImplicitDependencies( key, @@ -49,7 +56,7 @@ export async function normalizeProjectNodes( ? 'e2e' : 'app' : 'lib'; - const tags = ctx.projects?.[key]?.tags || []; + const tags = p.tags || []; toAdd.push({ name: key, diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts index a77005d75f81d..b54ed81af526a 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts @@ -477,7 +477,7 @@ describe('project-configuration-utils', () => { ['dummy', 'dummy.ts'] ); - expect(rootMap.get('libs/lib-a').targets.build.metadata).toEqual({ + expect(rootMap['libs/lib-a'].targets.build.metadata).toEqual({ description: 'do stuff', technologies: ['tech'], }); @@ -530,7 +530,7 @@ describe('project-configuration-utils', () => { ['dummy', 'dummy.ts'] ); - expect(rootMap.get('libs/lib-a').targets.build.metadata).toEqual({ + expect(rootMap['libs/lib-a'].targets.build.metadata).toEqual({ description: 'do cool stuff', technologies: ['tech', 'tech2'], }); @@ -566,7 +566,7 @@ describe('project-configuration-utils', () => { }, }, }); - expect(rootMap.get('libs/lib-a')).toMatchInlineSnapshot(` + expect(rootMap['libs/lib-a']).toMatchInlineSnapshot(` { "name": "lib-a", "root": "libs/lib-a", @@ -660,7 +660,7 @@ describe('project-configuration-utils', () => { newTarget: newTargetConfiguration, }, }); - const merged = rootMap.get('libs/lib-a'); + const merged = rootMap['libs/lib-a']; expect(merged.targets['existingTarget']).toEqual( existingTargetConfiguration ); @@ -719,7 +719,7 @@ describe('project-configuration-utils', () => { } as any, }, }); - const { targets } = rootMap.get('libs/lib-a'); + const { targets } = rootMap['libs/lib-a']; expect(targets.build).toBeUndefined(); // cwd was merged in, and ONLY_MODIFIES_EXISTING_TARGET was removed expect(targets.echo).toMatchInlineSnapshot(` @@ -747,8 +747,8 @@ describe('project-configuration-utils', () => { tags: ['b', 'c'], implicitDependencies: ['lib-c', '!lib-b'], }); - expect(rootMap.get('libs/lib-a').tags).toEqual(['a', 'b', 'c']); - expect(rootMap.get('libs/lib-a').implicitDependencies).toEqual([ + expect(rootMap['libs/lib-a'].tags).toEqual(['a', 'b', 'c']); + expect(rootMap['libs/lib-a'].implicitDependencies).toEqual([ 'lib-b', 'lib-c', '!lib-b', @@ -779,7 +779,7 @@ describe('project-configuration-utils', () => { }, }, }); - expect(rootMap.get('libs/lib-a').generators).toMatchInlineSnapshot(` + expect(rootMap['libs/lib-a'].generators).toMatchInlineSnapshot(` { "@nx/angular:component": { "flat": true, @@ -814,7 +814,7 @@ describe('project-configuration-utils', () => { production: ['{projectRoot}/**/*.prod.ts'], }, }); - expect(rootMap.get('libs/lib-a').namedInputs).toMatchInlineSnapshot(` + expect(rootMap['libs/lib-a'].namedInputs).toMatchInlineSnapshot(` { "another": [ "{projectRoot}/**/*.ts", @@ -847,7 +847,7 @@ describe('project-configuration-utils', () => { }, }, }); - expect(rootMap.get('libs/lib-a').release).toMatchInlineSnapshot(` + expect(rootMap['libs/lib-a'].release).toMatchInlineSnapshot(` { "version": { "generatorOptions": { @@ -885,7 +885,7 @@ describe('project-configuration-utils', () => { ['dummy', 'dummy.ts'] ); - expect(rootMap.get('libs/lib-a').metadata).toEqual({ + expect(rootMap['libs/lib-a'].metadata).toEqual({ technologies: ['technology'], targetGroups: { group1: ['target1', 'target2'], @@ -927,7 +927,7 @@ describe('project-configuration-utils', () => { ['dummy', 'dummy.ts'] ); - expect(rootMap.get('libs/lib-a').metadata).toEqual({ + expect(rootMap['libs/lib-a'].metadata).toEqual({ technologies: ['technology1', 'technology2'], }); expect(sourceMap['libs/lib-a']).toMatchObject({ @@ -971,7 +971,7 @@ describe('project-configuration-utils', () => { ['dummy', 'dummy.ts'] ); - expect(rootMap.get('libs/lib-a').metadata).toEqual({ + expect(rootMap['libs/lib-a'].metadata).toEqual({ targetGroups: { group1: ['target1', 'target2'], }, @@ -1110,7 +1110,7 @@ describe('project-configuration-utils', () => { }); it('should merge root level properties', () => { - const rootMap = new Map(); + const rootMap: Record = {}; const sourceMap: ConfigurationSourceMaps = { 'libs/lib-a': {}, }; @@ -1582,12 +1582,12 @@ describe('project-configuration-utils', () => { ); expect(projectConfigurations.projects).toEqual({ - a: { + 'libs/a': { name: 'a', root: 'libs/a', tags: ['fake-lib'], }, - b: { + 'libs/b': { name: 'b', root: 'libs/b', tags: ['fake-lib'], @@ -1609,7 +1609,7 @@ describe('project-configuration-utils', () => { ); expect(projectConfigurations.projects).toEqual({ - a: { + 'libs/a': { name: 'a', root: 'libs/a', tags: ['fake-lib'], @@ -1631,7 +1631,7 @@ describe('project-configuration-utils', () => { ); expect(projectConfigurations.projects).toEqual({ - a: { + 'libs/a': { name: 'a', root: 'libs/a', tags: ['fake-lib'], @@ -1642,10 +1642,10 @@ describe('project-configuration-utils', () => { }); class RootMapBuilder { - private rootMap: Map = new Map(); + private rootMap: Record = {}; addProject(p: ProjectConfiguration) { - this.rootMap.set(p.root, p); + this.rootMap[p.root] = p; return this; } 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 20876646abb7f..ea3330c2530bf 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.ts @@ -39,7 +39,7 @@ export type ConfigurationSourceMaps = Record< >; export function mergeProjectConfigurationIntoRootMap( - projectRootMap: Map, + projectRootMap: Record, project: ProjectConfiguration & { targets?: Record< string, @@ -57,13 +57,13 @@ export function mergeProjectConfigurationIntoRootMap( } const sourceMap = configurationSourceMaps?.[project.root]; - let matchingProject = projectRootMap.get(project.root); + let matchingProject = projectRootMap[project.root]; if (!matchingProject) { - projectRootMap.set(project.root, { + projectRootMap[project.root] = { root: project.root, - }); - matchingProject = projectRootMap.get(project.root); + }; + matchingProject = projectRootMap[project.root]; if (sourceMap) { sourceMap[`root`] = sourceInformation; } @@ -220,10 +220,8 @@ export function mergeProjectConfigurationIntoRootMap( } } - projectRootMap.set( - updatedProjectConfiguration.root, - updatedProjectConfiguration - ); + projectRootMap[updatedProjectConfiguration.root] = + updatedProjectConfiguration; } function mergeMetadata( @@ -302,10 +300,29 @@ function mergeMetadata( } export type ConfigurationResult = { - projects: Record; + /** + * A map of project configurations, keyed by project root. + */ + projects: { + [projectRoot: string]: ProjectConfiguration; + }; + + /** + * Node Name -> Node info + */ externalNodes: Record; + + /** + * Project Root -> Project Name + */ projectRootMap: Record; + sourceMaps: ConfigurationSourceMaps; + + /** + * The list of files that were used to create project configurations + */ + matchingProjectFiles: string[]; }; /** @@ -388,7 +405,7 @@ export async function createProjectConfigurations( return Promise.all(results).then((results) => { performance.mark('createNodes:merge - start'); - const projectRootMap: Map = new Map(); + const projectRootMap: Record = {}; const externalNodes: Record = {}; const configurationSourceMaps: Record< string, @@ -434,15 +451,18 @@ export async function createProjectConfigurations( Object.assign(externalNodes, pluginExternalNodes); } - let projects: Record; try { - projects = readProjectConfigurationsFromRootMap(projectRootMap); + // We still call this just to assert that the root map + // only contains valid project names. This is a safety check. + // + // The signature itself can't be changed as we need it to return + // project configurations for use in devkit. + readProjectConfigurationsFromRootMap(projectRootMap); } catch (e) { if ( isProjectsWithNoNameError(e) || isProjectsWithConflictingNamesError(e) ) { - projects = e.projects; errors.push(e); } else { throw e; @@ -467,24 +487,26 @@ export async function createProjectConfigurations( if (errors.length === 0) { return { - projects, + projects: projectRootMap, externalNodes, projectRootMap: rootMap, sourceMaps: configurationSourceMaps, + matchingProjectFiles: projectFiles, }; } else { throw new ProjectConfigurationsError(errors, { - projects, + projects: projectRootMap, externalNodes, projectRootMap: rootMap, sourceMaps: configurationSourceMaps, + matchingProjectFiles: projectFiles, }); } }); } export function readProjectConfigurationsFromRootMap( - projectRootMap: Map + projectRootMap: Record ) { const projects: Record = {}; // If there are projects that have the same name, that is an error. @@ -493,7 +515,8 @@ export function readProjectConfigurationsFromRootMap( const conflicts = new Map(); const projectRootsWithNoName: string[] = []; - for (const [root, configuration] of projectRootMap.entries()) { + for (const root in projectRootMap) { + const configuration = projectRootMap[root]; // We're setting `// targets` as a comment `targets` is empty due to Project Crystal. // Strip it before returning configuration for usage. if (configuration['// targets']) delete configuration['// targets']; @@ -779,9 +802,10 @@ export function readTargetDefaultsForTarget( } } -function createRootMap(projectRootMap: Map) { +function createRootMap(projectRootMap: Record) { const map: Record = {}; - for (const [projectRoot, { name: projectName }] of projectRootMap) { + for (const projectRoot in projectRootMap) { + const projectName = projectRootMap[projectRoot].name; map[projectRoot] = projectName; } return map;