cleanup(core): remove async flag from signature of buildProjectsConfigurationsFromProjectPathsAndPlugins (#20228)

This commit is contained in:
Craigory Coppola 2023-11-17 15:31:03 -05:00 committed by GitHub
parent 2a5d541243
commit 30d94f76ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 450 additions and 317 deletions

View File

@ -1,9 +0,0 @@
# Type alias: CreateNodesAsync<T\>
Ƭ **CreateNodesAsync**<`T`\>: readonly [projectFilePattern: string, createNodesFunction: CreateNodesFunctionAsync<T\>]
#### Type parameters
| Name | Type |
| :--- | :-------- |
| `T` | `unknown` |

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)) => [`CreateNodesResult`](../../devkit/documents/CreateNodesResult) Ƭ **CreateNodesFunction**<`T`\>: (`projectConfigurationFile`: `string`, `options`: `T` \| `undefined`, `context`: [`CreateNodesContext`](../../devkit/documents/CreateNodesContext)) => [`CreateNodesResult`](../../devkit/documents/CreateNodesResult) \| `Promise`<[`CreateNodesResult`](../../devkit/documents/CreateNodesResult)\>
#### Type parameters #### Type parameters
@ -10,7 +10,7 @@
#### Type declaration #### Type declaration
▸ (`projectConfigurationFile`, `options`, `context`): [`CreateNodesResult`](../../devkit/documents/CreateNodesResult) ▸ (`projectConfigurationFile`, `options`, `context`): [`CreateNodesResult`](../../devkit/documents/CreateNodesResult) \| `Promise`<[`CreateNodesResult`](../../devkit/documents/CreateNodesResult)\>
A function which parses a configuration file into a set of nodes. A function which parses a configuration file into a set of nodes.
Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGraph) Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGraph)
@ -25,4 +25,4 @@ Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGra
##### Returns ##### Returns
[`CreateNodesResult`](../../devkit/documents/CreateNodesResult) [`CreateNodesResult`](../../devkit/documents/CreateNodesResult) \| `Promise`<[`CreateNodesResult`](../../devkit/documents/CreateNodesResult)\>

View File

@ -1,20 +1,19 @@
# Type alias: NxPluginV2<TOptions, TCreateNodes\> # Type alias: NxPluginV2<TOptions\>
Ƭ **NxPluginV2**<`TOptions`, `TCreateNodes`\>: `Object` Ƭ **NxPluginV2**<`TOptions`\>: `Object`
A plugin for Nx which creates nodes and dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph) A plugin for Nx which creates nodes and dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph)
#### Type parameters #### Type parameters
| Name | Type | | Name | Type |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | :--------- | :-------- |
| `TOptions` | `unknown` | | `TOptions` | `unknown` |
| `TCreateNodes` | extends [`CreateNodes`](../../devkit/documents/CreateNodes)<`TOptions`\> \| [`CreateNodesAsync`](../../devkit/documents/CreateNodesAsync)<`TOptions`\> = [`CreateNodes`](../../devkit/documents/CreateNodes)<`TOptions`\> \| [`CreateNodesAsync`](../../devkit/documents/CreateNodesAsync)<`TOptions`\> |
#### Type declaration #### Type declaration
| Name | Type | Description | | Name | Type | Description |
| :-------------------- | :----------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | | :-------------------- | :----------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `createDependencies?` | [`CreateDependencies`](../../devkit/documents/CreateDependencies)<`TOptions`\> | Provides a function to analyze files to create dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph) | | `createDependencies?` | [`CreateDependencies`](../../devkit/documents/CreateDependencies)<`TOptions`\> | Provides a function to analyze files to create dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph) |
| `createNodes?` | `TCreateNodes` | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFile } | | `createNodes?` | [`CreateNodes`](../../devkit/documents/CreateNodes) | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFile } |
| `name` | `string` | - | | `name` | `string` | - |

View File

@ -65,7 +65,6 @@ It only uses language primitives and immutable objects
- [CreateDependencies](../../devkit/documents/CreateDependencies) - [CreateDependencies](../../devkit/documents/CreateDependencies)
- [CreateNodes](../../devkit/documents/CreateNodes) - [CreateNodes](../../devkit/documents/CreateNodes)
- [CreateNodesAsync](../../devkit/documents/CreateNodesAsync)
- [CreateNodesFunction](../../devkit/documents/CreateNodesFunction) - [CreateNodesFunction](../../devkit/documents/CreateNodesFunction)
- [CustomHasher](../../devkit/documents/CustomHasher) - [CustomHasher](../../devkit/documents/CustomHasher)
- [DynamicDependency](../../devkit/documents/DynamicDependency) - [DynamicDependency](../../devkit/documents/DynamicDependency)

View File

@ -65,7 +65,6 @@ It only uses language primitives and immutable objects
- [CreateDependencies](../../devkit/documents/CreateDependencies) - [CreateDependencies](../../devkit/documents/CreateDependencies)
- [CreateNodes](../../devkit/documents/CreateNodes) - [CreateNodes](../../devkit/documents/CreateNodes)
- [CreateNodesAsync](../../devkit/documents/CreateNodesAsync)
- [CreateNodesFunction](../../devkit/documents/CreateNodesFunction) - [CreateNodesFunction](../../devkit/documents/CreateNodesFunction)
- [CustomHasher](../../devkit/documents/CustomHasher) - [CustomHasher](../../devkit/documents/CustomHasher)
- [DynamicDependency](../../devkit/documents/DynamicDependency) - [DynamicDependency](../../devkit/documents/DynamicDependency)

View File

