Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support flat config #487

Merged
merged 16 commits into from
Apr 2, 2024
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 @@

> 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 Expand Up @@ -45,9 +45,9 @@
<div class="app">
<p>{{ $t('hello') }}</p>
<!-- supply-chain attack -->
<div v-html="$t('contents.banner')"></div>

Check warning on line 48 in docs/rules/no-html-messages.md

View workflow job for this annotation

GitHub Actions / Lint

'v-html' directive can lead to XSS attack

Check warning on line 48 in docs/rules/no-html-messages.md

View workflow job for this annotation

GitHub Actions / Lint

'v-html' directive can lead to XSS attack
<!-- XSS attack -->
<div v-html="$t('contents.modal')"></div>

Check warning on line 50 in docs/rules/no-html-messages.md

View workflow job for this annotation

GitHub Actions / Lint

'v-html' directive can lead to XSS attack

Check warning on line 50 in docs/rules/no-html-messages.md

View workflow job for this annotation

GitHub Actions / Lint

'v-html' directive can lead to XSS attack
</div>
</template>
```
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
}
}
Loading
Loading