123 lines
3.5 KiB
TypeScript
Executable File
123 lines
3.5 KiB
TypeScript
Executable File
import {
|
|
formatFiles,
|
|
GeneratorCallback,
|
|
joinPathFragments,
|
|
readProjectConfiguration,
|
|
runTasksInSerial,
|
|
Tree,
|
|
} from '@nx/devkit';
|
|
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
|
import { addAngularEsLintDependencies } from './lib/add-angular-eslint-dependencies';
|
|
import type { AddLintingGeneratorSchema } from './schema';
|
|
import {
|
|
findEslintFile,
|
|
isEslintConfigSupported,
|
|
replaceOverridesInLintConfig,
|
|
} from '@nx/eslint/src/generators/utils/eslint-file';
|
|
import { camelize, dasherize } from '@nx/devkit/src/utils/string-utils';
|
|
|
|
export async function addLintingGenerator(
|
|
tree: Tree,
|
|
options: AddLintingGeneratorSchema
|
|
): Promise<GeneratorCallback> {
|
|
const tasks: GeneratorCallback[] = [];
|
|
const rootProject = options.projectRoot === '.' || options.projectRoot === '';
|
|
const lintTask = await lintProjectGenerator(tree, {
|
|
linter: Linter.EsLint,
|
|
project: options.projectName,
|
|
tsConfigPaths: [
|
|
joinPathFragments(options.projectRoot, 'tsconfig.app.json'),
|
|
],
|
|
unitTestRunner: options.unitTestRunner,
|
|
setParserOptionsProject: options.setParserOptionsProject,
|
|
skipFormat: true,
|
|
rootProject: rootProject,
|
|
});
|
|
tasks.push(lintTask);
|
|
|
|
if (isEslintConfigSupported(tree)) {
|
|
const eslintFile = findEslintFile(tree, options.projectRoot);
|
|
// keep parser options if they exist
|
|
const hasParserOptions = tree
|
|
.read(joinPathFragments(options.projectRoot, eslintFile), 'utf8')
|
|
.includes(`${options.projectRoot}/tsconfig.*?.json`);
|
|
|
|
replaceOverridesInLintConfig(tree, options.projectRoot, [
|
|
{
|
|
files: ['*.ts'],
|
|
...(hasParserOptions
|
|
? {
|
|
parserOptions: {
|
|
project: [`${options.projectRoot}/tsconfig.*?.json`],
|
|
},
|
|
}
|
|
: {}),
|
|
extends: [
|
|
'plugin:@nx/angular',
|
|
'plugin:@angular-eslint/template/process-inline-templates',
|
|
],
|
|
rules: {
|
|
'@angular-eslint/directive-selector': [
|
|
'error',
|
|
{
|
|
type: 'attribute',
|
|
prefix: camelize(options.prefix),
|
|
style: 'camelCase',
|
|
},
|
|
],
|
|
'@angular-eslint/component-selector': [
|
|
'error',
|
|
{
|
|
type: 'element',
|
|
prefix: dasherize(options.prefix),
|
|
style: 'kebab-case',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['*.html'],
|
|
extends: ['plugin:@nx/angular-template'],
|
|
/**
|
|
* Having an empty rules object present makes it more obvious to the user where they would
|
|
* extend things from if they needed to
|
|
*/
|
|
rules: {},
|
|
},
|
|
...(isBuildableLibraryProject(tree, options.projectName)
|
|
? [
|
|
{
|
|
files: ['*.json'],
|
|
parser: 'jsonc-eslint-parser',
|
|
rules: {
|
|
'@nx/dependency-checks': 'error',
|
|
} as any,
|
|
},
|
|
]
|
|
: []),
|
|
]);
|
|
}
|
|
|
|
if (!options.skipPackageJson) {
|
|
const installTask = addAngularEsLintDependencies(tree);
|
|
tasks.push(installTask);
|
|
}
|
|
|
|
if (!options.skipFormat) {
|
|
await formatFiles(tree);
|
|
}
|
|
|
|
return runTasksInSerial(...tasks);
|
|
}
|
|
|
|
function isBuildableLibraryProject(tree: Tree, projectName: string): boolean {
|
|
const projectConfig = readProjectConfiguration(tree, projectName);
|
|
return (
|
|
projectConfig.projectType === 'library' &&
|
|
projectConfig.targets?.build &&
|
|
!!projectConfig.targets.build
|
|
);
|
|
}
|
|
|
|
export default addLintingGenerator;
|