Skip to content

Commit

Permalink
feat(plugin-eslint): support implicit configs
Browse files Browse the repository at this point in the history
  • Loading branch information
matejchalk committed May 28, 2024
1 parent a8c530a commit f89037a
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 42 deletions.
4 changes: 2 additions & 2 deletions packages/plugin-eslint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Detected ESLint rules are mapped to Code PushUp audits. Audit reports are calcul

4. Add this plugin to the `plugins` array in your Code PushUp CLI config file (e.g. `code-pushup.config.js`).

Pass in the path to your ESLint config file, along with glob patterns for which files you wish to target (relative to `process.cwd()`).
Pass in the glob patterns for which files you wish to target (relative to `process.cwd()`).
```js
import eslintPlugin from '@code-pushup/eslint-plugin';
Expand All @@ -52,7 +52,7 @@ Detected ESLint rules are mapped to Code PushUp audits. Audit reports are calcul
// ...
plugins: [
// ...
await eslintPlugin({ eslintrc: '.eslintrc.js', patterns: ['src/**/*.js'] }),
await eslintPlugin(['src/**/*.js']),
],
};
```
Expand Down
42 changes: 28 additions & 14 deletions packages/plugin-eslint/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,35 @@ import type { ESLint } from 'eslint';
import { type ZodType, z } from 'zod';
import { toArray } from '@code-pushup/utils';

