From ac1c775227c845ee945ae1fc77430236548fc8cb Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Fri, 23 Aug 2024 03:34:27 +0800 Subject: [PATCH] feat: support flat config (#53) * feat: support flat config chore: generate rules by scripts chore: run `lint:js` * chore: update `export` same as pre version * chore: update README.md --- README.md | 57 +++++++++++++-- package.json | 1 + scripts/update.ts | 37 ++++++++++ src/index.ts | 88 ++++++++++++------------ src/rules/index.ts | 16 +++++ src/rules/no-duplicate-store-ids.ts | 2 +- src/rules/no-return-global-properties.ts | 4 +- 7 files changed, 152 insertions(+), 53 deletions(-) create mode 100644 scripts/update.ts create mode 100644 src/rules/index.ts diff --git a/README.md b/README.md index 5b7000f..9d44789 100644 --- a/README.md +++ b/README.md @@ -21,19 +21,32 @@ npm install eslint-plugin-pinia --save-dev ## Usage -Add `pinia` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: +Add `pinia` to the plugins section of your `.eslintrc` or `eslint.config.js` configuration file. You can omit the `eslint-plugin-` prefix: ```json +// .eslintrc [Legacy Config] { "plugins": ["pinia"] } ``` +```js +// eslint.config.js +import pinia from 'eslint-plugin-pinia' + +export default [ + plugins: { + pinia + } +] +``` + ### Rule Configuration Then configure the rules you want to use under the rules section. ```json +// .eslintrc [Legacy Config] { "rules": { "pinia/require-export-define-store": [ @@ -43,28 +56,64 @@ Then configure the rules you want to use under the rules section. } ``` +```js +// eslint.config.js +import pinia from 'eslint-plugin-pinia' + +export default [ + { + plugin: { + pinia + }, + rules: { + "pinia/require-export-define-store": ["warn"] + } + } +] +``` + ### Recommended -To use the recommended configuration, extend it in your `.eslintrc` file: +To use the recommended configuration, extend it in your `.eslintrc` or `eslint.config.js` file: ```json +// .eslintrc [Legacy Config] { "extends": ["plugin:pinia/recommended"] } ``` -All recommend rules will be set to error by default. You can however disable some rules by setting turning them `off` in your `.eslintrc` file or by setting them to `warn` in your `.eslintrc`. +```js +// eslint.config.js +import pinia from 'eslint-plugin-pinia' + +export default [ + pinia.configs["recommended-flat"], +] +``` + +All recommend rules will be set to error by default. You can however disable some rules by setting turning them `off` in your configuration file or by setting them to `warn` in your configuration file. ### all rules -To use the all configuration, extend it in your `.eslintrc` file: +To use the all configuration, extend it in your `.eslintrc` or `eslint.config.js` file: ```json +// .eslintrc [Legacy Config] { "extends": ["plugin:pinia/all"] } ``` +```js +// eslint.config.js +import pinia from 'eslint-plugin-pinia' + +export default [ + pinia.configs["all-flat"], +] +``` + ## Rules diff --git a/package.json b/package.json index 19cb79d..8811bee 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "scripts": { "build": "unbuild", + "update": "tsx scripts/update", "lint:md": "markdownlint \"**/*.md\" --fix", "lint:eslint-docs": "npm run build && eslint-doc-generator --check", "lint:js": "eslint . --fix", diff --git a/scripts/update.ts b/scripts/update.ts new file mode 100644 index 0000000..bebc897 --- /dev/null +++ b/scripts/update.ts @@ -0,0 +1,37 @@ +import process from 'node:process' +import { resolve } from 'node:path' +import fs from 'node:fs' + +const cwd = process.cwd() + +const rulesDir = resolve(cwd, 'src', 'rules') + +function camelCase(str: string) { + return str + .replace(/[^\w-]+/, '') + .replace(/-([a-z])/g, (_, c) => c.toUpperCase()) +} + +function generateRules() { + const targetFile = 'index.ts' + + const header = '/* GENERATED BY SCRIPTS, DO NOT EDIT DIRECTLY */' + + const rules = fs.readdirSync(rulesDir) + .filter(i => i !== targetFile) + .map(i => i.replace('.ts', '')) + + const content = [ + header, + ...rules.map(i => `import ${camelCase(i)}, { RULE_NAME as ${camelCase(i)}Name } from './${i}'`), + '', + 'export default {', + ...rules.map(i => ` [${camelCase(i)}Name]: ${camelCase(i)},`), + '}', + '' + ].join('\n') + + fs.writeFileSync(resolve(rulesDir, targetFile), content) +} + +generateRules() diff --git a/src/index.ts b/src/index.ts index 090ae51..1deff83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,36 +1,14 @@ -import requireSetupStoreProps, { - RULE_NAME as requireSetupStorePropsName -} from './rules/require-setup-store-properties-export' - -import neverExportInitializedStore, { - RULE_NAME as neverExportInitializedStoreName -} from './rules/never-export-initialized-store' - -import preferNamingConvention, { - RULE_NAME as preferNamingConventionName -} from './rules/prefer-use-store-naming-convention' - -import preferSingleStore, { - RULE_NAME as preferSingleStoreName -} from './rules/prefer-single-store-per-file' - -import noReturnGlobalProperties, { - RULE_NAME as noReturnGlobalPropertiesName -} from './rules/no-return-global-properties' - -import noDuplicateStoreIds, { - RULE_NAME as noDuplicateStoreIdsName -} from './rules/no-duplicate-store-ids' - -const createConfig = (rules: Record) => ({ - plugins: ['pinia'], - rules: Object.keys(rules).reduce((acc, ruleName) => { - return { - ...acc, - [`pinia/${ruleName}`]: rules[ruleName] - } - }, {}) -}) +import { RULE_NAME as requireSetupStorePropsName } from './rules/require-setup-store-properties-export' +import { RULE_NAME as neverExportInitializedStoreName } from './rules/never-export-initialized-store' +import { RULE_NAME as preferNamingConventionName } from './rules/prefer-use-store-naming-convention' +import { RULE_NAME as preferSingleStoreName } from './rules/prefer-single-store-per-file' +import { RULE_NAME as noReturnGlobalPropertiesName } from './rules/no-return-global-properties' +import { RULE_NAME as noDuplicateStoreIdsName } from './rules/no-duplicate-store-ids' +import rules from './rules' + +const plugin = { + rules +} const allRules = { [requireSetupStorePropsName]: 'warn', @@ -48,17 +26,37 @@ const recommended = { [neverExportInitializedStoreName]: 'error' } -export default { - rules: { - [requireSetupStorePropsName]: requireSetupStoreProps, - [neverExportInitializedStoreName]: neverExportInitializedStore, - [preferNamingConventionName]: preferNamingConvention, - [preferSingleStoreName]: preferSingleStore, - [noReturnGlobalPropertiesName]: noReturnGlobalProperties, - [noDuplicateStoreIdsName]: noDuplicateStoreIds - }, - configs: { - all: createConfig(allRules), - recommended: createConfig(recommended) +function createConfig>(_rules: T, flat = false) { + const name = 'pinia' + const rules: Record<`pinia/${string}`, string> = Object.keys(_rules).reduce((acc, ruleName) => { + return { + ...acc, + [`${name}/${ruleName}`]: rules[ruleName] + } + }, {}) + if (flat) { + return { + plugins: { + [name]: plugin + }, + rules + } + } else { + return { + plugins: [name], + rules + } } } + +export const configs = { + all: createConfig(allRules), + recommended: createConfig(recommended), + 'all-flat': createConfig(allRules, true), + 'recommended-flat': createConfig(recommended, true) +} + +export default { + ...plugin, + configs, +} diff --git a/src/rules/index.ts b/src/rules/index.ts new file mode 100644 index 0000000..57d42a9 --- /dev/null +++ b/src/rules/index.ts @@ -0,0 +1,16 @@ +/* GENERATED BY SCRIPTS, DO NOT EDIT DIRECTLY */ +import neverExportInitializedStore, { RULE_NAME as neverExportInitializedStoreName } from './never-export-initialized-store' +import noDuplicateStoreIds, { RULE_NAME as noDuplicateStoreIdsName } from './no-duplicate-store-ids' +import noReturnGlobalProperties, { RULE_NAME as noReturnGlobalPropertiesName } from './no-return-global-properties' +import preferSingleStorePerFile, { RULE_NAME as preferSingleStorePerFileName } from './prefer-single-store-per-file' +import preferUseStoreNamingConvention, { RULE_NAME as preferUseStoreNamingConventionName } from './prefer-use-store-naming-convention' +import requireSetupStorePropertiesExport, { RULE_NAME as requireSetupStorePropertiesExportName } from './require-setup-store-properties-export' + +export default { + [neverExportInitializedStoreName]: neverExportInitializedStore, + [noDuplicateStoreIdsName]: noDuplicateStoreIds, + [noReturnGlobalPropertiesName]: noReturnGlobalProperties, + [preferSingleStorePerFileName]: preferSingleStorePerFile, + [preferUseStoreNamingConventionName]: preferUseStoreNamingConvention, + [requireSetupStorePropertiesExportName]: requireSetupStorePropertiesExport +} diff --git a/src/rules/no-duplicate-store-ids.ts b/src/rules/no-duplicate-store-ids.ts index 4bd701a..b64b876 100644 --- a/src/rules/no-duplicate-store-ids.ts +++ b/src/rules/no-duplicate-store-ids.ts @@ -1,5 +1,5 @@ -import { createEslintRule } from '../utils/rule-creator' import { AST_NODE_TYPES } from '@typescript-eslint/utils' +import { createEslintRule } from '../utils/rule-creator' export const RULE_NAME = 'no-duplicate-store-ids' export type MESSAGE_IDS = 'duplicatedStoreIds' diff --git a/src/rules/no-return-global-properties.ts b/src/rules/no-return-global-properties.ts index 3e416f4..3cf9299 100644 --- a/src/rules/no-return-global-properties.ts +++ b/src/rules/no-return-global-properties.ts @@ -1,4 +1,3 @@ -import {} from 'typescript' import { createEslintRule } from '../utils/rule-creator' export const RULE_NAME = 'no-return-global-properties' @@ -28,9 +27,8 @@ export default createEslintRule({ node.declarations.forEach((declaration) => { if (declaration.init && declaration.init.type === 'CallExpression') { const calleeName = declaration.init.callee.name - if (calleeName === 'useRoute' || calleeName === 'inject') { + if (calleeName === 'useRoute' || calleeName === 'inject') variablesUsingGlobalCallee.add(declaration.id.name) - } } }) },