From fc052a254d1e827c5135716305fcbf09b787ab29 Mon Sep 17 00:00:00 2001 From: ota Date: Wed, 5 Aug 2020 12:02:46 +0900 Subject: [PATCH 1/2] Fix false positives of key used in `` component in `no-unused-keys` rule. --- .vscode/settings.json | 3 +- lib/utils/collect-keys.js | 33 ++++++++++++++++--- .../valid/vue-cli-format/locales/en.json | 3 +- .../valid/vue-cli-format/locales/ja.json | 3 +- .../valid/vue-cli-format/src/App.vue | 3 ++ tests/lib/rules/no-unused-keys.js | 15 +++++++++ 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4dcd08ad..cd52d7d6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,6 @@ ], "eslint.alwaysShowStatus": true, "eslint.packageManager": "yarn", - "eslint.run": "onSave" + "eslint.run": "onSave", + "npm.packageManager": "yarn" } diff --git a/lib/utils/collect-keys.js b/lib/utils/collect-keys.js index 815dec07..1e5c155a 100644 --- a/lib/utils/collect-keys.js +++ b/lib/utils/collect-keys.js @@ -18,6 +18,7 @@ const debug = require('debug')('eslint-plugin-vue-i18n:collect-keys') * @typedef {import('vue-eslint-parser').AST.Node} Node * @typedef {import('vue-eslint-parser').AST.ESLintCallExpression} CallExpression * @typedef {import('vue-eslint-parser').AST.VDirective} VDirective + * @typedef {import('vue-eslint-parser').AST.VAttribute} VAttribute */ /** @@ -51,6 +52,17 @@ function getKeyFromVDirective (node) { } } +/** + * @param {VAttribute} node + */ +function getKeyFromI18nComponent (node) { + if (node.value && node.value.type === 'VLiteral') { + return node.value.value + } else { + return null + } +} + function getParser (parser) { if (parser) { try { @@ -132,11 +144,22 @@ function collectKeysFromAST (node, visitorKeys) { */ function enterNode (node) { if (node.type === 'VAttribute') { - if (node.directive && (node.key.name.name === 't' || node.key.name === 't' /* parser v5 */)) { - debug("call VAttribute[directive=true][key.name.name='t'] handling ...") - const key = getKeyFromVDirective(node) - if (key) { - results.add(key) + if (node.directive) { + if (node.key.name.name === 't' || node.key.name === 't' /* parser v5 */) { + debug("call VAttribute[directive=true][key.name.name='t'] handling ...") + const key = getKeyFromVDirective(node) + if (key) { + results.add(key) + } + } + } else { + if (node.key.name === 'path' && node.parent.parent.name === 'i18n') { + debug("call VElement[name=i18n] > VStartTag > VAttribute[key.name='path'] handling ...") + + const key = getKeyFromI18nComponent(node) + if (key) { + results.add(key) + } } } } else if (node.type === 'CallExpression') { diff --git a/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/en.json b/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/en.json index 35e427be..c1f057ef 100644 --- a/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/en.json +++ b/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/en.json @@ -5,5 +5,6 @@ "link": "@:messages.hello" }, "hello_dio": "hello underscore DIO!", - "hello {name}": "hello {name}!" + "hello {name}": "hello {name}!", + "term": "I accept xxx {0}." } diff --git a/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/ja.json b/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/ja.json index 0332aa11..29b032d7 100644 --- a/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/ja.json +++ b/tests/fixtures/no-unused-keys/valid/vue-cli-format/locales/ja.json @@ -5,5 +5,6 @@ "link": "@:messages.hello" }, "hello_dio": "こんにちは、アンダースコア DIO!", - "hello {name}": "こんにちは、{name}!" + "hello {name}": "こんにちは、{name}!", + "term": "私は xxx の{0}に同意します。" } diff --git a/tests/fixtures/no-unused-keys/valid/vue-cli-format/src/App.vue b/tests/fixtures/no-unused-keys/valid/vue-cli-format/src/App.vue index e28fedc2..0659cf5f 100644 --- a/tests/fixtures/no-unused-keys/valid/vue-cli-format/src/App.vue +++ b/tests/fixtures/no-unused-keys/valid/vue-cli-format/src/App.vue @@ -1,6 +1,9 @@ diff --git a/tests/lib/rules/no-unused-keys.js b/tests/lib/rules/no-unused-keys.js index 8bf140fb..3c7d61e1 100644 --- a/tests/lib/rules/no-unused-keys.js +++ b/tests/lib/rules/no-unused-keys.js @@ -56,6 +56,21 @@ new RuleTester({ } } ` + }, { + // component + filename: 'test.vue', + code: ` + + + { + "en": { + "message_key": "hi" + } + } + + ` }], invalid: [{ // sfc supports From a0367d8fd2522adb25d3a77dcbf4ca7487432337 Mon Sep 17 00:00:00 2001 From: ota Date: Wed, 5 Aug 2020 12:16:46 +0900 Subject: [PATCH 2/2] Add supports `` component --- lib/utils/collect-keys.js | 10 ++++++++-- tests/lib/rules/no-unused-keys.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/utils/collect-keys.js b/lib/utils/collect-keys.js index 1e5c155a..f55d105b 100644 --- a/lib/utils/collect-keys.js +++ b/lib/utils/collect-keys.js @@ -153,8 +153,14 @@ function collectKeysFromAST (node, visitorKeys) { } } } else { - if (node.key.name === 'path' && node.parent.parent.name === 'i18n') { - debug("call VElement[name=i18n] > VStartTag > VAttribute[key.name='path'] handling ...") + if ( + node.key.name === 'path' && + ( + node.parent.parent.name === 'i18n' || + node.parent.parent.name === 'i18n-t' + ) + ) { + debug("call VElement:matches([name=i18n], [name=i18n-t]) > VStartTag > VAttribute[key.name='path'] handling ...") const key = getKeyFromI18nComponent(node) if (key) { diff --git a/tests/lib/rules/no-unused-keys.js b/tests/lib/rules/no-unused-keys.js index 3c7d61e1..572bd937 100644 --- a/tests/lib/rules/no-unused-keys.js +++ b/tests/lib/rules/no-unused-keys.js @@ -71,6 +71,21 @@ new RuleTester({ } ` + }, { + // component + filename: 'test.vue', + code: ` + + + { + "en": { + "message_key": "hi" + } + } + + ` }], invalid: [{ // sfc supports