Skip to content

Commit

Permalink
feat: add stylistic configuration and integrate with ESLint
Browse files Browse the repository at this point in the history
  • Loading branch information
Simoon-F committed Jan 13, 2025
1 parent 548eabd commit 59701d9
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 123 deletions.
4 changes: 0 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
"source.organizeImports": "never"
},

// Specify ESLint to use the Node.js runtime
"eslint.options": {
"flags": ["unstable_ts_config"]
},
"eslint.runtime": "node",

/**
Expand Down
3 changes: 2 additions & 1 deletion eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import { avenger } from './src';

export default avenger({
typescript: true,
});
stylistic: true,
});
Empty file removed example/react.tsx
Empty file.
29 changes: 15 additions & 14 deletions generate-eslint-type/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import fs from 'node:fs/promises'
import { mergeFlatConfigs, typescript } from '../src'
import { builtinRules } from 'eslint/use-at-your-own-risk'
import { flatConfigsToRulesDTS } from 'eslint-typegen/core'
import { javascript } from 'src/configs/javascript'
import fs from 'node:fs/promises';
import { mergeFlatConfigs, stylistic, typescript } from '../src';
import { builtinRules } from 'eslint/use-at-your-own-risk';
import { flatConfigsToRulesDTS } from 'eslint-typegen/core';
import { javascript } from 'src/configs/javascript';

const configs = await mergeFlatConfigs(
{
plugins: {
'': {
rules: Object.fromEntries(builtinRules.entries())
}
}
rules: Object.fromEntries(builtinRules.entries()),
},
},
},
javascript(),
typescript()
)
typescript(),
stylistic(),
);

const configNames = configs.map(i => i.name).filter(Boolean) as string[]
const configNames = configs.map(i => i.name).filter(Boolean) as string[];

let dts = await flatConfigsToRulesDTS (configs, {
includeAugmentation: false,
})
});

dts += `
// Names of all the configs
export type ConfigNames = ${configNames.map(i => `'${i}'`).join(' | ')}
`
`;

await fs.writeFile('src/eslintype.d.ts', dts)
await fs.writeFile('src/eslintype.d.ts', dts);
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "pnpm generate:eslint:type && tsup",
"lint": "eslint --flag unstable_ts_config .",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"dev": "npx @eslint/config-inspector --config eslint.config.ts",
"generate:eslint:type": "tsx generate-eslint-type/index.ts",
Expand Down Expand Up @@ -45,6 +45,7 @@
"eslint": "^9.17.0"
},
"dependencies": {
"@stylistic/eslint-plugin": "^2.13.0",
"@typescript-eslint/eslint-plugin": "^8.19.1",
"@typescript-eslint/parser": "^8.19.1",
"eslint-flat-config-utils": "^1.0.0",
Expand Down
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/configs/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './javascript'
export * from './typescript'
export * from './javascript';
export * from './stylistic';
export * from './typescript';
38 changes: 19 additions & 19 deletions src/configs/javascript.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import globals from 'globals';
import type { IOptionsOverrides, EslintFlatConfigItem } from 'src/types';
import { default as unusedImportsPlugin } from 'eslint-plugin-unused-imports'
import { default as unusedImportsPlugin } from 'eslint-plugin-unused-imports';

export const javascript = async (
{ overrides = {} }: IOptionsOverrides = {}
{ overrides = {} }: IOptionsOverrides = {},
): Promise<EslintFlatConfigItem[]> => {
return [
{
Expand Down Expand Up @@ -211,18 +211,18 @@ export const javascript = async (
// 禁止使用特定的全局变量(如 global 和 self),推荐使用 globalThis
'no-restricted-globals': [
'error',
{ message: 'Use `globalThis` instead.', name: 'global' },
{ message: 'Use `globalThis` instead.', name: 'self' },
{ message: 'Use `globalThis` instead.', name: 'global' },
{ message: 'Use `globalThis` instead.', name: 'self' },
],

// 禁止使用特定的对象属性(如 __proto__、__defineGetter__)
'no-restricted-properties': [
'error',
{ message: 'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.', property: '__proto__' },
{ message: 'Use `Object.defineProperty` instead.', property: '__defineGetter__' },
{ message: 'Use `Object.defineProperty` instead.', property: '__defineSetter__' },
{ message: 'Use `Object.getOwnPropertyDescriptor` instead.', property: '__lookupGetter__' },
{ message: 'Use `Object.getOwnPropertyDescriptor` instead.', property: '__lookupSetter__' },
{ message: 'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.', property: '__proto__' },
{ message: 'Use `Object.defineProperty` instead.', property: '__defineGetter__' },
{ message: 'Use `Object.defineProperty` instead.', property: '__defineSetter__' },
{ message: 'Use `Object.getOwnPropertyDescriptor` instead.', property: '__lookupGetter__' },
{ message: 'Use `Object.getOwnPropertyDescriptor` instead.', property: '__lookupSetter__' },
],

// 禁止使用特定的语法(如 const enum 和 export =)
Expand Down Expand Up @@ -330,8 +330,8 @@ export const javascript = async (

// 强制使用对象属性简写(如 { x } 而不是 { x: x })
'object-shorthand': [
'error',
'always',
'error',
'always',
{
avoidQuotes: true,
ignoreConstructors: false,
Expand All @@ -343,7 +343,7 @@ export const javascript = async (

// 推荐使用箭头函数作为回调函数
'prefer-arrow-callback': [
'error',
'error',
{
allowNamedFunctions: false,
allowUnboundThis: true,
Expand All @@ -352,7 +352,7 @@ export const javascript = async (

// 推荐使用 const 声明不会重新赋值的变量
'prefer-const': [
'error',
'error',
{
destructuring: 'all',
ignoreReadBeforeAssign: true,
Expand Down Expand Up @@ -388,7 +388,7 @@ export const javascript = async (

// 检查未使用的变量
'unused-imports/no-unused-vars': [
'error',
'error',
{
args: 'after-used',
argsIgnorePattern: '^_',
Expand All @@ -410,8 +410,8 @@ export const javascript = async (
// 禁止 Yoda 条件(如 if (42 === value))
'yoda': ['error', 'never'],

...overrides
}
}
]
}
...overrides,
},
},
];
};
57 changes: 57 additions & 0 deletions src/configs/stylistic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { EslintFlatConfigItem, IOptionsOverrides, IStylisticConfig } from 'src/types';
import { loadModule } from '../utils';

export const DEFAULT_CONFIG: IStylisticConfig = {
indent: 2,
jsx: true,
quotes: 'single',
semi: true,
};

export const stylistic = async (
options: IStylisticConfig & IOptionsOverrides = {},
): Promise<EslintFlatConfigItem[]> => {
const {
indent,
jsx,
overrides = {},
quotes,
semi,
} = {
...DEFAULT_CONFIG,
...options,
};

const stylisticPlugin = await loadModule(import('@stylistic/eslint-plugin'));

const stylisticConfig = stylisticPlugin.configs.customize({
flat: true,
indent,
jsx,
pluginName: '@stylistic',
quotes,
semi,
});

return [
{
name: 'sj-distributor/stylistic/rules',
plugins: {
'@stylistic': stylisticPlugin,
},
rules: {
...stylisticConfig.rules,

// '@stylistic/object-curly-spacing': ['error', 'always'], // bracketSpacing: true
// '@stylistic/jsx-closing-bracket-location': ['error', 'line-aligned'], // jsxBracketSameLine: true
// '@stylistic/quotes': ['error', 'single'], // singleQuote: true
// '@stylistic/comma-dangle': ['error', 'always-multiline'], // trailingComma: 'all'
// '@stylistic/arrow-parens': ['error', 'as-needed'], // arrowParens: 'avoid'

curly: ['error', 'all'],

...overrides,
},
},
];
};
Loading

0 comments on commit 59701d9

Please sign in to comment.