Skip to content

Commit 687bada

Browse files
committed
feat(plugin-eslint): use artifacts options
1 parent 4e0ffa3 commit 687bada

File tree

4 files changed

+74
-99
lines changed

4 files changed

+74
-99
lines changed

packages/plugin-eslint/src/lib/eslint-plugin.int.test.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ describe('eslintPlugin', () => {
152152
await expect(
153153
// @ts-expect-error simulating invalid non-TS config
154154
eslintPlugin({ eslintrc: '.eslintrc.json' }),
155-
).rejects.toThrow('Invalid input');
155+
).rejects.toThrow('Failed parsing ESLint plugin config');
156156
});
157157

158158
it("should throw if eslintrc file doesn't exist", async () => {
@@ -176,14 +176,6 @@ describe('eslintPlugin', () => {
176176
},
177177
);
178178

179-
expect(typeof plugin.runner).toBe('object');
180-
const runnerConfig = plugin.runner as {
181-
command: string;
182-
args?: string[];
183-
outputFile: string;
184-
};
185-
expect(runnerConfig.command).toBe('node');
186-
expect(runnerConfig.args).toContain('echo "Generating artifacts"');
187-
expect(runnerConfig.outputFile).toBe('./artifacts/eslint-output.json');
179+
expect(typeof plugin.runner).toBe('function');
188180
});
189181
});

