From 2095aceb87c99006847e88604a423c36a3c4da31 Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 10:09:47 +0700 Subject: [PATCH 1/7] Custom locale loader --- lib/rules/no-html-messages.js | 2 +- lib/rules/no-missing-keys.js | 2 +- lib/rules/no-unused-keys.js | 2 +- lib/utils/index.js | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/rules/no-html-messages.js b/lib/rules/no-html-messages.js index aa01b074..1587e288 100644 --- a/lib/rules/no-html-messages.js +++ b/lib/rules/no-html-messages.js @@ -54,7 +54,7 @@ function create (context) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir) + const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-html-messages`) diff --git a/lib/rules/no-missing-keys.js b/lib/rules/no-missing-keys.js index 129c617d..b322cfb8 100644 --- a/lib/rules/no-missing-keys.js +++ b/lib/rules/no-missing-keys.js @@ -21,7 +21,7 @@ function create (context) { } const localeDir = settings['vue-i18n'].localeDir - const localeMessages = getLocaleMessages(localeDir) + const localeMessages = getLocaleMessages(localeDir, settings['vue-i18n'].localeLoader) return defineTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name='t']" (node) { diff --git a/lib/rules/no-unused-keys.js b/lib/rules/no-unused-keys.js index dbdfb077..348a0601 100644 --- a/lib/rules/no-unused-keys.js +++ b/lib/rules/no-unused-keys.js @@ -88,7 +88,7 @@ function create (context) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir) + const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-unused-keys`) diff --git a/lib/utils/index.js b/lib/utils/index.js index 98aca376..404ad8d9 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -43,12 +43,13 @@ function loadLocaleMessages (pattern) { let localeMessages = null // locale messages let localeDir = null // locale dir -function getLocaleMessages (localeDirectory) { +function getLocaleMessages (localeDirectory, customLoader) { + const loader = customLoader || loadLocaleMessages if (localeDir !== localeDirectory) { localeDir = localeDirectory - localeMessages = loadLocaleMessages(localeDir) + localeMessages = loader(localeDir) } else { - localeMessages = localeMessages || loadLocaleMessages(localeDir) + localeMessages = localeMessages || loader(localeDir) } return localeMessages } From 3a040fa9fbd142b13ef0391a437983b5a476d6ce Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 16:41:49 +0700 Subject: [PATCH 2/7] Strip unused localeDir var --- lib/rules/no-missing-keys.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/rules/no-missing-keys.js b/lib/rules/no-missing-keys.js index b322cfb8..873cff75 100644 --- a/lib/rules/no-missing-keys.js +++ b/lib/rules/no-missing-keys.js @@ -20,37 +20,36 @@ function create (context) { return {} } - const localeDir = settings['vue-i18n'].localeDir - const localeMessages = getLocaleMessages(localeDir, settings['vue-i18n'].localeLoader) + const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) return defineTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name='t']" (node) { - checkDirective(context, localeDir, localeMessages, node) + checkDirective(context, localeMessages, node) }, "VAttribute[directive=true][key.name.name='t']" (node) { - checkDirective(context, localeDir, localeMessages, node) + checkDirective(context, localeMessages, node) }, "VElement[name=i18n] > VStartTag > VAttribute[key.name='path']" (node) { - checkComponent(context, localeDir, localeMessages, node) + checkComponent(context, localeMessages, node) }, "VElement[name=i18n] > VStartTag > VAttribute[key.name.name='path']" (node) { - checkComponent(context, localeDir, localeMessages, node) + checkComponent(context, localeMessages, node) }, CallExpression (node) { - checkCallExpression(context, localeDir, localeMessages, node) + checkCallExpression(context, localeMessages, node) } }, { CallExpression (node) { - checkCallExpression(context, localeDir, localeMessages, node) + checkCallExpression(context, localeMessages, node) } }) } -function checkDirective (context, localeDir, localeMessages, node) { +function checkDirective (context, localeMessages, node) { if ((node.value && node.value.type === 'VExpressionContainer') && (node.value.expression && node.value.expression.type === 'Literal')) { const key = node.value.expression.value @@ -58,28 +57,28 @@ function checkDirective (context, localeDir, localeMessages, node) { // TODO: should be error return } - const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir) + const missings = findMissingsFromLocaleMessages(localeMessages, key) if (missings.length) { missings.forEach(missing => context.report({ node, ...missing })) } } } -function checkComponent (context, localeDir, localeMessages, node) { +function checkComponent (context, localeMessages, node) { if (node.value && node.value.type === 'VLiteral') { const key = node.value.value if (!key) { // TODO: should be error return } - const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir) + const missings = findMissingsFromLocaleMessages(localeMessages, key) if (missings.length) { missings.forEach(missing => context.report({ node, ...missing })) } } } -function checkCallExpression (context, localeDir, localeMessages, node) { +function checkCallExpression (context, localeMessages, node) { const funcName = (node.callee.type === 'MemberExpression' && node.callee.property.name) || node.callee.name if (!/^(\$t|t|\$tc|tc)$/.test(funcName) || !node.arguments || !node.arguments.length) { @@ -95,7 +94,7 @@ function checkCallExpression (context, localeDir, localeMessages, node) { return } - const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir) + const missings = findMissingsFromLocaleMessages(localeMessages, key) if (missings.length) { missings.forEach(missing => context.report({ node, ...missing })) } From 941659f72179d06780bb32b8775eea75fd6fbfd8 Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 17:09:44 +0700 Subject: [PATCH 3/7] Simplify getLocaleMessages calls --- lib/rules/no-html-messages.js | 2 +- lib/rules/no-missing-keys.js | 2 +- lib/rules/no-unused-keys.js | 2 +- lib/utils/index.js | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/rules/no-html-messages.js b/lib/rules/no-html-messages.js index 1587e288..ffd9eb6c 100644 --- a/lib/rules/no-html-messages.js +++ b/lib/rules/no-html-messages.js @@ -54,7 +54,7 @@ function create (context) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) + const localeMessages = getLocaleMessages(settings['vue-i18n']) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-html-messages`) diff --git a/lib/rules/no-missing-keys.js b/lib/rules/no-missing-keys.js index 873cff75..e3028a43 100644 --- a/lib/rules/no-missing-keys.js +++ b/lib/rules/no-missing-keys.js @@ -20,7 +20,7 @@ function create (context) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) + const localeMessages = getLocaleMessages(settings['vue-i18n']) return defineTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name='t']" (node) { diff --git a/lib/rules/no-unused-keys.js b/lib/rules/no-unused-keys.js index 348a0601..9ad477f3 100644 --- a/lib/rules/no-unused-keys.js +++ b/lib/rules/no-unused-keys.js @@ -88,7 +88,7 @@ function create (context) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir, settings['vue-i18n'].localeLoader) + const localeMessages = getLocaleMessages(settings['vue-i18n']) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-unused-keys`) diff --git a/lib/utils/index.js b/lib/utils/index.js index 404ad8d9..c8cd1d26 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -43,10 +43,10 @@ function loadLocaleMessages (pattern) { let localeMessages = null // locale messages let localeDir = null // locale dir -function getLocaleMessages (localeDirectory, customLoader) { - const loader = customLoader || loadLocaleMessages - if (localeDir !== localeDirectory) { - localeDir = localeDirectory +function getLocaleMessages (settings) { + const loader = settings.localeLoader || loadLocaleMessages + if (localeDir !== settings.localeDir) { + localeDir = settings.localeDir localeMessages = loader(localeDir) } else { localeMessages = localeMessages || loader(localeDir) From 17c7b04b90fc2d39ccef451a17df5f69b6e18719 Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 17:10:18 +0700 Subject: [PATCH 4/7] Accept locale and messages settings --- lib/utils/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index c8cd1d26..a30695ff 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -44,12 +44,14 @@ let localeMessages = null // locale messages let localeDir = null // locale dir function getLocaleMessages (settings) { - const loader = settings.localeLoader || loadLocaleMessages + if (settings.locale && settings.messages) { + return settings.messages[settings.locale] + } if (localeDir !== settings.localeDir) { localeDir = settings.localeDir - localeMessages = loader(localeDir) + localeMessages = loadLocaleMessages(localeDir) } else { - localeMessages = localeMessages || loader(localeDir) + localeMessages = localeMessages || loadLocaleMessages(localeDir) } return localeMessages } From b35bc14349c06dd6d4ec190c4a2b0f52b1884f1e Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 18:19:31 +0700 Subject: [PATCH 5/7] Move settings validation into utils --- lib/rules/no-html-messages.js | 12 ++++------ lib/rules/no-missing-keys.js | 13 ++++------- lib/rules/no-unused-keys.js | 12 ++++------ lib/utils/index.js | 37 ++++++++++++++++++++---------- tests/lib/rules/no-missing-keys.js | 2 +- tests/lib/rules/no-unused-keys.js | 2 +- 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/lib/rules/no-html-messages.js b/lib/rules/no-html-messages.js index ffd9eb6c..8f6b28c1 100644 --- a/lib/rules/no-html-messages.js +++ b/lib/rules/no-html-messages.js @@ -10,7 +10,8 @@ const { findExistLocaleMessage, getLocaleMessages, extractJsonInfo, - generateJsonAst + generateJsonAst, + validateSettings, } = require('../utils/index') const debug = require('debug')('eslint-plugin-vue-i18n:no-html-messages') @@ -45,16 +46,11 @@ function create (context) { return {} } - const { settings } = context - if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) { - context.report({ - loc: UNEXPECTED_ERROR_LOCATION, - message: `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation` - }) + if (!validateSettings(context)) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n']) + const localeMessages = getLocaleMessages(context) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-html-messages`) diff --git a/lib/rules/no-missing-keys.js b/lib/rules/no-missing-keys.js index e3028a43..8d1f83ab 100644 --- a/lib/rules/no-missing-keys.js +++ b/lib/rules/no-missing-keys.js @@ -7,20 +7,17 @@ const { UNEXPECTED_ERROR_LOCATION, defineTemplateBodyVisitor, getLocaleMessages, - findMissingsFromLocaleMessages + getSettings, + findMissingsFromLocaleMessages, + validateSettings, } = require('../utils/index') function create (context) { - const { settings } = context - if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) { - context.report({ - loc: UNEXPECTED_ERROR_LOCATION, - message: `You need to set 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation` - }) + if (!validateSettings(context)) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n']) + const localeMessages = getLocaleMessages(context) return defineTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name='t']" (node) { diff --git a/lib/rules/no-unused-keys.js b/lib/rules/no-unused-keys.js index 9ad477f3..f3b12ff6 100644 --- a/lib/rules/no-unused-keys.js +++ b/lib/rules/no-unused-keys.js @@ -12,7 +12,8 @@ const { findExistLocaleMessage, getLocaleMessages, extractJsonInfo, - generateJsonAst + generateJsonAst, + validateSettings, } = require('../utils/index') const debug = require('debug')('eslint-plugin-vue-i18n:no-unused-keys') @@ -79,16 +80,11 @@ function create (context) { return {} } - const { settings } = context - if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) { - context.report({ - loc: UNEXPECTED_ERROR_LOCATION, - message: `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation` - }) + if (!validateSettings(context)) { return {} } - const localeMessages = getLocaleMessages(settings['vue-i18n']) + const localeMessages = getLocaleMessages(context) const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages) if (!targetLocaleMessage) { debug(`ignore ${filename} in no-unused-keys`) diff --git a/lib/utils/index.js b/lib/utils/index.js index a30695ff..b0b9f048 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -40,20 +40,16 @@ function loadLocaleMessages (pattern) { }) } -let localeMessages = null // locale messages -let localeDir = null // locale dir +let localeDirCache = {} // locale messages + +function getLocaleMessages (context) { + const settings = getSettings(context) -function getLocaleMessages (settings) { if (settings.locale && settings.messages) { - return settings.messages[settings.locale] - } - if (localeDir !== settings.localeDir) { - localeDir = settings.localeDir - localeMessages = loadLocaleMessages(localeDir) - } else { - localeMessages = localeMessages || loadLocaleMessages(localeDir) + return [{ messages: settings.messages[settings.locale] }] } - return localeMessages + + return localeDirCache[settings.localeDir] = localeDirCache[settings.localeDir] || loadLocaleMessages(settings.localeDir) } function findMissingsFromLocaleMessages (localeMessages, key) { @@ -109,6 +105,22 @@ function generateJsonAst (context, json, filename) { return ast } +function getSettings(context) { + return context.settings['vue-i18n'] || {} +} + +function validateSettings(context) { + const settings = getSettings(context) + const isValid = !!(settings.locale || settings.localeDir || settings.messages) + if (!isValid) { + context.report({ + loc: UNEXPECTED_ERROR_LOCATION, + message: 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation', + }) + } + return isValid +} + module.exports = { UNEXPECTED_ERROR_LOCATION, defineTemplateBodyVisitor, @@ -116,5 +128,6 @@ module.exports = { findMissingsFromLocaleMessages, findExistLocaleMessage, extractJsonInfo, - generateJsonAst + generateJsonAst, + validateSettings, } diff --git a/tests/lib/rules/no-missing-keys.js b/tests/lib/rules/no-missing-keys.js index 38b5f90c..e1163c01 100644 --- a/tests/lib/rules/no-missing-keys.js +++ b/tests/lib/rules/no-missing-keys.js @@ -106,7 +106,7 @@ tester.run('no-missing-keys', rule, { // settings.vue-i18n.localeDir' error code: `$t('missing')`, errors: [ - `You need to set 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation` + 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation' ] }, { // nested basic diff --git a/tests/lib/rules/no-unused-keys.js b/tests/lib/rules/no-unused-keys.js index 9ccec451..85efd7e7 100644 --- a/tests/lib/rules/no-unused-keys.js +++ b/tests/lib/rules/no-unused-keys.js @@ -51,7 +51,7 @@ describe('no-unused-keys', () => { .filter(message => message.ruleId === 'vue-i18n/no-unused-keys') }).reduce((values, current) => values.concat(current), []) .forEach(message => { - assert.equal(message.message, `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`) + assert.equal(message.message, 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation') }) }) }) From 1ad0dd3b84f953751e74f85ae0d38230e61272aa Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Sun, 12 Jan 2020 18:46:23 +0700 Subject: [PATCH 6/7] Message settings test --- tests/lib/rules/no-missing-keys.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/lib/rules/no-missing-keys.js b/tests/lib/rules/no-missing-keys.js index e1163c01..62f14bbc 100644 --- a/tests/lib/rules/no-missing-keys.js +++ b/tests/lib/rules/no-missing-keys.js @@ -14,6 +14,13 @@ const settings = { } } +const messageSettings = { + 'vue-i18n': { + locale: 'en', + messages: { en: { hello: 'hello world' }}, + } +} + const tester = new RuleTester({ parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 2015 } @@ -60,6 +67,10 @@ tester.run('no-missing-keys', rule, { code: `` + }, { + // using message settings + settings: messageSettings, + code: `$t('hello')` }], invalid: [{ @@ -118,5 +129,12 @@ tester.run('no-missing-keys', rule, { `'missing.path' does not exist`, `'missing.path' does not exist` ] + }, { + // using message settings + settings: messageSettings, + code: `$t('missing')`, + errors: [ + `'missing' does not exist` + ] }] }) From 9cfbe33b2158120722648e40da83a228122f85ed Mon Sep 17 00:00:00 2001 From: Steve Lacey Date: Mon, 13 Jan 2020 10:49:46 +0700 Subject: [PATCH 7/7] Adjustments --- lib/rules/no-html-messages.js | 3 +-- lib/rules/no-missing-keys.js | 4 +--- lib/rules/no-unused-keys.js | 2 +- lib/utils/index.js | 22 +++++++++++++--------- tests/lib/rules/no-missing-keys.js | 9 ++++----- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/rules/no-html-messages.js b/lib/rules/no-html-messages.js index 8f6b28c1..93c13633 100644 --- a/lib/rules/no-html-messages.js +++ b/lib/rules/no-html-messages.js @@ -6,12 +6,11 @@ const { extname } = require('path') const parse5 = require('parse5') const { - UNEXPECTED_ERROR_LOCATION, findExistLocaleMessage, getLocaleMessages, extractJsonInfo, generateJsonAst, - validateSettings, + validateSettings } = require('../utils/index') const debug = require('debug')('eslint-plugin-vue-i18n:no-html-messages') diff --git a/lib/rules/no-missing-keys.js b/lib/rules/no-missing-keys.js index 8d1f83ab..3eef3c6a 100644 --- a/lib/rules/no-missing-keys.js +++ b/lib/rules/no-missing-keys.js @@ -4,12 +4,10 @@ 'use strict' const { - UNEXPECTED_ERROR_LOCATION, defineTemplateBodyVisitor, getLocaleMessages, - getSettings, findMissingsFromLocaleMessages, - validateSettings, + validateSettings } = require('../utils/index') function create (context) { diff --git a/lib/rules/no-unused-keys.js b/lib/rules/no-unused-keys.js index f3b12ff6..6c8bcf92 100644 --- a/lib/rules/no-unused-keys.js +++ b/lib/rules/no-unused-keys.js @@ -13,7 +13,7 @@ const { getLocaleMessages, extractJsonInfo, generateJsonAst, - validateSettings, + validateSettings } = require('../utils/index') const debug = require('debug')('eslint-plugin-vue-i18n:no-unused-keys') diff --git a/lib/utils/index.js b/lib/utils/index.js index b0b9f048..2536974d 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -40,16 +40,20 @@ function loadLocaleMessages (pattern) { }) } -let localeDirCache = {} // locale messages +const localeDirCache = {} // locale messages function getLocaleMessages (context) { const settings = getSettings(context) - if (settings.locale && settings.messages) { - return [{ messages: settings.messages[settings.locale] }] + if (settings.locales) { + return settings.locales } - return localeDirCache[settings.localeDir] = localeDirCache[settings.localeDir] || loadLocaleMessages(settings.localeDir) + if (!localeDirCache[settings.localeDir]) { + localeDirCache[settings.localeDir] = loadLocaleMessages(settings.localeDir) + } + + return localeDirCache[settings.localeDir] } function findMissingsFromLocaleMessages (localeMessages, key) { @@ -105,17 +109,17 @@ function generateJsonAst (context, json, filename) { return ast } -function getSettings(context) { +function getSettings (context) { return context.settings['vue-i18n'] || {} } -function validateSettings(context) { +function validateSettings (context) { const settings = getSettings(context) - const isValid = !!(settings.locale || settings.localeDir || settings.messages) + const isValid = !!(settings.localeDir || settings.locales) if (!isValid) { context.report({ loc: UNEXPECTED_ERROR_LOCATION, - message: 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation', + message: 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation' }) } return isValid @@ -129,5 +133,5 @@ module.exports = { findExistLocaleMessage, extractJsonInfo, generateJsonAst, - validateSettings, + validateSettings } diff --git a/tests/lib/rules/no-missing-keys.js b/tests/lib/rules/no-missing-keys.js index 62f14bbc..fc234024 100644 --- a/tests/lib/rules/no-missing-keys.js +++ b/tests/lib/rules/no-missing-keys.js @@ -14,10 +14,9 @@ const settings = { } } -const messageSettings = { +const settingLocales = { 'vue-i18n': { - locale: 'en', - messages: { en: { hello: 'hello world' }}, + locales: [{ name: 'en', messages: { hello: 'hello world' }}] } } @@ -69,7 +68,7 @@ tester.run('no-missing-keys', rule, { ` }, { // using message settings - settings: messageSettings, + settings: settingLocales, code: `$t('hello')` }], @@ -131,7 +130,7 @@ tester.run('no-missing-keys', rule, { ] }, { // using message settings - settings: messageSettings, + settings: settingLocales, code: `$t('missing')`, errors: [ `'missing' does not exist`