From c3ecea3c4bd4a772cd17493cd6e89097ad89e383 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Mon, 22 Feb 2021 19:50:22 +0900 Subject: [PATCH] Add @intlify/vue-i18n/no-deprecated-i18n-place-attr rule --- docs/rules/README.md | 1 + docs/rules/no-deprecated-i18n-place-attr.md | 95 ++++++++++++ lib/rules.ts | 2 + lib/rules/no-deprecated-i18n-place-attr.ts | 51 +++++++ lib/utils/index.ts | 48 ++++++ .../rules/no-deprecated-i18n-place-attr.ts | 138 ++++++++++++++++++ 6 files changed, 335 insertions(+) create mode 100644 docs/rules/no-deprecated-i18n-place-attr.md create mode 100644 lib/rules/no-deprecated-i18n-place-attr.ts create mode 100644 tests/lib/rules/no-deprecated-i18n-place-attr.ts diff --git a/docs/rules/README.md b/docs/rules/README.md index 2e9f264f..297948c6 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -9,6 +9,7 @@ | Rule ID | Description | | |:--------|:------------|:---| | [@intlify/vue-i18n/no-deprecated-i18n-component](./no-deprecated-i18n-component.html) | disallow using deprecated `` components (in Vue I18n 9.0.0+) | :black_nib: | +| [@intlify/vue-i18n/no-deprecated-i18n-place-attr](./no-deprecated-i18n-place-attr.html) | disallow using deprecated `place` attribute (Removed in Vue I18n 9.0.0+) | | | [@intlify/vue-i18n/no-html-messages](./no-html-messages.html) | disallow use HTML localization messages | :star: | | [@intlify/vue-i18n/no-missing-keys](./no-missing-keys.html) | disallow missing locale message key at localization methods | :star: | | [@intlify/vue-i18n/no-raw-text](./no-raw-text.html) | disallow to string literal in template or JSX | :star: | diff --git a/docs/rules/no-deprecated-i18n-place-attr.md b/docs/rules/no-deprecated-i18n-place-attr.md new file mode 100644 index 00000000..4c2f7a69 --- /dev/null +++ b/docs/rules/no-deprecated-i18n-place-attr.md @@ -0,0 +1,95 @@ +--- +title: '@intlify/vue-i18n/no-deprecated-i18n-place-attr' +description: disallow using deprecated `place` attribute (Removed in Vue I18n 9.0.0+) +--- + +# @intlify/vue-i18n/no-deprecated-i18n-place-attr + +> disallow using deprecated `place` attribute (Removed in Vue I18n 9.0.0+) + +If you are migrating from Vue I18n v8 to v9, the `place` attribute should be replaced with the `v-slot`. + +## :book: Rule Details + +This rule reports use of deprecated `place` attribute (Removed in Vue I18n 9.0.0+). + +:-1: Examples of **incorrect** code for this rule: + + + + + +```vue + + +``` + + + +:+1: Examples of **correct** code for this rule: + + + + + +```vue + + +``` + + + +## :books: Further reading + +- [Vue I18n > Breaking Changes - Remove place syntax with `place` attr and `places` prop](https://vue-i18n.intlify.dev/guide/migration/breaking.html#remove-place-syntax-with-place-attr-and-places-prop) +- [Vue I18n (v8) > Component interpolation - Places syntax usage](https://kazupon.github.io/vue-i18n/guide/interpolation.html#places-syntax-usage) + +## :mag: Implementation + +- [Rule source](https://github.com/intlify/eslint-plugin-vue-i18n/blob/master/lib/rules/no-deprecated-i18n-place-attr.ts) +- [Test source](https://github.com/intlify/eslint-plugin-vue-i18n/tree/master/tests/lib/rules/no-deprecated-i18n-place-attr.ts) diff --git a/lib/rules.ts b/lib/rules.ts index f90df138..86bce777 100644 --- a/lib/rules.ts +++ b/lib/rules.ts @@ -1,6 +1,7 @@ /** DON'T EDIT THIS FILE; was created by scripts. */ 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 noDuplicateKeysInLocale from './rules/no-duplicate-keys-in-locale' import noDynamicKeys from './rules/no-dynamic-keys' import noHtmlMessages from './rules/no-html-messages' @@ -15,6 +16,7 @@ import validMessageSyntax from './rules/valid-message-syntax' export = { 'key-format-style': keyFormatStyle, 'no-deprecated-i18n-component': noDeprecatedI18nComponent, + 'no-deprecated-i18n-place-attr': noDeprecatedI18nPlaceAttr, 'no-duplicate-keys-in-locale': noDuplicateKeysInLocale, 'no-dynamic-keys': noDynamicKeys, 'no-html-messages': noHtmlMessages, diff --git a/lib/rules/no-deprecated-i18n-place-attr.ts b/lib/rules/no-deprecated-i18n-place-attr.ts new file mode 100644 index 00000000..4dec11cb --- /dev/null +++ b/lib/rules/no-deprecated-i18n-place-attr.ts @@ -0,0 +1,51 @@ +/** + * @author Yosuke Ota + */ +import { + defineTemplateBodyVisitor, + getAttribute, + getDirective +} from '../utils/index' +import type { RuleContext, RuleListener } from '../types' +import type { AST as VAST } from 'vue-eslint-parser' + +function create(context: RuleContext): RuleListener { + return defineTemplateBodyVisitor(context, { + VElement(node: VAST.VElement) { + if (node.name !== 'i18n' && node.name !== 'i18n-t') { + return + } + for (const child of node.children) { + if (child.type !== 'VElement') { + continue + } + const placeAttr = + getAttribute(child, 'place') || getDirective(child, 'bind', 'place') + if (placeAttr) { + context.report({ + node: placeAttr.key, + messageId: 'deprecated' + }) + } + } + } + }) +} + +export = { + meta: { + type: 'problem', + docs: { + description: + 'disallow using deprecated `place` attribute (Removed in Vue I18n 9.0.0+)', + category: 'Recommended', + recommended: false + }, + fixable: null, + schema: [], + messages: { + deprecated: 'Deprecated `place` attribute was found. Use v-slot instead.' + } + }, + create +} diff --git a/lib/utils/index.ts b/lib/utils/index.ts index bad0c601..1684cf5d 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -57,6 +57,54 @@ export function defineTemplateBodyVisitor( ) } +/** + * Get the attribute which has the given name. + * @param {VElement} node The start tag node to check. + * @param {string} name The attribute name to check. + * @param {string} [value] The attribute value to check. + * @returns {VAttribute | null} The found attribute. + */ +export function getAttribute( + node: VAST.VElement, + name: string +): VAST.VAttribute | null { + return ( + node.startTag.attributes + .map(node => (!node.directive ? node : null)) + .find(node => { + return node && node.key.name === name + }) || null + ) +} + +/** + * Get the directive which has the given name. + * @param {VElement} node The start tag node to check. + * @param {string} name The directive name to check. + * @param {string} [argument] The directive argument to check. + * @returns {VDirective | null} The found directive. + */ +export function getDirective( + node: VAST.VElement, + name: string, + argument: string +): VAST.VDirective | null { + return ( + node.startTag.attributes + .map(node => (node.directive ? node : null)) + .find(node => { + return ( + node && + node.key.name.name === name && + (argument === undefined || + (node.key.argument && + node.key.argument.type === 'VIdentifier' && + node.key.argument.name) === argument) + ) + }) || null + ) +} + function loadLocaleMessages( localeFilesList: LocaleFiles[], cwd: string diff --git a/tests/lib/rules/no-deprecated-i18n-place-attr.ts b/tests/lib/rules/no-deprecated-i18n-place-attr.ts new file mode 100644 index 00000000..d36e0910 --- /dev/null +++ b/tests/lib/rules/no-deprecated-i18n-place-attr.ts @@ -0,0 +1,138 @@ +/** + * @author Yosuke Ota + */ +import { RuleTester } from 'eslint' +import rule = require('../../../lib/rules/no-deprecated-i18n-place-attr') + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('no-deprecated-i18n-place-attr', rule as never, { + valid: [ + { + code: ` + + ` + }, + { + code: ` + + ` + }, + { + code: ` + + ` + } + ], + invalid: [ + { + code: ` + + `, + errors: [ + { + message: + 'Deprecated `place` attribute was found. Use v-slot instead.', + line: 6, + column: 19 + }, + { + message: + 'Deprecated `place` attribute was found. Use v-slot instead.', + line: 7, + column: 16 + } + ] + }, + + { + code: ` + + `, + errors: [ + { + message: + 'Deprecated `place` attribute was found. Use v-slot instead.', + line: 6, + column: 19 + }, + { + message: + 'Deprecated `place` attribute was found. Use v-slot instead.', + line: 7, + column: 16 + } + ] + }, + { + code: ` + + `, + errors: ['Deprecated `place` attribute was found. Use v-slot instead.'] + } + ] +})