feat(core): add standard way to pass plugin options (#19589)

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
This commit is contained in:
Craigory Coppola 2023-10-16 18:24:11 -04:00 committed by GitHub
parent 7ea2374caa
commit f918a72307
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 295 additions and 174 deletions

View File

@ -1,10 +1,16 @@
# Type alias: CreateDependencies # Type alias: CreateDependencies<T\>
Ƭ **CreateDependencies**: (`context`: [`CreateDependenciesContext`](../../devkit/documents/CreateDependenciesContext)) => [`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[] \| `Promise`<[`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[]\> Ƭ **CreateDependencies**<`T`\>: (`options`: `T` \| `undefined`, `context`: [`CreateDependenciesContext`](../../devkit/documents/CreateDependenciesContext)) => [`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[] \| `Promise`<[`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[]\>
#### Type parameters
| Name | Type |
| :--- | :---------------------------------------------------------------------- |
| `T` | extends `Record`<`string`, `unknown`\> = `Record`<`string`, `unknown`\> |
#### Type declaration #### Type declaration
▸ (`context`): [`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[] \| `Promise`<[`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[]\> ▸ (`options`, `context`): [`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[] \| `Promise`<[`RawProjectGraphDependency`](../../devkit/documents/RawProjectGraphDependency)[]\>
A function which parses files in the workspace to create dependencies in the [ProjectGraph](../../devkit/documents/ProjectGraph) A function which parses files in the workspace to create dependencies in the [ProjectGraph](../../devkit/documents/ProjectGraph)
Use [validateDependency](../../devkit/documents/validateDependency) to validate dependencies Use [validateDependency](../../devkit/documents/validateDependency) to validate dependencies
@ -13,6 +19,7 @@ Use [validateDependency](../../devkit/documents/validateDependency) to validate
| Name | Type | | Name | Type |
| :-------- | :------------------------------------------------------------------------------ | | :-------- | :------------------------------------------------------------------------------ |
| `options` | `T` \| `undefined` |
| `context` | [`CreateDependenciesContext`](../../devkit/documents/CreateDependenciesContext) | | `context` | [`CreateDependenciesContext`](../../devkit/documents/CreateDependenciesContext) |
##### Returns ##### Returns

View File

@ -1,5 +1,11 @@
# Type alias: CreateNodes # Type alias: CreateNodes<T\>
Ƭ **CreateNodes**: readonly [projectFilePattern: string, createNodesFunction: CreateNodesFunction] Ƭ **CreateNodes**<`T`\>: readonly [projectFilePattern: string, createNodesFunction: CreateNodesFunction<T\>]
A pair of file patterns and [CreateNodesFunction](../../devkit/documents/CreateNodesFunction) A pair of file patterns and [CreateNodesFunction](../../devkit/documents/CreateNodesFunction)
#### Type parameters
| Name | Type |
| :--- | :---------------------------------------------------------------------- |
| `T` | extends `Record`<`string`, `unknown`\> = `Record`<`string`, `unknown`\> |

View File

@ -1,10 +1,16 @@
# Type alias: CreateNodesFunction # Type alias: CreateNodesFunction<T\>
Ƭ **CreateNodesFunction**: (`projectConfigurationFile`: `string`, `context`: [`CreateNodesContext`](../../devkit/documents/CreateNodesContext)) => { `externalNodes?`: `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> ; `projects?`: `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> } Ƭ **CreateNodesFunction**<`T`\>: (`projectConfigurationFile`: `string`, `options`: `T` \| `undefined`, `context`: [`CreateNodesContext`](../../devkit/documents/CreateNodesContext)) => { `externalNodes?`: `Record`<`string`, [`ProjectGraphExternalNode`](../../devkit/documents/ProjectGraphExternalNode)\> ; `projects?`: `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> }
#### Type parameters
| Name | Type |
| :--- | :---------------------------------------------------------------------- |
| `T` | extends `Record`<`string`, `unknown`\> = `Record`<`string`, `unknown`\> |
#### Type declaration #### Type declaration
▸ (`projectConfigurationFile`, `context`): `Object` ▸ (`projectConfigurationFile`, `options`, `context`): `Object`
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)
@ -14,6 +20,7 @@ Used for creating nodes for the [ProjectGraph](../../devkit/documents/ProjectGra
| Name | Type | | Name | Type |
| :------------------------- | :---------------------------------------------------------------- | | :------------------------- | :---------------------------------------------------------------- |
| `projectConfigurationFile` | `string` | | `projectConfigurationFile` | `string` |
| `options` | `T` \| `undefined` |
| `context` | [`CreateNodesContext`](../../devkit/documents/CreateNodesContext) | | `context` | [`CreateNodesContext`](../../devkit/documents/CreateNodesContext) |
##### Returns ##### Returns

View File

@ -32,8 +32,8 @@ Nx.json configuration
- [nxCloudEncryptionKey](../../devkit/documents/NxJsonConfiguration#nxcloudencryptionkey): string - [nxCloudEncryptionKey](../../devkit/documents/NxJsonConfiguration#nxcloudencryptionkey): string
- [nxCloudUrl](../../devkit/documents/NxJsonConfiguration#nxcloudurl): string - [nxCloudUrl](../../devkit/documents/NxJsonConfiguration#nxcloudurl): string
- [parallel](../../devkit/documents/NxJsonConfiguration#parallel): number - [parallel](../../devkit/documents/NxJsonConfiguration#parallel): number
- [plugins](../../devkit/documents/NxJsonConfiguration#plugins): string[] - [plugins](../../devkit/documents/NxJsonConfiguration#plugins): PluginDefinition[]
- [pluginsConfig](../../devkit/documents/NxJsonConfiguration#pluginsconfig): Record&lt;string, unknown&gt; - [pluginsConfig](../../devkit/documents/NxJsonConfiguration#pluginsconfig): Record&lt;string, Record&lt;string, unknown&gt;&gt;
- [release](../../devkit/documents/NxJsonConfiguration#release): NxReleaseConfiguration - [release](../../devkit/documents/NxJsonConfiguration#release): NxReleaseConfiguration
- [targetDefaults](../../devkit/documents/NxJsonConfiguration#targetdefaults): TargetDefaults - [targetDefaults](../../devkit/documents/NxJsonConfiguration#targetdefaults): TargetDefaults
- [tasksRunnerOptions](../../devkit/documents/NxJsonConfiguration#tasksrunneroptions): Object - [tasksRunnerOptions](../../devkit/documents/NxJsonConfiguration#tasksrunneroptions): Object
@ -198,7 +198,7 @@ Specifies how many tasks can be run in parallel.
### plugins ### plugins
`Optional` **plugins**: `string`[] `Optional` **plugins**: `PluginDefinition`[]
Plugins for extending the project graph Plugins for extending the project graph
@ -206,7 +206,7 @@ Plugins for extending the project graph
### pluginsConfig ### pluginsConfig
`Optional` **pluginsConfig**: `Record`<`string`, `unknown`\> `Optional` **pluginsConfig**: `Record`<`string`, `Record`<`string`, `unknown`\>\>
Configuration for Nx Plugins Configuration for Nx Plugins

View File

@ -1,13 +1,19 @@
# Type alias: NxPluginV2 # Type alias: NxPluginV2<T\>
Ƭ **NxPluginV2**: `Object` Ƭ **NxPluginV2**<`T`\>: `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
| Name | Type |
| :--- | :---------------------------------------------------------------------- |
| `T` | extends `Record`<`string`, `unknown`\> = `Record`<`string`, `unknown`\> |
#### Type declaration #### Type declaration
| Name | Type | Description | | Name | Type | Description |
| :-------------------- | :---------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | | :-------------------- | :---------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `createDependencies?` | [`CreateDependencies`](../../devkit/documents/CreateDependencies) | Provides a function to analyze files to create dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph) | | `createDependencies?` | [`CreateDependencies`](../../devkit/documents/CreateDependencies)<`T`\> | Provides a function to analyze files to create dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph) |
| `createNodes?` | [`CreateNodes`](../../devkit/documents/CreateNodes) | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFile } | | `createNodes?` | [`CreateNodes`](../../devkit/documents/CreateNodes)<`T`\> | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFile } |
| `name` | `string` | - | | `name` | `string` | - |

View File

@ -30,8 +30,8 @@ use ProjectsConfigurations or NxJsonConfiguration
- [nxCloudEncryptionKey](../../devkit/documents/Workspace#nxcloudencryptionkey): string - [nxCloudEncryptionKey](../../devkit/documents/Workspace#nxcloudencryptionkey): string
- [nxCloudUrl](../../devkit/documents/Workspace#nxcloudurl): string - [nxCloudUrl](../../devkit/documents/Workspace#nxcloudurl): string
- [parallel](../../devkit/documents/Workspace#parallel): number - [parallel](../../devkit/documents/Workspace#parallel): number
- [plugins](../../devkit/documents/Workspace#plugins): string[] - [plugins](../../devkit/documents/Workspace#plugins): PluginDefinition[]
- [pluginsConfig](../../devkit/documents/Workspace#pluginsconfig): Record&lt;string, unknown&gt; - [pluginsConfig](../../devkit/documents/Workspace#pluginsconfig): Record&lt;string, Record&lt;string, unknown&gt;&gt;
- [projects](../../devkit/documents/Workspace#projects): Record&lt;string, ProjectConfiguration&gt; - [projects](../../devkit/documents/Workspace#projects): Record&lt;string, ProjectConfiguration&gt;
- [release](../../devkit/documents/Workspace#release): NxReleaseConfiguration - [release](../../devkit/documents/Workspace#release): NxReleaseConfiguration
- [targetDefaults](../../devkit/documents/Workspace#targetdefaults): TargetDefaults - [targetDefaults](../../devkit/documents/Workspace#targetdefaults): TargetDefaults
@ -254,7 +254,7 @@ Specifies how many tasks can be run in parallel.
### plugins ### plugins
`Optional` **plugins**: `string`[] `Optional` **plugins**: `PluginDefinition`[]
Plugins for extending the project graph Plugins for extending the project graph
@ -266,7 +266,7 @@ Plugins for extending the project graph
### pluginsConfig ### pluginsConfig
`Optional` **pluginsConfig**: `Record`<`string`, `unknown`\> `Optional` **pluginsConfig**: `Record`<`string`, `Record`<`string`, `unknown`\>\>
Configuration for Nx Plugins Configuration for Nx Plugins

View File

@ -18,3 +18,39 @@ export default async function* execute(
yield* asyncGenerator(); yield* asyncGenerator();
} }
`; `;
export const NX_PLUGIN_V2_CONTENTS = `import { basename, dirname } from "path";
import { CreateNodes } from "@nx/devkit";
type PluginOptions = {
inferredTags: string[]
}
export const createNodes: CreateNodes<PluginOptions> = [
"**/my-project-file",
(f, options, ctx) => {
// f = path/to/my/file/my-project-file
const root = dirname(f);
// root = path/to/my/file
const name = basename(root);
// name = file
return {
projects: {
[name]: {
root,
targets: {
build: {
executor: "nx:run-commands",
options: {
command: "echo 'custom registered target'",
},
},
},
tags: options.inferredTags
},
},
};
},
];
`;

View File

@ -16,7 +16,10 @@ import {
} from '@nx/e2e/utils'; } from '@nx/e2e/utils';
import type { PackageJson } from 'nx/src/utils/package-json'; import type { PackageJson } from 'nx/src/utils/package-json';
import { ASYNC_GENERATOR_EXECUTOR_CONTENTS } from './nx-plugin.fixtures'; import {
ASYNC_GENERATOR_EXECUTOR_CONTENTS,
NX_PLUGIN_V2_CONTENTS,
} from './nx-plugin.fixtures';
import { join } from 'path'; import { join } from 'path';
describe('Nx Plugin', () => { describe('Nx Plugin', () => {
@ -263,7 +266,7 @@ describe('Nx Plugin', () => {
runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`); runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`);
}); });
it('should be able to infer projects and targets', async () => { it('should be able to infer projects and targets (v1)', async () => {
// Setup project inference + target inference // Setup project inference + target inference
updateFile( updateFile(
`libs/${plugin}/src/index.ts`, `libs/${plugin}/src/index.ts`,
@ -303,6 +306,36 @@ describe('Nx Plugin', () => {
); );
}); });
it('should be able to infer projects and targets (v2)', async () => {
// Setup project inference + target inference
updateFile(`libs/${plugin}/src/index.ts`, NX_PLUGIN_V2_CONTENTS);
// Register plugin in nx.json (required for inference)
updateFile(`nx.json`, (nxJson) => {
const nx = JSON.parse(nxJson);
nx.plugins = [
{
plugin: `@${npmScope}/${plugin}`,
options: { inferredTags: ['my-tag'] },
},
];
return JSON.stringify(nx, null, 2);
});
// Create project that should be inferred by Nx
const inferredProject = uniq('inferred');
createFile(`libs/${inferredProject}/my-project-file`);
// Attempt to use inferred project w/ Nx
expect(runCLI(`build ${inferredProject}`)).toContain(
'custom registered target'
);
const configuration = JSON.parse(
runCLI(`show project ${inferredProject} --json`)
);
expect(configuration.tags).toEqual(['my-tag']);
});
it('should be able to use local generators and executors', async () => { it('should be able to use local generators and executors', async () => {
const generator = uniq('generator'); const generator = uniq('generator');
const executor = uniq('executor'); const executor = uniq('executor');

View File

@ -70,7 +70,7 @@
"type": "array", "type": "array",
"description": "Plugins for extending the project graph.", "description": "Plugins for extending the project graph.",
"items": { "items": {
"type": "string" "$ref": "#/definitions/plugins"
} }
}, },
"defaultProject": { "defaultProject": {
@ -377,6 +377,27 @@
} }
}, },
"additionalProperties": false "additionalProperties": false
},
"plugins": {
"oneOf": [
{
"type": "string",
"description": "A plugin module to load with default options"
},
{
"type": "object",
"properties": {
"plugin": {
"type": "string",
"description": "The plugin module to load"
},
"options": {
"type": "object",
"description": "The options passed to the plugin when creating nodes and dependencies"
}
}
}
]
} }
} }
} }

View File

@ -2,7 +2,7 @@ import { existsSync } from 'fs';
import * as path from 'path'; import * as path from 'path';
import { readJsonFile } from '../utils/fileutils'; import { readJsonFile } from '../utils/fileutils';
import { ProjectsConfigurations } from '../config/workspace-json-project-json'; import { ProjectsConfigurations } from '../config/workspace-json-project-json';
import { NxPluginV2 } from '../devkit-exports'; import { NxPluginV2 } from '../utils/nx-plugin';
export const NX_ANGULAR_JSON_PLUGIN_NAME = 'nx-angular-json-plugin'; export const NX_ANGULAR_JSON_PLUGIN_NAME = 'nx-angular-json-plugin';
@ -10,7 +10,7 @@ export const NxAngularJsonPlugin: NxPluginV2 = {
name: NX_ANGULAR_JSON_PLUGIN_NAME, name: NX_ANGULAR_JSON_PLUGIN_NAME,
createNodes: [ createNodes: [
'angular.json', 'angular.json',
(f, ctx) => ({ (f, _, ctx) => ({
projects: readAngularJson(ctx.workspaceRoot), projects: readAngularJson(ctx.workspaceRoot),
}), }),
], ],

View File

@ -367,7 +367,7 @@ function addNrwlJsPluginsConfig(repoRoot: string) {
json.pluginsConfig = { json.pluginsConfig = {
'@nx/js': { '@nx/js': {
analyzeSourceFiles: true, analyzeSourceFiles: true,
} as NrwlJsPluginConfig, },
}; };
} }

View File

@ -176,12 +176,12 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
/** /**
* Plugins for extending the project graph * Plugins for extending the project graph
*/ */
plugins?: string[]; plugins?: PluginDefinition[];
/** /**
* Configuration for Nx Plugins * Configuration for Nx Plugins
*/ */
pluginsConfig?: Record<string, unknown>; pluginsConfig?: Record<string, Record<string, unknown>>;
/** /**
* Default project. When project isn't provided, the default project * Default project. When project isn't provided, the default project
@ -234,6 +234,10 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
useDaemonProcess?: boolean; useDaemonProcess?: boolean;
} }
export type PluginDefinition =
| string
| { plugin: string; options?: Record<string, unknown> };
export function readNxJson(root: string = workspaceRoot): NxJsonConfiguration { export function readNxJson(root: string = workspaceRoot): NxJsonConfiguration {
const nxJson = join(root, 'nx.json'); const nxJson = join(root, 'nx.json');
if (existsSync(nxJson)) { if (existsSync(nxJson)) {

View File

@ -213,7 +213,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
if (basename(projectFile) === 'project.json') { if (basename(projectFile) === 'project.json') {
const json = readJson(tree, projectFile); const json = readJson(tree, projectFile);
const config = buildProjectFromProjectJson(json, projectFile); const config = buildProjectFromProjectJson(json, projectFile);
mergeProjectConfigurationIntoRootMap(rootMap, config, projectFile); mergeProjectConfigurationIntoRootMap(rootMap, config);
} else { } else {
const packageJson = readJson<PackageJson>(tree, projectFile); const packageJson = readJson<PackageJson>(tree, projectFile);
const config = buildProjectConfigurationFromPackageJson( const config = buildProjectConfigurationFromPackageJson(
@ -228,8 +228,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
{ {
name: config.name, name: config.name,
root: config.root, root: config.root,
}, }
projectFile
); );
} }
} }

View File

@ -36,7 +36,7 @@ let parsedLockFile: ParsedLockFile = {};
export const createNodes: CreateNodes = [ export const createNodes: CreateNodes = [
// Look for all lockfiles // Look for all lockfiles
combineGlobPatterns(LOCKFILES), combineGlobPatterns(LOCKFILES),
(lockFile, context) => { (lockFile, _, context) => {
const pluginConfig = jsPluginConfig(context.nxJsonConfiguration); const pluginConfig = jsPluginConfig(context.nxJsonConfiguration);
if (!pluginConfig.analyzeLockfile) { if (!pluginConfig.analyzeLockfile) {
return {}; return {};
@ -74,6 +74,7 @@ export const createNodes: CreateNodes = [
]; ];
export const createDependencies: CreateDependencies = ( export const createDependencies: CreateDependencies = (
_,
ctx: CreateDependenciesContext ctx: CreateDependenciesContext
) => { ) => {
const pluginConfig = jsPluginConfig(ctx.nxJsonConfiguration); const pluginConfig = jsPluginConfig(ctx.nxJsonConfiguration);

View File

@ -55,7 +55,8 @@ describe('nx project.json plugin', () => {
'/root' '/root'
); );
expect(createNodes[1]('project.json', context)).toMatchInlineSnapshot(` expect(createNodes[1]('project.json', undefined, context))
.toMatchInlineSnapshot(`
{ {
"projects": { "projects": {
"root": { "root": {
@ -68,7 +69,7 @@ describe('nx project.json plugin', () => {
}, },
} }
`); `);
expect(createNodes[1]('packages/lib-a/project.json', context)) expect(createNodes[1]('packages/lib-a/project.json', undefined, context))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
{ {
"projects": { "projects": {

View File

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

View File

@ -15,7 +15,6 @@ import { applyImplicitDependencies } from './utils/implicit-project-dependencies
import { normalizeProjectNodes } from './utils/normalize-project-nodes'; import { normalizeProjectNodes } from './utils/normalize-project-nodes';
import { import {
CreateDependenciesContext, CreateDependenciesContext,
CreateNodesContext,
isNxPluginV1, isNxPluginV1,
isNxPluginV2, isNxPluginV2,
loadNxPlugins, loadNxPlugins,
@ -234,7 +233,7 @@ async function updateProjectGraphWithPlugins(
) { ) {
const plugins = await loadNxPlugins(context.nxJsonConfiguration?.plugins); const plugins = await loadNxPlugins(context.nxJsonConfiguration?.plugins);
let graph = initProjectGraph; let graph = initProjectGraph;
for (const plugin of plugins) { for (const { plugin } of plugins) {
try { try {
if ( if (
isNxPluginV1(plugin) && isNxPluginV1(plugin) &&
@ -280,12 +279,12 @@ async function updateProjectGraphWithPlugins(
); );
const createDependencyPlugins = plugins.filter( const createDependencyPlugins = plugins.filter(
(plugin) => isNxPluginV2(plugin) && plugin.createDependencies ({ plugin }) => isNxPluginV2(plugin) && plugin.createDependencies
); );
await Promise.all( await Promise.all(
createDependencyPlugins.map(async (plugin) => { createDependencyPlugins.map(async ({ plugin, options }) => {
try { try {
const dependencies = await plugin.createDependencies({ const dependencies = await plugin.createDependencies(options, {
...context, ...context,
}); });

View File

@ -111,7 +111,7 @@ describe('nx deps utils', () => {
createCache({}), createCache({}),
createPackageJsonDeps({ plugin: '2.0.0' }), createPackageJsonDeps({ plugin: '2.0.0' }),
createProjectsConfiguration({}), createProjectsConfiguration({}),
createNxJson({ pluginsConfig: { one: 1 } }), createNxJson({ pluginsConfig: { somePlugin: { one: 1 } } }),
createTsConfigJson() createTsConfigJson()
) )
).toEqual(true); ).toEqual(true);

View File

@ -2,7 +2,7 @@ import { existsSync } from 'fs';
import { ensureDirSync, renameSync } from 'fs-extra'; import { ensureDirSync, renameSync } from 'fs-extra';
import { join } from 'path'; import { join } from 'path';
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import { NxJsonConfiguration } from '../config/nx-json'; import { NxJsonConfiguration, PluginDefinition } from '../config/nx-json';
import { import {
FileData, FileData,
FileMap, FileMap,
@ -17,6 +17,7 @@ import {
readJsonFile, readJsonFile,
writeJsonFile, writeJsonFile,
} from '../utils/fileutils'; } from '../utils/fileutils';
import { PackageJson } from '../utils/package-json';
import { nxVersion } from '../utils/versions'; import { nxVersion } from '../utils/versions';
export interface FileMapCache { export interface FileMapCache {
@ -24,7 +25,7 @@ export interface FileMapCache {
nxVersion: string; nxVersion: string;
deps: Record<string, string>; deps: Record<string, string>;
pathMappings: Record<string, any>; pathMappings: Record<string, any>;
nxJsonPlugins: { name: string; version: string }[]; nxJsonPlugins: PluginData[];
pluginsConfig?: any; pluginsConfig?: any;
fileMap: FileMap; fileMap: FileMap;
} }
@ -111,10 +112,7 @@ export function createProjectFileMapCache(
fileMap: FileMap, fileMap: FileMap,
tsConfig: { compilerOptions?: { paths?: { [p: string]: any } } } tsConfig: { compilerOptions?: { paths?: { [p: string]: any } } }
) { ) {
const nxJsonPlugins = (nxJson?.plugins || []).map((p) => ({ const nxJsonPlugins = getNxJsonPluginsData(nxJson, packageJsonDeps);
name: p,
version: packageJsonDeps[p],
}));
const newValue: FileMapCache = { const newValue: FileMapCache = {
version: '6.0', version: '6.0',
nxVersion: nxVersion, nxVersion: nxVersion,
@ -207,16 +205,9 @@ export function shouldRecomputeWholeGraph(
} }
// a new plugin has been added // a new plugin has been added
if ((nxJson?.plugins || []).length !== cache.nxJsonPlugins.length)
return true;
// a plugin has changed
if ( if (
(nxJson?.plugins || []).some((t) => { JSON.stringify(getNxJsonPluginsData(nxJson, packageJsonDeps)) !==
const matchingPlugin = cache.nxJsonPlugins.find((p) => p.name === t); JSON.stringify(cache.nxJsonPlugins)
if (!matchingPlugin) return true;
return matchingPlugin.version !== packageJsonDeps[t];
})
) { ) {
return true; return true;
} }
@ -333,3 +324,24 @@ function processProjectNode(
} }
} }
} }
type PluginData = {
name: string;
version: string;
options?: Record<string, unknown>;
};
function getNxJsonPluginsData(
nxJson: NxJsonConfiguration,
packageJsonDeps: Record<string, string>
): PluginData[] {
return (nxJson?.plugins || []).map((p) => {
const [plugin, options] =
typeof p === 'string' ? [p] : [p.plugin, p.options];
return {
name: plugin,
version: packageJsonDeps[plugin],
options,
};
});
}

View File

@ -371,19 +371,15 @@ describe('mergeProjectConfigurationIntoRootMap', () => {
}, },
}) })
.getRootMap(); .getRootMap();
mergeProjectConfigurationIntoRootMap( mergeProjectConfigurationIntoRootMap(rootMap, {
rootMap, root: 'libs/lib-a',
{ name: 'lib-a',
root: 'libs/lib-a', targets: {
name: 'lib-a', build: {
targets: { command: 'tsc',
build: {
command: 'tsc',
},
}, },
}, },
'inferred-project-config-file.ts' });
);
expect(rootMap.get('libs/lib-a')).toMatchInlineSnapshot(` expect(rootMap.get('libs/lib-a')).toMatchInlineSnapshot(`
{ {
"name": "lib-a", "name": "lib-a",
@ -399,33 +395,6 @@ describe('mergeProjectConfigurationIntoRootMap', () => {
} }
`); `);
}); });
it("shouldn't overwrite project name, unless merging project from project.json", () => {
const rootMap = new RootMapBuilder()
.addProject({
name: 'bad-name',
root: 'libs/lib-a',
})
.getRootMap();
mergeProjectConfigurationIntoRootMap(
rootMap,
{
name: 'other-bad-name',
root: 'libs/lib-a',
},
'libs/lib-a/package.json'
);
expect(rootMap.get('libs/lib-a').name).toEqual('bad-name');
mergeProjectConfigurationIntoRootMap(
rootMap,
{
name: 'lib-a',
root: 'libs/lib-a',
},
'libs/lib-a/project.json'
);
expect(rootMap.get('libs/lib-a').name).toEqual('lib-a');
});
}); });
describe('readProjectsConfigurationsFromRootMap', () => { describe('readProjectsConfigurationsFromRootMap', () => {

View File

@ -1,5 +1,3 @@
import { basename } from 'node:path';
import { NxJsonConfiguration, TargetDefaults } from '../../config/nx-json'; import { NxJsonConfiguration, TargetDefaults } from '../../config/nx-json';
import { ProjectGraphExternalNode } from '../../config/project-graph'; import { ProjectGraphExternalNode } from '../../config/project-graph';
import { import {
@ -7,30 +5,20 @@ import {
TargetConfiguration, TargetConfiguration,
} from '../../config/workspace-json-project-json'; } from '../../config/workspace-json-project-json';
import { NX_PREFIX } from '../../utils/logger'; import { NX_PREFIX } from '../../utils/logger';
import { NxPluginV2 } from '../../utils/nx-plugin'; import { LoadedNxPlugin } from '../../utils/nx-plugin';
import { workspaceRoot } from '../../utils/workspace-root'; import { workspaceRoot } from '../../utils/workspace-root';
import minimatch = require('minimatch'); import minimatch = require('minimatch');
export function mergeProjectConfigurationIntoRootMap( export function mergeProjectConfigurationIntoRootMap(
projectRootMap: Map<string, ProjectConfiguration>, projectRootMap: Map<string, ProjectConfiguration>,
project: ProjectConfiguration, project: ProjectConfiguration
// project.json is a special case, so we need to detect it.
file: string
): void { ): void {
const matchingProject = projectRootMap.get(project.root); const matchingProject = projectRootMap.get(project.root);
if (!matchingProject) { if (!matchingProject) {
projectRootMap.set(project.root, project); projectRootMap.set(project.root, project);
return; return;
} else if (
project.name &&
project.name !== matchingProject.name &&
basename(file) === 'project.json'
) {
// `name` inside project.json overrides any names from
// inference plugins
matchingProject.name = project.name;
} }
// This handles top level properties that are overwritten. // This handles top level properties that are overwritten.
@ -41,7 +29,6 @@ export function mergeProjectConfigurationIntoRootMap(
const updatedProjectConfiguration = { const updatedProjectConfiguration = {
...matchingProject, ...matchingProject,
...project, ...project,
name: matchingProject.name,
}; };
// The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies) // The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies)
@ -79,7 +66,7 @@ export function mergeProjectConfigurationIntoRootMap(
export function buildProjectsConfigurationsFromProjectPathsAndPlugins( 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: NxPluginV2[], plugins: LoadedNxPlugin[],
root: string = workspaceRoot root: string = workspaceRoot
): { ): {
projects: Record<string, ProjectConfiguration>; projects: Record<string, ProjectConfiguration>;
@ -89,7 +76,7 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
const externalNodes: Record<string, ProjectGraphExternalNode> = {}; const externalNodes: Record<string, ProjectGraphExternalNode> = {};
// 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 of plugins) { for (const { plugin, options } of plugins) {
const [pattern, createNodes] = plugin.createNodes ?? []; const [pattern, createNodes] = plugin.createNodes ?? [];
if (!pattern) { if (!pattern) {
continue; continue;
@ -97,7 +84,7 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
for (const file of projectFiles) { for (const file of projectFiles) {
if (minimatch(file, pattern, { dot: true })) { if (minimatch(file, pattern, { dot: true })) {
const { projects: projectNodes, externalNodes: pluginExternalNodes } = const { projects: projectNodes, externalNodes: pluginExternalNodes } =
createNodes(file, { createNodes(file, options, {
nxJsonConfiguration: nxJson, nxJsonConfiguration: nxJson,
workspaceRoot: root, workspaceRoot: root,
}); });
@ -105,8 +92,7 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
projectNodes[node].name ??= node; projectNodes[node].name ??= node;
mergeProjectConfigurationIntoRootMap( mergeProjectConfigurationIntoRootMap(
projectRootMap, projectRootMap,
projectNodes[node], projectNodes[node]
file
); );
} }
Object.assign(externalNodes, pluginExternalNodes); Object.assign(externalNodes, pluginExternalNodes);

View File

@ -22,6 +22,7 @@ import {
} from '../../../plugins/package-json-workspaces'; } from '../../../plugins/package-json-workspaces';
import { buildProjectsConfigurationsFromProjectPathsAndPlugins } from './project-configuration-utils'; import { buildProjectsConfigurationsFromProjectPathsAndPlugins } from './project-configuration-utils';
import { import {
LoadedNxPlugin,
loadNxPlugins, loadNxPlugins,
loadNxPluginsSync, loadNxPluginsSync,
NxPluginV2, NxPluginV2,
@ -137,9 +138,9 @@ export async function retrieveProjectConfigurationsWithAngularProjects(
if ( if (
shouldMergeAngularProjects(workspaceRoot, true) && shouldMergeAngularProjects(workspaceRoot, true) &&
!plugins.some((p) => p.name === NX_ANGULAR_JSON_PLUGIN_NAME) !plugins.some((p) => p.plugin.name === NX_ANGULAR_JSON_PLUGIN_NAME)
) { ) {
plugins.push(NxAngularJsonPlugin); plugins.push({ plugin: NxAngularJsonPlugin });
} }
const globs = configurationGlobs(workspaceRoot, plugins); const globs = configurationGlobs(workspaceRoot, plugins);
@ -169,7 +170,7 @@ export function retrieveProjectConfigurationsSync(
function _retrieveProjectConfigurations( function _retrieveProjectConfigurations(
workspaceRoot: string, workspaceRoot: string,
nxJson: NxJsonConfiguration, nxJson: NxJsonConfiguration,
plugins: NxPluginV2[], plugins: LoadedNxPlugin[],
globs: string[] globs: string[]
): { ): {
externalNodes: Record<string, ProjectGraphExternalNode>; externalNodes: Record<string, ProjectGraphExternalNode>;
@ -236,8 +237,8 @@ export function retrieveProjectConfigurationsWithoutPluginInference(
projectGlobPatterns, projectGlobPatterns,
(configs: string[]) => { (configs: string[]) => {
const { projects } = createProjectConfigurations(root, nxJson, configs, [ const { projects } = createProjectConfigurations(root, nxJson, configs, [
getNxPackageJsonWorkspacesPlugin(root), { plugin: getNxPackageJsonWorkspacesPlugin(root) },
CreateProjectJsonProjectsPlugin, { plugin: CreateProjectJsonProjectsPlugin },
]); ]);
return { return {
projectNodes: projects, projectNodes: projects,
@ -273,7 +274,7 @@ export function createProjectConfigurations(
workspaceRoot: string, workspaceRoot: string,
nxJson: NxJsonConfiguration, nxJson: NxJsonConfiguration,
configFiles: string[], configFiles: string[],
plugins: NxPluginV2[] plugins: LoadedNxPlugin[]
): { ): {
projects: Record<string, ProjectConfiguration>; projects: Record<string, ProjectConfiguration>;
externalNodes: Record<string, ProjectGraphExternalNode>; externalNodes: Record<string, ProjectGraphExternalNode>;
@ -305,11 +306,11 @@ export function createProjectConfigurations(
export function configurationGlobs( export function configurationGlobs(
workspaceRoot: string, workspaceRoot: string,
plugins: NxPluginV2[] plugins: LoadedNxPlugin[]
): string[] { ): string[] {
const globPatterns: string[] = const globPatterns: string[] =
configurationGlobsWithoutPlugins(workspaceRoot); 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]);
} }

View File

@ -1,9 +1,7 @@
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import * as path from 'path'; import * as path from 'path';
import { import {
FileData,
FileMap, FileMap,
ProjectFileMap,
ProjectGraph, ProjectGraph,
ProjectGraphExternalNode, ProjectGraphExternalNode,
} from '../config/project-graph'; } from '../config/project-graph';
@ -19,10 +17,7 @@ import {
registerTranspiler, registerTranspiler,
registerTsConfigPaths, registerTsConfigPaths,
} from '../plugins/js/utils/register'; } from '../plugins/js/utils/register';
import { import { ProjectConfiguration } from '../config/workspace-json-project-json';
ProjectConfiguration,
ProjectsConfigurations,
} from '../config/workspace-json-project-json';
import { logger } from './logger'; import { logger } from './logger';
import { import {
createProjectRootMappingsFromProjectConfigurations, createProjectRootMappingsFromProjectConfigurations,
@ -32,7 +27,7 @@ import { normalizePath } from './path';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { getNxRequirePaths } from './installation-directory'; import { getNxRequirePaths } from './installation-directory';
import { readTsConfig } from '../plugins/js/utils/typescript'; import { readTsConfig } from '../plugins/js/utils/typescript';
import { NxJsonConfiguration } from '../config/nx-json'; import { NxJsonConfiguration, PluginDefinition } from '../config/nx-json';
import type * as ts from 'typescript'; import type * as ts from 'typescript';
import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-graph/utils/retrieve-workspace-files'; import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-graph/utils/retrieve-workspace-files';
@ -45,6 +40,7 @@ import {
} from '../adapter/angular-json'; } from '../adapter/angular-json';
import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces'; import { getNxPackageJsonWorkspacesPlugin } from '../../plugins/package-json-workspaces';
import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json'; import { CreateProjectJsonProjectsPlugin } from '../plugins/project-json/build-nodes/project-json';
import { FileMapCache } from '../project-graph/nx-deps-cache';
/** /**
* Context for {@link CreateNodesFunction} * Context for {@link CreateNodesFunction}
@ -58,8 +54,11 @@ export interface CreateNodesContext {
* 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 {@link ProjectGraph} * Used for creating nodes for the {@link ProjectGraph}
*/ */
export type CreateNodesFunction = ( export type CreateNodesFunction<
T extends Record<string, unknown> = Record<string, unknown>
> = (
projectConfigurationFile: string, projectConfigurationFile: string,
options: T | undefined,
context: CreateNodesContext context: CreateNodesContext
) => { ) => {
projects?: Record<string, ProjectConfiguration>; projects?: Record<string, ProjectConfiguration>;
@ -69,9 +68,11 @@ export type CreateNodesFunction = (
/** /**
* A pair of file patterns and {@link CreateNodesFunction} * A pair of file patterns and {@link CreateNodesFunction}
*/ */
export type CreateNodes = readonly [ export type CreateNodes<
T extends Record<string, unknown> = Record<string, unknown>
> = readonly [
projectFilePattern: string, projectFilePattern: string,
createNodesFunction: CreateNodesFunction createNodesFunction: CreateNodesFunction<T>
]; ];
/** /**
@ -110,27 +111,32 @@ export interface CreateDependenciesContext {
* A function which parses files in the workspace to create dependencies in the {@link ProjectGraph} * A function which parses files in the workspace to create dependencies in the {@link ProjectGraph}
* Use {@link validateDependency} to validate dependencies * Use {@link validateDependency} to validate dependencies
*/ */
export type CreateDependencies = ( export type CreateDependencies<
T extends Record<string, unknown> = Record<string, unknown>
> = (
options: T | undefined,
context: CreateDependenciesContext context: CreateDependenciesContext
) => RawProjectGraphDependency[] | Promise<RawProjectGraphDependency[]>; ) => RawProjectGraphDependency[] | Promise<RawProjectGraphDependency[]>;
/** /**
* 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<
T extends Record<string, unknown> = Record<string, unknown>
> = {
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?: CreateNodes; createNodes?: CreateNodes<T>;
// 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?
/** /**
* Provides a function to analyze files to create dependencies for the {@link ProjectGraph} * Provides a function to analyze files to create dependencies for the {@link ProjectGraph}
*/ */
createDependencies?: CreateDependencies; createDependencies?: CreateDependencies<T>;
}; };
export * from './nx-plugin.deprecated'; export * from './nx-plugin.deprecated';
@ -140,11 +146,16 @@ export * from './nx-plugin.deprecated';
*/ */
export type NxPlugin = NxPluginV1 | NxPluginV2; export type NxPlugin = NxPluginV1 | NxPluginV2;
export type LoadedNxPlugin = {
plugin: NxPluginV2 & Pick<NxPluginV1, 'processProjectGraph'>;
options?: Record<string, unknown>;
};
// Short lived cache (cleared between cmd runs) // Short lived cache (cleared between cmd runs)
// holding resolved nx plugin objects. // holding resolved nx plugin objects.
// Allows loadNxPlugins to be called multiple times w/o // Allows loadNxPlugins to be called multiple times w/o
// executing resolution mulitple times. // executing resolution mulitple times.
let nxPluginCache: Map<string, NxPlugin> = new Map(); let nxPluginCache: Map<string, LoadedNxPlugin['plugin']> = new Map();
function getPluginPathAndName( function getPluginPathAndName(
moduleName: string, moduleName: string,
@ -191,50 +202,66 @@ function getPluginPathAndName(
} }
export async function loadNxPluginAsync( export async function loadNxPluginAsync(
moduleName: string, pluginDefinition: PluginDefinition,
paths: string[], paths: string[],
root: string root: string
) { ): Promise<LoadedNxPlugin> {
const { plugin: moduleName, options } =
typeof pluginDefinition === 'object'
? pluginDefinition
: { plugin: pluginDefinition, options: undefined };
let pluginModule = nxPluginCache.get(moduleName); let pluginModule = nxPluginCache.get(moduleName);
if (pluginModule) { if (pluginModule) {
return pluginModule; return { plugin: pluginModule, options };
} }
let { pluginPath, name } = getPluginPathAndName(moduleName, paths, root); let { pluginPath, name } = getPluginPathAndName(moduleName, paths, root);
const plugin = (await import(pluginPath)) as NxPlugin; const plugin = ensurePluginIsV2(
(await import(pluginPath)) as LoadedNxPlugin['plugin']
);
plugin.name ??= name; plugin.name ??= name;
nxPluginCache.set(moduleName, plugin); nxPluginCache.set(moduleName, plugin);
return plugin; return { plugin, options };
} }
function loadNxPluginSync(moduleName: string, paths: string[], root: string) { function loadNxPluginSync(
pluginDefinition: PluginDefinition,
paths: string[],
root: string
): LoadedNxPlugin {
const { plugin: moduleName, options } =
typeof pluginDefinition === 'object'
? pluginDefinition
: { plugin: pluginDefinition, options: undefined };
let pluginModule = nxPluginCache.get(moduleName); let pluginModule = nxPluginCache.get(moduleName);
if (pluginModule) { if (pluginModule) {
return pluginModule; return { plugin: pluginModule, options };
} }
let { pluginPath, name } = getPluginPathAndName(moduleName, paths, root); let { pluginPath, name } = getPluginPathAndName(moduleName, paths, root);
const plugin = require(pluginPath) as NxPlugin; const plugin = ensurePluginIsV2(
require(pluginPath)
) as LoadedNxPlugin['plugin'];
plugin.name ??= name; plugin.name ??= name;
nxPluginCache.set(moduleName, plugin); nxPluginCache.set(moduleName, plugin);
return plugin; return { plugin, options };
} }
/** /**
* @deprecated Use loadNxPlugins instead. * @deprecated Use loadNxPlugins instead.
*/ */
export function loadNxPluginsSync( export function loadNxPluginsSync(
plugins: string[], plugins: NxJsonConfiguration['plugins'],
paths = getNxRequirePaths(), paths = getNxRequirePaths(),
root = workspaceRoot root = workspaceRoot
): (NxPluginV2 & Pick<NxPluginV1, 'processProjectGraph'>)[] { ): LoadedNxPlugin[] {
// TODO: This should be specified in nx.json // TODO: This should be specified in nx.json
// Temporarily load js as if it were a plugin which is built into nx // Temporarily load js as if it were a plugin which is built into nx
// In the future, this will be optional and need to be specified in nx.json // In the future, this will be optional and need to be specified in nx.json
const result: NxPlugin[] = [...getDefaultPluginsSync(root)]; const result: LoadedNxPlugin[] = [...getDefaultPluginsSync(root)];
if (shouldMergeAngularProjects(root, false)) { if (shouldMergeAngularProjects(root, false)) {
result.push(NxAngularJsonPlugin); result.push({ plugin: NxAngularJsonPlugin, options: undefined });
} }
plugins ??= []; plugins ??= [];
@ -253,19 +280,19 @@ export function loadNxPluginsSync(
// 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(
getNxPackageJsonWorkspacesPlugin(root), { plugin: getNxPackageJsonWorkspacesPlugin(root) },
CreateProjectJsonProjectsPlugin { plugin: CreateProjectJsonProjectsPlugin }
); );
return result.map(ensurePluginIsV2); return result;
} }
export async function loadNxPlugins( export async function loadNxPlugins(
plugins: string[], plugins: PluginDefinition[],
paths = getNxRequirePaths(), paths = getNxRequirePaths(),
root = workspaceRoot root = workspaceRoot
): Promise<(NxPluginV2 & Pick<NxPluginV1, 'processProjectGraph'>)[]> { ): Promise<LoadedNxPlugin[]> {
const result: NxPlugin[] = [...(await getDefaultPlugins(root))]; const result: LoadedNxPlugin[] = [...(await getDefaultPlugins(root))];
// TODO: These should be specified in nx.json // TODO: These should be specified in nx.json
// Temporarily load js as if it were a plugin which is built into nx // Temporarily load js as if it were a plugin which is built into nx
@ -279,11 +306,11 @@ 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(
getNxPackageJsonWorkspacesPlugin(root), { plugin: getNxPackageJsonWorkspacesPlugin(root) },
CreateProjectJsonProjectsPlugin { plugin: CreateProjectJsonProjectsPlugin }
); );
return result.map(ensurePluginIsV2); return result;
} }
function ensurePluginIsV2(plugin: NxPlugin): NxPluginV2 { function ensurePluginIsV2(plugin: NxPlugin): NxPluginV2 {
@ -494,22 +521,26 @@ function readPluginMainFromProjectConfiguration(
return main; return main;
} }
async function getDefaultPlugins(root: string) { async function getDefaultPlugins(root: string): Promise<LoadedNxPlugin[]> {
const plugins: NxPlugin[] = [await import('../plugins/js')]; const plugins: NxPluginV2[] = [await import('../plugins/js')];
if (shouldMergeAngularProjects(root, false)) { if (shouldMergeAngularProjects(root, false)) {
plugins.push( plugins.push(
await import('../adapter/angular-json').then((m) => m.NxAngularJsonPlugin) await import('../adapter/angular-json').then((m) => m.NxAngularJsonPlugin)
); );
} }
return plugins; return plugins.map((p) => ({
plugin: p,
}));
} }
function getDefaultPluginsSync(root: string) { function getDefaultPluginsSync(root: string): LoadedNxPlugin[] {
const plugins: NxPlugin[] = [require('../plugins/js')]; const plugins: NxPluginV2[] = [require('../plugins/js')];
if (shouldMergeAngularProjects(root, false)) { if (shouldMergeAngularProjects(root, false)) {
plugins.push(require('../adapter/angular-json').NxAngularJsonPlugin); plugins.push(require('../adapter/angular-json').NxAngularJsonPlugin);
} }
return plugins; return plugins.map((p) => ({
plugin: p,
}));
} }

View File

@ -21,7 +21,7 @@ export async function getLocalWorkspacePlugins(
if (existsSync(packageJsonPath)) { if (existsSync(packageJsonPath)) {
const packageJson: PackageJson = readJsonFile(packageJsonPath); const packageJson: PackageJson = readJsonFile(packageJsonPath);
const includeRuntimeCapabilities = nxJson?.plugins?.some((p) => const includeRuntimeCapabilities = nxJson?.plugins?.some((p) =>
p.startsWith(packageJson.name) (typeof p === 'string' ? p : p.plugin).startsWith(packageJson.name)
); );
const capabilities = await getPluginCapabilities( const capabilities = await getPluginCapabilities(
workspaceRoot, workspaceRoot,

View File

@ -103,11 +103,13 @@ async function tryGetModule(
packageJson['nx-migrations'] ?? packageJson['nx-migrations'] ??
packageJson['schematics'] ?? packageJson['schematics'] ??
packageJson['builders'] packageJson['builders']
? await loadNxPluginAsync( ? (
packageJson.name, await loadNxPluginAsync(
getNxRequirePaths(workspaceRoot), packageJson.name,
workspaceRoot getNxRequirePaths(workspaceRoot),
) workspaceRoot
)
).plugin
: ({ : ({
name: packageJson.name, name: packageJson.name,
} as NxPlugin); } as NxPlugin);