Skip to content

Commit

Permalink
feat(build): output rules for flat config in dts file
Browse files Browse the repository at this point in the history
  • Loading branch information
Sysix committed Oct 14, 2024
1 parent c6cbf39 commit fe61c85
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 53 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"license": "MIT",
"scripts": {
"generate": "node --import @oxc-node/core/register ./scripts/generate.ts && pnpm format",
"generate": "node --import @oxc-node/core/register ./scripts/generate.ts",
"clone": "node --import @oxc-node/core/register ./scripts/sparse-clone.ts",
"build": "vite build",
"lint": "npx oxlint && npx eslint --flag unstable_ts_config",
Expand Down
92 changes: 92 additions & 0 deletions scripts/config-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { writeFileSync } from 'node:fs';
import path from 'node:path';
import type { Rule } from './traverse-rules.js';
import { camelCase, kebabCase } from 'scule';

const __dirname = new URL('.', import.meta.url).pathname;

export enum RulesGrouping {
CATEGORY = 'category',
SCOPE = 'scope',
}

export type ResultMap = Map<string, string[]>;

export class ConfigGenerator {
private oxlintVersion: string;
private rulesGrouping: RulesGrouping;
private rulesArray: Rule[];
constructor(
oxlintVersion: string,
rulesArray: Rule[] = [],
rulesGrouping: RulesGrouping = RulesGrouping.SCOPE
) {
this.oxlintVersion = oxlintVersion;
this.rulesArray = rulesArray;
this.rulesGrouping = rulesGrouping;
}

public setRulesGrouping(rulesGrouping: RulesGrouping) {
this.rulesGrouping = rulesGrouping;
}

private groupItemsBy(
rules: Rule[],
rulesGrouping: RulesGrouping
): Map<string, string[]> {
const map = new Map<string, string[]>();
for (const item of rules) {
const key = item[rulesGrouping];
const group = map.get(key) || [];
group.push(item.value);
map.set(key, group);
}

return map;
}

public async generateRulesCode() {
console.log(
`Generating config for ${this.oxlintVersion}, grouped by ${this.rulesGrouping}`
);

const rulesGrouping = this.rulesGrouping;
const rulesArray = this.rulesArray;

const rulesMap = this.groupItemsBy(rulesArray, rulesGrouping);

const exportGrouping: string[] = [];
let code =
'// These rules are automatically generated by scripts/generate-rules.ts\n\n';

code += `import * as rules from "./rules-by-${this.rulesGrouping}.js";\n\n`;

for (const grouping of rulesMap.keys()) {
exportGrouping.push(grouping);

code += `const ${camelCase(grouping)}Config = {\n`;

code += `\tname: 'oxlint/${kebabCase(grouping)}',\n`;
code += `\trules: rules.${camelCase(grouping)}Rules,`;
code += '\n} as const;\n\n';
}

code += 'export {\n';
code += exportGrouping
.map((grouping) => {
return `\t${camelCase(grouping)}Config as "flat/${kebabCase(grouping)}"`;
})
.join(',\n');
code += '\n}';

return code;
}

public async generateRules() {
const output = await this.generateRulesCode();
writeFileSync(
path.resolve(__dirname, '..', `src/configs-by-${this.rulesGrouping}.ts`),
output
);
}
}
15 changes: 9 additions & 6 deletions scripts/generate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { writeFileSync } from 'node:fs';
import { RulesGenerator, RulesGrouping } from './rules-generator.js';
import { ConfigGenerator } from './config-generator.js';
import { traverseRules } from './traverse-rules.js';
import { getLatestVersionFromClonedRepo } from './oxlint-version.js';
import { TARGET_DIRECTORY, VERSION_PREFIX } from './constants.js';
Expand All @@ -24,13 +25,15 @@ if (!oxlintVersion) {
);
}

const generator = new RulesGenerator(oxlintVersion, successResultArray);

