Skip to content

Commit

Permalink
feat: support flat config (#487)
Browse files Browse the repository at this point in the history
* refactor: update scripts

* refactor: remove unnecesarry codes

* refactor: update scripts

* chore: change node register to jiti from ts-node

* feat: flat config implementation

* fix: update separate

* fix: integration tests

* fix: format

* chore: bump node

* chore: bump eslint

* fix: forgot commit

* fix: forgot lock file

* fix: add ignore lint for tests

* fix: test

* docs: updates

* Create pink-hairs-fail.md

---------

Co-authored-by: Yosuke Ota <[email protected]>
  • Loading branch information
kazupon and ota-meshi committed Apr 2, 2024
1 parent 44fea72 commit 01324a0
Show file tree
Hide file tree
Showing 50 changed files with 814 additions and 508 deletions.
5 changes: 5 additions & 0 deletions .changeset/pink-hairs-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@intlify/eslint-plugin-vue-i18n": minor
---

feat: support flat config
5 changes: 3 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/dist
/docs/.vitepress/cache
/docs/.vitepress/dist
/lib/configs/**/*.ts
/node_modules
# /tests/fixtures Used testcases
/tests-integrations/config-recommended
#/tests/fixtures # use testing
/tests/integrations
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 18
- name: Enable corepack
run: corepack enable
- name: Install
Expand All @@ -30,7 +30,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node: [16, 18, 20]
node: [18, 20]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/tests/fixtures
/tests-integrations/config-recommended
/docs/.vitepress/cache
/scripts/update-**.ts

# ignore files
/CHANGELOG.md
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Available Rules

- :star: mark: the rule which is enabled by `plugin:@intlify/vue-i18n/recommended` preset.
- :star: mark: the rule which is enabled by `plugin:@intlify/vue-i18n/recommended` or `*.configs["flat/recommended"]` preset.
- :black_nib: mark: the rule which is fixable by `eslint --fix` command.

## Recommended
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/no-html-messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ since: v0.1.0

> disallow use HTML localization messages
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule.
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule.

This rule reports in order to reduce the risk of injecting potentially unsafe localization message into the browser leading to supply-chain attack or XSS attack.

Expand Down
2 changes: 1 addition & 1 deletion docs/rules/no-missing-keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ since: v0.1.0

> disallow missing locale message key at localization methods
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule.
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule.

This rule warns locale message key missing if the key does not exist in locale messages.

Expand Down
2 changes: 1 addition & 1 deletion docs/rules/no-raw-text.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ since: v0.2.0

> disallow to string literal in template or JSX
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule.
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule.

This rule warns the usage of literal the bellow:

Expand Down
2 changes: 1 addition & 1 deletion docs/rules/no-v-html.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ since: v0.1.0

> disallow use of localization methods on v-html to prevent XSS attack
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` property in a configuration file enables this rule.
- :star: The `"extends": "plugin:@intlify/vue-i18n/recommended"` or `*.configs["flat/recommended"]` property in a configuration file enables this rule.

This rule reports all uses of localization methods on `v-html` directive in order to reduce the risk of injecting potentially unsafe / unescaped html into the browser leading to Cross-Site Scripting (XSS) attacks.

Expand Down
89 changes: 86 additions & 3 deletions docs/started.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,83 @@ npm install --save-dev eslint @intlify/eslint-plugin-vue-i18n

## :rocket: Usage

Configure your `.eslintrc.*` file.
### Configuration `eslint.config.[c|m]js`

Use `eslint.config.[c|m]js` file to configure rules. This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new.

Example eslint.config.js:

```js
import vueI18n from '@intlify/eslint-plugin-vue-i18n'

export default [
// add more generic rulesets here, such as:
// js.configs.recommended, // '@eslint/js'
// ...vue.configs['flat/recommended'], // 'eslint-plugin-vue'

...vueI18n.configs['flat/recommended'],
{
rules: {
// Optional.
'@intlify/vue-i18n/no-dynamic-keys': 'error',
'@intlify/vue-i18n/no-unused-keys': [
'error',
{
extensions: ['.js', '.vue']
}
]
},
settings: {
'vue-i18n': {
localeDir: './path/to/locales/*.{json,json5,yaml,yml}', // extension is glob formatting!
// or
// localeDir: {
// pattern: './path/to/locales/*.{json,json5,yaml,yml}', // extension is glob formatting!
// localeKey: 'file' // or 'path' or 'key'
// }
// or
// localeDir: [
// {
// // 'file' case
// pattern: './path/to/locales1/*.{json,json5,yaml,yml}',
// localeKey: 'file'
// },
// {
// // 'path' case
// pattern: './path/to/locales2/*.{json,json5,yaml,yml}',
// localePattern: /^.*\/(?<locale>[A-Za-z0-9-_]+)\/.*\.(json5?|ya?ml)$/,
// localeKey: 'path'
// },
// {
// // 'key' case
// pattern: './path/to/locales3/*.{json,json5,yaml,yml}',
// localeKey: 'key'
// },
// ]

// Specify the version of `vue-i18n` you are using.
// If not specified, the message will be parsed twice.
messageSyntaxVersion: '^9.0.0'
}
}
}
]
```

See the [rule list](./rules/index.md) to get the `configs` & `rules` that this plugin provides.

#### Bundle Configurations `eslint.config.[c|m]js`

This plugin provides some predefined configs. You can use the following configs by adding them to `eslint.config.[c|m]js`. (All flat configs in this plugin are provided as arrays, so spread syntax is required when combining them with other configs.)

- `*.configs["flat/base"]`: Settings and rules to enable correct ESLint parsing.
- `*.configs["flat/recommended"]`: Above, plus rules to enforce subjective community defaults to ensure consistency.

### Configuration `.eslintrc.*`

Use `.eslintrc.*` file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.

Example `.eslintrc.js`:

For example:

Expand Down Expand Up @@ -74,7 +150,14 @@ module.export = {
}
```

See [the rule list](/rules/)
See the [rule list](./rules/index.md) to get the `configs` & `rules` that this plugin provides.

#### Bundle Configurations `.eslintrc.*`

This plugin provides some predefined configs. You can use the following configs by adding them to `.eslintrc.*`. (All flat configs in this plugin are provided as arrays, so spread syntax is required when combining them with other configs.)

- `"plugin:@intlify/vue-i18n/base"`: Settings and rules to enable correct ESLint parsing.
- `"plugin:@intlify/vue-i18n/recommended"`: Above, plus rules to enforce subjective community defaults to ensure consistency.

### `settings['vue-i18n']`

Expand Down Expand Up @@ -102,7 +185,7 @@ If you want to run `eslint` from command line, make sure you include the `.vue`,

Examples:

```bash
```sh
eslint --ext .js,.vue,.json src
eslint "src/**/*.{js,vue,json}"
# Specify the extension you use.
Expand Down
8 changes: 0 additions & 8 deletions lib/configs.ts

This file was deleted.

7 changes: 1 addition & 6 deletions lib/configs/base.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
/** DON'T EDIT THIS FILE; was created by scripts. */
export = {
parser: require.resolve('vue-eslint-parser'),
plugins: ['@intlify/vue-i18n'],
overrides: [
{
files: ['*.json', '*.json5'],
// TODO: If you do not use vue-eslint-parser, you will get an error in vue rules.
// see https://github.com/vuejs/eslint-plugin-vue/pull/1262
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
parser: require.resolve('jsonc-eslint-parser')
}
},
{
files: ['*.yaml', '*.yml'],
// TODO: If you do not use vue-eslint-parser, you will get an error in vue rules.
// see https://github.com/vuejs/eslint-plugin-vue/pull/1262
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
parser: require.resolve('yaml-eslint-parser')
},
rules: {
// ESLint core rules known to cause problems with YAML.
// https://github.com/ota-meshi/eslint-plugin-yml/blob/4e468109b9d2f4376b8d4d1221adba27c6ee04b2/src/configs/base.ts#L7-L11
'no-irregular-whitespace': 'off',
'spaced-comment': 'off'
}
Expand Down
35 changes: 35 additions & 0 deletions lib/configs/flat/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/** DON'T EDIT THIS FILE; was created by scripts. */
export = [
{
name: '@intlify/vue-i18n:base:setup',
plugins: {
get '@intlify/vue-i18n'() {
return require('../../index')
}
}
},
{
name: '@intlify/vue-i18n:base:setup:json',
files: ['*.json', '**/*.json', '*.json5', '**/*.json5'],
languageOptions: {
parser: require('vue-eslint-parser'),
parserOptions: {
parser: require('jsonc-eslint-parser')
}
}
},
{
name: '@intlify/vue-i18n:base:setup:yaml',
files: ['*.yaml', '**/*.yaml', '*.yml', '**/*.yml'],
languageOptions: {
parser: require('vue-eslint-parser'),
parserOptions: {
parser: require('yaml-eslint-parser')
}
},
rules: {
'no-irregular-whitespace': 'off',
'spaced-comment': 'off'
}
}
]
28 changes: 28 additions & 0 deletions lib/configs/flat/recommended.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/** DON'T EDIT THIS FILE; was created by scripts. */
const globals = require('globals')
const config = require('./base')
export = [
...config,
{
name: '@intlify/vue-i18n:recommended:setup',
languageOptions: {
ecmaVersion: 2018,
sourceType: 'module',
globals: globals.browser,
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
}
},
{
name: '@intlify/vue-i18n:recommended:rules',
rules: {
'@intlify/vue-i18n/no-html-messages': 'warn',
'@intlify/vue-i18n/no-missing-keys': 'warn',
'@intlify/vue-i18n/no-raw-text': 'warn',
'@intlify/vue-i18n/no-v-html': 'warn'
}
}
]
64 changes: 56 additions & 8 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,59 @@
/**
* @fileoverview ESLint plugin for vue-i18n
* @author kazuya kawaguchi (a.k.a. kazupon)
*/
import configs from './configs'
import rules from './rules'
/** DON'T EDIT THIS FILE; was created by scripts. */
// configs
import base from './configs/base'
import recommended from './configs/recommended'
import flatBase from './configs/flat/base'
import flatRecommended from './configs/flat/recommended'

// rules
import keyFormatStyle from './rules/key-format-style'
import noDeprecatedI18nComponent from './rules/no-deprecated-i18n-component'
import noDeprecatedI18nPlaceAttr from './rules/no-deprecated-i18n-place-attr'
import noDeprecatedI18nPlacesProp from './rules/no-deprecated-i18n-places-prop'
import noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale'
import noDynamicKeys from './rules/no-dynamic-keys'
import noHtmlMessages from './rules/no-html-messages'
import noI18nTPathProp from './rules/no-i18n-t-path-prop'
import noMissingKeysInOtherLocales from './rules/no-missing-keys-in-other-locales'
import noMissingKeys from './rules/no-missing-keys'
import noRawText from './rules/no-raw-text'
import noUnknownLocale from './rules/no-unknown-locale'
import noUnusedKeys from './rules/no-unused-keys'
import noVHtml from './rules/no-v-html'
import preferLinkedKeyWithParen from './rules/prefer-linked-key-with-paren'
import preferSfcLangAttr from './rules/prefer-sfc-lang-attr'
import sfcLocaleAttr from './rules/sfc-locale-attr'
import validMessageSyntax from './rules/valid-message-syntax'

// export plugin
export = {
configs,
rules
configs: {
// eslintrc configs
base,
recommended,

// flat configs
'flat/base': flatBase,
'flat/recommended': flatRecommended
},
rules: {
'key-format-style': keyFormatStyle,
'no-deprecated-i18n-component': noDeprecatedI18nComponent,
'no-deprecated-i18n-place-attr': noDeprecatedI18nPlaceAttr,
'no-deprecated-i18n-places-prop': noDeprecatedI18nPlacesProp,
'no-duplicate-keys-in-locale': noDuplicateKeysInLocale,
'no-dynamic-keys': noDynamicKeys,
'no-html-messages': noHtmlMessages,
'no-i18n-t-path-prop': noI18nTPathProp,
'no-missing-keys-in-other-locales': noMissingKeysInOtherLocales,
'no-missing-keys': noMissingKeys,
'no-raw-text': noRawText,
'no-unknown-locale': noUnknownLocale,
'no-unused-keys': noUnusedKeys,
'no-v-html': noVHtml,
'prefer-linked-key-with-paren': preferLinkedKeyWithParen,
'prefer-sfc-lang-attr': preferSfcLangAttr,
'sfc-locale-attr': sfcLocaleAttr,
'valid-message-syntax': validMessageSyntax
}
}

0 comments on commit 01324a0

Please sign in to comment.