Skip to content

Commit

Permalink
feat: add eslint flat config
Browse files Browse the repository at this point in the history
  • Loading branch information
allohamora committed Sep 21, 2024
1 parent b511f08 commit 1222648
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 162 deletions.
6 changes: 4 additions & 2 deletions __tests__/categories/js/eslint/eslint-test.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { Config } from 'src/categories/js/eslint/config/config.interface';

export const createConfig = ({
dependencies = [],
imports = [],
configs = [],
eslintConfig = {},
ignore = [],
typescript = false,
scripts = [],
mutations = [],
}: Partial<Config> = {}) => {
return { dependencies, eslintConfig, ignore, scripts, mutations };
return { dependencies, imports, configs, eslintConfig, typescript, scripts, mutations };
};
21 changes: 10 additions & 11 deletions __tests__/categories/js/eslint/eslint.entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,21 @@ describe('eslint', () => {
expect(npmMocked.installDevelopmentDependencies).toHaveBeenCalledWith('eslint', ...config.dependencies);
});

test('should add .eslintrc.json to root', async () => {
const config = createConfig({ eslintConfig: { extends: ['__test__'] } });
test('should add eslint.config.mjs to root', async () => {
const config = createConfig({ eslintConfig: { ignores: ['__test__'] } });
configMocked.getConfig.mockReturnValueOnce(config);

await eslint();

expect(fsMocked.addJsonFileToRoot).toHaveBeenCalledWith('.eslintrc.json', config.eslintConfig);
});

test('should add .eslintignore to root', async () => {
const config = createConfig({ ignore: ['node_modules', 'dist'] });
configMocked.getConfig.mockReturnValueOnce(config);
const configFile = `export default [
{
ignores: [
'__test__'
],
}
];`;

await eslint();

expect(fsMocked.addFileToRoot).toHaveBeenCalledWith('.eslintignore', 'node_modules\ndist');
expect(fsMocked.addFileToRoot).toHaveBeenCalledWith('eslint.config.mjs', configFile);
});

test('should add npm script to package.json', async () => {
Expand Down
19 changes: 11 additions & 8 deletions __tests__/categories/js/eslint/eslint.utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ describe('prettierMutation', () => {

const expected = createConfig({
dependencies: ['eslint-plugin-prettier', 'eslint-config-prettier'],
eslintConfig: { extends: ['plugin:prettier/recommended'] },
imports: [`import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'`],
configs: ['eslintPluginPrettierRecommended'],
});

expect(actual).toEqual(expected);
Expand All @@ -44,14 +45,16 @@ describe('prettierMutation', () => {

const actual = createConfig({
dependencies: ['__test__'],
eslintConfig: { extends: ['__test__'] },
imports: ['__test__'],
configs: ['__test__'],
});

await prettierMutation(actual);

const expected = createConfig({
dependencies: ['__test__', 'eslint-plugin-prettier', 'eslint-config-prettier'],
eslintConfig: { extends: ['__test__', 'plugin:prettier/recommended'] },
imports: ['__test__', `import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'`],
configs: ['__test__', 'eslintPluginPrettierRecommended'],
});

expect(actual).toEqual(expected);
Expand All @@ -60,8 +63,8 @@ describe('prettierMutation', () => {

describe('jestMutation', () => {
test('should add jest env if jest installed', async () => {
const actual = createConfig({ eslintConfig: { env: {} } });
const expected = createConfig({ eslintConfig: { env: { jest: true } } });
const actual = createConfig({ eslintConfig: { languageOptions: { globals: [] } } });
const expected = createConfig({ eslintConfig: { languageOptions: { globals: ['jest'] } } });

jestUtilsMocked.isJestInstalled.mockResolvedValue(true);

Expand All @@ -72,7 +75,7 @@ describe('jestMutation', () => {

test('should add jest env object if not exists', async () => {
const actual = createConfig();
const expected = createConfig({ eslintConfig: { env: { jest: true } } });
const expected = createConfig({ eslintConfig: { languageOptions: { globals: ['jest'] } } });

jestUtilsMocked.isJestInstalled.mockResolvedValueOnce(true);

Expand All @@ -94,7 +97,7 @@ describe('jestMutation', () => {
});

describe('isEslintInstalled', () => {
test('should call isInstalledAndInRootCheck with eslint and .eslintrc.json', () => {
expect(installedMocked.isInstalledAndInRootCheck).toHaveBeenCalledWith('eslint', '.eslintrc.json');
test('should call isInstalledAndInRootCheck with eslint and eslint.config.mjs', () => {
expect(installedMocked.isInstalledAndInRootCheck).toHaveBeenCalledWith('eslint', 'eslint.config.mjs');
});
});
26 changes: 9 additions & 17 deletions src/categories/js/eslint/config/config.interface.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
import { Mutation } from 'src/utils/mutation';

export type EslintConfig = {
parser?: string;
parserOptions?: {
project?: string;
ecmaVersion?: string;
sourceType?: string;
files?: string[];
ignores?: string[];
languageOptions?: {
globals?: string[];
parserOptions?: Record<string, unknown>;
};
env?: {
es6?: boolean;
node?: boolean;
browser?: boolean;
jest?: boolean;
es2020?: boolean;
};
root?: boolean;
ignorePatterns?: string[];
plugins?: string[];
extends?: string[];
plugins?: Record<string, string>;
rules?: Record<string, string | unknown[]>;
};

export type Config = {
dependencies: string[];
imports: string[];
configs: string[];
eslintConfig: EslintConfig;
ignore: string[];
typescript?: boolean;
scripts: { name: string; script: string }[];
mutations: Mutation<Config>[];
};
18 changes: 6 additions & 12 deletions src/categories/js/eslint/config/default.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ import { jestMutation, prettierMutation } from '../eslint.utils';
import { Config } from './config.interface';

export const defaultConfig: Config = {
dependencies: [],
dependencies: ['globals', '@eslint/js'],
imports: [`import globals from 'globals'`, `import eslint from '@eslint/js'`],
configs: [`eslint.configs.recommended`],
eslintConfig: {
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
languageOptions: {
globals: ['node'],
},
env: {
es6: true,
node: true,
browser: true,
},
root: true,
extends: ['eslint:recommended'],
ignores: ['node_modules', 'dist'],
},
ignore: ['node_modules', 'dist'],
scripts: [
{ name: 'lint', script: 'eslint "**/*.js"' },
{ name: 'lint:fix', script: 'eslint "**/*.js" --fix' },
Expand Down
41 changes: 26 additions & 15 deletions src/categories/js/eslint/config/node:ts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,46 @@ import { Config } from './config.interface';

export const nodeTsConfig: Config = {
dependencies: [
'globals',
'@eslint/js',
'typescript-eslint',
'@typescript-eslint/eslint-plugin',
'@typescript-eslint/parser',
'eslint-plugin-beautiful-sort',
'eslint-plugin-deprecation',
],
imports: [
`import globals from 'globals'`,
`import eslint from '@eslint/js'`,
`import tseslint from 'typescript-eslint'`,
`import tsPlugin from '@typescript-eslint/eslint-plugin'`,
`import beautifulSort from 'eslint-plugin-beautiful-sort'`,
`import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'`,
],
configs: ['eslint.configs.recommended', '...tseslint.configs.recommended'],
eslintConfig: {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
files: ['**/*.ts'],
languageOptions: {
globals: ['node'],
parserOptions: {
project: true,
},
},
plugins: ['@typescript-eslint/eslint-plugin', 'beautiful-sort'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:deprecation/recommended'],
root: true,
env: {
node: true,
ignores: ['node_modules', 'dist'],
plugins: {
'@typescript-eslint': 'tsPlugin',
'beautiful-sort': 'beautifulSort',
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'no-use-before-define': 'error',
'object-shorthand': 'warn',

'no-async-promise-executor': 'warn',
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-floating-promises': 'warn',

'@typescript-eslint/no-misused-promises': 'warn',
'@typescript-eslint/no-deprecated': 'error',
'beautiful-sort/import': [
'error',
{
Expand All @@ -41,7 +52,7 @@ export const nodeTsConfig: Config = {
],
},
},
ignore: ['node_modules', 'dist'],
typescript: true,
scripts: [
{ name: 'lint', script: 'eslint "**/*.ts"' },
{ name: 'lint:fix', script: 'eslint "**/*.ts" --fix' },
Expand Down
82 changes: 0 additions & 82 deletions src/categories/js/eslint/config/react:ts.config.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/categories/js/eslint/eslint.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { jsCategoryState } from 'src/states/categories';
import { defaultConfig } from './config/default.config';
import { nodeTsConfig } from './config/node:ts.config';
import { reactTsConfig } from './config/react:ts.config';

export const [getConfig] = jsCategoryState.useConfigState({
default: defaultConfig,
'node:ts': nodeTsConfig,
'react:ts': reactTsConfig,
});
3 changes: 1 addition & 2 deletions src/categories/js/eslint/eslint.const.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export const SCRIPT_NAME = 'eslint';
export const PACKAGE_NAME = SCRIPT_NAME;
export const CLI_NAME = PACKAGE_NAME;
export const CONFIG_FILE_NAME = '.eslintrc.json';
export const CONFIG_IGNORE_FILE_NAME = '.eslintignore';
export const CONFIG_FILE_NAME = 'eslint.config.mjs';
Loading

0 comments on commit 1222648

Please sign in to comment.