nx/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts
2023-08-10 09:39:23 -04:00

164 lines
5.0 KiB
TypeScript
Executable File

import {
convertNxGenerator,
formatFiles,
GeneratorCallback,
Tree,
} from '@nx/devkit';
import { ConvertTSLintToESLintSchema, ProjectConverter } from '@nx/linter';
import {
addLintingToApplication,
NormalizedSchema as AddLintForApplicationSchema,
} from '@nx/node/src/generators/application/application';
import {
addLint as addLintingToLibraryGenerator,
NormalizedSchema as AddLintForLibrarySchema,
} from '@nx/js/src/generators/library/library';
import type { Linter } from 'eslint';
/**
* @deprecated This generator will be removed in v17
*/
export async function conversionGenerator(
host: Tree,
options: ConvertTSLintToESLintSchema
) {
/**
* The ProjectConverter instance encapsulates all the standard operations we need
* to perform in order to convert a project from TSLint to ESLint, as well as some
* extensibility points for adjusting the behavior on a per package basis.
*
* E.g. @nx/angular projects might need to make different changes to the final
* ESLint config when compared with @nx/nest projects.
*
* See the ProjectConverter implementation for a full breakdown of what it does.
*/
const projectConverter = new ProjectConverter({
host,
projectName: options.project,
ignoreExistingTslintConfig: options.ignoreExistingTslintConfig,
eslintInitializer: async ({ projectName, projectConfig }) => {
/**
* Using .js is not an option with NestJS, so we always set it to false when
* delegating to the external (more generic) generators below.
*/
const js = false;
/**
* We set the parserOptions.project config just in case the converted config uses
* rules which require type-checking. Later in the conversion we check if it actually
* does and remove the config again if it doesn't, so that it is most efficient.
*/
const setParserOptionsProject = true;
if (projectConfig.projectType === 'application') {
await addLintingToApplication(host, {
linter: 'eslint',
name: projectName,
appProjectRoot: projectConfig.root,
js,
setParserOptionsProject,
parsedTags: [],
skipFormat: options.skipFormat,
} as AddLintForApplicationSchema);
}
if (projectConfig.projectType === 'library') {
await addLintingToLibraryGenerator(host, {
linter: 'eslint',
name: projectName,
projectRoot: projectConfig.root,
js,
setParserOptionsProject,
projectDirectory: '',
fileName: '',
parsedTags: [],
skipFormat: true,
} as AddLintForLibrarySchema);
}
},
});
/**
* If root eslint configuration already exists it will not be recreated
* but we also don't want to re-run the tslint config conversion
* as it was likely already done
*/
const rootEslintConfigExists = host.exists('.eslintrc.json');
/**
* Create the standard (which is applicable to the current package) ESLint setup
* for converting the project.
*/
const eslintInitInstallTask = await projectConverter.initESLint();
/**
* Convert the root tslint.json and apply the converted rules to the root .eslintrc.json.
*/
const rootConfigInstallTask = await projectConverter.convertRootTSLintConfig(
(json) => removeCodelyzerRelatedRules(json),
rootEslintConfigExists
);
/**
* Convert the project's tslint.json to an equivalent ESLint config.
*/
const projectConfigInstallTask = await projectConverter.convertProjectConfig(
(json) => json
);
/**
* Clean up the original TSLint configuration for the project.
*/
projectConverter.removeProjectTSLintFile();
// Only project shouldn't be added as a default
const { project, ...defaults } = options;
/**
* Store user preferences for the collection
*/
projectConverter.setDefaults('@nx/nest', defaults);
/**
* Based on user preference and remaining usage, remove TSLint from the workspace entirely.
*/
let uninstallTSLintTask: GeneratorCallback = () => Promise.resolve(undefined);
if (
options.removeTSLintIfNoMoreTSLintTargets &&
!projectConverter.isTSLintUsedInWorkspace()
) {
uninstallTSLintTask = projectConverter.removeTSLintFromWorkspace();
}
if (!options.skipFormat) {
await formatFiles(host);
}
return async () => {
await eslintInitInstallTask();
await rootConfigInstallTask();
await projectConfigInstallTask();
await uninstallTSLintTask();
};
}
export const conversionSchematic = convertNxGenerator(conversionGenerator);
/**
* Remove any @angular-eslint rules that were applied as a result of converting prior codelyzer
* rules, because they are only relevant for Angular projects.
*/
function removeCodelyzerRelatedRules(json: Linter.Config): Linter.Config {
for (const ruleName of Object.keys(json.rules)) {
if (ruleName.startsWith('@angular-eslint')) {
delete json.rules[ruleName];
}
}
if (json.plugins) {
json.plugins = json.plugins.filter(
(plugin) => !plugin.startsWith('@angular-eslint')
);
}
return json;
}