Skip to content

Commit

Permalink
feat: add buildFromOxlintConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
Sysix committed Oct 27, 2024
1 parent caf5f58 commit fe27e5d
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 77 deletions.
14 changes: 10 additions & 4 deletions src/__snapshots__/build-from-oxlint-config.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`custom plugins, custom categories > customPluginCustomCategories 1`] = `
exports[`buildFromOxlintConfig > custom plugins, custom categories > customPluginCustomCategories 1`] = `
{
"no-await-in-loop": "off",
"constructor-super": "off",
"getter-return": "off",
"import/export": "off",
"import/no-deprecated": "off",
"import/no-unused-modules": "off",
"no-undef": "off",
"no-unreachable": "off",
}
`;

exports[`custom plugins, default categories > customPluginDefaultCategories 1`] = `
exports[`buildFromOxlintConfig > custom plugins, default categories > customPluginDefaultCategories 1`] = `
{
"no-async-promise-executor": "off",
"no-caller": "off",
Expand Down Expand Up @@ -52,7 +58,7 @@ exports[`custom plugins, default categories > customPluginDefaultCategories 1`]
}
`;

exports[`default plugins (react, unicorn, typescript), default categories > defaultPluginDefaultCategories 1`] = `
exports[`buildFromOxlintConfig > default plugins (react, unicorn, typescript), default categories > defaultPluginDefaultCategories 1`] = `
{
"@typescript-eslint/no-dupe-class-members": "off",
"@typescript-eslint/no-duplicate-enum-values": "off",
Expand Down
168 changes: 108 additions & 60 deletions src/build-from-oxlint-config.spec.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,130 @@
import { expect, it } from 'vitest';
import { buildFromObject } from './build-from-oxlint-config.js';
import { describe, expect, it } from 'vitest';
import {
buildFromOxlintConfig,
buildFromOxlintConfigFile,
} from './build-from-oxlint-config.js';
import fs from 'node:fs';

it('detect active rules inside "rules" scope', () => {
['error', ['error'], 'warn', ['warn'], 1, [1], 2, [2]].forEach(
(ruleSetting) => {
const rules = buildFromObject({
describe('buildFromOxlintConfig', () => {
it('detect active rules inside "rules" scope', () => {
['error', ['error'], 'warn', ['warn'], 1, [1], 2, [2]].forEach(
(ruleSetting) => {
const rules = buildFromOxlintConfig({
plugins: [],
rules: {
eqeqeq: ruleSetting,
},
});

expect('eqeqeq' in rules).toBe(true);
expect(rules.eqeqeq).toBe('off');
}
);
});

it('skip deactive rules inside "rules" scope', () => {
['off', ['off'], 0, [0]].forEach((ruleSetting) => {
const rules = buildFromOxlintConfig({
plugins: [],
rules: {
eqeqeq: ruleSetting,
},
});

expect('eqeqeq' in rules).toBe(true);
expect(rules.eqeqeq).toBe('off');
}
);
});

it('skip deactive rules inside "rules" scope', () => {
['off', ['off'], 0, [0]].forEach((ruleSetting) => {
const rules = buildFromObject({
plugins: [],
rules: {
eqeqeq: ruleSetting,
},
expect('eqeqeq' in rules).toBe(false);
});
});

it('skip deactive categories', () => {
expect(
buildFromOxlintConfig({
categories: {
correctness: 'off',
},
})
).toStrictEqual({});
});

expect('eqeqeq' in rules).toBe(false);
it('default plugins (react, unicorn, typescript), default categories', () => {
// snapshot because it can change with the next release
expect(buildFromOxlintConfig({})).toMatchSnapshot(
'defaultPluginDefaultCategories'
);
});

it('custom plugins, default categories', () => {
// snapshot because it can change with the next release
expect(
buildFromOxlintConfig({
plugins: ['unicorn'],
})
).toMatchSnapshot('customPluginDefaultCategories');
});
});

it('skip deactive categories', () => {
expect(
buildFromObject({
it('custom plugins, custom categories', () => {
// snapshot because it can change with the next release
expect(
buildFromOxlintConfig({
plugins: ['import'],
categories: {
nursery: 'warn',
correctness: 'off',
},
})
).toMatchSnapshot('customPluginCustomCategories');
});

it('skip deactive rules, for custom enable category', () => {
const rules = buildFromOxlintConfig({
plugins: ['import'],
categories: {
nursery: 'warn',
correctness: 'off',
},
})
).toStrictEqual({});
rules: {
'import/no-unused-modules': 'off',
},
});
expect('import/no-unused-modules' in rules).toBe(false);
});
});

it('default plugins (react, unicorn, typescript), default categories', () => {
// snapshot because it can change with the next release
expect(buildFromObject({})).toMatchSnapshot('defaultPluginDefaultCategories');
});
const createConfigFileAndBuildFromIt = (
filename: string,
content: unknown
): Record<string, unknown> => {
fs.writeFileSync(filename, JSON.stringify(content));

it('custom plugins, default categories', () => {
// snapshot because it can change with the next release
expect(
buildFromObject({
plugins: ['unicorn'],
})
).toMatchSnapshot('customPluginDefaultCategories');
});
const rules = buildFromOxlintConfigFile(filename);

it('custom plugins, custom categories', () => {
// snapshot because it can change with the next release
expect(
buildFromObject({
plugins: ['eslint'],
categories: {
perf: 'warn',
correctness: 'off',
fs.unlinkSync(filename);

return rules;
};

describe('buildFromOxlintConfigFile', () => {
it('successfully parse oxlint config', () => {
const rules = createConfigFileAndBuildFromIt('success-config.json', {
rules: {
'no-await-loop': 'on',
},
})
).toMatchSnapshot('customPluginCustomCategories');
});
});

expect('no-await-loop' in rules).toBe(true);
});

it('failes to find oxlint config', () => {
const rules = buildFromOxlintConfigFile('not-found.json');

expect(rules).toStrictEqual({});
});

it('failes to parse oxlint config', () => {
const rules = createConfigFileAndBuildFromIt(
'invalid-config.json',
'["this", is an invalid json format]'
);

it('skip deactive rules, for custom enable category', () => {
const rules = buildFromObject({
plugins: ['eslint'],
categories: {
perf: 'warn',
correctness: 'off',
},
rules: {
'no-await-in-loop': 'off',
},
expect(rules).toStrictEqual({});
});
expect('no-await-in-loop' in rules).toBe(false);
});
26 changes: 18 additions & 8 deletions src/build-from-oxlint-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,29 @@ const scopeMaps = {

const getConfigContent = (
oxlintConfigFile: string
): Record<string, unknown> => {
): Record<string, unknown> | undefined => {
try {
const buffer = fs.readFileSync(oxlintConfigFile, 'utf8');

try {
const configContent = JSON.parse(buffer);

if (typeof configContent !== 'object') {
throw new Error('not an valid config file');
}

return configContent;
} catch {
console.error(
`eslint-plugin-oxlint: could not parse oxlint config file: ${oxlintConfigFile}`
);
return {};
return undefined;
}
} catch {
console.error(
`eslint-plugin-oxlint: could not find oxlint config file: ${oxlintConfigFile}`
);
return {};
return undefined;
}
};

Expand Down Expand Up @@ -98,7 +102,7 @@ const readPluginsFromConfig = (config: Record<string, unknown>): string[] => {
['react', 'unicorn', 'typescript'];
};

export const buildFromObject = (
export const buildFromOxlintConfig = (
config: Record<string, unknown>
): Record<string, 'off'> => {
const rules: Record<string, 'off'> = {};
Expand Down Expand Up @@ -134,10 +138,16 @@ export const buildFromObject = (
return rules;
};

export default function buildFromOxlintConfigFile(
export const buildFromOxlintConfigFile = (
oxlintConfigFile: string
): Record<string, 'off'> {
): Record<string, 'off'> => {
const config = getConfigContent(oxlintConfigFile);

return buildFromObject(config);
}
// we could not parse form the file, do not build with default values
// we can not be sure if the setup is right
if (config === undefined) {
return {};
}

return buildFromOxlintConfig(config);
};
10 changes: 6 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import * as ruleMapsByScope from './rules-by-scope.js';
import * as ruleMapsByCategory from './rules-by-category.js';
import configByScope from './configs-by-scope.js';
import configByCategory from './configs-by-category.js';
import * as build from './build-from-oxlint-config.js';

export {
buildFromOxlintConfig,
buildFromOxlintConfigFile,
} from './build-from-oxlint-config.js';

type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (
x: infer I
) => void
Expand All @@ -17,9 +22,6 @@ const allRules: UnionToIntersection<AllRules> = Object.assign(
...Object.values(ruleMapsByScope)
);

export const buildFromOxlintConfigFile = build.default;
export const buildFromOxlintConfig = build.buildFromObject;

export default {
configs: {
recommended: {
Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import dts from 'vite-plugin-dts';
export default defineConfig({
test: {
coverage: {
exclude: ['lib'],
include: ['src', 'scripts'],
},
},
build: {
Expand Down

0 comments on commit fe27e5d

Please sign in to comment.