- Enable generating the new & minimal TS setup by default when generating the `ts` preset with CNW. The existing `NX_ADD_TS_PLUGIN` environment variable is kept with its default value inverted and set to `true`. It can be used to opt out of the new TS setup by running CNW with `NX_ADD_TS_PLUGIN=false`. - Throw an error when running generators that don't yet support the new TS setup. - We'll add support for those generators incrementally in follow-up PRs. <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> <!-- Fixes NXC-1066 --> <!-- Fixes NXC-1068 --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
210 lines
5.5 KiB
TypeScript
210 lines
5.5 KiB
TypeScript
import type { Tree } from '@nx/devkit';
|
|
import {
|
|
addProjectConfiguration,
|
|
extractLayoutDirectory,
|
|
formatFiles,
|
|
generateFiles,
|
|
GeneratorCallback,
|
|
getPackageManagerCommand,
|
|
getWorkspaceLayout,
|
|
joinPathFragments,
|
|
names,
|
|
offsetFromRoot,
|
|
readJson,
|
|
readNxJson,
|
|
readProjectConfiguration,
|
|
runTasksInSerial,
|
|
updateProjectConfiguration,
|
|
} from '@nx/devkit';
|
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
import { addPropertyToJestConfig, configurationGenerator } from '@nx/jest';
|
|
import { getRelativePathToRootTsConfig } from '@nx/js';
|
|
import { setupVerdaccio } from '@nx/js/src/generators/setup-verdaccio/generator';
|
|
import { addLocalRegistryScripts } from '@nx/js/src/utils/add-local-registry-scripts';
|
|
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
import { Linter, LinterType, lintProjectGenerator } from '@nx/eslint';
|
|
import { join } from 'path';
|
|
import type { Schema } from './schema';
|
|
|
|
interface NormalizedSchema extends Schema {
|
|
projectRoot: string;
|
|
projectName: string;
|
|
pluginPropertyName: string;
|
|
linter: Linter | LinterType;
|
|
}
|
|
|
|
async function normalizeOptions(
|
|
host: Tree,
|
|
options: Schema
|
|
): Promise<NormalizedSchema> {
|
|
const projectName = options.rootProject ? 'e2e' : `${options.pluginName}-e2e`;
|
|
|
|
const nxJson = readNxJson(host);
|
|
const addPlugin =
|
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
nxJson.useInferencePlugins !== false;
|
|
|
|
options.addPlugin ??= addPlugin;
|
|
|
|
let projectRoot: string;
|
|
const projectNameAndRootOptions = await determineProjectNameAndRootOptions(
|
|
host,
|
|
{
|
|
name: projectName,
|
|
projectType: 'application',
|
|
directory:
|
|
options.rootProject || !options.projectDirectory
|
|
? projectName
|
|
: `${options.projectDirectory}-e2e`,
|
|
}
|
|
);
|
|
projectRoot = projectNameAndRootOptions.projectRoot;
|
|
|
|
const pluginPropertyName = names(options.pluginName).propertyName;
|
|
|
|
return {
|
|
...options,
|
|
projectName,
|
|
linter: options.linter ?? Linter.EsLint,
|
|
pluginPropertyName,
|
|
projectRoot,
|
|
};
|
|
}
|
|
|
|
function validatePlugin(host: Tree, pluginName: string) {
|
|
try {
|
|
readProjectConfiguration(host, pluginName);
|
|
} catch {
|
|
throw new Error(`Project name "${pluginName}" doesn't not exist.`);
|
|
}
|
|
}
|
|
|
|
function addFiles(host: Tree, options: NormalizedSchema) {
|
|
const projectConfiguration = readProjectConfiguration(
|
|
host,
|
|
options.pluginName
|
|
);
|
|
const { name: pluginPackageName } = readJson(
|
|
host,
|
|
join(projectConfiguration.root, 'package.json')
|
|
);
|
|
|
|
generateFiles(host, join(__dirname, './files'), options.projectRoot, {
|
|
...options,
|
|
tmpl: '',
|
|
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
|
packageManagerCommands: getPackageManagerCommand('npm'),
|
|
pluginPackageName,
|
|
});
|
|
}
|
|
|
|
async function addJest(host: Tree, options: NormalizedSchema) {
|
|
addProjectConfiguration(host, options.projectName, {
|
|
root: options.projectRoot,
|
|
projectType: 'application',
|
|
sourceRoot: `${options.projectRoot}/src`,
|
|
targets: {},
|
|
implicitDependencies: [options.pluginName],
|
|
});
|
|
|
|
const jestTask = await configurationGenerator(host, {
|
|
project: options.projectName,
|
|
targetName: 'e2e',
|
|
setupFile: 'none',
|
|
supportTsx: false,
|
|
skipSerializers: true,
|
|
skipFormat: true,
|
|
addPlugin: options.addPlugin,
|
|
});
|
|
|
|
const { startLocalRegistryPath, stopLocalRegistryPath } =
|
|
addLocalRegistryScripts(host);
|
|
|
|
addPropertyToJestConfig(
|
|
host,
|
|
join(options.projectRoot, 'jest.config.ts'),
|
|
'globalSetup',
|
|
join(offsetFromRoot(options.projectRoot), startLocalRegistryPath)
|
|
);
|
|
addPropertyToJestConfig(
|
|
host,
|
|
join(options.projectRoot, 'jest.config.ts'),
|
|
'globalTeardown',
|
|
join(offsetFromRoot(options.projectRoot), stopLocalRegistryPath)
|
|
);
|
|
|
|
const project = readProjectConfiguration(host, options.projectName);
|
|
const e2eTarget = project.targets.e2e;
|
|
|
|
project.targets.e2e = {
|
|
...e2eTarget,
|
|
dependsOn: [`^build`],
|
|
options: {
|
|
...e2eTarget.options,
|
|
runInBand: true,
|
|
},
|
|
};
|
|
|
|
updateProjectConfiguration(host, options.projectName, project);
|
|
|
|
return jestTask;
|
|
}
|
|
|
|
async function addLintingToApplication(
|
|
tree: Tree,
|
|
options: NormalizedSchema
|
|
): Promise<GeneratorCallback> {
|
|
const lintTask = await lintProjectGenerator(tree, {
|
|
linter: options.linter,
|
|
project: options.projectName,
|
|
tsConfigPaths: [
|
|
joinPathFragments(options.projectRoot, 'tsconfig.app.json'),
|
|
],
|
|
unitTestRunner: 'jest',
|
|
skipFormat: true,
|
|
setParserOptionsProject: false,
|
|
addPlugin: options.addPlugin,
|
|
});
|
|
|
|
return lintTask;
|
|
}
|
|
|
|
export async function e2eProjectGenerator(host: Tree, schema: Schema) {
|
|
return await e2eProjectGeneratorInternal(host, {
|
|
addPlugin: false,
|
|
...schema,
|
|
});
|
|
}
|
|
|
|
export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
|
|
assertNotUsingTsSolutionSetup(host, 'plugin', 'e2e-project');
|
|
|
|
const tasks: GeneratorCallback[] = [];
|
|
|
|
validatePlugin(host, schema.pluginName);
|
|
const options = await normalizeOptions(host, schema);
|
|
addFiles(host, options);
|
|
tasks.push(
|
|
await setupVerdaccio(host, {
|
|
skipFormat: true,
|
|
})
|
|
);
|
|
tasks.push(await addJest(host, options));
|
|
|
|
if (options.linter !== Linter.None) {
|
|
tasks.push(
|
|
await addLintingToApplication(host, {
|
|
...options,
|
|
})
|
|
);
|
|
}
|
|
|
|
if (!options.skipFormat) {
|
|
await formatFiles(host);
|
|
}
|
|
|
|
return runTasksInSerial(...tasks);
|
|
}
|
|
|
|
export default e2eProjectGenerator;
|