@ -59,7 +59,7 @@ A simplified version of Nx's built-in `project.json` plugin is shown below, whic
export const createNodes: CreateNodes = [ export const createNodes: CreateNodes = [
'**/project.json', '**/project.json',
(projectConfigurationFile: string, opts, context: CreateNodesContext) => { (projectConfigurationFile: string, opts, context: CreateNodesContext) => {
const projectConfiguration = readJson(projectConfigurationFile); const projectConfiguration = readJsonFile(projectConfigurationFile);
const root = dirname(projectConfigurationFile); const root = dirname(projectConfigurationFile);
return { return {

View File

@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../dist/out-tsc", "outDir": "../../dist/out-tsc",
"types": ["node"], "types": ["node"],
"lib": ["DOM", "es2019"] "lib": ["DOM", "es2022"]
}, },
"files": [ "files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/cssmodule.d.ts",

View File

@ -13,4 +13,5 @@ module.exports = {
moduleFileExtensions: ['ts', 'js', 'html'], moduleFileExtensions: ['ts', 'js', 'html'],
coverageReporters: ['html'], coverageReporters: ['html'],
maxWorkers: 1, maxWorkers: 1,
testEnvironment: 'node',
}; };

View File

@ -2,7 +2,6 @@
export default { export default {
displayName: 'nx-dev-models-document', displayName: 'nx-dev-models-document',
globals: {}, globals: {},
testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]sx?$': [ '^.+\\.[tj]sx?$': [
'ts-jest', 'ts-jest',

View File

@ -2,7 +2,6 @@
export default { export default {
displayName: 'nx-dev-models-menu', displayName: 'nx-dev-models-menu',
globals: {}, globals: {},
testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]sx?$': [ '^.+\\.[tj]sx?$': [
'ts-jest', 'ts-jest',

View File

@ -2,7 +2,6 @@
export default { export default {
displayName: 'nx-dev-models-package', displayName: 'nx-dev-models-package',
globals: {}, globals: {},
testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]sx?$': [ '^.+\\.[tj]sx?$': [
'ts-jest', 'ts-jest',

View File

@ -8,4 +8,5 @@ export default {
coverageDirectory: '../../coverage/nx-dev/ui-sponsor-card', coverageDirectory: '../../coverage/nx-dev/ui-sponsor-card',
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
testEnvironment: 'jsdom',
}; };

View File

@ -2,7 +2,6 @@
export default { export default {
displayName: 'nx-dev-util-ai', displayName: 'nx-dev-util-ai',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
testEnvironment: 'node',
transform: { transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }], '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
}, },

View File

@ -6,7 +6,6 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'angular', displayName: 'angular',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'], setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'create-nx-plugin', displayName: 'create-nx-plugin',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'create-nx-workspace', displayName: 'create-nx-workspace',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'cypress', displayName: 'cypress',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -58,6 +58,7 @@ describe('add-nx-cypress-plugin migration', () => {
}) })
); );
updateProjectConfiguration(tree, 'e2e', { updateProjectConfiguration(tree, 'e2e', {
name: 'e2e',
root: 'e2e', root: 'e2e',
targets: { targets: {
e2e: { e2e: {

View File

@ -6,7 +6,6 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'],
globals: {}, globals: {},
displayName: 'react-native', displayName: 'react-native',
testEnvironment: 'node',
verbose: true, verbose: true,
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'cli', displayName: 'cli',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -3,7 +3,7 @@ import type {
TargetConfiguration, TargetConfiguration,
} from 'nx/src/config/workspace-json-project-json'; } from 'nx/src/config/workspace-json-project-json';
import type { Tree } from 'nx/src/generators/tree'; import type { Tree } from 'nx/src/generators/tree';
import type { CreateNodes, CreateNodesAsync } from 'nx/src/utils/nx-plugin'; import type { CreateNodes } from 'nx/src/utils/nx-plugin';
import { requireNx } from '../../nx'; import { requireNx } from '../../nx';
const { const {
readNxJson, readNxJson,
@ -19,7 +19,7 @@ export async function replaceProjectConfigurationsWithPlugin<T = unknown>(
tree: Tree, tree: Tree,
rootMappings: Map<string, string>, rootMappings: Map<string, string>,
pluginPath: string, pluginPath: string,
createNodes: CreateNodes<T> | CreateNodesAsync<T>, createNodes: CreateNodes<T>,
pluginOptions: T pluginOptions: T
): Promise<void> { ): Promise<void> {
const nxJson = readNxJson(tree); const nxJson = readNxJson(tree);

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'esbuild', displayName: 'esbuild',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'packages-eslint-plugin', displayName: 'packages-eslint-plugin',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'eslint', displayName: 'eslint',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'],
globals: {}, globals: {},
displayName: 'expo', displayName: 'expo',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'express', displayName: 'express',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'jest', displayName: 'jest',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'js', displayName: 'js',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'nest', displayName: 'nest',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'next', displayName: 'next',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'node', displayName: 'node',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'nx', displayName: 'nx',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -1,5 +1,5 @@
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import { readNxJson } from '../../config/nx-json'; import { readNxJson, NxJsonConfiguration } from '../../config/nx-json';
import { import {
FileData, FileData,
FileMap, FileMap,
@ -136,7 +136,10 @@ function computeWorkspaceConfigHash(
return hashArray(projectConfigurationStrings); return hashArray(projectConfigurationStrings);
} }
async function processCollectedUpdatedAndDeletedFiles() { async function processCollectedUpdatedAndDeletedFiles(
projects: Record<string, ProjectConfiguration>,
nxJson: NxJsonConfiguration
) {
try { try {
performance.mark('hash-watched-changes-start'); performance.mark('hash-watched-changes-start');
const updatedFiles = [...collectedUpdatedFiles.values()]; const updatedFiles = [...collectedUpdatedFiles.values()];
@ -149,14 +152,7 @@ async function processCollectedUpdatedAndDeletedFiles() {
'hash-watched-changes-end' 'hash-watched-changes-end'
); );
const nxJson = readNxJson(workspaceRoot); const workspaceConfigHash = computeWorkspaceConfigHash(projects);
const { projectNodes } = await retrieveProjectConfigurations(
workspaceRoot,
nxJson
);
const workspaceConfigHash = computeWorkspaceConfigHash(projectNodes);
serverLogger.requestLog( serverLogger.requestLog(
`Updated file-hasher based on watched changes, recomputing project graph...` `Updated file-hasher based on watched changes, recomputing project graph...`
); );
@ -172,7 +168,7 @@ async function processCollectedUpdatedAndDeletedFiles() {
} else { } else {
if (fileMapWithFiles) { if (fileMapWithFiles) {
fileMapWithFiles = updateFileMap( fileMapWithFiles = updateFileMap(
projectNodes, projects,
fileMapWithFiles.fileMap, fileMapWithFiles.fileMap,
fileMapWithFiles.allWorkspaceFiles, fileMapWithFiles.allWorkspaceFiles,
new Map(Object.entries(updatedFileHashes)), new Map(Object.entries(updatedFileHashes)),
@ -197,13 +193,24 @@ async function processCollectedUpdatedAndDeletedFiles() {
`Error detected when recomputing project file map: ${e.message}` `Error detected when recomputing project file map: ${e.message}`
); );
resetInternalState(); resetInternalState();
return e; throw e;
} }
} }
async function processFilesAndCreateAndSerializeProjectGraph() { async function processFilesAndCreateAndSerializeProjectGraph() {
const err = await processCollectedUpdatedAndDeletedFiles(); try {
if (err) { const nxJson = readNxJson(workspaceRoot);
const configResult = await retrieveProjectConfigurations(
workspaceRoot,
nxJson
);
await processCollectedUpdatedAndDeletedFiles(
configResult.projectNodes,
nxJson
);
writeSourceMaps(configResult.sourceMaps);
return createAndSerializeProjectGraph(configResult.projectNodes);
} catch (err) {
return Promise.resolve({ return Promise.resolve({
error: err, error: err,
projectGraph: null, projectGraph: null,
@ -211,8 +218,6 @@ async function processFilesAndCreateAndSerializeProjectGraph() {
allWorkspaceFiles: null, allWorkspaceFiles: null,
serializedProjectGraph: null, serializedProjectGraph: null,
}); });
} else {
return createAndSerializeProjectGraph();
} }
} }
@ -231,7 +236,9 @@ function copyFileMap(m: FileMap) {
return c; return c;
} }
async function createAndSerializeProjectGraph(): Promise<{ async function createAndSerializeProjectGraph(
projects: Record<string, ProjectConfiguration>
): Promise<{
error: string | null; error: string | null;
projectGraph: ProjectGraph | null; projectGraph: ProjectGraph | null;
fileMap: FileMap | null; fileMap: FileMap | null;
@ -240,15 +247,11 @@ async function createAndSerializeProjectGraph(): Promise<{
}> { }> {
try { try {
performance.mark('create-project-graph-start'); performance.mark('create-project-graph-start');
const projectConfigurations = await retrieveProjectConfigurations(
workspaceRoot,
readNxJson(workspaceRoot)
);
const fileMap = copyFileMap(fileMapWithFiles.fileMap); const fileMap = copyFileMap(fileMapWithFiles.fileMap);
const allWorkspaceFiles = copyFileData(fileMapWithFiles.allWorkspaceFiles); const allWorkspaceFiles = copyFileData(fileMapWithFiles.allWorkspaceFiles);
const { projectGraph, projectFileMapCache } = const { projectGraph, projectFileMapCache } =
await buildProjectGraphUsingFileMap( await buildProjectGraphUsingFileMap(
projectConfigurations.projectNodes, projects,
knownExternalNodes, knownExternalNodes,
fileMap, fileMap,
allWorkspaceFiles, allWorkspaceFiles,
@ -274,8 +277,6 @@ async function createAndSerializeProjectGraph(): Promise<{
'json-stringify-end' 'json-stringify-end'
); );
writeSourceMaps(projectConfigurations.sourceMaps);
return { return {
error: null, error: null,
projectGraph, projectGraph,

View File

@ -51,7 +51,6 @@ export type {
NxPluginV2, NxPluginV2,
ProjectTargetConfigurator, ProjectTargetConfigurator,
CreateNodes, CreateNodes,
CreateNodesAsync,
CreateNodesFunction, CreateNodesFunction,
CreateNodesResult, CreateNodesResult,
CreateNodesContext, CreateNodesContext,

View File

@ -5,6 +5,7 @@ import {
getGlobPatternsFromPackageManagerWorkspaces, getGlobPatternsFromPackageManagerWorkspaces,
} from '../../../plugins/package-json-workspaces'; } from '../../../plugins/package-json-workspaces';
import { buildProjectFromProjectJson } from '../../plugins/project-json/build-nodes/project-json'; import { buildProjectFromProjectJson } from '../../plugins/project-json/build-nodes/project-json';
import { getDefaultPluginsSync } from '../../utils/nx-plugin.deprecated';
import { renamePropertyWithStableKeys } from '../../adapter/angular-json'; import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
import { import {
ProjectConfiguration, ProjectConfiguration,
@ -14,7 +15,7 @@ import {
mergeProjectConfigurationIntoRootMap, mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap, readProjectConfigurationsFromRootMap,
} from '../../project-graph/utils/project-configuration-utils'; } from '../../project-graph/utils/project-configuration-utils';
import { retrieveProjectConfigurationPathsWithoutPluginInference } from '../../project-graph/utils/retrieve-workspace-files'; import { retrieveProjectConfigurationPaths } from '../../project-graph/utils/retrieve-workspace-files';
import { output } from '../../utils/output'; import { output } from '../../utils/output';
import { PackageJson } from '../../utils/package-json'; import { PackageJson } from '../../utils/package-json';
import { joinPathFragments, normalizePath } from '../../utils/path'; import { joinPathFragments, normalizePath } from '../../utils/path';
@ -191,9 +192,9 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
readJson(tree, p) readJson(tree, p)
), ),
]; ];
const globbedFiles = retrieveProjectConfigurationPaths(
const globbedFiles = retrieveProjectConfigurationPathsWithoutPluginInference( tree.root,
tree.root getDefaultPluginsSync(tree.root)
); );
const createdFiles = findCreatedProjectFiles(tree, patterns); const createdFiles = findCreatedProjectFiles(tree, patterns);
const deletedFiles = findDeletedProjectFiles(tree, patterns); const deletedFiles = findDeletedProjectFiles(tree, patterns);

View File

@ -4,12 +4,13 @@ import { dirname } from 'path';
import { readJson, writeJson } from '../../generators/utils/json'; import { readJson, writeJson } from '../../generators/utils/json';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { retrieveProjectConfigurationPaths } from '../../project-graph/utils/retrieve-workspace-files'; import { retrieveProjectConfigurationPaths } from '../../project-graph/utils/retrieve-workspace-files';
import { loadNxPlugins } from '../../utils/nx-plugin';
export default async function (tree: Tree) { export default async function (tree: Tree) {
const nxJson = readNxJson(tree); const nxJson = readNxJson(tree);
const projectFiles = await retrieveProjectConfigurationPaths( const projectFiles = await retrieveProjectConfigurationPaths(
tree.root, tree.root,
nxJson await loadNxPlugins(nxJson?.plugins)
); );
const projectJsons = projectFiles.filter((f) => f.endsWith('project.json')); const projectJsons = projectFiles.filter((f) => f.endsWith('project.json'));

View File

@ -3,9 +3,9 @@ import { dirname, join } from 'node:path';
import { ProjectConfiguration } from '../../../config/workspace-json-project-json'; import { ProjectConfiguration } from '../../../config/workspace-json-project-json';
import { toProjectName } from '../../../config/workspaces'; import { toProjectName } from '../../../config/workspaces';
import { readJsonFile } from '../../../utils/fileutils'; import { readJsonFile } from '../../../utils/fileutils';
import { CreateNodes, NxPluginV2 } from '../../../utils/nx-plugin'; import { NxPluginV2 } from '../../../utils/nx-plugin';
export const CreateProjectJsonProjectsPlugin: NxPluginV2<void, CreateNodes> = { 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}',

View File

@ -12,7 +12,6 @@ export const getTouchedProjectsFromProjectGlobChanges: TouchedProjectLocator =
async (touchedFiles, projectGraphNodes, nxJson): Promise<string[]> => { async (touchedFiles, projectGraphNodes, nxJson): Promise<string[]> => {
const globPattern = combineGlobPatterns( const globPattern = combineGlobPatterns(
configurationGlobs( configurationGlobs(
workspaceRoot,
await loadNxPlugins( await loadNxPlugins(
nxJson?.plugins, nxJson?.plugins,
getNxRequirePaths(workspaceRoot), getNxRequirePaths(workspaceRoot),

View File

@ -33,6 +33,7 @@ import { readNxJson } from '../config/configuration';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { PackageJson } from '../utils/package-json'; import { PackageJson } from '../utils/package-json';
import { getNxRequirePaths } from '../utils/installation-directory'; import { getNxRequirePaths } from '../utils/installation-directory';
import { output } from '../utils/output';
let storedFileMap: FileMap | null = null; let storedFileMap: FileMap | null = null;
let storedAllWorkspaceFiles: FileData[] | null = null; let storedAllWorkspaceFiles: FileData[] | null = null;
@ -244,13 +245,13 @@ async function updateProjectGraphWithPlugins(
plugin.processProjectGraph && plugin.processProjectGraph &&
!plugin.createDependencies !plugin.createDependencies
) { ) {
// TODO(@AgentEnder): Enable after rewriting nx-js-graph-plugin to v2 output.warn({
// output.warn({ title: `${plugin.name} is a v1 plugin.`,
// title: `${plugin.name} is a v1 plugin.`, bodyLines: [
// bodyLines: [ 'Nx has recently released a v2 model for project graph plugins. The `processProjectGraph` method is deprecated. Plugins should use some combination of `createNodes` and `createDependencies` instead.',
// 'Nx has recently released a v2 model for project graph plugins. The `processProjectGraph` method is deprecated. Plugins should use some combination of `createNodes` and `createDependencies` instead.', ],
// ], });
// }); performance.mark(`${plugin.name}:processProjectGraph - start`);
graph = await plugin.processProjectGraph(graph, { graph = await plugin.processProjectGraph(graph, {
...context, ...context,
projectsConfigurations: { projectsConfigurations: {
@ -265,6 +266,12 @@ async function updateProjectGraphWithPlugins(
...context.nxJsonConfiguration, ...context.nxJsonConfiguration,
}, },
}); });
performance.mark(`${plugin.name}:processProjectGraph - end`);
performance.measure(
`${plugin.name}:processProjectGraph`,
`${plugin.name}:processProjectGraph - start`,
`${plugin.name}:processProjectGraph - end`
);
} }
} catch (e) { } catch (e) {
let message = `Failed to process the project graph with "${plugin.name}".`; let message = `Failed to process the project graph with "${plugin.name}".`;
@ -287,6 +294,7 @@ async function updateProjectGraphWithPlugins(
); );
await Promise.all( await Promise.all(
createDependencyPlugins.map(async ({ plugin, options }) => { createDependencyPlugins.map(async ({ plugin, options }) => {
performance.mark(`${plugin.name}:createDependencies - start`);
try { try {
const dependencies = await plugin.createDependencies(options, { const dependencies = await plugin.createDependencies(options, {
...context, ...context,
@ -308,6 +316,12 @@ async function updateProjectGraphWithPlugins(
} }
throw new Error(message); throw new Error(message);
} }
performance.mark(`${plugin.name}:createDependencies - end`);
performance.measure(
`${plugin.name}:createDependencies`,
`${plugin.name}:createDependencies - start`,
`${plugin.name}:createDependencies - end`
);
}) })
); );
return builder.getUpdatedProjectGraph(); return builder.getUpdatedProjectGraph();

View File

@ -3,7 +3,10 @@ import { existsSync, readFileSync } from 'fs';
import { extname, join, relative, sep } from 'path'; import { extname, join, relative, sep } from 'path';
import { readNxJson } from '../config/configuration'; import { readNxJson } from '../config/configuration';
import { FileData } from '../config/project-graph'; import { FileData } from '../config/project-graph';
import { ProjectsConfigurations } from '../config/workspace-json-project-json'; import {
ProjectConfiguration,
ProjectsConfigurations,
} from '../config/workspace-json-project-json';
import type { NxArgs } from '../utils/command-line-utils'; import type { NxArgs } from '../utils/command-line-utils';
import { workspaceRoot } from '../utils/workspace-root'; import { workspaceRoot } from '../utils/workspace-root';
import { readJsonFile } from '../utils/fileutils'; import { readJsonFile } from '../utils/fileutils';
@ -14,10 +17,17 @@ import {
} from './project-graph'; } from './project-graph';
import { toOldFormat } from '../adapter/angular-json'; import { toOldFormat } from '../adapter/angular-json';
import { getIgnoreObject } from '../utils/ignore'; import { getIgnoreObject } from '../utils/ignore';
import { retrieveProjectConfigurationPathsWithoutPluginInference } from './utils/retrieve-workspace-files'; import { retrieveProjectConfigurationPaths } from './utils/retrieve-workspace-files';
import { buildProjectsConfigurationsFromProjectPathsAndPlugins } from './utils/project-configuration-utils'; import {
mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap,
} from './utils/project-configuration-utils';
import { NxJsonConfiguration } from '../config/nx-json'; import { NxJsonConfiguration } from '../config/nx-json';
import { getDefaultPluginsSync } from '../utils/nx-plugin.deprecated'; import { getDefaultPluginsSync } from '../utils/nx-plugin.deprecated';
import minimatch = require('minimatch');
import { CreateNodesResult } from '../devkit-exports';
import { CreatePackageJsonProjectsNextToProjectJson } from '../plugins/project-json/build-nodes/package-json-next-to-project-json';
import { LoadedNxPlugin } from '../utils/nx-plugin';
export interface Change { export interface Change {
type: string; type: string;
@ -168,13 +178,45 @@ export { FileData };
// TODO(17): Remove these exports // TODO(17): Remove these exports
export { readNxJson, workspaceLayout } from '../config/configuration'; export { readNxJson, workspaceLayout } from '../config/configuration';
/**
* TODO(v18): Remove this function.
*/
function getProjectsSyncNoInference(root: string, nxJson: NxJsonConfiguration) { function getProjectsSyncNoInference(root: string, nxJson: NxJsonConfiguration) {
const paths = retrieveProjectConfigurationPathsWithoutPluginInference(root); const projectFiles = retrieveProjectConfigurationPaths(
return buildProjectsConfigurationsFromProjectPathsAndPlugins(
nxJson,
paths,
getDefaultPluginsSync(root),
root, root,
true getDefaultPluginsSync(root)
); );
const plugins: LoadedNxPlugin[] = [
{ plugin: CreatePackageJsonProjectsNextToProjectJson },
...getDefaultPluginsSync(root),
];
const projectRootMap: Map<string, ProjectConfiguration> = new Map();
// We iterate over plugins first - this ensures that plugins specified first take precedence.
for (const { plugin, options } of plugins) {
const [pattern, createNodes] = plugin.createNodes ?? [];
if (!pattern) {
continue;
}
for (const file of projectFiles) {
if (minimatch(file, pattern, { dot: true })) {
let r = createNodes(file, options, {
nxJsonConfiguration: nxJson,
workspaceRoot: root,
}) as CreateNodesResult;
for (const node in r.projects) {
const project = {
root: node,
...r.projects[node],
};
mergeProjectConfigurationIntoRootMap(projectRootMap, project);
}
}
}
}
return {
projects: readProjectConfigurationsFromRootMap(projectRootMap),
};
} }

View File

@ -4,7 +4,7 @@ import {
} from '../../config/workspace-json-project-json'; } from '../../config/workspace-json-project-json';
import { import {
ConfigurationSourceMaps, ConfigurationSourceMaps,
SourceInformation, isCompatibleTarget,
mergeProjectConfigurationIntoRootMap, mergeProjectConfigurationIntoRootMap,
mergeTargetConfigurations, mergeTargetConfigurations,
readProjectConfigurationsFromRootMap, readProjectConfigurationsFromRootMap,
@ -996,6 +996,112 @@ describe('project-configuration-utils', () => {
`); `);
}); });
}); });
describe('isCompatibleTarget', () => {
it('should return true if only one target specifies an executor', () => {
expect(
isCompatibleTarget(
{
executor: 'nx:run-commands',
},
{}
)
).toBe(true);
});
it('should return true if both targets specify the same executor', () => {
expect(
isCompatibleTarget(
{
executor: 'nx:run-commands',
},
{
executor: 'nx:run-commands',
}
)
).toBe(true);
});
it('should return false if both targets specify different executors', () => {
expect(
isCompatibleTarget(
{
executor: 'nx:run-commands',
},
{
executor: 'other-executor',
}
)
).toBe(false);
});
it('should return true if both targets specify the same command', () => {
expect(
isCompatibleTarget(
{
command: 'echo',
},
{
command: 'echo',
}
)
).toBe(true);
expect(
isCompatibleTarget(
{
command: 'echo',
},
{
executor: 'nx:run-commands',
options: {
command: 'echo',
},
}
)
).toBe(true);
});
it('should return false if both targets specify different commands', () => {
expect(
isCompatibleTarget(
{
command: 'echo',
},
{
command: 'echo2',
}
)
).toBe(false);
expect(
isCompatibleTarget(
{
command: 'echo',
},
{
executor: 'nx:run-commands',
options: {
command: 'echo2',
},
}
)
).toBe(false);
});
it('should return false if one target specifies an executor and the other a command', () => {
expect(
isCompatibleTarget(
{
executor: 'nx:noop',
},
{
command: 'echo',
}
)
).toBe(false);
});
});
}); });
class RootMapBuilder { class RootMapBuilder {

View File

@ -8,7 +8,6 @@ import {
import { NX_PREFIX } from '../../utils/logger'; import { NX_PREFIX } from '../../utils/logger';
import { CreateNodesResult, LoadedNxPlugin } from '../../utils/nx-plugin'; import { CreateNodesResult, LoadedNxPlugin } from '../../utils/nx-plugin';
import { workspaceRoot } from '../../utils/workspace-root'; import { workspaceRoot } from '../../utils/workspace-root';
import { output } from '../../utils/output';
import minimatch = require('minimatch'); import minimatch = require('minimatch');
@ -147,32 +146,13 @@ export function mergeProjectConfigurationIntoRootMap(
); );
} }
type CreateNodesResultWithMetadata = { export type ConfigurationResult = {
result: CreateNodesResult | Promise<CreateNodesResult>;
pluginName: string;
file: string;
};
type ConfigurationResult = {
projects: Record<string, ProjectConfiguration>; projects: Record<string, ProjectConfiguration>;
externalNodes: Record<string, ProjectGraphExternalNode>; externalNodes: Record<string, ProjectGraphExternalNode>;
rootMap: Record<string, string>; rootMap: Record<string, string>;
sourceMaps: ConfigurationSourceMaps; sourceMaps: ConfigurationSourceMaps;
}; };
/**
* ** DO NOT USE ** - Please use without the `skipAsync` parameter.
* @deprecated
* @todo(@agentender): Remove in Nx 18 alongside the removal of its usage.
*/
export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
nxJson: NxJsonConfiguration,
projectFiles: string[], // making this parameter allows devkit to pick up newly created projects
plugins: LoadedNxPlugin[],
root: string,
skipAsync: true
): ConfigurationResult;
/** /**
* Transforms a list of project paths into a map of project configurations. * Transforms a list of project paths into a map of project configurations.
* *
@ -185,46 +165,92 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
nxJson: NxJsonConfiguration, nxJson: NxJsonConfiguration,
projectFiles: string[], // making this parameter allows devkit to pick up newly created projects projectFiles: string[], // making this parameter allows devkit to pick up newly created projects
plugins: LoadedNxPlugin[], plugins: LoadedNxPlugin[],
root: string, root: string = workspaceRoot
skipAsync?: false ): Promise<ConfigurationResult> {
): Promise<ConfigurationResult>; type CreateNodesResultWithContext = CreateNodesResult & {
export function buildProjectsConfigurationsFromProjectPathsAndPlugins( file: string;
nxJson: NxJsonConfiguration, pluginName: string;
projectFiles: string[], // making this parameter allows devkit to pick up newly created projects };
plugins: LoadedNxPlugin[],
root: string = workspaceRoot, const results: Array<Promise<Array<CreateNodesResultWithContext>>> = [];
skipAsync: boolean = false
): ConfigurationResult | Promise<ConfigurationResult> {
const results: Array<CreateNodesResultWithMetadata> = [];
// We iterate over plugins first - this ensures that plugins specified first take precedence. // We iterate over plugins first - this ensures that plugins specified first take precedence.
for (const { plugin, options } of plugins) { for (const { plugin, options } of plugins) {
const [pattern, createNodes] = plugin.createNodes ?? []; const [pattern, createNodes] = plugin.createNodes ?? [];
const pluginResults: Array<
CreateNodesResultWithContext | Promise<CreateNodesResultWithContext>
> = [];
performance.mark(`${plugin.name}:createNodes - start`);
if (!pattern) { if (!pattern) {
continue; continue;
} }
for (const file of projectFiles) { for (const file of projectFiles) {
performance.mark(`${plugin.name}:createNodes:${file} - start`);
if (minimatch(file, pattern, { dot: true })) { if (minimatch(file, pattern, { dot: true })) {
results.push({ try {
result: createNodes(file, options, { let r = createNodes(file, options, {
nxJsonConfiguration: nxJson, nxJsonConfiguration: nxJson,
workspaceRoot: root, workspaceRoot: root,
}), });
pluginName: plugin.name,
if (r instanceof Promise) {
pluginResults.push(
r
.catch((e) => {
performance.mark(`${plugin.name}:createNodes:${file} - end`);
throw new CreateNodesError(
`Unable to create nodes for ${file} using plugin ${plugin.name}.`,
e
);
})
.then((r) => {
performance.mark(`${plugin.name}:createNodes:${file} - end`);
performance.measure(
`${plugin.name}:createNodes:${file}`,
`${plugin.name}:createNodes:${file} - start`,
`${plugin.name}:createNodes:${file} - end`
);
return { ...r, file, pluginName: plugin.name };
})
);
} else {
performance.mark(`${plugin.name}:createNodes:${file} - end`);
performance.measure(
`${plugin.name}:createNodes:${file}`,
`${plugin.name}:createNodes:${file} - start`,
`${plugin.name}:createNodes:${file} - end`
);
pluginResults.push({
...r,
file, file,
pluginName: plugin.name,
}); });
} }
} catch (e) {
throw new CreateNodesError(
`Unable to create nodes for ${file} using plugin ${plugin.name}.`,
e
);
} }
} }
}
// If there are no promises (counter undefined) or all promises have resolved (counter === 0)
results.push(
Promise.all(pluginResults).then((results) => {
performance.mark(`${plugin.name}:createNodes - end`);
performance.measure(
`${plugin.name}:createNodes`,
`${plugin.name}:createNodes - start`,
`${plugin.name}:createNodes - end`
);
return results;
})
);
}
return skipAsync return Promise.all(results).then((results) => {
? combineSyncConfigurationResults(results) performance.mark('createNodes:merge - start');
: combineAsyncConfigurationResults(results);
}
function combineSyncConfigurationResults(
resultsWithMetadata: CreateNodesResultWithMetadata[]
): ConfigurationResult {
const projectRootMap: Map<string, ProjectConfiguration> = new Map(); const projectRootMap: Map<string, ProjectConfiguration> = new Map();
const externalNodes: Record<string, ProjectGraphExternalNode> = {}; const externalNodes: Record<string, ProjectGraphExternalNode> = {};
const configurationSourceMaps: Record< const configurationSourceMaps: Record<
@ -232,61 +258,51 @@ function combineSyncConfigurationResults(
Record<string, SourceInformation> Record<string, SourceInformation>
> = {}; > = {};
let warned = false; for (const result of results.flat()) {
for (const { result, pluginName, file } of resultsWithMetadata) { const {
if (typeof result === 'object' && 'then' in result) { projects: projectNodes,
if (!warned) { externalNodes: pluginExternalNodes,
output.warn({ file,
title: 'One or more plugins in this workspace are async.', pluginName,
bodyLines: [ } = result;
'Configuration from these plugins will not be visible to readWorkspaceConfig or readWorkspaceConfiguration. If you are using these methods, consider reading project info from the graph with createProjectGraphAsync instead.',
'If you are not using one of these methods, please open an issue at http://github.com/nrwl/nx',
],
});
warned = true;
}
continue;
}
const { projects: projectNodes, externalNodes: pluginExternalNodes } =
result;
for (const node in projectNodes) { for (const node in projectNodes) {
mergeProjectConfigurationIntoRootMap( const project = {
projectRootMap,
{
root: node, root: node,
...projectNodes[node], ...projectNodes[node],
}, };
try {
mergeProjectConfigurationIntoRootMap(
projectRootMap,
project,
configurationSourceMaps, configurationSourceMaps,
[pluginName, file] [file, pluginName]
); );
} catch (e) {
throw new CreateNodesError(
`Unable to merge project information for "${project.root}" from ${result.file} using plugin ${result.pluginName}.`,
e
);
}
} }
Object.assign(externalNodes, pluginExternalNodes); Object.assign(externalNodes, pluginExternalNodes);
} }
const rootMap = createRootMap(projectRootMap); const rootMap = createRootMap(projectRootMap);
performance.mark('createNodes:merge - end');
performance.measure(
'createNodes:merge',
'createNodes:merge - start',
'createNodes:merge - end'
);
return { return {
projects: readProjectConfigurationsFromRootMap(projectRootMap), projects: readProjectConfigurationsFromRootMap(projectRootMap),
externalNodes, externalNodes,
rootMap, rootMap,
sourceMaps: configurationSourceMaps, sourceMaps: configurationSourceMaps,
}; };
} });
function combineAsyncConfigurationResults(
results: Array<CreateNodesResultWithMetadata>
): Promise<ConfigurationResult> {
return Promise.all(
results.map((resultWithMetadata) =>
typeof resultWithMetadata.result === 'object' &&
'then' in resultWithMetadata.result
? resultWithMetadata.result.then((resolvedResult) => ({
...resultWithMetadata,
result: resolvedResult,
}))
: resultWithMetadata
)
).then((r) => combineSyncConfigurationResults(r));
} }
export function readProjectConfigurationsFromRootMap( export function readProjectConfigurationsFromRootMap(
@ -327,6 +343,23 @@ export function readProjectConfigurationsFromRootMap(
return projects; return projects;
} }
class CreateNodesError extends Error {
constructor(msg, cause: Error | unknown) {
const message = `${msg} ${
!cause
? ''
: cause instanceof Error
? `\n\n\t Inner Error: ${cause.stack}`
: cause
}`;
// These errors are thrown during a JS callback which is invoked via rust.
// The errors messaging gets lost in the rust -> js -> rust transition, but
// logging the error here will ensure that it is visible in the console.
console.error(message);
super(message, { cause });
}
}
/** /**
* Merges two targets. * Merges two targets.
* *
@ -417,8 +450,29 @@ export function mergeTargetConfigurations(
* If the executors are both specified and don't match, the options aren't considered * If the executors are both specified and don't match, the options aren't considered
* "compatible" and shouldn't be merged. * "compatible" and shouldn't be merged.
*/ */
function isCompatibleTarget(a: TargetConfiguration, b: TargetConfiguration) { export function isCompatibleTarget(
return !a.executor || !b.executor || a.executor === b.executor; a: TargetConfiguration,
b: TargetConfiguration
) {
if (a.command || b.command) {
const aCommand =
a.command ??
(a.executor === 'nx:run-commands' ? a.options?.command : null);
const bCommand =
b.command ??
(b.executor === 'nx:run-commands' ? b.options?.command : null);
const sameCommand = aCommand === bCommand;
const aHasNoExecutor = !a.command && !a.executor;
const bHasNoExecutor = !b.command && !b.executor;
return sameCommand || aHasNoExecutor || bHasNoExecutor;
}
const oneHasNoExecutor = !a.executor || !b.executor;
const bothHaveSameExecutor = a.executor === b.executor;
return oneHasNoExecutor || bothHaveSameExecutor;
} }
function mergeConfigurations<T extends Object>( function mergeConfigurations<T extends Object>(

View File

@ -1,3 +1,4 @@
import { getDefaultPlugins } from '../../utils/nx-plugin';
import { TempFs } from '../../internal-testing-utils/temp-fs'; import { TempFs } from '../../internal-testing-utils/temp-fs';
import { retrieveProjectConfigurationPaths } from './retrieve-workspace-files'; import { retrieveProjectConfigurationPaths } from './retrieve-workspace-files';
@ -24,11 +25,13 @@ describe('retrieveProjectConfigurationPaths', () => {
name: 'project-1', name: 'project-1',
}) })
); );
expect(
await retrieveProjectConfigurationPaths(fs.tempDir, {}) const configPaths = await retrieveProjectConfigurationPaths(
).not.toContain('not-projects/project.json'); fs.tempDir,
expect(await retrieveProjectConfigurationPaths(fs.tempDir, {})).toContain( await getDefaultPlugins(fs.tempDir)
'projects/project.json'
); );
expect(configPaths).not.toContain('not-projects/project.json');
expect(configPaths).toContain('projects/project.json');
}); });
}); });

View File

@ -16,16 +16,16 @@ import {
ProjectGraphExternalNode, ProjectGraphExternalNode,
} from '../../config/project-graph'; } from '../../config/project-graph';
import type { NxWorkspaceFiles } from '../../native'; import type { NxWorkspaceFiles } from '../../native';
import { import { getNxPackageJsonWorkspacesPlugin } from '../../../plugins/package-json-workspaces';
getGlobPatternsFromPackageManagerWorkspaces,
getNxPackageJsonWorkspacesPlugin,
} from '../../../plugins/package-json-workspaces';
import { import {
ConfigurationSourceMaps, ConfigurationSourceMaps,
SourceInformation,
buildProjectsConfigurationsFromProjectPathsAndPlugins, buildProjectsConfigurationsFromProjectPathsAndPlugins,
} from './project-configuration-utils'; } from './project-configuration-utils';
import { LoadedNxPlugin, loadNxPlugins } from '../../utils/nx-plugin'; import {
getDefaultPlugins,
LoadedNxPlugin,
loadNxPlugins,
} from '../../utils/nx-plugin';
import { CreateProjectJsonProjectsPlugin } from '../../plugins/project-json/build-nodes/project-json'; import { CreateProjectJsonProjectsPlugin } from '../../plugins/project-json/build-nodes/project-json';
import { import {
globWithWorkspaceContext, globWithWorkspaceContext,
@ -49,7 +49,7 @@ export async function retrieveWorkspaceFiles(
getNxRequirePaths(workspaceRoot), getNxRequirePaths(workspaceRoot),
workspaceRoot workspaceRoot
); );
let globs = configurationGlobs(workspaceRoot, plugins); let globs = configurationGlobs(plugins);
performance.mark('native-file-deps:end'); performance.mark('native-file-deps:end');
performance.measure( performance.measure(
'native-file-deps', 'native-file-deps',
@ -122,7 +122,7 @@ export async function retrieveProjectConfigurations(
workspaceRoot workspaceRoot
); );
const globs = configurationGlobs(workspaceRoot, plugins); const globs = configurationGlobs(plugins);
return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs); return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs);
} }
@ -147,7 +147,7 @@ export async function retrieveProjectConfigurationsWithAngularProjects(
plugins.push({ plugin: NxAngularJsonPlugin }); plugins.push({ plugin: NxAngularJsonPlugin });
} }
const globs = configurationGlobs(workspaceRoot, plugins); const globs = configurationGlobs(plugins);
return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs); return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs);
} }
@ -189,21 +189,12 @@ function _retrieveProjectConfigurations(
).then(() => result); ).then(() => result);
} }
export async function retrieveProjectConfigurationPaths( export function retrieveProjectConfigurationPaths(
root: string, root: string,
nxJson: NxJsonConfiguration plugins: LoadedNxPlugin[]
): Promise<string[]> {
const projectGlobPatterns = configurationGlobs(
root,
await loadNxPlugins(nxJson?.plugins ?? [], getNxRequirePaths(root), root)
);
return globWithWorkspaceContext(root, projectGlobPatterns);
}
export function retrieveProjectConfigurationPathsWithoutPluginInference(
root: string
): string[] { ): string[] {
return globWithWorkspaceContext(root, configurationGlobsWithoutPlugins(root)); const projectGlobPatterns = configurationGlobs(plugins);
return globWithWorkspaceContext(root, projectGlobPatterns);
} }
const projectsWithoutPluginCache = new Map< const projectsWithoutPluginCache = new Map<
@ -216,7 +207,8 @@ export async function retrieveProjectConfigurationsWithoutPluginInference(
root: string root: string
): Promise<Record<string, ProjectConfiguration>> { ): Promise<Record<string, ProjectConfiguration>> {
const nxJson = readNxJson(root); const nxJson = readNxJson(root);
const projectGlobPatterns = configurationGlobsWithoutPlugins(root); const plugins = await getDefaultPlugins(root);
const projectGlobPatterns = retrieveProjectConfigurationPaths(root, plugins);
const cacheKey = root + ',' + projectGlobPatterns.join(','); const cacheKey = root + ',' + projectGlobPatterns.join(',');
if (projectsWithoutPluginCache.has(cacheKey)) { if (projectsWithoutPluginCache.has(cacheKey)) {
@ -302,12 +294,8 @@ export async function createProjectConfigurations(
}; };
} }
export function configurationGlobs( export function configurationGlobs(plugins: LoadedNxPlugin[]): string[] {
workspaceRoot: string, const globPatterns = [];
plugins: LoadedNxPlugin[]
): string[] {
const globPatterns: string[] =
configurationGlobsWithoutPlugins(workspaceRoot);
for (const { plugin } of plugins) { for (const { plugin } of plugins) {
if (plugin.createNodes) { if (plugin.createNodes) {
globPatterns.push(plugin.createNodes[0]); globPatterns.push(plugin.createNodes[0]);
@ -315,11 +303,3 @@ export function configurationGlobs(
} }
return globPatterns; return globPatterns;
} }
function configurationGlobsWithoutPlugins(workspaceRoot: string): string[] {
return [
'project.json',
'**/project.json',
...getGlobPatternsFromPackageManagerWorkspaces(workspaceRoot),
];
}

View File

@ -1,25 +1,10 @@
import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces'; import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces';
import { import { shouldMergeAngularProjects } from '../adapter/angular-json';
NxAngularJsonPlugin,
shouldMergeAngularProjects,
} from '../adapter/angular-json';
import { NxJsonConfiguration, PluginConfiguration } from '../config/nx-json';
import { ProjectGraphProcessor } from '../config/project-graph'; import { ProjectGraphProcessor } from '../config/project-graph';
import { import { TargetConfiguration } from '../config/workspace-json-project-json';
ProjectConfiguration, import { CreatePackageJsonProjectsNextToProjectJson } from '../plugins/project-json/build-nodes/package-json-next-to-project-json';
TargetConfiguration,
} from '../config/workspace-json-project-json';
import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json'; import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json';
import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-graph/utils/retrieve-workspace-files'; import { LoadedNxPlugin, NxPluginV2 } from './nx-plugin';
import { getNxRequirePaths } from './installation-directory';
import {
ensurePluginIsV2,
getPluginPathAndName,
LoadedNxPlugin,
nxPluginCache,
NxPluginV2,
} from './nx-plugin';
import { workspaceRoot } from './workspace-root';
/** /**
* @deprecated Add targets to the projects in a {@link CreateNodes} function instead. This will be removed in Nx 18 * @deprecated Add targets to the projects in a {@link CreateNodes} function instead. This will be removed in Nx 18
@ -55,11 +40,15 @@ export type NxPluginV1 = {
* @todo(@agentender) v18: Remove this fn when we remove readWorkspaceConfig * @todo(@agentender) v18: Remove this fn when we remove readWorkspaceConfig
*/ */
export function getDefaultPluginsSync(root: string): LoadedNxPlugin[] { export function getDefaultPluginsSync(root: string): LoadedNxPlugin[] {
const plugins: NxPluginV2[] = [require('../plugins/js')]; const plugins: NxPluginV2[] = [
require('../plugins/js'),
...(shouldMergeAngularProjects(root, false)
? [require('../adapter/angular-json').NxAngularJsonPlugin]
: []),
getNxPackageJsonWorkspacesPlugin(root),
CreateProjectJsonProjectsPlugin,
];
if (shouldMergeAngularProjects(root, false)) {
plugins.push(require('../adapter/angular-json').NxAngularJsonPlugin);
}
return plugins.map((p) => ({ return plugins.map((p) => ({
plugin: p, plugin: p,
})); }));

View File

@ -41,11 +41,6 @@ import { shouldMergeAngularProjects } 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 { 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';
import {
mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap,
} from '../project-graph/utils/project-configuration-utils';
import { globWithWorkspaceContext } from './workspace-context';
import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-graph/utils/retrieve-workspace-files'; import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-graph/utils/retrieve-workspace-files';
/** /**
@ -64,17 +59,7 @@ export type CreateNodesFunction<T = unknown> = (
projectConfigurationFile: string, projectConfigurationFile: string,
options: T | undefined, options: T | undefined,
context: CreateNodesContext context: CreateNodesContext
) => CreateNodesResult; ) => CreateNodesResult | Promise<CreateNodesResult>;
/**
* A function which parses a configuration file into a set of nodes.
* Used for creating nodes for the {@link ProjectGraph}
*/
export type CreateNodesFunctionAsync<T = unknown> = (
projectConfigurationFile: string,
options: T | undefined,
context: CreateNodesContext
) => Promise<CreateNodesResult>;
export interface CreateNodesResult { export interface CreateNodesResult {
/** /**
@ -96,11 +81,6 @@ export type CreateNodes<T = unknown> = readonly [
createNodesFunction: CreateNodesFunction<T> createNodesFunction: CreateNodesFunction<T>
]; ];
export type CreateNodesAsync<T = unknown> = readonly [
projectFilePattern: string,
createNodesFunction: CreateNodesFunctionAsync<T>
];
/** /**
* Context for {@link CreateDependencies} * Context for {@link CreateDependencies}
*/ */
@ -145,19 +125,14 @@ export type CreateDependencies<T = unknown> = (
/** /**
* A plugin for Nx which creates nodes and dependencies for the {@link ProjectGraph} * A plugin for Nx which creates nodes and dependencies for the {@link ProjectGraph}
*/ */
export type NxPluginV2< export type NxPluginV2<TOptions = unknown> = {
TOptions = unknown,
TCreateNodes extends CreateNodes<TOptions> | CreateNodesAsync<TOptions> =
| CreateNodes<TOptions>
| CreateNodesAsync<TOptions>
> = {
name: string; name: string;
/** /**
* Provides a file pattern and function that retrieves configuration info from * Provides a file pattern and function that retrieves configuration info from
* those files. e.g. { '**\/*.csproj': buildProjectsFromCsProjFile } * those files. e.g. { '**\/*.csproj': buildProjectsFromCsProjFile }
*/ */
createNodes?: TCreateNodes; createNodes?: CreateNodes;
// Todo(@AgentEnder): This shouldn't be a full processor, since its only responsible for defining edges between projects. What do we want the API to be? // Todo(@AgentEnder): This shouldn't be a full processor, since its only responsible for defining edges between projects. What do we want the API to be?
/** /**
@ -248,7 +223,7 @@ export async function loadNxPluginAsync(
if (pluginModule) { if (pluginModule) {
return { plugin: pluginModule, options }; return { plugin: pluginModule, options };
} }
performance.mark(`Load Nx Plugin: ${moduleName} - start`);
let { pluginPath, name } = await getPluginPathAndName( let { pluginPath, name } = await getPluginPathAndName(
moduleName, moduleName,
paths, paths,
@ -260,6 +235,12 @@ export async function loadNxPluginAsync(
); );
plugin.name ??= name; plugin.name ??= name;
nxPluginCache.set(moduleName, plugin); nxPluginCache.set(moduleName, plugin);
performance.mark(`Load Nx Plugin: ${moduleName} - end`);
performance.measure(
`Load Nx Plugin: ${moduleName}`,
`Load Nx Plugin: ${moduleName} - start`,
`Load Nx Plugin: ${moduleName} - end`
);
return { plugin, options }; return { plugin, options };
} }
@ -269,7 +250,9 @@ export async function loadNxPlugins(
root = workspaceRoot, root = workspaceRoot,
projects?: Record<string, ProjectConfiguration> projects?: Record<string, ProjectConfiguration>
): Promise<LoadedNxPlugin[]> { ): Promise<LoadedNxPlugin[]> {
const result: LoadedNxPlugin[] = [...(await getDefaultPlugins(root))]; const result: LoadedNxPlugin[] = [
{ plugin: CreatePackageJsonProjectsNextToProjectJson },
];
// When loading plugins for `createNodes`, we don't know what projects exist yet. // When loading plugins for `createNodes`, we don't know what projects exist yet.
projects ??= await retrieveProjectConfigurationsWithoutPluginInference(root); projects ??= await retrieveProjectConfigurationsWithoutPluginInference(root);
@ -281,10 +264,7 @@ export async function loadNxPlugins(
} }
// We push the nx core node plugins onto the end, s.t. it overwrites any other plugins // We push the nx core node plugins onto the end, s.t. it overwrites any other plugins
result.push( result.push(...(await getDefaultPlugins(root)));
{ plugin: getNxPackageJsonWorkspacesPlugin(root) },
{ plugin: CreateProjectJsonProjectsPlugin }
);
return result; return result;
} }
@ -515,17 +495,22 @@ function readPluginMainFromProjectConfiguration(
return main; return main;
} }
async function getDefaultPlugins(root: string): Promise<LoadedNxPlugin[]> { export async function getDefaultPlugins(
root: string
): Promise<LoadedNxPlugin[]> {
const plugins: NxPluginV2[] = [ const plugins: NxPluginV2[] = [
CreatePackageJsonProjectsNextToProjectJson,
await import('../plugins/js'), await import('../plugins/js'),
...(shouldMergeAngularProjects(root, false)
? [
await import('../adapter/angular-json').then(
(m) => m.NxAngularJsonPlugin
),
]
: []),
getNxPackageJsonWorkspacesPlugin(root),
CreateProjectJsonProjectsPlugin,
]; ];
if (shouldMergeAngularProjects(root, false)) {
plugins.push(
await import('../adapter/angular-json').then((m) => m.NxAngularJsonPlugin)
);
}
return plugins.map((p) => ({ return plugins.map((p) => ({
plugin: p, plugin: p,
})); }));

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'plugin', displayName: 'plugin',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'],
globals: {}, globals: {},
displayName: 'react-native', displayName: 'react-native',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'react', displayName: 'react',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'rollup', displayName: 'rollup',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'],
globals: {}, globals: {},
displayName: 'storybook', displayName: 'storybook',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'tao', displayName: 'tao',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'web', displayName: 'web',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'webpack', displayName: 'webpack',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -6,6 +6,5 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
globals: {}, globals: {},
displayName: 'workspace', displayName: 'workspace',
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -2,7 +2,6 @@
export default { export default {
displayName: 'tools-documentation-create-embeddings', displayName: 'tools-documentation-create-embeddings',
preset: './jest.preset.js', preset: './jest.preset.js',
testEnvironment: 'node',
transform: { transform: {
'^.+\\.(ts|tsx|js|jsx|mts|mjs)$': [ '^.+\\.(ts|tsx|js|jsx|mts|mjs)$': [
'ts-jest', 'ts-jest',

View File

@ -12,6 +12,5 @@ export default {
], ],
}, },
moduleFileExtensions: ['ts', 'js', 'html'], moduleFileExtensions: ['ts', 'js', 'html'],
testEnvironment: 'node',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
}; };

View File

@ -9,7 +9,7 @@
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"skipLibCheck": true, "skipLibCheck": true,
"types": ["node", "jest"], "types": ["node", "jest"],
"lib": ["ES2021"], "lib": ["ES2022"],
"declaration": true, "declaration": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"baseUrl": ".", "baseUrl": ".",