diff --git a/packages/nx/src/adapter/ngcli-adapter.ts b/packages/nx/src/adapter/ngcli-adapter.ts index 5eb32c91683e8..ea461cec888f4 100644 --- a/packages/nx/src/adapter/ngcli-adapter.ts +++ b/packages/nx/src/adapter/ngcli-adapter.ts @@ -1190,7 +1190,8 @@ async function getWrappedWorkspaceNodeModulesArchitectHost( private readExecutorsJson( nodeModule: string, - builder: string + builder: string, + extraRequirePaths: string[] = [] ): { executorsFilePath: string; executorConfig: ExecutorJsonEntryConfig; @@ -1200,7 +1201,9 @@ async function getWrappedWorkspaceNodeModulesArchitectHost( readPluginPackageJson( nodeModule, this.projects, - this.root ? [this.root, __dirname] : [__dirname] + this.root + ? [this.root, __dirname, ...extraRequirePaths] + : [__dirname, ...extraRequirePaths] ); const executorsFile = packageJson.executors ?? packageJson.builders; @@ -1210,9 +1213,8 @@ async function getWrappedWorkspaceNodeModulesArchitectHost( ); } - const executorsFilePath = require.resolve( - join(dirname(packageJsonPath), executorsFile) - ); + const basePath = dirname(packageJsonPath); + const executorsFilePath = require.resolve(join(basePath, executorsFile)); const executorsJson = readJsonFile(executorsFilePath); const executorConfig = executorsJson.builders?.[builder] ?? executorsJson.executors?.[builder]; @@ -1224,7 +1226,7 @@ async function getWrappedWorkspaceNodeModulesArchitectHost( if (typeof executorConfig === 'string') { // Angular CLI can have a builder pointing to another package:builder const [packageName, executorName] = executorConfig.split(':'); - return this.readExecutorsJson(packageName, executorName); + return this.readExecutorsJson(packageName, executorName, [basePath]); } return { executorsFilePath, executorConfig, isNgCompat: true }; diff --git a/packages/nx/src/command-line/run/executor-utils.ts b/packages/nx/src/command-line/run/executor-utils.ts index d24006801b8f2..2840c1b5367af 100644 --- a/packages/nx/src/command-line/run/executor-utils.ts +++ b/packages/nx/src/command-line/run/executor-utils.ts @@ -99,7 +99,8 @@ function readExecutorJson( nodeModule: string, executor: string, root: string, - projects: Record + projects: Record, + extraRequirePaths: string[] = [] ): { executorsFilePath: string; executorConfig: { @@ -114,8 +115,14 @@ function readExecutorJson( nodeModule, projects, root - ? [root, __dirname, process.cwd(), ...getNxRequirePaths()] - : [__dirname, process.cwd(), ...getNxRequirePaths()] + ? [ + root, + __dirname, + process.cwd(), + ...getNxRequirePaths(), + ...extraRequirePaths, + ] + : [__dirname, process.cwd(), ...getNxRequirePaths(), ...extraRequirePaths] ); const executorsFile = packageJson.executors ?? packageJson.builders; @@ -125,9 +132,8 @@ function readExecutorJson( ); } - const executorsFilePath = require.resolve( - join(dirname(packageJsonPath), executorsFile) - ); + const basePath = dirname(packageJsonPath); + const executorsFilePath = require.resolve(join(basePath, executorsFile)); const executorsJson = readJsonFile(executorsFilePath); const executorConfig = executorsJson.executors?.[executor] || executorsJson.builders?.[executor]; @@ -139,7 +145,9 @@ function readExecutorJson( if (typeof executorConfig === 'string') { // Angular CLI can have a builder pointing to another package:builder const [packageName, executorName] = executorConfig.split(':'); - return readExecutorJson(packageName, executorName, root, projects); + return readExecutorJson(packageName, executorName, root, projects, [ + basePath, + ]); } const isNgCompat = !executorsJson.executors?.[executor]; return { executorsFilePath, executorConfig, isNgCompat }; diff --git a/packages/nx/src/utils/plugins/plugin-capabilities.ts b/packages/nx/src/utils/plugins/plugin-capabilities.ts index aceb5c4a90cc9..5f20fbf61b70a 100644 --- a/packages/nx/src/utils/plugins/plugin-capabilities.ts +++ b/packages/nx/src/utils/plugins/plugin-capabilities.ts @@ -182,6 +182,7 @@ export async function listPluginCapabilities( ...Object.keys(plugin.executors).map( (name) => `${chalk.bold(name)} : ${resolveExecutorDescription( + pluginName, plugin.executors[name], projects )}` @@ -204,20 +205,38 @@ export async function listPluginCapabilities( } function resolveExecutorDescription( + pluginName: string, executorJsonEntry: ExecutorsJsonEntry, - projects: Record + projects: Record, + requirePaths = getNxRequirePaths(workspaceRoot) ) { try { if (typeof executorJsonEntry === 'string') { // it points to another executor, resolve it const [pkgName, executor] = executorJsonEntry.split(':'); + // read the package.json of the parent plugin + const { path: packageJsonPath } = readPluginPackageJson( + pluginName, + projects, + requirePaths + ); + // accumulate the require paths to resolve nested packages + const cummulativeRequirePaths = [ + ...requirePaths, + dirname(packageJsonPath), + ]; const collection = loadExecutorsCollection( - workspaceRoot, pkgName, - projects + projects, + cummulativeRequirePaths ); - return resolveExecutorDescription(collection[executor], projects); + return resolveExecutorDescription( + pkgName, + collection[executor], + projects, + cummulativeRequirePaths + ); } return executorJsonEntry.description; @@ -227,14 +246,14 @@ function resolveExecutorDescription( } function loadExecutorsCollection( - workspaceRoot: string, pluginName: string, - projects: Record + projects: Record, + requirePaths: string[] ): { [name: string]: ExecutorsJsonEntry } { const { json: packageJson, path: packageJsonPath } = readPluginPackageJson( pluginName, projects, - getNxRequirePaths(workspaceRoot) + requirePaths ); return {