Skip to content

Commit

Permalink
feat(linter): collect all parent eslint configs
Browse files Browse the repository at this point in the history
  • Loading branch information
meeroslav committed Nov 29, 2023
1 parent c59224e commit c167227
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 28 deletions.
4 changes: 3 additions & 1 deletion e2e/eslint/src/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,9 @@ describe('Linter', () => {
);

const lintResults = runCLI(`lint ${myapp}`);
expect(lintResults).toContain('All files pass linting');
expect(lintResults).toContain(
`Successfully ran target lint for project ${myapp}`
);

const { targets } = readJson(`apps/${myapp}/project.json`);
expect(targets.lint).not.toBeDefined();
Expand Down
12 changes: 5 additions & 7 deletions packages/eslint/src/plugins/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe('@nx/eslint/plugin', () => {
"inputs": [
"default",
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/apps/my-app/.eslintrc.json",
"{workspaceRoot}/tools/eslint-rules/**/*",
{
"externalDependencies": [
Expand All @@ -69,9 +70,6 @@ describe('@nx/eslint/plugin', () => {
"options": {
"cwd": "apps/my-app",
},
"outputs": [
"{options.outputFile}",
],
},
},
},
Expand Down Expand Up @@ -105,7 +103,7 @@ describe('@nx/eslint/plugin', () => {
"targets": {
"lint": {
"cache": true,
"command": "ESLINT_USE_FLAT_CONFIG=true eslint ./src",
"command": "eslint ./src",
"inputs": [
"default",
"{workspaceRoot}/eslint.config.js",
Expand All @@ -118,10 +116,10 @@ describe('@nx/eslint/plugin', () => {
],
"options": {
"cwd": ".",
"env": {
"ESLINT_USE_FLAT_CONFIG": "true",
},
},
"outputs": [
"{options.outputFile}",
],
},
},
},
Expand Down
65 changes: 45 additions & 20 deletions packages/eslint/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,27 @@ export const createNodes: CreateNodes<EslintPluginOptions> = [
(configFilePath, options, context) => {
const projectRoot = dirname(configFilePath);

if (!projectHasEslintConfig(projectRoot, context.workspaceRoot)) {
return {};
}

options = normalizeOptions(options);
const projectName = basename(projectRoot);

if (options.excludedProjects.includes(projectName)) {
return {};
}

const rootEslintConfigFile = findBaseEslintFile(context.workspaceRoot);
const eslintConfigs = getEslintConfigsForProject(
projectRoot,
context.workspaceRoot
);
if (!eslintConfigs.length) {
return {};
}

return {
projects: {
[projectName]: {
root: projectRoot,
targets: buildEslintTargets(
rootEslintConfigFile,
eslintConfigs,
projectRoot,
options,
context
Expand All @@ -52,35 +54,58 @@ export const createNodes: CreateNodes<EslintPluginOptions> = [
},
];

function projectHasEslintConfig(
function getEslintConfigsForProject(
projectRoot: string,
workspaceRoot: string
): boolean {
const siblingFiles = readdirSync(join(workspaceRoot, projectRoot));
): string[] {
const detectedConfigs = new Set<string>();
const baseConfig = findBaseEslintFile(workspaceRoot);
if (baseConfig) {
detectedConfigs.add(baseConfig);
}

let siblingFiles = readdirSync(join(workspaceRoot, projectRoot));

if (projectRoot === '.') {
// If there's no src folder, it's not a standalone project
if (!siblingFiles.includes('src')) {
return false;
return [];
}
// If it's standalone but doesn't have eslint config, it's not a lintable
if (!siblingFiles.some((f) => ESLINT_CONFIG_FILENAMES.includes(f))) {
return false;
const config = siblingFiles.find((f) =>
ESLINT_CONFIG_FILENAMES.includes(f)
);
if (!config) {
return [];
}
return true;
detectedConfigs.add(config);
return Array.from(detectedConfigs);
}
// if it has an eslint config it's lintable
if (siblingFiles.some((f) => ESLINT_CONFIG_FILENAMES.includes(f))) {
return true;
while (projectRoot !== '.') {
// if it has an eslint config it's lintable
const config = siblingFiles.find((f) =>
ESLINT_CONFIG_FILENAMES.includes(f)
);
if (config) {
detectedConfigs.add(`${projectRoot}/${config}`);
return Array.from(detectedConfigs);
}
projectRoot = dirname(projectRoot);
siblingFiles = readdirSync(join(workspaceRoot, projectRoot));
}
// check whether the root has an eslint config
return readdirSync(workspaceRoot).some((f) =>
const config = readdirSync(workspaceRoot).find((f) =>
ESLINT_CONFIG_FILENAMES.includes(f)
);
if (config) {
detectedConfigs.add(config);
return Array.from(detectedConfigs);
}
return [];
}

function buildEslintTargets(
rootEslintConfigFile: string,
eslintConfigs: string[],
projectRoot: string,
options: EslintPluginOptions,
context: CreateNodesContext
Expand All @@ -101,7 +126,7 @@ function buildEslintTargets(
cwd: projectRoot,
},
};
if (isFlatConfig(rootEslintConfigFile)) {
if (eslintConfigs.some((config) => isFlatConfig(config))) {
baseTargetConfig.options.env = {
ESLINT_USE_FLAT_CONFIG: 'true',
};
Expand All @@ -112,7 +137,7 @@ function buildEslintTargets(
cache: targetDefaults?.cache ?? true,
inputs: targetDefaults?.inputs ?? [
'default',
`{workspaceRoot}/${rootEslintConfigFile}`,
...eslintConfigs.map((config) => `{workspaceRoot}/${config}`),
'{workspaceRoot}/tools/eslint-rules/**/*',
{ externalDependencies: ['eslint'] },
],
Expand Down

0 comments on commit c167227

Please sign in to comment.