From 39646cfa9ad173251a7171773c15c45173712755 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Fri, 31 Mar 2023 17:22:34 -0400 Subject: [PATCH] feat(core): allow referencing other packages to specify implementations for executors + generators (#15987) --- packages/nx/src/config/workspaces.ts | 55 ++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/nx/src/config/workspaces.ts b/packages/nx/src/config/workspaces.ts index cf4348bd66e5b..4030440f46bbe 100644 --- a/packages/nx/src/config/workspaces.ts +++ b/packages/nx/src/config/workspaces.ts @@ -40,7 +40,6 @@ import { import { getNxRequirePaths } from '../utils/installation-directory'; import { getIgnoredGlobs } from '../utils/ignore'; import { - createProjectRootMappings, findProjectForPath, normalizeProjectRoot, } from '../project-graph/utils/find-project-for-path'; @@ -183,7 +182,10 @@ export class Workspaces { const { executorsFilePath, executorConfig, isNgCompat } = this.readExecutorsJson(nodeModule, executor); const executorsDir = path.dirname(executorsFilePath); - const schemaPath = path.join(executorsDir, executorConfig.schema || ''); + const schemaPath = this.resolveSchema( + executorConfig.schema, + executorsDir + ); const schema = normalizeExecutorSchema(readJsonFile(schemaPath)); const implementationFactory = this.getImplementationFactory( @@ -246,7 +248,10 @@ export class Workspaces { generatorsJson.generators?.[normalizedGeneratorName] || generatorsJson.schematics?.[normalizedGeneratorName]; const isNgCompat = !generatorsJson.generators?.[normalizedGeneratorName]; - const schemaPath = path.join(generatorsDir, generatorConfig.schema || ''); + const schemaPath = this.resolveSchema( + generatorConfig.schema, + generatorsDir + ); const schema = readJsonFile(schemaPath); if (!schema.properties || typeof schema.properties !== 'object') { schema.properties = {}; @@ -346,11 +351,10 @@ export class Workspaces { const [implementationModulePath, implementationExportName] = implementation.split('#'); return () => { - const possibleModulePath = path.join(directory, implementationModulePath); - const validImplementations = ['', '.js', '.ts'].map( - (x) => possibleModulePath + x + const modulePath = this.resolveImplementation( + implementationModulePath, + directory ); - const modulePath = validImplementations.find((f) => existsSync(f)); if (extname(modulePath) === '.ts') { registerPluginTSTranspiler(); } @@ -361,6 +365,43 @@ export class Workspaces { }; } + private resolveSchema(schemaPath: string, directory: string): string { + const maybeSchemaPath = join(directory, schemaPath); + if (existsSync(maybeSchemaPath)) { + return maybeSchemaPath; + } + + return require.resolve(schemaPath, { + paths: [directory], + }); + } + + private resolveImplementation( + implementationModulePath: string, + directory: string + ): string { + const validImplementations = ['', '.js', '.ts'].map( + (x) => implementationModulePath + x + ); + + for (const maybeImplementation of validImplementations) { + const maybeImplementationPath = join(directory, maybeImplementation); + if (existsSync(maybeImplementationPath)) { + return maybeImplementationPath; + } + + try { + return require.resolve(maybeImplementation, { + paths: [directory], + }); + } catch {} + } + + throw new Error( + `Could not resolve "${implementationModulePath}" from "${directory}".` + ); + } + private readExecutorsJson(nodeModule: string, executor: string) { const { json: packageJson, path: packageJsonPath } = readPluginPackageJson( nodeModule,