feat(core): enable linter on root projects (#13347)
This commit is contained in:
parent
8200870c8e
commit
110b5f2867
@ -438,6 +438,78 @@ export function tslibC(): string {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Root projects migration', () => {
|
||||
afterEach(() => cleanupProject());
|
||||
|
||||
it('should set root project config to app and e2e app and migrate when another lib is added', () => {
|
||||
const myapp = uniq('myapp');
|
||||
const mylib = uniq('mylib');
|
||||
|
||||
newProject();
|
||||
runCLI(`generate @nrwl/react:app ${myapp} --rootProject=true`);
|
||||
|
||||
let rootEslint = readJson('.eslintrc.json');
|
||||
let e2eEslint = readJson('e2e/.eslintrc.json');
|
||||
expect(() => checkFilesExist(`.eslintrc.${myapp}.json`)).toThrow();
|
||||
|
||||
// should directly refer to nx plugin
|
||||
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
|
||||
expect(e2eEslint.plugins).toEqual(['@nrwl/nx']);
|
||||
// should only extend framework plugin
|
||||
expect(rootEslint.extends).toEqual(['plugin:@nrwl/nx/react']);
|
||||
expect(e2eEslint.extends).toEqual(['plugin:cypress/recommended']);
|
||||
// should have plugin extends
|
||||
expect(rootEslint.overrides[0].extends).toEqual([
|
||||
'plugin:@nrwl/nx/typescript',
|
||||
]);
|
||||
expect(rootEslint.overrides[1].extends).toEqual([
|
||||
'plugin:@nrwl/nx/javascript',
|
||||
]);
|
||||
expect(e2eEslint.overrides[0].extends).toEqual([
|
||||
'plugin:@nrwl/nx/typescript',
|
||||
]);
|
||||
expect(e2eEslint.overrides[1].extends).toEqual([
|
||||
'plugin:@nrwl/nx/javascript',
|
||||
]);
|
||||
|
||||
console.log(JSON.stringify(rootEslint, null, 2));
|
||||
console.log(JSON.stringify(e2eEslint, null, 2));
|
||||
|
||||
runCLI(`generate @nrwl/react:lib ${mylib}`);
|
||||
// should add new tslint
|
||||
expect(() => checkFilesExist(`.eslintrc.${myapp}.json`)).not.toThrow();
|
||||
const appEslint = readJson(`.eslintrc.${myapp}.json`);
|
||||
rootEslint = readJson('.eslintrc.json');
|
||||
e2eEslint = readJson('e2e/.eslintrc.json');
|
||||
const libEslint = readJson(`libs/${mylib}/.eslintrc.json`);
|
||||
|
||||
// should directly refer to nx plugin only in the root
|
||||
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
|
||||
expect(appEslint.plugins).toBeUndefined();
|
||||
expect(e2eEslint.plugins).toBeUndefined();
|
||||
// should extend framework plugin and root config
|
||||
expect(appEslint.extends).toEqual([
|
||||
'plugin:@nrwl/nx/react',
|
||||
'./.eslintrc.json',
|
||||
]);
|
||||
expect(e2eEslint.extends).toEqual([
|
||||
'plugin:cypress/recommended',
|
||||
'../.eslintrc.json',
|
||||
]);
|
||||
expect(libEslint.extends).toEqual([
|
||||
'plugin:@nrwl/nx/react',
|
||||
'../../.eslintrc.json',
|
||||
]);
|
||||
// should have no plugin extends
|
||||
expect(appEslint.overrides[0].extends).toBeUndefined();
|
||||
expect(appEslint.overrides[1].extends).toBeUndefined();
|
||||
expect(e2eEslint.overrides[0].extends).toBeUndefined();
|
||||
expect(e2eEslint.overrides[1].extends).toBeUndefined();
|
||||
expect(libEslint.overrides[1].extends).toBeUndefined();
|
||||
expect(libEslint.overrides[1].extends).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@ -19,6 +19,10 @@ import {
|
||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import {
|
||||
globalJavaScriptOverrides,
|
||||
globalTypeScriptOverrides,
|
||||
} from '@nrwl/linter/src/generators/init/global-eslint-config';
|
||||
|
||||
import { join } from 'path';
|
||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||
@ -177,6 +181,7 @@ export async function addLinter(host: Tree, options: CypressProjectSchema) {
|
||||
],
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
|
||||
if (!options.linter || options.linter !== Linter.EsLint) {
|
||||
@ -192,8 +197,16 @@ export async function addLinter(host: Tree, options: CypressProjectSchema) {
|
||||
: () => {};
|
||||
|
||||
updateJson(host, join(options.projectRoot, '.eslintrc.json'), (json) => {
|
||||
json.extends = ['plugin:cypress/recommended', ...json.extends];
|
||||
if (options.rootProject) {
|
||||
json.plugins = ['@nrwl/nx'];
|
||||
json.extends = ['plugin:cypress/recommended'];
|
||||
} else {
|
||||
json.extends = ['plugin:cypress/recommended', ...json.extends];
|
||||
}
|
||||
json.overrides = [
|
||||
...(options.rootProject
|
||||
? [globalTypeScriptOverrides, globalJavaScriptOverrides]
|
||||
: []),
|
||||
/**
|
||||
* In order to ensure maximum efficiency when typescript-eslint generates TypeScript Programs
|
||||
* behind the scenes during lint runs, we need to make sure the project is configured to use its
|
||||
|
||||
@ -30,7 +30,8 @@
|
||||
"builders": "./executors.json",
|
||||
"schematics": "./generators.json",
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.0.0"
|
||||
"eslint": "^8.0.0",
|
||||
"js-yaml": "4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
|
||||
80
packages/linter/src/generators/init/global-eslint-config.ts
Normal file
80
packages/linter/src/generators/init/global-eslint-config.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { ESLint, Linter as LinterType } from 'eslint';
|
||||
|
||||
/**
|
||||
* This configuration is intended to apply to all TypeScript source files.
|
||||
* See the eslint-plugin-nx package for what is in the referenced shareable config.
|
||||
*/
|
||||
export const globalTypeScriptOverrides = {
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: ['plugin:@nrwl/nx/typescript'],
|
||||
/**
|
||||
* Having an empty rules object present makes it more obvious to the user where they would
|
||||
* extend things from if they needed to
|
||||
*/
|
||||
rules: {},
|
||||
};
|
||||
|
||||
/**
|
||||
* This configuration is intended to apply to all JavaScript source files.
|
||||
* See the eslint-plugin-nx package for what is in the referenced shareable config.
|
||||
*/
|
||||
export const globalJavaScriptOverrides = {
|
||||
files: ['*.js', '*.jsx'],
|
||||
extends: ['plugin:@nrwl/nx/javascript'],
|
||||
/**
|
||||
* Having an empty rules object present makes it more obvious to the user where they would
|
||||
* extend things from if they needed to
|
||||
*/
|
||||
rules: {},
|
||||
};
|
||||
|
||||
/**
|
||||
* This configuration is intended to apply to all "source code" (but not
|
||||
* markup like HTML, or other custom file types like GraphQL)
|
||||
*/
|
||||
export const moduleBoundariesOverride = {
|
||||
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
||||
rules: {
|
||||
'@nrwl/nx/enforce-module-boundaries': [
|
||||
'error',
|
||||
{
|
||||
enforceBuildableLibDependency: true,
|
||||
allow: [],
|
||||
depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }],
|
||||
},
|
||||
],
|
||||
} as LinterType.RulesRecord,
|
||||
};
|
||||
|
||||
export const getGlobalEsLintConfiguration = (
|
||||
unitTestRunner?: string,
|
||||
rootProject?: boolean
|
||||
) => {
|
||||
const config: ESLint.ConfigData = {
|
||||
root: true,
|
||||
ignorePatterns: rootProject ? ['!**/*'] : ['**/*'],
|
||||
plugins: ['@nrwl/nx'],
|
||||
/**
|
||||
* We leverage ESLint's "overrides" capability so that we can set up a root config which will support
|
||||
* all permutations of Nx workspaces across all frameworks, libraries and tools.
|
||||
*
|
||||
* The key point is that we need entirely different ESLint config to apply to different types of files,
|
||||
* but we still want to share common config where possible.
|
||||
*/
|
||||
overrides: [
|
||||
...(rootProject ? [] : [moduleBoundariesOverride]),
|
||||
globalTypeScriptOverrides,
|
||||
globalJavaScriptOverrides,
|
||||
],
|
||||
};
|
||||
if (unitTestRunner === 'jest') {
|
||||
config.overrides.push({
|
||||
files: ['*.spec.ts', '*.spec.tsx', '*.spec.js', '*.spec.jsx'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {},
|
||||
});
|
||||
}
|
||||
return config;
|
||||
};
|
||||
116
packages/linter/src/generators/init/init-migration.ts
Normal file
116
packages/linter/src/generators/init/init-migration.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { basename, dirname } from 'path';
|
||||
import { findEslintFile } from '../utils/eslint-file';
|
||||
import { getGlobalEsLintConfiguration } from './global-eslint-config';
|
||||
|
||||
const FILE_EXTENSION_REGEX = /(?<!(^|\/))(\.[^/.]+)$/;
|
||||
|
||||
export function migrateConfigToMonorepoStyle(
|
||||
projects: ProjectConfiguration[],
|
||||
tree: Tree,
|
||||
unitTestRunner: string
|
||||
): void {
|
||||
// copy the root's .eslintrc.json to new name
|
||||
const rootProject = projects.find((p) => p.root === '.');
|
||||
const eslintPath =
|
||||
rootProject.targets?.lint?.options?.eslintConfig || findEslintFile(tree);
|
||||
const pathSegments = eslintPath.split(FILE_EXTENSION_REGEX).filter(Boolean);
|
||||
const rootProjEslintPath =
|
||||
pathSegments.length > 1
|
||||
? pathSegments.join(`.${rootProject.name}`)
|
||||
: `.${rootProject.name}.${rootProject.name}`;
|
||||
tree.write(rootProjEslintPath, tree.read(eslintPath));
|
||||
|
||||
// update root project's configuration
|
||||
const lintTarget = findLintTarget(rootProject);
|
||||
lintTarget.options.eslintConfig = rootProjEslintPath;
|
||||
updateProjectConfiguration(tree, rootProject.name, rootProject);
|
||||
|
||||
// replace root eslint with default global
|
||||
tree.delete(eslintPath);
|
||||
writeJson(
|
||||
tree,
|
||||
'.eslintrc.json',
|
||||
getGlobalEsLintConfiguration(unitTestRunner)
|
||||
);
|
||||
|
||||
// update extens in all projects' eslint configs
|
||||
projects.forEach((project) => {
|
||||
const lintTarget = findLintTarget(project);
|
||||
if (lintTarget) {
|
||||
const projectEslintPath = joinPathFragments(
|
||||
project.root,
|
||||
lintTarget.options.eslintConfig || findEslintFile(tree, project.root)
|
||||
);
|
||||
migrateEslintFile(projectEslintPath, tree);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function findLintTarget(
|
||||
project: ProjectConfiguration
|
||||
): TargetConfiguration {
|
||||
return Object.entries(project.targets).find(
|
||||
([name, target]) =>
|
||||
name === 'lint' || target.executor === '@nrwl/linter:eslint'
|
||||
)?.[1];
|
||||
}
|
||||
|
||||
function migrateEslintFile(projectEslintPath: string, tree: Tree) {
|
||||
if (projectEslintPath.endsWith('.json')) {
|
||||
updateJson(tree, projectEslintPath, (json) => {
|
||||
// we have a new root now
|
||||
delete json.root;
|
||||
// remove nrwl/nx plugins
|
||||
if (json.plugins) {
|
||||
json.plugins = json.plugins.filter((p) => p !== '@nrwl/nx');
|
||||
if (json.plugins.length === 0) {
|
||||
delete json.plugins;
|
||||
}
|
||||
}
|
||||
// add extends
|
||||
json.extends = json.extends || [];
|
||||
const pathToRootConfig = `${offsetFromRoot(
|
||||
dirname(projectEslintPath)
|
||||
)}.eslintrc.json`;
|
||||
if (json.extends.indexOf(pathToRootConfig) === -1) {
|
||||
json.extends.push(pathToRootConfig);
|
||||
}
|
||||
// cleanup overrides
|
||||
if (json.overrides) {
|
||||
json.overrides.forEach((override) => {
|
||||
if (override.extends) {
|
||||
override.extends = override.extends.filter(
|
||||
(ext) =>
|
||||
ext !== 'plugin:@nrwl/nx/typescript' &&
|
||||
ext !== 'plugin:@nrwl/nx/javascript'
|
||||
);
|
||||
if (override.extends.length === 0) {
|
||||
delete override.extends;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return json;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
projectEslintPath.endsWith('.yml') ||
|
||||
projectEslintPath.endsWith('.yaml')
|
||||
) {
|
||||
console.warn('YAML eslint config is not supported yet for migration');
|
||||
}
|
||||
if (projectEslintPath.endsWith('.js') || projectEslintPath.endsWith('.cjs')) {
|
||||
console.warn('YAML eslint config is not supported yet for migration');
|
||||
}
|
||||
}
|
||||
@ -16,88 +16,15 @@ import {
|
||||
|
||||
import { Linter } from '../utils/linter';
|
||||
import { findEslintFile } from '../utils/eslint-file';
|
||||
import { ESLint } from 'eslint';
|
||||
import { getGlobalEsLintConfiguration } from './global-eslint-config';
|
||||
|
||||
export interface LinterInitOptions {
|
||||
linter?: Linter;
|
||||
unitTestRunner?: string;
|
||||
skipPackageJson?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
const getGlobalEsLintConfiguration = (unitTestRunner?: string) => {
|
||||
const config: ESLint.ConfigData = {
|
||||
root: true,
|
||||
ignorePatterns: ['**/*'],
|
||||
plugins: ['@nrwl/nx'],
|
||||
/**
|
||||
* We leverage ESLint's "overrides" capability so that we can set up a root config which will support
|
||||
* all permutations of Nx workspaces across all frameworks, libraries and tools.
|
||||
*
|
||||
* The key point is that we need entirely different ESLint config to apply to different types of files,
|
||||
* but we still want to share common config where possible.
|
||||
*/
|
||||
overrides: [
|
||||
/**
|
||||
* This configuration is intended to apply to all "source code" (but not
|
||||
* markup like HTML, or other custom file types like GraphQL)
|
||||
*/
|
||||
{
|
||||
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
||||
rules: {
|
||||
'@nrwl/nx/enforce-module-boundaries': [
|
||||
'error',
|
||||
{
|
||||
enforceBuildableLibDependency: true,
|
||||
allow: [],
|
||||
depConstraints: [
|
||||
{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* This configuration is intended to apply to all TypeScript source files.
|
||||
* See the eslint-plugin-nx package for what is in the referenced shareable config.
|
||||
*/
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: ['plugin:@nrwl/nx/typescript'],
|
||||
/**
|
||||
* Having an empty rules object present makes it more obvious to the user where they would
|
||||
* extend things from if they needed to
|
||||
*/
|
||||
rules: {},
|
||||
},
|
||||
|
||||
/**
|
||||
* This configuration is intended to apply to all JavaScript source files.
|
||||
* See the eslint-plugin-nx package for what is in the referenced shareable config.
|
||||
*/
|
||||
{
|
||||
files: ['*.js', '*.jsx'],
|
||||
extends: ['plugin:@nrwl/nx/javascript'],
|
||||
/**
|
||||
* Having an empty rules object present makes it more obvious to the user where they would
|
||||
* extend things from if they needed to
|
||||
*/
|
||||
rules: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
if (unitTestRunner === 'jest') {
|
||||
config.overrides.push({
|
||||
files: ['*.spec.ts', '*.spec.tsx', '*.spec.js', '*.spec.jsx'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {},
|
||||
});
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
function addTargetDefaults(tree: Tree) {
|
||||
const workspaceConfiguration = readWorkspaceConfiguration(tree);
|
||||
|
||||
@ -133,7 +60,7 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
||||
writeJson(
|
||||
tree,
|
||||
'.eslintrc.json',
|
||||
getGlobalEsLintConfiguration(options.unitTestRunner)
|
||||
getGlobalEsLintConfiguration(options.unitTestRunner, options.rootProject)
|
||||
);
|
||||
addTargetDefaults(tree);
|
||||
|
||||
|
||||
@ -11,6 +11,11 @@ import { Linter } from '../utils/linter';
|
||||
import { findEslintFile } from '../utils/eslint-file';
|
||||
import { join } from 'path';
|
||||
import { lintInitGenerator } from '../init/init';
|
||||
import {
|
||||
findLintTarget,
|
||||
migrateConfigToMonorepoStyle,
|
||||
} from '../init/init-migration';
|
||||
import { readWorkspace } from 'nx/src/generators/utils/project-configuration';
|
||||
|
||||
interface LintProjectOptions {
|
||||
project: string;
|
||||
@ -21,6 +26,7 @@ interface LintProjectOptions {
|
||||
setParserOptionsProject?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
unitTestRunner?: string;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
function createEsLintConfiguration(
|
||||
@ -74,6 +80,15 @@ function createEsLintConfiguration(
|
||||
});
|
||||
}
|
||||
|
||||
export function mapLintPattern(
|
||||
projectRoot: string,
|
||||
extension: string,
|
||||
rootProject?: boolean
|
||||
) {
|
||||
const infix = rootProject ? 'src/' : '';
|
||||
return `${projectRoot}/${infix}**/*.${extension}`;
|
||||
}
|
||||
|
||||
export async function lintProjectGenerator(
|
||||
tree: Tree,
|
||||
options: LintProjectOptions
|
||||
@ -82,6 +97,7 @@ export async function lintProjectGenerator(
|
||||
linter: options.linter,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
|
||||
@ -92,11 +108,38 @@ export async function lintProjectGenerator(
|
||||
lintFilePatterns: options.eslintFilePatterns,
|
||||
},
|
||||
};
|
||||
createEsLintConfiguration(
|
||||
tree,
|
||||
projectConfig,
|
||||
options.setParserOptionsProject
|
||||
);
|
||||
|
||||
// we are adding new project which is not the root project or
|
||||
// companion e2e app so we should check if migration to
|
||||
// monorepo style is needed
|
||||
if (!options.rootProject) {
|
||||
const projects = readWorkspace(tree).projects;
|
||||
if (isMigrationToMonorepoNeeded(projects, tree)) {
|
||||
// we only migrate project configurations that have been created
|
||||
const filteredProjects = [];
|
||||
Object.entries(projects).forEach(([name, project]) => {
|
||||
if (name !== options.project) {
|
||||
filteredProjects.push(project);
|
||||
}
|
||||
});
|
||||
migrateConfigToMonorepoStyle(
|
||||
filteredProjects,
|
||||
tree,
|
||||
options.unitTestRunner
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// our root `.eslintrc` is already the project config, so we should not override it
|
||||
// additionally, the companion e2e app would have `rootProject: true`
|
||||
// so we need to check for the root path as well
|
||||
if (!options.rootProject || projectConfig.root !== '.') {
|
||||
createEsLintConfiguration(
|
||||
tree,
|
||||
projectConfig,
|
||||
options.setParserOptionsProject
|
||||
);
|
||||
}
|
||||
|
||||
updateProjectConfiguration(tree, options.project, projectConfig);
|
||||
|
||||
@ -106,3 +149,40 @@ export async function lintProjectGenerator(
|
||||
|
||||
return installTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect based on the state of lint target configuration of the root project
|
||||
* if we should migrate eslint configs to monorepo style
|
||||
*
|
||||
* @param tree
|
||||
* @returns
|
||||
*/
|
||||
function isMigrationToMonorepoNeeded(
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
tree: Tree
|
||||
): boolean {
|
||||
const configs = Object.values(projects);
|
||||
if (configs.length === 1) {
|
||||
return false;
|
||||
}
|
||||
// get root project
|
||||
const rootProject = configs.find((p) => p.root === '.');
|
||||
if (!rootProject || !rootProject.targets) {
|
||||
return false;
|
||||
}
|
||||
// find if root project has lint target
|
||||
const lintTarget = findLintTarget(rootProject);
|
||||
if (!lintTarget) {
|
||||
return false;
|
||||
}
|
||||
// if there is no override for `eslintConfig` we should migrate
|
||||
if (!lintTarget.options.eslintConfig) {
|
||||
return true;
|
||||
}
|
||||
// check if target has `eslintConfig` override and if it's not pointing to the source .eslintrc
|
||||
const rootEslintrc = findEslintFile(tree);
|
||||
return (
|
||||
lintTarget.options.eslintConfig === rootEslintrc ||
|
||||
lintTarget.options.eslintConfig === `./${rootEslintrc}`
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import { joinPathFragments, Tree } from '@nrwl/devkit';
|
||||
|
||||
export const eslintConfigFileWhitelist = [
|
||||
'.eslintrc',
|
||||
@ -9,9 +9,9 @@ export const eslintConfigFileWhitelist = [
|
||||
'.eslintrc.json',
|
||||
];
|
||||
|
||||
export function findEslintFile(tree: Tree): string | null {
|
||||
export function findEslintFile(tree: Tree, projectRoot = ''): string | null {
|
||||
for (const file of eslintConfigFileWhitelist) {
|
||||
if (tree.exists(file)) {
|
||||
if (tree.exists(joinPathFragments(projectRoot, file))) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {
|
||||
createReactEslintJson,
|
||||
extendReactEslintJson,
|
||||
extraEslintDependencies,
|
||||
} from '../../utils/lint';
|
||||
import { NormalizedSchema, Schema } from './schema';
|
||||
@ -27,6 +27,7 @@ import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
||||
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
||||
import { mapLintPattern } from '@nrwl/linter/src/generators/lint-project/lint-project';
|
||||
|
||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
@ -38,20 +39,22 @@ async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||
],
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,tsx,js,jsx}`],
|
||||
eslintFilePatterns: [
|
||||
mapLintPattern(
|
||||
options.appProjectRoot,
|
||||
'{ts,tsx,js,jsx}',
|
||||
options.rootProject
|
||||
),
|
||||
],
|
||||
skipFormat: true,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
tasks.push(lintTask);
|
||||
|
||||
const reactEslintJson = createReactEslintJson(
|
||||
options.appProjectRoot,
|
||||
options.setParserOptionsProject
|
||||
);
|
||||
|
||||
updateJson(
|
||||
host,
|
||||
joinPathFragments(options.appProjectRoot, '.eslintrc.json'),
|
||||
() => reactEslintJson
|
||||
extendReactEslintJson
|
||||
);
|
||||
|
||||
const installTask = await addDependenciesToPackageJson(
|
||||
|
||||
@ -12,5 +12,6 @@ export async function addCypress(host: Tree, options: NormalizedSchema) {
|
||||
name: options.e2eProjectName,
|
||||
directory: options.directory,
|
||||
project: options.projectName,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,6 +17,15 @@ export const extraEslintDependencies = {
|
||||
},
|
||||
};
|
||||
|
||||
export const extendReactEslintJson = (json: Linter.Config) => {
|
||||
const { extends: pluginExtends, ...config } = json;
|
||||
|
||||
return {
|
||||
extends: ['plugin:@nrwl/nx/react', ...(pluginExtends || [])],
|
||||
...config,
|
||||
};
|
||||
};
|
||||
|
||||
export const createReactEslintJson = (
|
||||
projectRoot: string,
|
||||
setParserOptionsProject: boolean
|
||||
|
||||
@ -67,7 +67,7 @@ async function createPreset(tree: Tree, options: Schema) {
|
||||
await reactApplicationGenerator(tree, {
|
||||
name: options.name,
|
||||
style: options.style,
|
||||
linter: 'none',
|
||||
linter: options.linter,
|
||||
unitTestRunner: 'none',
|
||||
standaloneConfig: options.standaloneConfig,
|
||||
rootProject: true,
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
"@nrwl/js": ["packages/js/src"],
|
||||
"@nrwl/js/*": ["packages/js/*"],
|
||||
"@nrwl/linter": ["packages/linter"],
|
||||
"@nrwl/linter/*": ["packages/linter/*"],
|
||||
"@nrwl/nest": ["packages/nest"],
|
||||
"@nrwl/next": ["packages/next"],
|
||||
"@nrwl/node": ["packages/node"],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user