From 43f054ee998f0787a2de49fb6e111d968f7f9fb6 Mon Sep 17 00:00:00 2001 From: FrozenPandaz Date: Tue, 18 Apr 2023 12:04:01 -0400 Subject: [PATCH] fix(angular): fix resolve builder in ngcli adapter --- packages/nx/src/adapter/ngcli-adapter.ts | 110 +++++++++++++++++++++-- packages/nx/src/config/workspaces.ts | 2 +- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/packages/nx/src/adapter/ngcli-adapter.ts b/packages/nx/src/adapter/ngcli-adapter.ts index 5eb810b39bf81..e80c75459886e 100644 --- a/packages/nx/src/adapter/ngcli-adapter.ts +++ b/packages/nx/src/adapter/ngcli-adapter.ts @@ -42,8 +42,15 @@ import { NX_ERROR, NX_PREFIX } from '../utils/logger'; import { readModulePackageJson } from '../utils/package-json'; import { detectPackageManager } from '../utils/package-manager'; import { toNewFormat, toOldFormat } from './angular-json'; -import { Workspaces } from '../config/workspaces'; -import { ExecutorsJson } from '../config/misc-interfaces'; +import { normalizeExecutorSchema, Workspaces } from '../config/workspaces'; +import { + CustomHasher, + Executor, + ExecutorConfig, + ExecutorsJson, + TaskGraphExecutor, +} from '../config/misc-interfaces'; +import { readPluginPackageJson } from 'nx/src/utils/nx-plugin'; class WrappedWorkspaceNodeModulesArchitectHost extends WorkspaceNodeModulesArchitectHost { private workspaces = new Workspaces(this.root); @@ -54,10 +61,11 @@ class WrappedWorkspaceNodeModulesArchitectHost extends WorkspaceNodeModulesArchi async resolveBuilder(builderStr: string): Promise { const [packageName, builderName] = builderStr.split(':'); - const { executorsFilePath, executorConfig } = this.workspaces[ - 'readExecutorsJson' - ](packageName, builderName); - const builderInfo = this.workspaces.readExecutor(packageName, builderName); + const { executorsFilePath, executorConfig } = this.readExecutorsJson( + packageName, + builderName + ); + const builderInfo = this.readExecutor(packageName, builderName); return { name: builderStr, builderName, @@ -65,12 +73,100 @@ class WrappedWorkspaceNodeModulesArchitectHost extends WorkspaceNodeModulesArchi readJsonFile(executorsFilePath).builders[builderName] .description, optionSchema: builderInfo.schema, - import: this.workspaces['resolveImplementation']( + import: this.workspaces['resolveImplementation'].bind(this.workspaces)( executorConfig.implementation, dirname(executorsFilePath) ), }; } + + private readExecutorsJson(nodeModule: string, builder: string) { + const { json: packageJson, path: packageJsonPath } = readPluginPackageJson( + nodeModule, + this.workspaces['resolvePaths'].bind(this.workspaces)() + ); + const executorsFile = packageJson.executors ?? packageJson.builders; + + if (!executorsFile) { + throw new Error( + `The "${nodeModule}" package does not support Nx executors or Angular Devkit Builders.` + ); + } + + const executorsFilePath = require.resolve( + join(dirname(packageJsonPath), executorsFile) + ); + const executorsJson = readJsonFile(executorsFilePath); + const executorConfig: { + implementation: string; + batchImplementation?: string; + schema: string; + hasher?: string; + } = executorsJson.builders?.[builder]; + if (!executorConfig) { + throw new Error( + `Cannot find builder '${builder}' in ${executorsFilePath}.` + ); + } + return { executorsFilePath, executorConfig, isNgCompat: true }; + } + + private readExecutor( + nodeModule: string, + executor: string + ): ExecutorConfig & { isNgCompat: boolean } { + try { + const { executorsFilePath, executorConfig, isNgCompat } = + this.readExecutorsJson(nodeModule, executor); + const executorsDir = dirname(executorsFilePath); + const schemaPath = this.workspaces['resolveSchema'].bind(this.workspaces)( + executorConfig.schema, + executorsDir + ); + const schema = normalizeExecutorSchema(readJsonFile(schemaPath)); + + const implementationFactory = this.getImplementationFactory( + executorConfig.implementation, + executorsDir + ); + + const batchImplementationFactory = executorConfig.batchImplementation + ? this.getImplementationFactory( + executorConfig.batchImplementation, + executorsDir + ) + : null; + + const hasherFactory = executorConfig.hasher + ? this.getImplementationFactory( + executorConfig.hasher, + executorsDir + ) + : null; + + return { + schema, + implementationFactory, + batchImplementationFactory, + hasherFactory, + isNgCompat, + }; + } catch (e) { + throw new Error( + `Unable to resolve ${nodeModule}:${executor}.\n${e.message}` + ); + } + } + + private getImplementationFactory( + implementation: string, + executorsDir: string + ): () => T { + return this.workspaces['getImplementationFactory'].bind(this.workspaces)( + implementation, + executorsDir + ); + } } export async function scheduleTarget( diff --git a/packages/nx/src/config/workspaces.ts b/packages/nx/src/config/workspaces.ts index bfe50cf131df5..dee7377261462 100644 --- a/packages/nx/src/config/workspaces.ts +++ b/packages/nx/src/config/workspaces.ts @@ -482,7 +482,7 @@ function findMatchingProjectInCwd( return matchingProject; } -function normalizeExecutorSchema( +export function normalizeExecutorSchema( schema: Partial ): ExecutorConfig['schema'] { const version = (schema.version ??= 1);