Skip to content

Commit b101a0d

Browse files
committed
feat: wip
1 parent 49a0ddd commit b101a0d

File tree

12 files changed

+122
-56
lines changed

12 files changed

+122
-56
lines changed

code-pushup.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export default mergeConfigs(
3737
{
3838
plugins: [
3939
await stylelintPlugin({
40-
configFile: 'packages/plugin-stylelint/mocks/fixtures/basic/.stylelintrc.json',
40+
configFile:
41+
'packages/plugin-stylelint/mocks/fixtures/basic/.stylelintrc.json',
4142
files: 'packages/plugin-stylelint/mocks/fixtures/basic/**/*.css', // Adjust the path to your CSS files
4243
}),
4344
],
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"extends": "stylelint-config-standard",
33
"rules": {
4-
"block-no-empty": null
4+
"block-no-empty": "impossibleValue"
55
}
66
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { type LinterOptions } from 'stylelint';
2-
import type { RunnerFunction } from '@code-pushup/models';
2+
import type { Audit, RunnerFunction } from '@code-pushup/models';
33
import { lintStyles } from './stylelint-runner.js';
44
import { mapStylelintResultsToAudits } from './utils.js';
55

6-
export function createRunnerFunction(opt: LinterOptions): RunnerFunction {
6+
export function createRunnerFunction(
7+
opt: LinterOptions,
8+
expectedAudits: Audit[],
9+
): RunnerFunction {
710
return async () => {
811
const report = await lintStyles(opt);
9-
return mapStylelintResultsToAudits(report);
12+
return mapStylelintResultsToAudits(report, expectedAudits);
1013
};
1114
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type NormalizedStyleLintConfig = {
2+
config: { rules: Record<string, unknown[]> };
3+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import path from 'node:path';
2+
import { describe, expect, it } from 'vitest';
3+
import { getNormalizedConfigForFile } from './normalize-config';
4+
5+
describe('getNormalizedConfigForFile', () => {
6+
it('should load config from specified configFile and respect the value of specifically set rules', async () => {
7+
const configFile = path.join(
8+
process.cwd(),
9+
'packages/plugin-stylelint/mocks/fixtures/basic/.stylelintrc.json',
10+
);
11+
12+
const parsed = await getNormalizedConfigForFile({ configFile });
13+
14+
expect(parsed.config.rules['block-no-empty']).toStrictEqual([
15+
'impossibleValue',
16+
]); // The default value is [ true ], so having the not even valid value from the config file is correct
17+
});
18+
19+
it('should load config from specified configFile and add default rules', async () => {
20+
const configFile = path.join(
21+
process.cwd(),
22+
'packages/plugin-stylelint/mocks/fixtures/basic/.stylelintrc.json',
23+
);
24+
25+
const parsed = await getNormalizedConfigForFile({ configFile });
26+
expect(Object.keys(parsed.config.rules).length).toBeGreaterThan(1);
27+
});
28+
});

packages/plugin-stylelint/src/lib/runner/normalize-config.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import stylelint, {getConfigForFile, type LinterOptions} from "stylelint";
2-
import path from "node:path";
3-
import * as process from "node:process";
1+
import path from 'node:path';
2+
import * as process from 'node:process';
3+
import stylelint, { type LinterOptions, getConfigForFile } from 'stylelint';
4+
import type { NormalizedStyleLintConfig } from './model.js';
45

5-
export function getNormalizedConfigForFile(options: LinterOptions) {
6+
export function getNormalizedConfigForFile(
7+
options: LinterOptions,
8+
): NormalizedStyleLintConfig {
69
const _linter = stylelint._createLinter(options);
7-
const configFile = options.configFile ?? path.join(options?.cwd ?? process.cwd(), '.stylelintrc.json');
10+
const configFile =
11+
options.configFile ??
12+
path.join(options?.cwd ?? process.cwd(), '.stylelintrc.json');
813
return getConfigForFile(_linter, configFile);
914
}
10-

packages/plugin-stylelint/src/lib/runner/stylelint-runner.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import stylelint, { type LinterOptions } from 'stylelint';
22

33
// Run Stylelint Programmatically
4-
export async function lintStyles({config, ...options}: Omit<LinterOptions, 'formatter'>) {
4+
export async function lintStyles({
5+
config,
6+
...options
7+
}: Omit<LinterOptions, 'formatter'>) {
58
try {
69
// eslint-disable-next-line functional/immutable-data
710
globalThis.console.assert = globalThis.console.assert || (() => {});

packages/plugin-stylelint/src/lib/runner/utils.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
import stylelint, { type LintResult } from 'stylelint';
22
import type { Audit, AuditReport } from '@code-pushup/models';
33

4-
export function mapStylelintResultsToAudits(results: LintResult[]): Audit[] {
4+
export function mapStylelintResultsToAudits(
5+
results: LintResult[],
6+
expectedAudits: Audit[],
7+
): Audit[] {
8+
const initialAuditMap = expectedAudits.reduce((map, audit) => {
9+
return map.set(audit.slug, {
10+
...audit,
11+
score: 1,
12+
value: 0,
13+
details: {
14+
issues: [],
15+
},
16+
});
17+
}, new Map<string, AuditReport>());
18+
519
const auditMap = results.reduce((map, result) => {
620
const { source, warnings } = result;
721

@@ -12,23 +26,18 @@ export function mapStylelintResultsToAudits(results: LintResult[]): Audit[] {
1226
return warnings.reduce((innerMap, warning) => {
1327
const { rule, severity, line, text } = warning;
1428

15-
const existingAudit: AuditReport = innerMap.get(rule) || {
16-
slug: rule,
17-
title: '',
18-
score: 1,
19-
value: 0,
20-
details: {
21-
issues: [],
22-
},
23-
};
29+
const existingAudit = innerMap.get(rule);
30+
if (!existingAudit) {
31+
return innerMap;
32+
}
2433

2534
const updatedAudit: AuditReport = {
2635
...existingAudit,
2736
score: 0, // At least one issue exists
2837
value: existingAudit.value + 1,
2938
details: {
3039
issues: [
31-
...(existingAudit?.details?.issues ?? []),
40+
...(existingAudit.details?.issues ?? []),
3241
{
3342
severity,
3443
message: text,
@@ -43,9 +52,11 @@ export function mapStylelintResultsToAudits(results: LintResult[]): Audit[] {
4352
},
4453
};
4554

46-
return new Map(innerMap).set(rule, updatedAudit);
55+
return innerMap.set(rule, updatedAudit);
4756
}, map);
48-
}, new Map<string, AuditReport>());
57+
}, initialAuditMap);
58+
59+
console.log('auditMap: ', auditMap);
4960

5061
return [...auditMap.values()];
5162
}
Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import {createRequire} from 'node:module';
2-
import type {LinterOptions} from 'stylelint';
3-
import type {Audit, PluginConfig} from '@code-pushup/models';
4-
import {createRunnerFunction} from './runner/index.js';
5-
import {getNormalizedConfigForFile} from "./runner/normalize-config.js";
1+
import { createRequire } from 'node:module';
2+
import type { LinterOptions } from 'stylelint';
3+
import type { PluginConfig } from '@code-pushup/models';
4+
import { createRunnerFunction } from './runner/index.js';
5+
import { getAudits } from './utils.js';
66

7-
8-
export type StylelintPluginConfig = Pick<LinterOptions, 'configFile' | 'files'> & {
9-
onlyAudits?: string[]
10-
}
7+
export type StylelintPluginConfig = Pick<
8+
LinterOptions,
9+
'configFile' | 'files'
10+
> & {
11+
onlyAudits?: string[];
12+
};
1113

1214
/**
1315
* Instantiates Code PushUp code stylelint plugin for core config.
@@ -36,7 +38,7 @@ export async function stylelintPlugin(
3638
'../../package.json',
3739
) as typeof import('../../package.json');
3840

39-
console.log('getNormalizedConfigForFile: ', await getNormalizedConfigForFile(options ?? {}));
41+
const audits = await getAudits(options ?? {});
4042

4143
return {
4244
slug: 'stylelint',
@@ -46,23 +48,17 @@ export async function stylelintPlugin(
4648
docsUrl: 'https://www.npmjs.com/package/@code-pushup/stylelint-plugin/',
4749
packageName: packageJson.name,
4850
version: packageJson.version,
49-
audits: Object.keys(options?.config?.rules ?? {
50-
'color-no-invalid-hex': true,
51-
}).map(slug => ({
52-
slug,
53-
title: slug,
54-
docsUrl: `https://stylelint.io/user-guide/rules/${slug}`,
55-
})),
56-
runner: createRunnerFunction(options ?? {}),
51+
audits,
52+
runner: createRunnerFunction(options ?? {}, audits),
5753
};
5854
}
5955

60-
async function getAudits(options: StylelintPluginConfig): Promise<Audit[]> {
61-
const {onlyAudits = [], ...rawCfg} = options;
62-
const config = await getNormalizedConfigForFile(rawCfg);
63-
return Object.keys(config.rules).filter(rule => onlyAudits.length > 0 && config.rules[rule] !== false).map(rule => ({
64-
slug: rule,
65-
title: rule,
66-
docsUrl: `https://stylelint.io/user-guide/rules/${rule}`,
67-
}));
68-
}
56+
// async function getAudits(options: StylelintPluginConfig): Promise<Audit[]> {
57+
// const {onlyAudits = [], ...rawCfg} = options;
58+
// const config = await getNormalizedConfigForFile(rawCfg);
59+
// return Object.keys(config.rules).filter(rule => onlyAudits.length > 0 && config.rules[rule] !== false).map(rule => ({
60+
// slug: rule,
61+
// title: rule,
62+
// docsUrl: `https://stylelint.io/user-guide/rules/${rule}`,
63+
// }));
64+
// }

packages/plugin-stylelint/src/lib/utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Config, ConfigRuleSettings } from 'stylelint';
22
import type { Audit, Group } from '@code-pushup/models';
33
import { truncateDescription, truncateTitle } from '@code-pushup/utils';
4+
import { getNormalizedConfigForFile } from './runner/normalize-config';
5+
import type { StylelintPluginConfig } from './stylelint-plugin';
46

57
export async function listAuditsAndGroups(
68
rules: Config['rules'] = [],
@@ -35,3 +37,18 @@ export function ruleToAudit(rule: ConfigRuleSettings<any, Object>): Audit {
3537
}),
3638
};
3739
}
40+
41+
export function auditSlugToFullAudit(slug: string): Audit {
42+
return {
43+
slug,
44+
title: slug,
45+
docsUrl: `https://stylelint.io/user-guide/rules/${slug}`,
46+
};
47+
}
48+
49+
export async function getAudits(
50+
options: StylelintPluginConfig,
51+
): Promise<Audit[]> {
52+
const normalizedConfig = await getNormalizedConfigForFile(options);
53+
return Object.keys(normalizedConfig.config.rules).map(auditSlugToFullAudit);
54+
}

0 commit comments

Comments
 (0)