packages/plugin-eslint/src/lib/eslint-plugin.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { createRequire } from 'node:module';
2-
import path from 'node:path';
3-
import { fileURLToPath } from 'node:url';
42
import type { PluginConfig } from '@code-pushup/models';
53
import { parseSchema } from '@code-pushup/utils';
64
import {
@@ -11,7 +9,7 @@ import {
119
} from './config.js';
1210
import { ESLINT_PLUGIN_SLUG } from './constants.js';
1311
import { listAuditsAndGroups } from './meta/index.js';
14-
import { createRunnerConfig } from './runner/index.js';
12+
import { createRunnerFunction } from './runner/index.js';
1513

1614
/**
1715
* Instantiates Code PushUp ESLint plugin for use in core config.
@@ -42,22 +40,14 @@ export async function eslintPlugin(
4240
schemaType: 'ESLint plugin config',
4341
});
4442

45-
const parsedOptions = options
43+
const { groups: customGroups, artifacts } = options
4644
? parseSchema(eslintPluginOptionsSchema, options, {
4745
schemaType: 'ESLint plugin options',
4846
})
49-
: undefined;
50-
51-
const customGroups = parsedOptions?.groups;
47+
: {};
5248

5349
const { audits, groups } = await listAuditsAndGroups(targets, customGroups);
5450

55-
const runnerScriptPath = path.join(
56-
fileURLToPath(path.dirname(import.meta.url)),
57-
'..',
58-
'bin.js',
59-
);
60-
6151
const packageJson = createRequire(import.meta.url)(
6252
'../../package.json',
6353
) as typeof import('../../package.json');
@@ -74,11 +64,10 @@ export async function eslintPlugin(
7464
audits,
7565
groups,
7666

77-
runner: await createRunnerConfig(
78-
runnerScriptPath,
67+
runner: await createRunnerFunction({
7968
audits,
8069
targets,
81-
parsedOptions?.artifacts,
82-
),
70+
...(artifacts ? { artifacts } : {}),
71+
}),
8372
};
8473
}

packages/plugin-eslint/src/lib/runner/index.ts

Lines changed: 39 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import type {
44
Audit,
55
AuditOutput,
66
AuditOutputs,
7+
PersistConfig,
78
PluginArtifactOptions,
89
RunnerConfig,
910
RunnerFilesPaths,
11+
RunnerFunction,
1012
} from '@code-pushup/models';
11-
import { pluginArtifactOptionsSchema } from '@code-pushup/models';
1213
import {
1314
asyncSequential,
1415
createRunnerFiles,
@@ -55,91 +56,62 @@ export async function createRunnerConfig(
5556
scriptPath: string,
5657
audits: Audit[],
5758
targets: ESLintTarget[],
58-
artifactOptions?: PluginArtifactOptions,
5959
): Promise<RunnerConfig> {
60-
const parsedOptions = artifactOptions
61-
? pluginArtifactOptionsSchema.parse(artifactOptions)
62-
: undefined;
63-
6460
const config: ESLintPluginRunnerConfig = {
6561
targets,
66-
slugs: audits.map(a => a.slug),
62+
slugs: audits.map(audit => audit.slug),
6763
};
68-
69-
const { runnerConfigPath, runnerOutputPath } = parsedOptions
70-
? await createCustomRunnerPaths(parsedOptions, config)
71-
: await createRunnerFiles('eslint', JSON.stringify(config));
72-
73-
const args = [
74-
filePathToCliArg(scriptPath),
75-
...objectToCliArgs({ runnerConfigPath, runnerOutputPath }),
76-
...resolveCommandArgs(parsedOptions?.generateArtifactsCommand),
77-
];
64+
const { runnerConfigPath, runnerOutputPath } = await createRunnerFiles(
65+
'eslint',
66+
JSON.stringify(config),
67+
);
7868

7969
return {
8070
command: 'node',
81-
args,
71+
args: [
72+
filePathToCliArg(scriptPath),
73+
...objectToCliArgs({ runnerConfigPath, runnerOutputPath }),
74+
],
8275
configFile: runnerConfigPath,
8376
outputFile: runnerOutputPath,
8477
};
8578
}
8679

87-
export async function generateAuditOutputs(options: {
80+
export function createRunnerFunction(options: {
8881
audits: Audit[];
8982
targets: ESLintTarget[];
9083
artifacts?: PluginArtifactOptions;
91-
}): Promise<AuditOutputs> {
84+
}): RunnerFunction {
9285
const { audits, targets, artifacts } = options;
9386
const config: ESLintPluginRunnerConfig = {
9487
targets,
9588
slugs: audits.map(audit => audit.slug),
9689
};
9790

98-
ui().logger.log(`ESLint plugin executing ${targets.length} lint targets`);
99-
100-
const linterOutputs = artifacts
101-
? await loadArtifacts(artifacts)
102-
: await asyncSequential(targets, lint);
103-
const lintResults = mergeLinterOutputs(linterOutputs);
104-
const failedAudits = lintResultsToAudits(lintResults);
105-
106-
return config.slugs.map(
107-
(slug): AuditOutput =>
108-
failedAudits.find(audit => audit.slug === slug) ?? {
109-
slug,
110-
score: 1,
111-
value: 0,
112-
displayValue: 'passed',
113-
details: { issues: [] },
114-
},
115-
);
116-
}
117-
118-
async function createCustomRunnerPaths(
119-
options: PluginArtifactOptions,
120-
config: ESLintPluginRunnerConfig,
121-
): Promise<RunnerFilesPaths> {
122-
const artifactPaths = Array.isArray(options.artifactsPaths)
123-
? options.artifactsPaths
124-
: [options.artifactsPaths];
125-
126-
const runnerOutputPath = artifactPaths[0] ?? '';
127-
const runnerConfigPath = path.join(
128-
path.dirname(runnerOutputPath),
129-
'plugin-config.json',
130-
);
131-
132-
await ensureDirectoryExists(path.dirname(runnerConfigPath));
133-
await writeFile(runnerConfigPath, JSON.stringify(config));
134-
135-
return { runnerConfigPath, runnerOutputPath };
136-
}
137-
138-
function resolveCommandArgs(
139-
command?: string | { command: string; args?: string[] },
140-
): string[] {
141-
if (!command) return [];
142-
return typeof command === 'string'
143-
? [command]
144-
: [command.command, ...(command.args ?? [])];
91+
return async ({ outputDir }: PersistConfig): Promise<AuditOutputs> => {
92+
ui().logger.log(`ESLint plugin executing ${targets.length} lint targets`);
93+
94+
const linterOutputs = artifacts
95+
? await loadArtifacts(artifacts)
96+
: await asyncSequential(
97+
targets.map(target => ({
98+
...target,
99+
outputDir,
100+
})),
101+
lint,
102+
);
103+
const lintResults = mergeLinterOutputs(linterOutputs);
104+
const failedAudits = lintResultsToAudits(lintResults);
105+
106+
return config.slugs.map(
107+
(slug): AuditOutput =>
108+
failedAudits.find(audit => audit.slug === slug) ?? {
109+
slug,
110+
score: 1,
111+
value: 0,
112+
displayValue: 'passed',
113+
details: { issues: [] },
114+
},
115+
);
116+
};
145117
}

packages/plugin-eslint/src/lib/runner/index.unit.test.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,33 @@ import type {
77
} from '@code-pushup/models';
88
import { ui } from '@code-pushup/utils';
99
import type { ESLintTarget } from '../config.js';
10-
import { generateAuditOutputs } from './index.js';
10+
import { createRunnerFunction } from './index.js';
1111
import * as lintModule from './lint.js';
1212
import type { LinterOutput } from './types.js';
1313
import * as utilsFileModule from './utils.js';
1414

15-
describe('generateAuditOutputs', () => {
15+
describe('call createRunnerFunction', () => {
16+
it('should create runnerFunction correctly', () => {
17+
expect(
18+
createRunnerFunction({
19+
audits: [
20+
{ slug: 'max-lines', title: 'Max lines', description: 'Test' },
21+
{
22+
slug: 'no-unused-vars',
23+
title: 'No unused vars',
24+
description: 'Test',
25+
},
26+
],
27+
targets: [{ patterns: ['src/**/*.ts'] }],
28+
artifacts: {
29+
artifactsPaths: ['path/to/artifacts.json'],
30+
},
31+
}),
32+
).toStrictEqual(expect.any(Function));
33+
});
34+
});
35+
36+
describe('execute created runnerFunction', () => {
1637
const loadArtifactsSpy = vi.spyOn(utilsFileModule, 'loadArtifacts');
1738
const lintSpy = vi.spyOn(lintModule, 'lint');
1839

@@ -120,11 +141,11 @@ describe('generateAuditOutputs', () => {
120141
loadArtifactsSpy.mockResolvedValue(mockLinterOutputs);
121142

122143
await expect(
123-
generateAuditOutputs({
144+
createRunnerFunction({
124145
audits: mockAudits,
125146
targets: mockTargets,
126147
artifacts,
127-
}),
148+
})({}),
128149
).resolves.toStrictEqual(mockedAuditOutputs);
129150

130151
expect(loadArtifactsSpy).toHaveBeenCalledWith(artifacts);
@@ -137,9 +158,10 @@ describe('generateAuditOutputs', () => {
137158
lintSpy.mockResolvedValueOnce(mockLinterOutputs.at(0)!);
138159

139160
await expect(
140-
generateAuditOutputs({
161+
createRunnerFunction({
141162
audits: mockAudits,
142163
targets: mockTargets,
164+
})({
143165
outputDir: 'custom-output',
144166
}),
145167
).resolves.toStrictEqual(mockedAuditOutputs);

0 commit comments

Comments
 (0)