Leosvel Pérez Espinosa ec801b4c16
feat(misc): enable new ts minimal setup by default and guard execution of generators with no support for it (#28199)
- 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 #
2024-10-02 08:29:06 -04:00

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;