generator.setRulesGrouping(RulesGrouping.SCOPE);
await generator.generateRules();
generator.setRulesGrouping(RulesGrouping.CATEGORY);
await generator.generateRules();
const rulesGenerator = new RulesGenerator(oxlintVersion, successResultArray);
const configGenerator = new ConfigGenerator(oxlintVersion, successResultArray);

[rulesGenerator, configGenerator].forEach(async (generator) => {
generator.setRulesGrouping(RulesGrouping.SCOPE);
await generator.generateRules();
generator.setRulesGrouping(RulesGrouping.CATEGORY);
await generator.generateRules();
});
// Update package.json version
writeFileSync(
'../package.json',
Expand Down
7 changes: 3 additions & 4 deletions scripts/rules-generator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { writeFileSync } from 'node:fs';
import path from 'node:path';
import type { Rule } from './traverse-rules.js';
import { camelCase } from 'scule';

const __dirname = new URL('.', import.meta.url).pathname;

Expand Down Expand Up @@ -62,16 +63,14 @@ export class RulesGenerator {
exportGrouping.push(grouping);
const rules = rulesMap.get(grouping);

code += `const ${grouping.replace(/_(\w)/g, (_, c) =>
c.toUpperCase()
)}Rules = {\n`;
code += `const ${camelCase(grouping)}Rules = {\n`;

code += rules
?.map((rule) => {
return ` '${rule.replace(/_/g, '-')}': "off"`;
})
.join(',\n');
code += '\n} as const\n\n';
code += '\n} as const;\n\n';
}

code += 'export {\n';
Expand Down
108 changes: 108 additions & 0 deletions src/configs-by-category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// These rules are automatically generated by scripts/generate-rules.ts

import * as rules from "./rules-by-category.js";

const pedanticConfig = {
name: 'oxlint/pedantic',
rules: rules.pedanticRules,
} as const;

const nurseryConfig = {
name: 'oxlint/nursery',
rules: rules.nurseryRules,
} as const;

const restrictionConfig = {
name: 'oxlint/restriction',
rules: rules.restrictionRules,
} as const;

const styleConfig = {
name: 'oxlint/style',
rules: rules.styleRules,
} as const;

const conditionalFixConfig = {
name: 'oxlint/conditional-fix',
rules: rules.conditionalFixRules,
} as const;

const dangerousFixConfig = {
name: 'oxlint/dangerous-fix',
rules: rules.dangerousFixRules,
} as const;

const conditionalFixSuggestionConfig = {
name: 'oxlint/conditional-fix-suggestion',
rules: rules.conditionalFixSuggestionRules,
} as const;

const pendingConfig = {
name: 'oxlint/pending',
rules: rules.pendingRules,
} as const;

const correctnessConfig = {
name: 'oxlint/correctness',
rules: rules.correctnessRules,
} as const;

const perfConfig = {
name: 'oxlint/perf',
rules: rules.perfRules,
} as const;

const conditionalSuggestionFixConfig = {
name: 'oxlint/conditional-suggestion-fix',
rules: rules.conditionalSuggestionFixRules,
} as const;

const fixConfig = {
name: 'oxlint/fix',
rules: rules.fixRules,
} as const;

const suggestionConfig = {
name: 'oxlint/suggestion',
rules: rules.suggestionRules,
} as const;

const fixDangerousConfig = {
name: 'oxlint/fix-dangerous',
rules: rules.fixDangerousRules,
} as const;

const suspiciousConfig = {
name: 'oxlint/suspicious',
rules: rules.suspiciousRules,
} as const;

const conditionalSuggestionConfig = {
name: 'oxlint/conditional-suggestion',
rules: rules.conditionalSuggestionRules,
} as const;

const dangerousSuggestionConfig = {
name: 'oxlint/dangerous-suggestion',
rules: rules.dangerousSuggestionRules,
} as const;

export {
pedanticConfig as "flat/pedantic",
nurseryConfig as "flat/nursery",
restrictionConfig as "flat/restriction",
styleConfig as "flat/style",
conditionalFixConfig as "flat/conditional-fix",
dangerousFixConfig as "flat/dangerous-fix",
conditionalFixSuggestionConfig as "flat/conditional-fix-suggestion",
pendingConfig as "flat/pending",
correctnessConfig as "flat/correctness",
perfConfig as "flat/perf",
conditionalSuggestionFixConfig as "flat/conditional-suggestion-fix",
fixConfig as "flat/fix",
suggestionConfig as "flat/suggestion",
fixDangerousConfig as "flat/fix-dangerous",
suspiciousConfig as "flat/suspicious",
conditionalSuggestionConfig as "flat/conditional-suggestion",
dangerousSuggestionConfig as "flat/dangerous-suggestion"
}
96 changes: 96 additions & 0 deletions src/configs-by-scope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// These rules are automatically generated by scripts/generate-rules.ts

import * as rules from "./rules-by-scope.js";

const eslintConfig = {
name: 'oxlint/eslint',
rules: rules.eslintRules,
} as const;

const typescriptConfig = {
name: 'oxlint/typescript',
rules: rules.typescriptRules,
} as const;

const importConfig = {
name: 'oxlint/import',
rules: rules.importRules,
} as const;

const jestConfig = {
name: 'oxlint/jest',
rules: rules.jestRules,
} as const;

const jsdocConfig = {
name: 'oxlint/jsdoc',
rules: rules.jsdocRules,
} as const;

const jsxA11yConfig = {
name: 'oxlint/jsx-a11y',
rules: rules.jsxA11yRules,
} as const;

const nextjsConfig = {
name: 'oxlint/nextjs',
rules: rules.nextjsRules,
} as const;

const nodeConfig = {
name: 'oxlint/node',
rules: rules.nodeRules,
} as const;

const promiseConfig = {
name: 'oxlint/promise',
rules: rules.promiseRules,
} as const;

const reactConfig = {
name: 'oxlint/react',
rules: rules.reactRules,
} as const;

const reactPerfConfig = {
name: 'oxlint/react-perf',
rules: rules.reactPerfRules,
} as const;

const securityConfig = {
name: 'oxlint/security',
rules: rules.securityRules,
} as const;

const treeShakingConfig = {
name: 'oxlint/tree-shaking',
rules: rules.treeShakingRules,
} as const;

const unicornConfig = {
name: 'oxlint/unicorn',
rules: rules.unicornRules,
} as const;

const vitestConfig = {
name: 'oxlint/vitest',
rules: rules.vitestRules,
} as const;

export {
eslintConfig as "flat/eslint",
typescriptConfig as "flat/typescript",
importConfig as "flat/import",
jestConfig as "flat/jest",
jsdocConfig as "flat/jsdoc",
jsxA11yConfig as "flat/jsx-a11y",
nextjsConfig as "flat/nextjs",
nodeConfig as "flat/node",
promiseConfig as "flat/promise",
reactConfig as "flat/react",
reactPerfConfig as "flat/react-perf",
securityConfig as "flat/security",
treeShakingConfig as "flat/tree-shaking",
unicornConfig as "flat/unicorn",
vitestConfig as "flat/vitest"
}
9 changes: 5 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as ruleMapsByScope from './rules-by-scope.js';
import * as ruleMapsByCategory from './rules-by-category.js';
import { createFlatRulesConfig } from './utils.js';
import * as configMapsByScope from './configs-by-scope.js';
import * as configMapsByCategory from './configs-by-category.js';

type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (
x: infer I
Expand Down Expand Up @@ -36,7 +37,7 @@ export default {
name: 'oxlint ignore rules recommended',
rules: ruleMapsByCategory.correctnessRules,
},
...createFlatRulesConfig(ruleMapsByScope),
...createFlatRulesConfig(ruleMapsByCategory),
...configMapsByScope,
...configMapsByCategory,
},
};
} as const;
Loading

0 comments on commit fe61c85

Please sign in to comment.