chore(core): copy isNxExecutor out of Workspaces class (#17996)
This commit is contained in:
parent
6ccbbbc98f
commit
1c6a359130
@ -1,13 +1,9 @@
|
||||
import type { Schema } from './schema';
|
||||
import {
|
||||
logger,
|
||||
readCachedProjectGraph,
|
||||
workspaceRoot,
|
||||
Workspaces,
|
||||
} from '@nx/devkit';
|
||||
import { logger, readCachedProjectGraph, workspaceRoot } from '@nx/devkit';
|
||||
import { scheduleTarget } from 'nx/src/adapter/ngcli-adapter';
|
||||
import { executeWebpackDevServerBuilder } from '../webpack-dev-server/webpack-dev-server.impl';
|
||||
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
|
||||
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
|
||||
import {
|
||||
getDynamicRemotes,
|
||||
getStaticRemotes,
|
||||
@ -25,7 +21,6 @@ export function executeModuleFederationDevServerBuilder(
|
||||
const projectGraph = readCachedProjectGraph();
|
||||
const { projects: workspaceProjects } =
|
||||
readProjectsConfigurationFromProjectGraph(projectGraph);
|
||||
const ws = new Workspaces(workspaceRoot);
|
||||
const project = workspaceProjects[context.target.project];
|
||||
|
||||
let pathToManifestFile = join(
|
||||
@ -101,7 +96,11 @@ export function executeModuleFederationDevServerBuilder(
|
||||
if (options.verbose) {
|
||||
const [collection, executor] =
|
||||
workspaceProjects[remote].targets[target].executor.split(':');
|
||||
const { schema } = ws.readExecutor(collection, executor);
|
||||
const { schema } = getExecutorInformation(
|
||||
collection,
|
||||
executor,
|
||||
workspaceRoot
|
||||
);
|
||||
|
||||
if (schema.additionalProperties || 'verbose' in schema.properties) {
|
||||
runOptions.verbose = options.verbose;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { Schema } from './schema';
|
||||
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
|
||||
import { readCachedProjectGraph, workspaceRoot, Workspaces } from '@nx/devkit';
|
||||
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
|
||||
import { readCachedProjectGraph, workspaceRoot } from '@nx/devkit';
|
||||
import {
|
||||
getDynamicRemotes,
|
||||
getStaticRemotes,
|
||||
@ -21,7 +22,6 @@ export function executeModuleFederationDevSSRBuilder(
|
||||
const projectGraph = readCachedProjectGraph();
|
||||
const { projects: workspaceProjects } =
|
||||
readProjectsConfigurationFromProjectGraph(projectGraph);
|
||||
const ws = new Workspaces(workspaceRoot);
|
||||
const project = workspaceProjects[context.target.project];
|
||||
|
||||
let pathToManifestFile = join(
|
||||
@ -90,7 +90,11 @@ export function executeModuleFederationDevSSRBuilder(
|
||||
if (options.verbose) {
|
||||
const [collection, executor] =
|
||||
workspaceProjects[remote].targets[target].executor.split(':');
|
||||
const { schema } = ws.readExecutor(collection, executor);
|
||||
const { schema } = getExecutorInformation(
|
||||
collection,
|
||||
executor,
|
||||
workspaceRoot
|
||||
);
|
||||
|
||||
if (schema.additionalProperties || 'verbose' in schema.properties) {
|
||||
runOptions.verbose = options.verbose;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { getTempTailwindPath } from '../../utils/ct-helpers';
|
||||
import { ExecutorContext, stripIndents } from '@nx/devkit';
|
||||
import * as executorUtils from 'nx/src/command-line/run/executor-utils';
|
||||
import * as path from 'path';
|
||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||
import cypressExecutor, { CypressExecutorOptions } from './cypress.impl';
|
||||
@ -43,9 +44,17 @@ describe('Cypress builder', () => {
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
(devkit as any).readTargetOptions = jest.fn().mockReturnValue({
|
||||
jest.spyOn(devkit, 'readTargetOptions').mockReturnValue({
|
||||
watch: true,
|
||||
});
|
||||
jest.spyOn(executorUtils, 'getExecutorInformation').mockReturnValue({
|
||||
schema: { properties: {} },
|
||||
hasherFactory: jest.fn(),
|
||||
implementationFactory: jest.fn(),
|
||||
batchImplementationFactory: jest.fn(),
|
||||
isNgCompat: true,
|
||||
isNxExecutor: true,
|
||||
});
|
||||
let runExecutor: any;
|
||||
let mockGetTailwindPath: jest.Mock<ReturnType<typeof getTempTailwindPath>> =
|
||||
getTempTailwindPath as any;
|
||||
@ -57,9 +66,6 @@ describe('Cypress builder', () => {
|
||||
baseUrl: 'http://localhost:4200',
|
||||
},
|
||||
]);
|
||||
(devkit as any).Workspaces = jest.fn().mockReturnValue({
|
||||
readExecutor: () => ({ schema: { properties: {} } }),
|
||||
});
|
||||
(devkit as any).stripIndents = (s) => s;
|
||||
(devkit as any).parseTargetString = (s) => {
|
||||
const [project, target, configuration] = s.split(':');
|
||||
|
||||
@ -5,11 +5,11 @@ import {
|
||||
readTargetOptions,
|
||||
runExecutor,
|
||||
stripIndents,
|
||||
Workspaces,
|
||||
Target,
|
||||
targetToTargetString,
|
||||
output,
|
||||
} from '@nx/devkit';
|
||||
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
|
||||
import 'dotenv/config';
|
||||
import { existsSync, readdirSync, unlinkSync, writeFileSync } from 'fs';
|
||||
import { basename, dirname, join } from 'path';
|
||||
@ -421,9 +421,12 @@ ${e.message || e}`);
|
||||
context.projectsConfigurations?.projects?.[target.project];
|
||||
const targetConfig = projectConfig.targets[target.target];
|
||||
|
||||
const workspace = new Workspaces(context.root);
|
||||
const [collection, executor] = targetConfig.executor.split(':');
|
||||
const { schema } = workspace.readExecutor(collection, executor);
|
||||
const { schema } = getExecutorInformation(
|
||||
collection,
|
||||
executor,
|
||||
context.root
|
||||
);
|
||||
|
||||
// NOTE: schema won't have a default since readTargetOptions would have
|
||||
// already set that and this check wouldn't need to be made
|
||||
|
||||
@ -4,7 +4,7 @@ import type { ExecutorContext } from 'nx/src/config/misc-interfaces';
|
||||
import { combineOptionsForExecutor } from 'nx/src/utils/params';
|
||||
import { requireNx } from '../../nx';
|
||||
|
||||
const { Workspaces } = requireNx();
|
||||
const { Workspaces, getExecutorInformation } = requireNx();
|
||||
|
||||
/**
|
||||
* Reads and combines options for a given target.
|
||||
@ -22,7 +22,11 @@ export function readTargetOptions<T = any>(
|
||||
|
||||
const ws = new Workspaces(context.root);
|
||||
const [nodeModule, executorName] = targetConfiguration.executor.split(':');
|
||||
const { schema } = ws.readExecutor(nodeModule, executorName);
|
||||
const { schema } = getExecutorInformation(
|
||||
nodeModule,
|
||||
executorName,
|
||||
context.root
|
||||
);
|
||||
|
||||
const defaultProject = ws.calculateDefaultProjectName(
|
||||
context.cwd,
|
||||
|
||||
@ -46,7 +46,8 @@ import {
|
||||
toNewFormat,
|
||||
toOldFormat,
|
||||
} from './angular-json';
|
||||
import { normalizeExecutorSchema, Workspaces } from '../config/workspaces';
|
||||
import { normalizeExecutorSchema } from '../command-line/run/executor-utils';
|
||||
import { Workspaces } from '../config/workspaces';
|
||||
import {
|
||||
CustomHasher,
|
||||
Executor,
|
||||
@ -55,6 +56,11 @@ import {
|
||||
TaskGraphExecutor,
|
||||
} from '../config/misc-interfaces';
|
||||
import { readPluginPackageJson } from '../utils/nx-plugin';
|
||||
import {
|
||||
getImplementationFactory,
|
||||
resolveImplementation,
|
||||
resolveSchema,
|
||||
} from '../config/schema-utils';
|
||||
|
||||
export async function scheduleTarget(
|
||||
root: string,
|
||||
@ -106,7 +112,7 @@ export async function scheduleTarget(
|
||||
readJsonFile<ExecutorsJson>(executorsFilePath).builders[builderName]
|
||||
.description,
|
||||
optionSchema: builderInfo.schema,
|
||||
import: this.workspaces['resolveImplementation'].bind(this.workspaces)(
|
||||
import: resolveImplementation(
|
||||
executorConfig.implementation,
|
||||
dirname(executorsFilePath)
|
||||
),
|
||||
@ -153,9 +159,7 @@ export async function scheduleTarget(
|
||||
const { executorsFilePath, executorConfig, isNgCompat } =
|
||||
this.readExecutorsJson(nodeModule, executor);
|
||||
const executorsDir = dirname(executorsFilePath);
|
||||
const schemaPath = this.workspaces['resolveSchema'].bind(
|
||||
this.workspaces
|
||||
)(executorConfig.schema, executorsDir);
|
||||
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
|
||||
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
||||
|
||||
const implementationFactory = this.getImplementationFactory<Executor>(
|
||||
@ -195,10 +199,7 @@ export async function scheduleTarget(
|
||||
implementation: string,
|
||||
executorsDir: string
|
||||
): () => T {
|
||||
return this.workspaces['getImplementationFactory'].bind(this.workspaces)(
|
||||
implementation,
|
||||
executorsDir
|
||||
);
|
||||
return getImplementationFactory(implementation, executorsDir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
128
packages/nx/src/command-line/run/executor-utils.ts
Normal file
128
packages/nx/src/command-line/run/executor-utils.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
import { readPluginPackageJson } from '../../utils/nx-plugin';
|
||||
import {
|
||||
CustomHasher,
|
||||
Executor,
|
||||
ExecutorConfig,
|
||||
ExecutorsJson,
|
||||
TaskGraphExecutor,
|
||||
} from '../../config/misc-interfaces';
|
||||
import { readJsonFile } from '../../utils/fileutils';
|
||||
import {
|
||||
getImplementationFactory,
|
||||
resolveSchema,
|
||||
} from '../../config/schema-utils';
|
||||
import { getNxRequirePaths } from '../../utils/installation-directory';
|
||||
|
||||
export function normalizeExecutorSchema(
|
||||
schema: Partial<ExecutorConfig['schema']>
|
||||
): ExecutorConfig['schema'] {
|
||||
const version = (schema.version ??= 1);
|
||||
return {
|
||||
version,
|
||||
outputCapture:
|
||||
schema.outputCapture ?? version < 2 ? 'direct-nodejs' : 'pipe',
|
||||
properties:
|
||||
!schema.properties || typeof schema.properties !== 'object'
|
||||
? {}
|
||||
: schema.properties,
|
||||
...schema,
|
||||
};
|
||||
}
|
||||
|
||||
export function getExecutorInformation(
|
||||
nodeModule: string,
|
||||
executor: string,
|
||||
root: string
|
||||
): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } {
|
||||
try {
|
||||
const { executorsFilePath, executorConfig, isNgCompat } = readExecutorsJson(
|
||||
nodeModule,
|
||||
executor,
|
||||
root
|
||||
);
|
||||
const executorsDir = dirname(executorsFilePath);
|
||||
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
|
||||
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
||||
|
||||
const implementationFactory = getImplementationFactory<Executor>(
|
||||
executorConfig.implementation,
|
||||
executorsDir
|
||||
);
|
||||
|
||||
const batchImplementationFactory = executorConfig.batchImplementation
|
||||
? getImplementationFactory<TaskGraphExecutor>(
|
||||
executorConfig.batchImplementation,
|
||||
executorsDir
|
||||
)
|
||||
: null;
|
||||
|
||||
const hasherFactory = executorConfig.hasher
|
||||
? getImplementationFactory<CustomHasher>(
|
||||
executorConfig.hasher,
|
||||
executorsDir
|
||||
)
|
||||
: null;
|
||||
|
||||
return {
|
||||
schema,
|
||||
implementationFactory,
|
||||
batchImplementationFactory,
|
||||
hasherFactory,
|
||||
isNgCompat,
|
||||
isNxExecutor: !isNgCompat,
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unable to resolve ${nodeModule}:${executor}.\n${e.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function readExecutorsJson(
|
||||
nodeModule: string,
|
||||
executor: string,
|
||||
root: string
|
||||
): {
|
||||
executorsFilePath: string;
|
||||
executorConfig: {
|
||||
implementation: string;
|
||||
batchImplementation?: string;
|
||||
schema: string;
|
||||
hasher?: string;
|
||||
};
|
||||
isNgCompat: boolean;
|
||||
} {
|
||||
const { json: packageJson, path: packageJsonPath } = readPluginPackageJson(
|
||||
nodeModule,
|
||||
root
|
||||
? [root, __dirname, process.cwd(), ...getNxRequirePaths()]
|
||||
: [__dirname, process.cwd(), ...getNxRequirePaths()]
|
||||
);
|
||||
const executorsFile = packageJson.executors ?? packageJson.builders;
|
||||
|
||||
if (!executorsFile) {
|
||||
throw new Error(
|
||||
`The "${nodeModule}" package does not support Nx executors.`
|
||||
);
|
||||
}
|
||||
|
||||
const executorsFilePath = require.resolve(
|
||||
join(dirname(packageJsonPath), executorsFile)
|
||||
);
|
||||
const executorsJson = readJsonFile<ExecutorsJson>(executorsFilePath);
|
||||
const executorConfig: {
|
||||
implementation: string;
|
||||
batchImplementation?: string;
|
||||
schema: string;
|
||||
hasher?: string;
|
||||
} = executorsJson.executors?.[executor] || executorsJson.builders?.[executor];
|
||||
if (!executorConfig) {
|
||||
throw new Error(
|
||||
`Cannot find executor '${executor}' in ${executorsFilePath}.`
|
||||
);
|
||||
}
|
||||
const isNgCompat = !executorsJson.executors?.[executor];
|
||||
return { executorsFilePath, executorConfig, isNgCompat };
|
||||
}
|
||||
@ -32,6 +32,7 @@ import {
|
||||
getLastValueFromAsyncIterableIterator,
|
||||
isAsyncIterator,
|
||||
} from '../../utils/async-iterator';
|
||||
import { getExecutorInformation } from './executor-utils';
|
||||
|
||||
export interface Target {
|
||||
project: string;
|
||||
@ -131,9 +132,10 @@ async function parseExecutorAndTarget(
|
||||
}
|
||||
|
||||
const [nodeModule, executor] = targetConfig.executor.split(':');
|
||||
const { schema, implementationFactory } = ws.readExecutor(
|
||||
const { schema, implementationFactory } = getExecutorInformation(
|
||||
nodeModule,
|
||||
executor
|
||||
executor,
|
||||
root
|
||||
);
|
||||
|
||||
return { executor, implementationFactory, nodeModule, schema, targetConfig };
|
||||
@ -195,7 +197,7 @@ async function runExecutorInternal<T extends { success: boolean }>(
|
||||
isVerbose
|
||||
);
|
||||
|
||||
if (ws.isNxExecutor(nodeModule, executor)) {
|
||||
if (getExecutorInformation(nodeModule, executor, root).isNxExecutor) {
|
||||
const implementation = implementationFactory() as Executor<any>;
|
||||
const r = implementation(combinedOptions, {
|
||||
root,
|
||||
|
||||
73
packages/nx/src/config/schema-utils.ts
Normal file
73
packages/nx/src/config/schema-utils.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { extname, join } from 'path';
|
||||
import { registerPluginTSTranspiler } from '../utils/nx-plugin';
|
||||
|
||||
/**
|
||||
* This function is used to get the implementation factory of an executor or generator.
|
||||
* @param implementation path to the implementation
|
||||
* @param directory path to the directory
|
||||
* @returns a function that returns the implementation
|
||||
*/
|
||||
export function getImplementationFactory<T>(
|
||||
implementation: string,
|
||||
directory: string
|
||||
): () => T {
|
||||
const [implementationModulePath, implementationExportName] =
|
||||
implementation.split('#');
|
||||
return () => {
|
||||
const modulePath = resolveImplementation(
|
||||
implementationModulePath,
|
||||
directory
|
||||
);
|
||||
if (extname(modulePath) === '.ts') {
|
||||
registerPluginTSTranspiler();
|
||||
}
|
||||
const module = require(modulePath);
|
||||
return implementationExportName
|
||||
? module[implementationExportName]
|
||||
: module.default ?? module;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to resolve the implementation of an executor or generator.
|
||||
* @param implementationModulePath
|
||||
* @param directory
|
||||
* @returns path to the implementation
|
||||
*/
|
||||
export function 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}".`
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveSchema(schemaPath: string, directory: string): string {
|
||||
const maybeSchemaPath = join(directory, schemaPath);
|
||||
if (existsSync(maybeSchemaPath)) {
|
||||
return maybeSchemaPath;
|
||||
}
|
||||
|
||||
return require.resolve(schemaPath, {
|
||||
paths: [directory],
|
||||
});
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { sync as globSync } from 'fast-glob';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { existsSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { basename, dirname, extname, join } from 'path';
|
||||
import { basename, dirname, join } from 'path';
|
||||
import { performance } from 'perf_hooks';
|
||||
import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { readJsonFile, readYamlFile } from '../utils/fileutils';
|
||||
@ -10,7 +10,6 @@ import {
|
||||
loadNxPlugins,
|
||||
loadNxPluginsSync,
|
||||
readPluginPackageJson,
|
||||
registerPluginTSTranspiler,
|
||||
} from '../utils/nx-plugin';
|
||||
|
||||
import type { NxJsonConfiguration, TargetDefaults } from './nx-json';
|
||||
@ -20,14 +19,9 @@ import {
|
||||
TargetConfiguration,
|
||||
} from './workspace-json-project-json';
|
||||
import {
|
||||
CustomHasher,
|
||||
Executor,
|
||||
ExecutorConfig,
|
||||
ExecutorsJson,
|
||||
Generator,
|
||||
GeneratorsJson,
|
||||
GeneratorsJsonEntry,
|
||||
TaskGraphExecutor,
|
||||
} from './misc-interfaces';
|
||||
import { PackageJson } from '../utils/package-json';
|
||||
import { output } from '../utils/output';
|
||||
@ -42,6 +36,7 @@ import {
|
||||
findProjectForPath,
|
||||
normalizeProjectRoot,
|
||||
} from '../project-graph/utils/find-project-for-path';
|
||||
import { getImplementationFactory, resolveSchema } from './schema-utils';
|
||||
|
||||
export class Workspaces {
|
||||
private cachedProjectsConfig: ProjectsConfigurations;
|
||||
@ -169,61 +164,10 @@ export class Workspaces {
|
||||
return projects;
|
||||
}
|
||||
|
||||
isNxExecutor(nodeModule: string, executor: string) {
|
||||
return !this.readExecutor(nodeModule, executor).isNgCompat;
|
||||
}
|
||||
|
||||
isNxGenerator(collectionName: string, generatorName: string) {
|
||||
return !this.readGenerator(collectionName, generatorName).isNgCompat;
|
||||
}
|
||||
|
||||
readExecutor(
|
||||
nodeModule: string,
|
||||
executor: string
|
||||
): ExecutorConfig & { isNgCompat: boolean } {
|
||||
try {
|
||||
const { executorsFilePath, executorConfig, isNgCompat } =
|
||||
this.readExecutorsJson(nodeModule, executor);
|
||||
const executorsDir = path.dirname(executorsFilePath);
|
||||
const schemaPath = this.resolveSchema(
|
||||
executorConfig.schema,
|
||||
executorsDir
|
||||
);
|
||||
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
||||
|
||||
const implementationFactory = this.getImplementationFactory<Executor>(
|
||||
executorConfig.implementation,
|
||||
executorsDir
|
||||
);
|
||||
|
||||
const batchImplementationFactory = executorConfig.batchImplementation
|
||||
? this.getImplementationFactory<TaskGraphExecutor>(
|
||||
executorConfig.batchImplementation,
|
||||
executorsDir
|
||||
)
|
||||
: null;
|
||||
|
||||
const hasherFactory = executorConfig.hasher
|
||||
? this.getImplementationFactory<CustomHasher>(
|
||||
executorConfig.hasher,
|
||||
executorsDir
|
||||
)
|
||||
: null;
|
||||
|
||||
return {
|
||||
schema,
|
||||
implementationFactory,
|
||||
batchImplementationFactory,
|
||||
hasherFactory,
|
||||
isNgCompat,
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unable to resolve ${nodeModule}:${executor}.\n${e.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
readGenerator(
|
||||
collectionName: string,
|
||||
generatorName: string
|
||||
@ -251,17 +195,14 @@ export class Workspaces {
|
||||
generatorsJson.generators?.[normalizedGeneratorName] ||
|
||||
generatorsJson.schematics?.[normalizedGeneratorName];
|
||||
const isNgCompat = !generatorsJson.generators?.[normalizedGeneratorName];
|
||||
const schemaPath = this.resolveSchema(
|
||||
generatorConfig.schema,
|
||||
generatorsDir
|
||||
);
|
||||
const schemaPath = resolveSchema(generatorConfig.schema, generatorsDir);
|
||||
const schema = readJsonFile(schemaPath);
|
||||
if (!schema.properties || typeof schema.properties !== 'object') {
|
||||
schema.properties = {};
|
||||
}
|
||||
generatorConfig.implementation =
|
||||
generatorConfig.implementation || generatorConfig.factory;
|
||||
const implementationFactory = this.getImplementationFactory<Generator>(
|
||||
const implementationFactory = getImplementationFactory<Generator>(
|
||||
generatorConfig.implementation,
|
||||
generatorsDir
|
||||
);
|
||||
@ -322,97 +263,6 @@ export class Workspaces {
|
||||
}
|
||||
}
|
||||
|
||||
private getImplementationFactory<T>(
|
||||
implementation: string,
|
||||
directory: string
|
||||
): () => T {
|
||||
const [implementationModulePath, implementationExportName] =
|
||||
implementation.split('#');
|
||||
return () => {
|
||||
const modulePath = this.resolveImplementation(
|
||||
implementationModulePath,
|
||||
directory
|
||||
);
|
||||
if (extname(modulePath) === '.ts') {
|
||||
registerPluginTSTranspiler();
|
||||
}
|
||||
const module = require(modulePath);
|
||||
return implementationExportName
|
||||
? module[implementationExportName]
|
||||
: module.default ?? module;
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
this.resolvePaths()
|
||||
);
|
||||
const executorsFile = packageJson.executors ?? packageJson.builders;
|
||||
|
||||
if (!executorsFile) {
|
||||
throw new Error(
|
||||
`The "${nodeModule}" package does not support Nx executors.`
|
||||
);
|
||||
}
|
||||
|
||||
const executorsFilePath = require.resolve(
|
||||
path.join(path.dirname(packageJsonPath), executorsFile)
|
||||
);
|
||||
const executorsJson = readJsonFile<ExecutorsJson>(executorsFilePath);
|
||||
const executorConfig: {
|
||||
implementation: string;
|
||||
batchImplementation?: string;
|
||||
schema: string;
|
||||
hasher?: string;
|
||||
} =
|
||||
executorsJson.executors?.[executor] || executorsJson.builders?.[executor];
|
||||
if (!executorConfig) {
|
||||
throw new Error(
|
||||
`Cannot find executor '${executor}' in ${executorsFilePath}.`
|
||||
);
|
||||
}
|
||||
const isNgCompat = !executorsJson.executors?.[executor];
|
||||
return { executorsFilePath, executorConfig, isNgCompat };
|
||||
}
|
||||
|
||||
private readGeneratorsJson(
|
||||
collectionName: string,
|
||||
generator: string
|
||||
@ -485,22 +335,6 @@ function findMatchingProjectInCwd(
|
||||
return matchingProject;
|
||||
}
|
||||
|
||||
export function normalizeExecutorSchema(
|
||||
schema: Partial<ExecutorConfig['schema']>
|
||||
): ExecutorConfig['schema'] {
|
||||
const version = (schema.version ??= 1);
|
||||
return {
|
||||
version,
|
||||
outputCapture:
|
||||
schema.outputCapture ?? version < 2 ? 'direct-nodejs' : 'pipe',
|
||||
properties:
|
||||
!schema.properties || typeof schema.properties !== 'object'
|
||||
? {}
|
||||
: schema.properties,
|
||||
...schema,
|
||||
};
|
||||
}
|
||||
|
||||
function findFullGeneratorName(
|
||||
name: string,
|
||||
generators: {
|
||||
|
||||
@ -4,3 +4,4 @@
|
||||
* These may not be available in certain version of Nx, so be sure to check them first.
|
||||
*/
|
||||
export { createTempNpmDirectory } from './utils/package-manager';
|
||||
export { getExecutorInformation } from './command-line/run/executor-utils';
|
||||
|
||||
@ -5,7 +5,6 @@ import {
|
||||
CompleteTaskMessage,
|
||||
BatchResults,
|
||||
} from './batch-messages';
|
||||
import { Workspaces } from '../../config/workspaces';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
import { combineOptionsForExecutor } from '../../utils/params';
|
||||
import { TaskGraph } from '../../config/task-graph';
|
||||
@ -16,11 +15,11 @@ import {
|
||||
} from '../../project-graph/project-graph';
|
||||
import { readNxJson } from '../../config/configuration';
|
||||
import { isAsyncIterator } from '../../utils/async-iterator';
|
||||
import { getExecutorInformation } from '../../command-line/run/executor-utils';
|
||||
|
||||
function getBatchExecutor(executorName: string) {
|
||||
const workspace = new Workspaces(workspaceRoot);
|
||||
const [nodeModule, exportName] = executorName.split(':');
|
||||
return workspace.readExecutor(nodeModule, exportName);
|
||||
return getExecutorInformation(nodeModule, exportName, workspaceRoot);
|
||||
}
|
||||
|
||||
async function runTasks(
|
||||
|
||||
@ -3,6 +3,7 @@ import { Workspaces } from '../config/workspaces';
|
||||
import { removeTasksFromTaskGraph } from './utils';
|
||||
import { Task, TaskGraph } from '../config/task-graph';
|
||||
import { DependencyType, ProjectGraph } from '../config/project-graph';
|
||||
import * as executorUtils from '../command-line/run/executor-utils';
|
||||
|
||||
function createMockTask(id: string): Task {
|
||||
const [project, target] = id.split(':');
|
||||
@ -43,20 +44,20 @@ describe('TasksSchedule', () => {
|
||||
roots: ['lib1:build', 'app2:build'],
|
||||
};
|
||||
const workspace: Partial<Workspaces> = {
|
||||
readExecutor() {
|
||||
return {
|
||||
schema: {
|
||||
version: 2,
|
||||
properties: {},
|
||||
},
|
||||
implementationFactory: jest.fn(),
|
||||
batchImplementationFactory: jest.fn(),
|
||||
} as any;
|
||||
},
|
||||
readNxJson() {
|
||||
return {};
|
||||
},
|
||||
};
|
||||
jest.spyOn(executorUtils, 'getExecutorInformation').mockReturnValue({
|
||||
schema: {
|
||||
version: 2,
|
||||
properties: {},
|
||||
},
|
||||
implementationFactory: jest.fn(),
|
||||
batchImplementationFactory: jest.fn(),
|
||||
isNgCompat: true,
|
||||
isNxExecutor: true,
|
||||
});
|
||||
|
||||
const projectGraph: ProjectGraph = {
|
||||
nodes: {
|
||||
@ -269,20 +270,20 @@ describe('TasksSchedule', () => {
|
||||
roots: ['app1:test', 'app2:test', 'lib1:test'],
|
||||
};
|
||||
const workspace: Partial<Workspaces> = {
|
||||
readExecutor() {
|
||||
return {
|
||||
schema: {
|
||||
version: 2,
|
||||
properties: {},
|
||||
},
|
||||
implementationFactory: jest.fn(),
|
||||
batchImplementationFactory: jest.fn(),
|
||||
} as any;
|
||||
},
|
||||
readNxJson() {
|
||||
return {};
|
||||
},
|
||||
};
|
||||
jest.spyOn(executorUtils, 'getExecutorInformation').mockReturnValue({
|
||||
schema: {
|
||||
version: 2,
|
||||
properties: {},
|
||||
},
|
||||
implementationFactory: jest.fn(),
|
||||
batchImplementationFactory: jest.fn(),
|
||||
isNgCompat: true,
|
||||
isNxExecutor: true,
|
||||
});
|
||||
|
||||
const projectGraph: ProjectGraph = {
|
||||
nodes: {
|
||||
|
||||
@ -16,6 +16,7 @@ import { joinPathFragments } from '../utils/path';
|
||||
import { isRelativePath } from '../utils/fileutils';
|
||||
import { serializeOverridesIntoCommandLine } from '../utils/serialize-overrides-into-command-line';
|
||||
import { splitByColons, splitTarget } from '../utils/split-target';
|
||||
import { getExecutorInformation } from '../command-line/run/executor-utils';
|
||||
|
||||
export function getCommandAsString(execCommand: string, task: Task) {
|
||||
const args = getPrintableCommandArgsForTask(task);
|
||||
@ -250,7 +251,7 @@ export async function getExecutorForTask(
|
||||
const executor = await getExecutorNameForTask(task, projectGraph);
|
||||
const [nodeModule, executorName] = executor.split(':');
|
||||
|
||||
return workspace.readExecutor(nodeModule, executorName);
|
||||
return getExecutorInformation(nodeModule, executorName, workspaceRoot);
|
||||
}
|
||||
|
||||
export async function getCustomHasher(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user