export const eslintTargetSchema = z.object({
eslintrc: z.union(
[
z.string({ description: 'Path to ESLint config file' }),
z.record(z.string(), z.unknown(), {
description: 'ESLint config object',
}) as ZodType<ESLint.ConfigData>,
],
{ description: 'ESLint config as file path or inline object' },
),
patterns: z.union([z.string(), z.array(z.string()).min(1)], {
description:
'Lint target files. May contain file paths, directory paths or glob patterns',
}),
const patternsSchema = z.union([z.string(), z.array(z.string()).min(1)], {
description:
'Lint target files. May contain file paths, directory paths or glob patterns',
});

const eslintrcSchema = z.union(
[
z.string({ description: 'Path to ESLint config file' }),
z.record(z.string(), z.unknown(), {
description: 'ESLint config object',
}) as ZodType<ESLint.ConfigData>,
],
{ description: 'ESLint config as file path or inline object' },
);

const eslintTargetObjectSchema = z.object({
eslintrc: eslintrcSchema.optional(),
patterns: patternsSchema,
});
type ESLintTargetObject = z.infer<typeof eslintTargetObjectSchema>;

export const eslintTargetSchema = z
.union([patternsSchema, eslintTargetObjectSchema])
.transform(
(target): ESLintTargetObject =>
typeof target === 'string' || Array.isArray(target)
? { patterns: target }
: target,
);
export type ESLintTarget = z.infer<typeof eslintTargetSchema>;

export const eslintPluginConfigSchema = z
Expand Down
6 changes: 0 additions & 6 deletions packages/plugin-eslint/src/lib/nx.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ describe('Nx helpers', () => {
it('should include eslintrc and patterns of each project', async () => {
await expect(eslintConfigFromAllNxProjects()).resolves.toEqual([
{
eslintrc: './packages/cli/.eslintrc.json',
patterns: [
'packages/cli/**/*.ts',
'packages/cli/package.json',
Expand All @@ -53,7 +52,6 @@ describe('Nx helpers', () => {
],
},
{
eslintrc: './packages/core/.eslintrc.json',
patterns: [
'packages/core/**/*.ts',
'packages/core/package.json',
Expand All @@ -64,7 +62,6 @@ describe('Nx helpers', () => {
],
},
{
eslintrc: './packages/nx-plugin/.eslintrc.json',
patterns: [
'packages/nx-plugin/**/*.ts',
'packages/nx-plugin/package.json',
Expand All @@ -76,7 +73,6 @@ describe('Nx helpers', () => {
],
},
{
eslintrc: './packages/utils/.eslintrc.json',
patterns: [
'packages/utils/**/*.ts',
'packages/utils/package.json',
Expand Down Expand Up @@ -118,7 +114,6 @@ describe('Nx helpers', () => {
expect(targets).toEqual(
expectedProjects.map(
(p): ESLintTarget => ({
eslintrc: `./packages/${p}/.eslintrc.json`,
patterns: expect.arrayContaining([`packages/${p}/**/*.ts`]),
}),
),
Expand Down Expand Up @@ -148,7 +143,6 @@ describe('Nx helpers', () => {
const targets = await eslintConfigFromNxProject(project);

expect(targets).toEqual({
eslintrc: `./packages/${project}/.eslintrc.json`,
patterns: expect.arrayContaining([`packages/${project}/**/*.ts`]),
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,12 @@ describe('nxProjectsToConfig', () => {

expect(config).toEqual<ESLintPluginConfig>([
{
eslintrc: './apps/client/.eslintrc.json',
patterns: expect.arrayContaining(['apps/client/**/*.ts']),
},
{
eslintrc: './apps/server/.eslintrc.json',
patterns: expect.arrayContaining(['apps/server/**/*.ts']),
},
{
eslintrc: './libs/models/.eslintrc.json',
patterns: expect.arrayContaining(['libs/models/**/*.ts']),
},
]);
Expand Down Expand Up @@ -108,7 +105,6 @@ describe('nxProjectsToConfig', () => {

expect(config).toEqual<ESLintPluginConfig>([
{
eslintrc: './libs/models/.eslintrc.json',
patterns: expect.arrayContaining(['libs/models/**/*.ts']),
},
]);
Expand Down Expand Up @@ -150,11 +146,9 @@ describe('nxProjectsToConfig', () => {

expect(config).toEqual<ESLintPluginConfig>([
{
eslintrc: './apps/client/.eslintrc.json',
patterns: expect.arrayContaining(['apps/client/**/*.ts']),
},
{
eslintrc: './apps/server/.eslintrc.json',
patterns: expect.arrayContaining(['apps/server/**/*.ts']),
},
]);
Expand Down Expand Up @@ -222,11 +216,9 @@ describe('nxProjectsToConfig', () => {
'apps/client/**/*.ts',
'apps/client/**/*.html',
]),
eslintrc: './apps/client/.eslintrc.json',
},
{
patterns: expect.arrayContaining(['apps/server/**/*.ts']),
eslintrc: './apps/server/.eslintrc.json',
},
] satisfies ESLintPluginConfig);
});
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin-eslint/src/lib/nx/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ export function getLintFilePatterns(project: ProjectConfiguration): string[] {
: toArray(options.lintFilePatterns);
}

export function getEslintConfig(project: ProjectConfiguration): string {
export function getEslintConfig(
project: ProjectConfiguration,
): string | undefined {
const options = project.targets?.['lint']?.options as
| { eslintConfig?: string }
| undefined;
return options?.eslintConfig ?? `./${project.root}/.eslintrc.json`;
return options?.eslintConfig;
}
8 changes: 4 additions & 4 deletions packages/plugin-eslint/src/lib/runner/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ function executeLint({
command: 'npx',
args: [
'eslint',
`--config=${configPath}`,
'--no-eslintrc',
...(configPath ? [`--config=${configPath}`] : []),
...(typeof eslintrc === 'object' ? ['--no-eslintrc'] : []),
'--no-error-on-unmatched-pattern',
'--format=json',
...toArray(patterns).map(pattern =>
Expand Down Expand Up @@ -77,9 +77,9 @@ function loadRuleOptionsPerFile(

async function withConfig<T>(
eslintrc: ESLintTarget['eslintrc'],
fn: (configPath: string) => Promise<T>,
fn: (configPath: string | undefined) => Promise<T>,
): Promise<T> {
if (typeof eslintrc === 'string') {
if (typeof eslintrc !== 'object') {
return fn(eslintrc);
}

Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-eslint/src/lib/runner/lint.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ describe('lint', () => {
await lint(config);
expect(ESLint).toHaveBeenCalledWith<ConstructorParameters<typeof ESLint>>({
overrideConfigFile: '.eslintrc.js',
useEslintrc: false,
errorOnUnmatchedPattern: false,
});

Expand All @@ -108,7 +107,6 @@ describe('lint', () => {
args: [
'eslint',
'--config=.eslintrc.js',
'--no-eslintrc',
'--no-error-on-unmatched-pattern',
'--format=json',
expect.stringContaining('**/*.js'), // wraps in quotes on Unix
Expand Down
9 changes: 5 additions & 4 deletions packages/plugin-eslint/src/lib/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import type { ESLintTarget } from './config';

export function setupESLint(eslintrc: ESLintTarget['eslintrc']) {
return new ESLint({
...(typeof eslintrc === 'string'
? { overrideConfigFile: eslintrc }
: { baseConfig: eslintrc }),
useEslintrc: false,
...(typeof eslintrc === 'string' && { overrideConfigFile: eslintrc }),
...(typeof eslintrc === 'object' && {
baseConfig: eslintrc,
useEslintrc: false,
}),
errorOnUnmatchedPattern: false,
});
}

0 comments on commit f89037a

Please sign in to comment.