Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@intlify/eslint-plugin-vue-i18n

Package Overview
Dependencies
Maintainers
2
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@intlify/eslint-plugin-vue-i18n - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

dist/rules/no-missing-keys-in-other-locales.js

25

CHANGELOG.md

@@ -0,2 +1,27 @@

Version 9 of Highlight.js has reached EOL and is no longer supported.
Please upgrade or ask whatever dependency you are using to upgrade.
https://github.com/highlightjs/highlight.js/issues/2877
## v0.10.0 (2021-01-04)
#### :star: Features
* [#149](https://github.com/intlify/eslint-plugin-vue-i18n/pull/149) Add `prefer-linked-key-with-paren` rule ([@ota-meshi](https://github.com/ota-meshi))
* [#148](https://github.com/intlify/eslint-plugin-vue-i18n/pull/148) Add `no-missing-keys-in-other-locales` rule ([@ota-meshi](https://github.com/ota-meshi))
* [#148](https://github.com/intlify/eslint-plugin-vue-i18n/pull/148) Change `no-missing-keys` rule to not report if there is one matching key ([@ota-meshi](https://github.com/ota-meshi))
* [#147](https://github.com/intlify/eslint-plugin-vue-i18n/pull/147) Add `valid-message-syntax` rule ([@ota-meshi](https://github.com/ota-meshi))
* [#145](https://github.com/intlify/eslint-plugin-vue-i18n/pull/145) Supports vue-i18n v9 message format ([@ota-meshi](https://github.com/ota-meshi))
#### :bug: Bug Fixes
* [#150](https://github.com/intlify/eslint-plugin-vue-i18n/pull/150) Fix false negatives for member expression in `no-dynamic-keys` rule ([@ota-meshi](https://github.com/ota-meshi))
#### :pencil: Documentation
* [#153](https://github.com/intlify/eslint-plugin-vue-i18n/pull/153) Replace documentation example with `vue-eslint-editor` ([@ota-meshi](https://github.com/ota-meshi))
* [#144](https://github.com/intlify/eslint-plugin-vue-i18n/pull/144) Chores: Add to documentation that eslint-plugin-jsonc and eslint-plugin-yml can be used ([@ota-meshi](https://github.com/ota-meshi))
* [#122](https://github.com/intlify/eslint-plugin-vue-i18n/pull/122) Docs: Fix typo and dead link ([@mfmfuyu](https://github.com/mfmfuyu))
#### Committers: 2
- Yosuke Ota ([@ota-meshi](https://github.com/ota-meshi))
- fuyu ([@mfmfuyu](https://github.com/mfmfuyu))
## v0.9.0 (2020-08-17)

@@ -3,0 +28,0 @@

8

dist/rules.js

@@ -9,2 +9,3 @@ "use strict";

const no_html_messages_1 = __importDefault(require("./rules/no-html-messages"));
const no_missing_keys_in_other_locales_1 = __importDefault(require("./rules/no-missing-keys-in-other-locales"));
const no_missing_keys_1 = __importDefault(require("./rules/no-missing-keys"));

@@ -14,2 +15,4 @@ const no_raw_text_1 = __importDefault(require("./rules/no-raw-text"));

const no_v_html_1 = __importDefault(require("./rules/no-v-html"));
const prefer_linked_key_with_paren_1 = __importDefault(require("./rules/prefer-linked-key-with-paren"));
const valid_message_syntax_1 = __importDefault(require("./rules/valid-message-syntax"));
module.exports = {

@@ -20,6 +23,9 @@ 'key-format-style': key_format_style_1.default,

'no-html-messages': no_html_messages_1.default,
'no-missing-keys-in-other-locales': no_missing_keys_in_other_locales_1.default,
'no-missing-keys': no_missing_keys_1.default,
'no-raw-text': no_raw_text_1.default,
'no-unused-keys': no_unused_keys_1.default,
'no-v-html': no_v_html_1.default
'no-v-html': no_v_html_1.default,
'prefer-linked-key-with-paren': prefer_linked_key_with_paren_1.default,
'valid-message-syntax': valid_message_syntax_1.default
};

243

dist/rules/key-format-style.js

@@ -11,3 +11,2 @@ "use strict";

const allowedCaseOptions = ['camelCase', 'kebab-case', 'snake_case'];
const unknownKey = Symbol('unknown key');
function create(context) {

@@ -19,3 +18,27 @@ var _a, _b;

const allowArray = (_b = context.options[1]) === null || _b === void 0 ? void 0 : _b.allowArray;
function createVisitor(targetLocaleMessage, { skipNode, resolveKey, resolveReportNode }) {
function reportUnknown(reportNode) {
context.report({
message: `Unexpected object key. Use ${expectCasing} string key instead`,
loc: reportNode.loc
});
}
function verifyKey(key, reportNode) {
if (typeof key === 'number') {
if (!allowArray) {
context.report({
message: `Unexpected array element`,
loc: reportNode.loc
});
}
}
else {
if (!checker(key)) {
context.report({
message: `"${key}" is not ${expectCasing}`,
loc: reportNode.loc
});
}
}
}
function createVisitorForJson(targetLocaleMessage) {
let keyStack = {

@@ -25,10 +48,3 @@ inLocale: targetLocaleMessage.localeKey === 'file'

return {
enterNode(node) {
if (skipNode(node)) {
return;
}
const key = resolveKey(node);
if (key == null) {
return;
}
JSONProperty(node) {
const { inLocale } = keyStack;

@@ -43,151 +59,86 @@ keyStack = {

}
if (key === unknownKey) {
context.report({
message: `Unexpected object key. Use ${expectCasing} string key instead`,
loc: resolveReportNode(node).loc
});
}
else if (typeof key === 'number') {
if (!allowArray) {
context.report({
message: `Unexpected array element`,
loc: resolveReportNode(node).loc
});
}
}
else {
if (!checker(key)) {
context.report({
message: `"${key}" is not ${expectCasing}`,
loc: resolveReportNode(node).loc
});
}
}
const key = node.key.type === 'JSONLiteral' ? `${node.key.value}` : node.key.name;
verifyKey(key, node.key);
},
leaveNode(node) {
if (keyStack.node === node) {
keyStack = keyStack.upper;
}
'JSONProperty:exit'() {
keyStack = keyStack.upper;
},
'JSONArrayExpression > *'(node) {
const key = node.parent.elements.indexOf(node);
verifyKey(key, node);
}
};
}
function createVisitorForJson(targetLocaleMessage) {
return createVisitor(targetLocaleMessage, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'JSONExpressionStatement' ||
node.type === 'JSONProperty') {
return true;
}
const parent = node.parent;
if (parent.type === 'JSONProperty' && parent.key === node) {
return true;
}
return false;
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'JSONProperty') {
return parent.key.type === 'JSONLiteral'
? `${parent.key.value}`
: parent.key.name;
}
else if (parent.type === 'JSONArrayExpression') {
return parent.elements.indexOf(node);
}
return null;
},
resolveReportNode(node) {
const parent = node.parent;
return parent.type === 'JSONProperty' ? parent.key : node;
}
});
}
function createVisitorForYaml(targetLocaleMessage) {
const yamlKeyNodes = new Set();
return createVisitor(targetLocaleMessage, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'YAMLDocument' ||
node.type === 'YAMLDirective' ||
node.type === 'YAMLAnchor' ||
node.type === 'YAMLTag') {
let keyStack = {
inLocale: targetLocaleMessage.localeKey === 'file'
};
function withinKey(node) {
for (const keyNode of yamlKeyNodes) {
if (keyNode.range[0] <= node.range[0] &&
node.range[0] < keyNode.range[1]) {
return true;
}
if (yamlKeyNodes.has(node)) {
return true;
}
return false;
}
return {
YAMLPair(node) {
const { inLocale } = keyStack;
keyStack = {
node,
inLocale: true,
upper: keyStack
};
if (!inLocale) {
return;
}
const parent = node.parent;
if (yamlKeyNodes.has(parent)) {
yamlKeyNodes.add(node);
return true;
}
if (node.type === 'YAMLPair') {
if (node.key != null) {
if (withinKey(node)) {
return;
}
yamlKeyNodes.add(node.key);
return true;
}
return false;
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'YAMLPair') {
if (parent.key == null) {
return unknownKey;
}
if (parent.key.type === 'YAMLScalar') {
const key = parent.key.value;
return typeof key === 'string' ? key : String(key);
}
return unknownKey;
if (node.key == null) {
reportUnknown(node);
}
else if (parent.type === 'YAMLSequence') {
return parent.entries.indexOf(node);
else if (node.key.type === 'YAMLScalar') {
const keyValue = node.key.value;
const key = typeof keyValue === 'string' ? keyValue : String(keyValue);
verifyKey(key, node.key);
}
return null;
else {
reportUnknown(node);
}
},
resolveReportNode(node) {
const parent = node.parent;
return parent.type === 'YAMLPair' ? parent.key || parent : node;
}
});
}
if (path_1.extname(filename) === '.vue') {
return {
Program() {
const documentFragment = context.parserServices.getDocumentFragment &&
context.parserServices.getDocumentFragment();
const i18nBlocks = (documentFragment &&
documentFragment.children.filter((node) => node.type === 'VElement' && node.name === 'i18n')) ||
[];
if (!i18nBlocks.length) {
'YAMLPair:exit'() {
keyStack = keyStack.upper;
},
'YAMLSequence > *'(node) {
if (withinKey(node)) {
return;
}
const localeMessages = index_1.getLocaleMessages(context);
for (const block of i18nBlocks) {
if (block.startTag.attributes.some(attr => !attr.directive && attr.key.name === 'src')) {
continue;
}
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(block);
if (!targetLocaleMessage) {
continue;
}
const parserLang = targetLocaleMessage.getParserLang();
let visitor;
if (parserLang === 'json') {
visitor = createVisitorForJson(targetLocaleMessage);
}
else if (parserLang === 'yaml') {
visitor = createVisitorForYaml(targetLocaleMessage);
}
if (visitor == null) {
return;
}
targetLocaleMessage.traverseNodes({
enterNode: visitor.enterNode,
leaveNode: visitor.leaveNode
});
}
const key = node.parent.entries.indexOf(node);
verifyKey(key, node);
}
};
}
if (path_1.extname(filename) === '.vue') {
return index_1.defineCustomBlocksVisitor(context, ctx => {
const localeMessages = index_1.getLocaleMessages(context);
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(ctx.parserServices.customBlock);
if (!targetLocaleMessage) {
return {};
}
return createVisitorForJson(targetLocaleMessage);
}, ctx => {
const localeMessages = index_1.getLocaleMessages(context);
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(ctx.parserServices.customBlock);
if (!targetLocaleMessage) {
return {};
}
return createVisitorForYaml(targetLocaleMessage);
});
}
else if (context.parserServices.isJSON || context.parserServices.isYAML) {

@@ -201,14 +152,6 @@ const localeMessages = index_1.getLocaleMessages(context);

if (context.parserServices.isJSON) {
const { enterNode, leaveNode } = createVisitorForJson(targetLocaleMessage);
return {
'[type=/^JSON/]': enterNode,
'[type=/^JSON/]:exit': leaveNode
};
return createVisitorForJson(targetLocaleMessage);
}
else if (context.parserServices.isYAML) {
const { enterNode, leaveNode } = createVisitorForYaml(targetLocaleMessage);
return {
'[type=/^YAML/]': enterNode,
'[type=/^YAML/]:exit': leaveNode
};
return createVisitorForYaml(targetLocaleMessage);
}

@@ -215,0 +158,0 @@ return {};

@@ -12,3 +12,3 @@ "use strict";

if (fullPath.startsWith(process.cwd())) {
return fullPath.replace(process.cwd(), '.');
return fullPath.replace(process.cwd() + '/', './');
}

@@ -21,20 +21,10 @@ return fullPath;

const ignoreI18nBlock = Boolean(options.ignoreI18nBlock);
function createVisitor(targetLocaleMessage, otherLocaleMessages, { skipNode, resolveKey, resolveReportNode }) {
let pathStack;
function createInitPathStack(targetLocaleMessage, otherLocaleMessages) {
if (targetLocaleMessage.localeKey === 'file') {
const locale = targetLocaleMessage.locales[0];
pathStack = {
keyPath: '',
locale,
otherDictionaries: otherLocaleMessages.map(lm => {
return {
dict: lm.getMessagesFromLocale(locale),
source: lm
};
})
};
return createInitLocalePathStack(locale, otherLocaleMessages);
}
else {
pathStack = {
keyPath: '',
return {
keyPath: [],
locale: null,

@@ -44,28 +34,29 @@ otherDictionaries: []

}
}
function createInitLocalePathStack(locale, otherLocaleMessages) {
return {
keyPath: [],
locale,
otherDictionaries: otherLocaleMessages.map(lm => {
return {
dict: lm.getMessagesFromLocale(locale),
source: lm
};
})
};
}
function createVerifyContext(targetLocaleMessage, otherLocaleMessages) {
let pathStack = createInitPathStack(targetLocaleMessage, otherLocaleMessages);
const existsKeyNodes = {};
const existsLocaleNodes = {};
function pushKey(exists, key, reportNode) {
const keyNodes = exists[key] || (exists[key] = []);
keyNodes.push(reportNode);
}
return {
enterNode(node) {
if (skipNode(node)) {
return;
}
const key = resolveKey(node);
if (key == null) {
return;
}
enterKey(key, reportNode) {
if (pathStack.locale == null) {
const locale = key;
verifyDupeKey(existsLocaleNodes, locale, node);
pathStack = {
upper: pathStack,
node,
keyPath: '',
locale,
otherDictionaries: otherLocaleMessages.map(lm => {
return {
dict: lm.getMessagesFromLocale(locale),
source: lm
};
})
};
pushKey(existsLocaleNodes, locale, reportNode);
pathStack = Object.assign({ upper: pathStack, node: reportNode }, createInitLocalePathStack(locale, otherLocaleMessages));
return;

@@ -81,9 +72,9 @@ }

});
const keyPath = key_path_1.joinPath(pathStack.keyPath, key);
const keyPath = [...pathStack.keyPath, key];
const keyPathStr = key_path_1.joinPath(...keyPath);
const nextOtherDictionaries = [];
for (const value of keyOtherValues) {
if (typeof value.value === 'string') {
const reportNode = resolveReportNode(node);
context.report({
message: `duplicate key '${keyPath}' in '${pathStack.locale}'. "${getMessageFilepath(value.source.fullpath)}" has the same key`,
message: `duplicate key '${keyPathStr}' in '${pathStack.locale}'. "${getMessageFilepath(value.source.fullpath)}" has the same key`,
loc: reportNode.loc

@@ -99,7 +90,7 @@ });

}
verifyDupeKey(existsKeyNodes[pathStack.locale] ||
(existsKeyNodes[pathStack.locale] = {}), keyPath, node);
pushKey(existsKeyNodes[pathStack.locale] ||
(existsKeyNodes[pathStack.locale] = {}), keyPathStr, reportNode);
pathStack = {
upper: pathStack,
node,
node: reportNode,
keyPath,

@@ -110,147 +101,117 @@ locale: pathStack.locale,

},
leaveNode(node) {
leaveKey(node) {
if (pathStack.node === node) {
pathStack = pathStack.upper;
}
},
reports() {
for (const localeNodes of [
existsLocaleNodes,
...Object.values(existsKeyNodes)
]) {
for (const key of Object.keys(localeNodes)) {
const keyNodes = localeNodes[key];
if (keyNodes.length > 1) {
for (const keyNode of keyNodes) {
context.report({
message: `duplicate key '${key}'`,
loc: keyNode.loc
});
}
}
}
}
}
};
function verifyDupeKey(exists, key, node) {
const keyNodes = exists[key] || (exists[key] = []);
keyNodes.push({
node,
reported: false
});
if (keyNodes.length > 1) {
for (const keyNode of keyNodes.filter(e => !e.reported)) {
const reportNode = resolveReportNode(keyNode.node);
context.report({
message: `duplicate key '${key}'`,
loc: reportNode.loc
});
keyNode.reported = true;
}
}
}
}
function createVisitorForJson(_sourceCode, targetLocaleMessage, otherLocaleMessages) {
return createVisitor(targetLocaleMessage, otherLocaleMessages, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'JSONExpressionStatement' ||
node.type === 'JSONProperty') {
return true;
}
const parent = node.parent;
if (parent.type === 'JSONProperty' && parent.key === node) {
return true;
}
return false;
const verifyContext = createVerifyContext(targetLocaleMessage, otherLocaleMessages);
return {
JSONProperty(node) {
const key = node.key.type === 'JSONLiteral' ? `${node.key.value}` : node.key.name;
verifyContext.enterKey(key, node.key);
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'JSONProperty') {
return parent.key.type === 'JSONLiteral'
? `${parent.key.value}`
: parent.key.name;
}
else if (parent.type === 'JSONArrayExpression') {
return parent.elements.indexOf(node);
}
return null;
'JSONProperty:exit'(node) {
verifyContext.leaveKey(node.key);
},
resolveReportNode(node) {
const parent = node.parent;
return parent.type === 'JSONProperty' ? parent.key : node;
'JSONArrayExpression > *'(node) {
const key = node.parent.elements.indexOf(node);
verifyContext.enterKey(key, node);
},
'JSONArrayExpression > *:exit'(node) {
verifyContext.leaveKey(node);
},
'Program:exit'() {
verifyContext.reports();
}
});
};
}
function createVisitorForYaml(sourceCode, targetLocaleMessage, otherLocaleMessages) {
const verifyContext = createVerifyContext(targetLocaleMessage, otherLocaleMessages);
const yamlKeyNodes = new Set();
return createVisitor(targetLocaleMessage, otherLocaleMessages, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'YAMLDocument' ||
node.type === 'YAMLDirective' ||
node.type === 'YAMLAnchor' ||
node.type === 'YAMLTag') {
function withinKey(node) {
for (const keyNode of yamlKeyNodes) {
if (keyNode.range[0] <= node.range[0] &&
node.range[0] < keyNode.range[1]) {
return true;
}
if (yamlKeyNodes.has(node)) {
return true;
}
const parent = node.parent;
if (yamlKeyNodes.has(parent)) {
yamlKeyNodes.add(node);
return true;
}
if (node.type === 'YAMLPair') {
}
return false;
}
return {
YAMLPair(node) {
if (node.key != null) {
if (withinKey(node)) {
return;
}
yamlKeyNodes.add(node.key);
return true;
}
return false;
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'YAMLPair' && parent.key) {
const key = parent.key.type !== 'YAMLScalar'
? sourceCode.getText(parent.key)
: parent.key.value;
return typeof key === 'boolean' || key === null ? String(key) : key;
else {
return;
}
else if (parent.type === 'YAMLSequence') {
return parent.entries.indexOf(node);
}
return null;
const keyValue = node.key.type !== 'YAMLScalar'
? sourceCode.getText(node.key)
: node.key.value;
const key = typeof keyValue === 'boolean' || keyValue === null
? String(keyValue)
: keyValue;
verifyContext.enterKey(key, node.key);
},
resolveReportNode(node) {
const parent = node.parent;
return parent.type === 'YAMLPair' ? parent.key || parent : node;
'YAMLPair:exit'(node) {
verifyContext.leaveKey(node.key);
},
'YAMLSequence > *'(node) {
const key = node.parent.entries.indexOf(node);
verifyContext.enterKey(key, node);
},
'YAMLSequence > *:exit'(node) {
verifyContext.leaveKey(node);
},
'Program:exit'() {
verifyContext.reports();
}
});
};
}
if (path_1.extname(filename) === '.vue') {
return {
Program() {
const documentFragment = context.parserServices.getDocumentFragment &&
context.parserServices.getDocumentFragment();
const i18nBlocks = (documentFragment &&
documentFragment.children.filter((node) => node.type === 'VElement' && node.name === 'i18n')) ||
[];
if (!i18nBlocks.length) {
return;
}
const localeMessages = index_1.getLocaleMessages(context);
for (const block of i18nBlocks) {
if (block.startTag.attributes.some(attr => !attr.directive && attr.key.name === 'src')) {
continue;
}
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(block);
if (!targetLocaleMessage) {
continue;
}
const sourceCode = targetLocaleMessage.getSourceCode();
if (!sourceCode) {
continue;
}
const otherLocaleMessages = ignoreI18nBlock
? []
: localeMessages.localeMessages.filter(lm => lm !== targetLocaleMessage);
const parserLang = targetLocaleMessage.getParserLang();
let visitor;
if (parserLang === 'json') {
visitor = createVisitorForJson(sourceCode, targetLocaleMessage, otherLocaleMessages);
}
else if (parserLang === 'yaml') {
visitor = createVisitorForYaml(sourceCode, targetLocaleMessage, otherLocaleMessages);
}
if (visitor == null) {
return;
}
targetLocaleMessage.traverseNodes({
enterNode: visitor.enterNode,
leaveNode: visitor.leaveNode
});
}
return index_1.defineCustomBlocksVisitor(context, ctx => {
const localeMessages = index_1.getLocaleMessages(context);
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(ctx.parserServices.customBlock);
if (!targetLocaleMessage) {
return {};
}
};
const otherLocaleMessages = ignoreI18nBlock
? []
: localeMessages.localeMessages.filter(lm => lm !== targetLocaleMessage);
return createVisitorForJson(ctx.getSourceCode(), targetLocaleMessage, otherLocaleMessages);
}, ctx => {
const localeMessages = index_1.getLocaleMessages(context);
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(ctx.parserServices.customBlock);
if (!targetLocaleMessage) {
return {};
}
const otherLocaleMessages = ignoreI18nBlock
? []
: localeMessages.localeMessages.filter(lm => lm !== targetLocaleMessage);
return createVisitorForYaml(ctx.getSourceCode(), targetLocaleMessage, otherLocaleMessages);
});
}

@@ -267,14 +228,6 @@ else if (context.parserServices.isJSON || context.parserServices.isYAML) {

if (context.parserServices.isJSON) {
const { enterNode, leaveNode } = createVisitorForJson(sourceCode, targetLocaleMessage, otherLocaleMessages);
return {
'[type=/^JSON/]': enterNode,
'[type=/^JSON/]:exit': leaveNode
};
return createVisitorForJson(sourceCode, targetLocaleMessage, otherLocaleMessages);
}
else if (context.parserServices.isYAML) {
const { enterNode, leaveNode } = createVisitorForYaml(sourceCode, targetLocaleMessage, otherLocaleMessages);
return {
'[type=/^YAML/]': enterNode,
'[type=/^YAML/]:exit': leaveNode
};
return createVisitorForYaml(sourceCode, targetLocaleMessage, otherLocaleMessages);
}

@@ -281,0 +234,0 @@ return {};

"use strict";
const index_1 = require("../utils/index");
function isStatic(node) {
if (node.type === 'Literal') {
return true;
}
if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {
return true;
}
return false;
}
function getNodeName(context, node) {
if (node.type === 'Identifier') {
return node.name;
}
const sourceCode = context.getSourceCode();
if (sourceCode.ast.range[0] <= node.range[0] &&
node.range[1] <= sourceCode.ast.range[1]) {
return sourceCode
.getTokens(node)
.map(t => t.value)
.join('');
}
const tokenStore = context.parserServices.getTemplateBodyTokenStore();
return tokenStore
.getTokens(node)
.map(t => t.value)
.join('');
}
function checkDirective(context, node) {

@@ -7,4 +34,4 @@ if (node.value &&

node.value.expression &&
node.value.expression.type === 'Identifier') {
const name = node.value.expression.name;
!isStatic(node.value.expression)) {
const name = getNodeName(context, node.value.expression);
context.report({

@@ -17,3 +44,2 @@ node,

function checkComponent(context, node) {
const parent = node.parent;
if (node.name.type === 'VIdentifier' &&

@@ -24,7 +50,7 @@ node.name.name === 'bind' &&

node.argument.name === 'path' &&
parent.value &&
parent.value.type === 'VExpressionContainer' &&
parent.value.expression &&
parent.value.expression.type === 'Identifier') {
const name = parent.value.expression.name;
node.parent.value &&
node.parent.value.type === 'VExpressionContainer' &&
node.parent.value.expression &&
!isStatic(node.parent.value.expression)) {
const name = getNodeName(context, node.parent.value.expression);
context.report({

@@ -48,4 +74,4 @@ node,

const [keyNode] = node.arguments;
if (keyNode.type === 'Identifier') {
const name = keyNode.name;
if (!isStatic(keyNode)) {
const name = getNodeName(context, keyNode);
context.report({

@@ -52,0 +78,0 @@ node,

@@ -68,36 +68,11 @@ "use strict";

if (path_1.extname(filename) === '.vue') {
return {
Program() {
const documentFragment = context.parserServices.getDocumentFragment &&
context.parserServices.getDocumentFragment();
const i18nBlocks = (documentFragment &&
documentFragment.children.filter((node) => node.type === 'VElement' && node.name === 'i18n')) ||
[];
if (!i18nBlocks.length) {
return;
}
const localeMessages = index_1.getLocaleMessages(context);
for (const block of i18nBlocks) {
if (block.startTag.attributes.some(attr => !attr.directive && attr.key.name === 'src')) {
continue;
}
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(block);
if (!targetLocaleMessage) {
continue;
}
targetLocaleMessage.traverseNodes({
enterNode(node) {
if (node.type === 'JSONLiteral') {
verifyJSONLiteral(node);
}
else if (node.type === 'YAMLScalar') {
verifyYAMLScalar(node);
}
},
leaveNode() {
}
});
}
}
};
return index_1.defineCustomBlocksVisitor(context, () => {
return {
JSONLiteral: verifyJSONLiteral
};
}, () => {
return {
YAMLScalar: verifyYAMLScalar
};
});
}

@@ -104,0 +79,0 @@ else if (context.parserServices.isJSON) {

@@ -39,5 +39,9 @@ "use strict";

}
const missings = localeMessages.findMissingPaths(String(key));
if (missings.length) {
missings.forEach(data => context.report({ node, messageId: 'missing', data }));
const missingPath = localeMessages.findMissingPath(String(key));
if (missingPath) {
context.report({
node,
messageId: 'missing',
data: { path: missingPath }
});
}

@@ -56,5 +60,9 @@ }

}
const missings = localeMessages.findMissingPaths(key);
if (missings.length) {
missings.forEach(data => context.report({ node, messageId: 'missing', data }));
const missingPath = localeMessages.findMissingPath(key);
if (missingPath) {
context.report({
node,
messageId: 'missing',
data: { path: missingPath }
});
}

@@ -86,5 +94,5 @@ }

}
const missings = localeMessages.findMissingPaths(String(key));
if (missings.length) {
missings.forEach(data => context.report({ node, messageId: 'missing', data }));
const missingPath = localeMessages.findMissingPath(String(key));
if (missingPath) {
context.report({ node, messageId: 'missing', data: { path: missingPath } });
}

@@ -103,3 +111,3 @@ }

messages: {
missing: "'{{path}}' does not exist in '{{locale}}'"
missing: "'{{path}}' does not exist in localization message resources"
}

@@ -106,0 +114,0 @@ },

@@ -15,5 +15,5 @@ "use strict";

}
function getUsedKeysMap(targetLocaleMessage, values, usedkeys) {
function getUsedKeysMap(targetLocaleMessage, values, usedkeys, context) {
const usedKeysMap = {};
for (const key of [...usedkeys, ...collect_linked_keys_1.collectLinkedKeys(values)]) {
for (const key of [...usedkeys, ...collect_linked_keys_1.collectLinkedKeys(values, context)]) {
const paths = key.split('.');

@@ -38,18 +38,11 @@ let map = usedKeysMap;

const enableFix = options.enableFix;
function createVisitor(usedKeys, { skipNode, resolveKey, resolveReportNode, buildFixer, buildAllFixer }) {
let pathStack = { usedKeys, keyPath: '' };
function createVerifyContext(usedKeys, { buildFixer, buildAllFixer }) {
let pathStack = { usedKeys, keyPath: [] };
const reports = [];
return {
enterNode(node) {
if (skipNode(node)) {
return;
}
const key = resolveKey(node);
if (key == null) {
return;
}
const keyPath = key_path_1.joinPath(pathStack.keyPath, key);
enterKey(key, reportNode, ignoreReport) {
const keyPath = [...pathStack.keyPath, key];
pathStack = {
upper: pathStack,
node,
node: reportNode,
usedKeys: (pathStack.usedKeys && pathStack.usedKeys[key]) ||

@@ -61,14 +54,11 @@ false,

if (isUnused) {
const reportNode = resolveReportNode(node);
if (reportNode == null) {
return;
}
reports.push({
node: reportNode,
keyPath
});
if (!ignoreReport)
reports.push({
node: reportNode,
keyPath
});
}
},
leaveNode(node) {
if (pathStack.node === node) {
leaveKey(reportNode) {
if (pathStack.node === reportNode) {
pathStack = pathStack.upper;

@@ -79,5 +69,6 @@ }

for (const { node, keyPath } of reports) {
const keyPathStr = key_path_1.joinPath(...keyPath);
const fix = buildFixer(node);
context.report({
message: `unused '${keyPath}' key`,
message: `unused '${keyPathStr}' key`,
loc: node.loc,

@@ -87,3 +78,3 @@ fix: enableFix ? fix : null,

{
desc: `Remove the '${keyPath}' key.`,
desc: `Remove the '${keyPathStr}' key.`,
fix

@@ -104,35 +95,3 @@ },

function createVisitorForJson(sourceCode, usedKeys) {
return createVisitor(usedKeys, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'JSONExpressionStatement' ||
node.type === 'JSONProperty') {
return true;
}
const parent = node.parent;
if (parent.type === 'JSONProperty' && parent.key === node) {
return true;
}
return false;
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'JSONProperty') {
return parent.key.type === 'JSONLiteral'
? `${parent.key.value}`
: parent.key.name;
}
else if (parent.type === 'JSONArrayExpression') {
return parent.elements.indexOf(node);
}
return null;
},
resolveReportNode(node) {
if (node.type === 'JSONObjectExpression' ||
node.type === 'JSONArrayExpression') {
return null;
}
const parent = node.parent;
return parent.type === 'JSONProperty' ? parent.key : node;
},
const verifyContext = createVerifyContext(usedKeys, {
buildFixer(node) {

@@ -147,2 +106,25 @@ return fixer => fixer.removeRange(fixRemoveRange(node));

});
function isIgnore(node) {
return (node.type === 'JSONArrayExpression' ||
node.type === 'JSONObjectExpression');
}
return {
JSONProperty(node) {
const key = node.key.type === 'JSONLiteral' ? `${node.key.value}` : node.key.name;
verifyContext.enterKey(key, node.key, isIgnore(node.value));
},
'JSONProperty:exit'(node) {
verifyContext.leaveKey(node.key);
},
'JSONArrayExpression > *'(node) {
const key = node.parent.elements.indexOf(node);
verifyContext.enterKey(key, node, isIgnore(node));
},
'JSONArrayExpression > *:exit'(node) {
verifyContext.leaveKey(node);
},
'Program:exit'() {
verifyContext.reports();
}
};
function* fixAllRemoveKeys(fixer, nodes) {

@@ -195,46 +177,3 @@ const ranges = nodes.map(node => fixRemoveRange(node));

function createVisitorForYaml(sourceCode, usedKeys) {
const yamlKeyNodes = new Set();
return createVisitor(usedKeys, {
skipNode(node) {
if (node.type === 'Program' ||
node.type === 'YAMLDocument' ||
node.type === 'YAMLDirective' ||
node.type === 'YAMLAnchor' ||
node.type === 'YAMLTag') {
return true;
}
if (yamlKeyNodes.has(node)) {
return true;
}
const parent = node.parent;
if (yamlKeyNodes.has(parent)) {
yamlKeyNodes.add(node);
return true;
}
if (node.type === 'YAMLPair') {
yamlKeyNodes.add(node.key);
return true;
}
return false;
},
resolveKey(node) {
const parent = node.parent;
if (parent.type === 'YAMLPair' && parent.key) {
const key = parent.key.type !== 'YAMLScalar'
? sourceCode.getText(parent.key)
: parent.key.value;
return typeof key === 'boolean' || key === null ? String(key) : key;
}
else if (parent.type === 'YAMLSequence') {
return parent.entries.indexOf(node);
}
return null;
},
resolveReportNode(node) {
if (node.type === 'YAMLMapping' || node.type === 'YAMLSequence') {
return null;
}
const parent = node.parent;
return parent.type === 'YAMLPair' ? parent.key : node;
},
const verifyContext = createVerifyContext(usedKeys, {
buildFixer(node) {

@@ -288,3 +227,3 @@ return function* (fixer) {

else if (parent.type === 'YAMLSequence') {
if (parent.entries.every(p => removeNodes.includes(p))) {
if (parent.entries.every(p => p && removeNodes.includes(p))) {
const before = sourceCode.getTokenBefore(parent);

@@ -312,2 +251,48 @@ if (before) {

});
const yamlKeyNodes = new Set();
function withinKey(node) {
for (const keyNode of yamlKeyNodes) {
if (keyNode.range[0] <= node.range[0] &&
node.range[0] < keyNode.range[1]) {
return true;
}
}
return false;
}
function isIgnore(node) {
return Boolean(node && (node.type === 'YAMLMapping' || node.type === 'YAMLSequence'));
}
return {
YAMLPair(node) {
if (node.key != null) {
if (withinKey(node)) {
return;
}
yamlKeyNodes.add(node.key);
}
else {
return;
}
const keyValue = node.key.type !== 'YAMLScalar'
? sourceCode.getText(node.key)
: node.key.value;
const key = typeof keyValue === 'boolean' || keyValue === null
? String(keyValue)
: keyValue;
verifyContext.enterKey(key, node.key, isIgnore(node.value));
},
'YAMLPair:exit'(node) {
verifyContext.leaveKey(node.key);
},
'YAMLSequence > *'(node) {
const key = node.parent.entries.indexOf(node);
verifyContext.enterKey(key, node, isIgnore(node));
},
'YAMLSequence > *:exit'(node) {
verifyContext.leaveKey(node);
},
'Program:exit'() {
verifyContext.reports();
}
};
function* fixForBlock(fixer, removeNode) {

@@ -391,46 +376,15 @@ const parent = removeNode.parent;

if (path_1.extname(filename) === '.vue') {
return {
Program(node) {
const documentFragment = context.parserServices.getDocumentFragment &&
context.parserServices.getDocumentFragment();
const i18nBlocks = (documentFragment &&
documentFragment.children.filter((node) => node.type === 'VElement' && node.name === 'i18n')) ||
[];
if (!i18nBlocks.length) {
return;
}
const createCustomBlockRule = (createVisitor) => {
return ctx => {
const localeMessages = index_1.getLocaleMessages(context);
const usedLocaleMessageKeys = collect_keys_1.collectKeysFromAST(node, context.getSourceCode().visitorKeys);
for (const block of i18nBlocks) {
if (block.startTag.attributes.some(attr => !attr.directive && attr.key.name === 'src')) {
continue;
}
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(block);
if (!targetLocaleMessage) {
continue;
}
const sourceCode = targetLocaleMessage.getSourceCode();
if (!sourceCode) {
continue;
}
const usedKeys = getUsedKeysMap(targetLocaleMessage, targetLocaleMessage.messages, usedLocaleMessageKeys);
const parserLang = targetLocaleMessage.getParserLang();
let visitor;
if (parserLang === 'json') {
visitor = createVisitorForJson(sourceCode, usedKeys);
}
else if (parserLang === 'yaml') {
visitor = createVisitorForYaml(sourceCode, usedKeys);
}
if (visitor == null) {
return;
}
targetLocaleMessage.traverseNodes({
enterNode: visitor.enterNode,
leaveNode: visitor.leaveNode
});
visitor.reports();
const usedLocaleMessageKeys = collect_keys_1.collectKeysFromAST(context.getSourceCode().ast, context.getSourceCode().visitorKeys);
const targetLocaleMessage = localeMessages.findBlockLocaleMessage(ctx.parserServices.customBlock);
if (!targetLocaleMessage) {
return {};
}
}
const usedKeys = getUsedKeysMap(targetLocaleMessage, targetLocaleMessage.messages, usedLocaleMessageKeys, context);
return createVisitor(ctx.getSourceCode(), usedKeys);
};
};
return index_1.defineCustomBlocksVisitor(context, createCustomBlockRule(createVisitorForJson), createCustomBlockRule(createVisitorForYaml));
}

@@ -448,22 +402,8 @@ else if (context.parserServices.isJSON || context.parserServices.isYAML) {

const sourceCode = context.getSourceCode();
const usedKeys = getUsedKeysMap(targetLocaleMessage, targetLocaleMessage.messages, usedLocaleMessageKeys);
const usedKeys = getUsedKeysMap(targetLocaleMessage, targetLocaleMessage.messages, usedLocaleMessageKeys, context);
if (context.parserServices.isJSON) {
const { enterNode, leaveNode, reports } = createVisitorForJson(sourceCode, usedKeys);
return {
'[type=/^JSON/]': enterNode,
'[type=/^JSON/]:exit': leaveNode,
'Program:exit'() {
reports();
}
};
return createVisitorForJson(sourceCode, usedKeys);
}
else if (context.parserServices.isYAML) {
const { enterNode, leaveNode, reports } = createVisitorForYaml(sourceCode, usedKeys);
return {
'[type=/^YAML/]': enterNode,
'[type=/^YAML/]:exit': leaveNode,
'Program:exit'() {
reports();
}
};
return createVisitorForYaml(sourceCode, usedKeys);
}

@@ -470,0 +410,0 @@ return {};

@@ -10,3 +10,3 @@ "use strict";

var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};

@@ -13,0 +13,0 @@ Object.defineProperty(exports, "__esModule", { value: true });

@@ -17,3 +17,3 @@ "use strict";

var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);

@@ -20,0 +20,0 @@ return result;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.collectLinkedKeys = void 0;
const linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
const linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
const bracketsMatcher = /[()]/g;
function* extractUsedKeysFromLinks(object) {
const traverser_1 = require("./message-compiler/traverser");
const parser_1 = require("./message-compiler/parser");
const parser_v8_1 = require("./message-compiler/parser-v8");
const utils_1 = require("./message-compiler/utils");
function* extractUsedKeysFromLinks(object, messageSyntaxVersions) {
for (const value of Object.values(object)) {

@@ -13,23 +14,36 @@ if (!value) {

if (typeof value === 'object') {
yield* extractUsedKeysFromLinks(value);
yield* extractUsedKeysFromLinks(value, messageSyntaxVersions);
}
else if (typeof value === 'string') {
if (value.indexOf('@:') >= 0 || value.indexOf('@.') >= 0) {
const matches = value.match(linkKeyMatcher);
for (const idx in matches) {
const link = matches[idx];
const linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
const [linkPrefix] = linkKeyPrefixMatches;
const linkPlaceholder = link
.replace(linkPrefix, '')
.replace(bracketsMatcher, '');
yield linkPlaceholder;
}
if (messageSyntaxVersions.v9) {
yield* extractUsedKeysFromAST(parser_1.parse(value).ast);
}
if (messageSyntaxVersions.v8) {
yield* extractUsedKeysFromAST(parser_v8_1.parse(value).ast);
}
}
}
}
function collectLinkedKeys(object) {
return [...new Set(extractUsedKeysFromLinks(object))];
function collectLinkedKeys(object, context) {
return [
...new Set(extractUsedKeysFromLinks(object, utils_1.getMessageSyntaxVersions(context)))
].filter(s => !!s);
}
exports.collectLinkedKeys = collectLinkedKeys;
function extractUsedKeysFromAST(ast) {
const keys = new Set();
traverser_1.traverseNode(ast, node => {
if (node.type === 6) {
if (node.key.type === 7) {
keys.add(node.key.value);
}
else if (node.key.type === 9) {
keys.add(node.key.value);
}
else if (node.key.type === 5) {
keys.add(String(node.key.index));
}
}
});
return keys;
}
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -6,3 +25,3 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocaleMessages = exports.defineTemplateBodyVisitor = void 0;
exports.defineCustomBlocksVisitor = exports.getLocaleMessages = exports.defineTemplateBodyVisitor = void 0;
const glob_1 = __importDefault(require("glob"));

@@ -13,2 +32,4 @@ const path_1 = require("path");

const cache_function_1 = require("./cache-function");
const jsoncESLintParser = __importStar(require("jsonc-eslint-parser"));
const yamlESLintParser = __importStar(require("yaml-eslint-parser"));
const UNEXPECTED_ERROR_LOCATION = { line: 1, column: 0 };

@@ -171,1 +192,43 @@ function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor) {

}
function defineCustomBlocksVisitor(context, jsonRule, yamlRule) {
if (!context.parserServices.defineCustomBlocksVisitor) {
return {};
}
const jsonVisitor = context.parserServices.defineCustomBlocksVisitor(context, jsoncESLintParser, {
target(lang, block) {
if (block.name !== 'i18n') {
return false;
}
return !lang || lang === 'json' || lang === 'json5';
},
create: jsonRule
});
const yamlVisitor = context.parserServices.defineCustomBlocksVisitor(context, yamlESLintParser, {
target(lang, block) {
if (block.name !== 'i18n') {
return false;
}
return lang === 'yaml' || lang === 'yml';
},
create: yamlRule
});
return compositingVisitors(jsonVisitor, yamlVisitor);
}
exports.defineCustomBlocksVisitor = defineCustomBlocksVisitor;
function compositingVisitors(visitor, ...visitors) {
for (const v of visitors) {
for (const key in v) {
if (visitor[key]) {
const o = visitor[key];
visitor[key] = (...args) => {
o(...args);
v[key](...args);
};
}
else {
visitor[key] = v[key];
}
}
}
return visitor;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.joinPath = void 0;
function joinPath(base, ...paths) {
let result = base;
function joinPath(...paths) {
let result = '';
for (const p of paths) {

@@ -7,0 +7,0 @@ if (typeof p === 'number') {

@@ -13,2 +13,3 @@ "use strict";

const js_yaml_1 = __importDefault(require("js-yaml"));
const key_path_1 = require("./key-path");
class LocaleMessage {

@@ -37,20 +38,2 @@ constructor({ fullpath, locales, localeKey }) {

}
hasMessage(locale, key) {
return this.getMessage(locale, key) != null;
}
getMessage(locale, key) {
const paths = key.split('.');
const length = paths.length;
let last = this.getMessagesFromLocale(locale);
let i = 0;
while (i < length) {
const value = last && typeof last !== 'string' ? last[paths[i]] : undefined;
if (value == null) {
return null;
}
last = value;
i++;
}
return last !== null && last !== void 0 ? last : null;
}
getMessagesFromLocale(locale) {

@@ -71,3 +54,3 @@ if (this.localeKey === 'file') {

class BlockLocaleMessage extends LocaleMessage {
constructor({ block, fullpath, locales, localeKey, context, lang = 'json' }) {
constructor({ block, fullpath, locales, localeKey, lang = 'json' }) {
super({

@@ -78,5 +61,3 @@ fullpath,

});
this._parsed = null;
this._messages = null;
this.context = context;
this.block = block;

@@ -89,48 +70,13 @@ this.lang = lang || 'json';

}
const parsed = this._getParsed();
if (!parsed) {
return {};
}
return (this._messages = parsed.getStaticValue(parsed.ast));
}
getAST() {
const parsed = this._getParsed();
if (!parsed) {
return null;
}
return parsed.ast;
}
getParserLang() {
const parsed = this._getParsed();
if (!parsed) {
return null;
}
return parsed.lang;
}
traverseNodes(visitor) {
const parsed = this._getParsed();
if (!parsed) {
return;
}
parsed.traverseNodes(parsed.ast, visitor);
}
getSourceCode() {
const parsed = this._getParsed();
if (!parsed) {
return null;
}
return parsed.getSourceCode();
}
_getParsed() {
if (this._parsed) {
return this._parsed;
}
const { lang } = this;
if (lang === 'json' || lang === 'json5') {
return (this._parsed = parsers_1.parseJsonInI18nBlock(this.context, this.block));
this._messages = parsers_1.parseJsonValuesInI18nBlock(this.block) || {};
}
else if (lang === 'yaml' || lang === 'yml') {
return (this._parsed = parsers_1.parseYamlInI18nBlock(this.context, this.block));
this._messages = parsers_1.parseYamlValuesInI18nBlock(this.block) || {};
}
return null;
else {
this._messages = {};
}
return this._messages;
}

@@ -148,3 +94,3 @@ }

const ext = path_1.extname(fileName).toLowerCase();
if (ext === '.json' || ext === '.js') {
if (ext === '.js') {
const key = require.resolve(fileName);

@@ -157,3 +103,3 @@ delete require.cache[key];

}
else if (ext === '.json5') {
else if (ext === '.json' || ext === '.json5') {
return json5_1.default.parse(fs_1.default.readFileSync(fileName, 'utf8'));

@@ -190,4 +136,4 @@ }

}
findMissingPaths(key) {
const missings = [];
findMissingPath(key) {
let missingPath = [];
for (const locale of this.locales) {

@@ -198,2 +144,3 @@ const paths = key.split('.');

let i = 0;
let missing = false;
while (i < length) {

@@ -206,6 +153,6 @@ const values = lasts

if (values.length === 0) {
missings.push({
locale,
path: paths.slice(0, i + 1).join('.')
});
if (missingPath.length <= i) {
missingPath = paths.slice(0, i + 1);
}
missing = true;
break;

@@ -216,6 +163,9 @@ }

}
if (!missing) {
return null;
}
}
return missings.sort(({ locale: localeA }, { locale: localeB }) => localeA > localeB ? 1 : localeA < localeB ? -1 : 0);
return key_path_1.joinPath(...missingPath);
}
}
exports.LocaleMessages = LocaleMessages;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseYamlInI18nBlock = exports.parseJsonInI18nBlock = void 0;
const jsonc_eslint_parser_1 = require("jsonc-eslint-parser");
const yaml_eslint_parser_1 = require("yaml-eslint-parser");
const eslint_1 = require("eslint");
const vue_eslint_parser_1 = require("vue-eslint-parser");
const location_fixer_1 = require("./location-fixer");
exports.parseYamlValuesInI18nBlock = exports.parseJsonValuesInI18nBlock = void 0;
const json5_1 = __importDefault(require("json5"));
const js_yaml_1 = __importDefault(require("js-yaml"));
function hasEndTag(element) {
return !!element.endTag;
}
function getSourceCodeString(context, i18nBlock) {
var _a, _b;
const tokenStore = context.parserServices.getTemplateBodyTokenStore();
const tokens = tokenStore.getTokensBetween(i18nBlock.startTag, i18nBlock.endTag);
if (tokens.length ||
i18nBlock.startTag.range[1] === i18nBlock.endTag.range[0]) {
return tokens.map(t => t.value).join('');
}
const df = (_b = (_a = context.parserServices).getDocumentFragment) === null || _b === void 0 ? void 0 : _b.call(_a);
if (!df) {
return '';
}
const start = i18nBlock.startTag.range[1];
const end = i18nBlock.endTag.range[0];
let sourceCode = '';
for (const token of df.tokens) {
if (start <= token.range[0] && token.range[1] <= end) {
sourceCode += token.value;
}
if (end <= token.range[0]) {
break;
}
}
return sourceCode;
}
function parseInI18nBlock(context, i18nBlock, parseForESLint) {
function parseValuesInI18nBlock(i18nBlock, parse) {
if (!hasEndTag(i18nBlock)) {
return null;
}
const sourceString = getSourceCodeString(context, i18nBlock);
const text = i18nBlock.children[0];
const sourceString = text != null && text.type === 'VText' ? text.value : '';
if (!sourceString.trim()) {
return null;
}
const offsetIndex = i18nBlock.startTag.range[1];
const sourceCode = context.getSourceCode();
const locationFixer = new location_fixer_1.LocationFixer(sourceCode, offsetIndex, sourceCode.text.slice(offsetIndex, i18nBlock.endTag.range[0]), sourceString);
let ast, visitorKeys;
try {
const result = parseForESLint(sourceString, {
ecmaVersion: 2019,
loc: true,
range: true,
raw: true,
tokens: true,
comment: true,
eslintVisitorKeys: true,
eslintScopeManager: true
});
ast = result.ast;
visitorKeys = result.visitorKeys;
return parse(sourceString);
}
catch (e) {
const { line, column } = locationFixer.getFixLoc(e.lineNumber, e.column, e.index);
context.report({
message: e.message,
loc: { line, column }
});
return null;
}
vue_eslint_parser_1.AST.traverseNodes(ast, {
visitorKeys,
enterNode(node, parent) {
node.parent = parent || null;
locationFixer.fixLocations(node);
},
leaveNode() {
}
});
for (const token of ast.tokens || []) {
locationFixer.fixLocations(token);
}
for (const comment of ast.comments || []) {
locationFixer.fixLocations(comment);
}
let resourceSourceCode;
return {
ast,
sourceString,
getSourceCode() {
return (resourceSourceCode ||
(resourceSourceCode = new eslint_1.SourceCode(sourceCode.text, ast)));
},
traverseNodes(node, visitor) {
vue_eslint_parser_1.AST.traverseNodes(node, Object.assign({ visitorKeys }, visitor));
}
};
}
function parseJsonInI18nBlock(context, i18nBlock) {
const result = parseInI18nBlock(context, i18nBlock, jsonc_eslint_parser_1.parseForESLint);
if (result == null) {
return result;
}
return Object.assign({ lang: 'json', getStaticValue(node) {
return jsonc_eslint_parser_1.getStaticJSONValue(node);
} }, result);
function parseJsonValuesInI18nBlock(i18nBlock) {
return parseValuesInI18nBlock(i18nBlock, code => json5_1.default.parse(code));
}
exports.parseJsonInI18nBlock = parseJsonInI18nBlock;
function parseYamlInI18nBlock(context, i18nBlock) {
const result = parseInI18nBlock(context, i18nBlock, yaml_eslint_parser_1.parseForESLint);
if (result == null) {
return result;
}
return Object.assign({ lang: 'yaml', getStaticValue(node) {
return yaml_eslint_parser_1.getStaticYAMLValue(node);
} }, result);
exports.parseJsonValuesInI18nBlock = parseJsonValuesInI18nBlock;
function parseYamlValuesInI18nBlock(i18nBlock) {
return parseValuesInI18nBlock(i18nBlock, code => js_yaml_1.default.safeLoad(code));
}
exports.parseYamlInI18nBlock = parseYamlInI18nBlock;
exports.parseYamlValuesInI18nBlock = parseYamlValuesInI18nBlock;
{
"name": "@intlify/eslint-plugin-vue-i18n",
"description": "ESLint plugin for Vue I18n",
"version": "0.9.0",
"version": "0.10.0",
"author": {

@@ -27,3 +27,3 @@ "name": "kazuya kawaguchi",

"dependencies": {
"fast-diff": "^1.2.0",
"@intlify/message-compiler": "^9.0.0-beta.16",
"glob": "^7.1.3",

@@ -33,7 +33,8 @@ "ignore": "^5.0.5",

"json5": "^2.1.3",
"jsonc-eslint-parser": "^0.5.2",
"jsonc-eslint-parser": "^0.6.2",
"lodash": "^4.17.11",
"parse5": "^6.0.0",
"vue-eslint-parser": "^7.0.0",
"yaml-eslint-parser": "^0.0.8"
"semver": "^7.3.4",
"vue-eslint-parser": "^7.3.0",
"yaml-eslint-parser": "^0.2.1"
},

@@ -44,2 +45,3 @@ "devDependencies": {

"@types/eslint-scope": "^3.7.0",
"@types/eslint-visitor-keys": "^1.0.0",
"@types/js-yaml": "^3.12.5",

@@ -50,11 +52,14 @@ "@types/json5": "^0.0.30",

"@types/parse5": "^5.0.3",
"@typescript-eslint/eslint-plugin": "^3.8.0",
"@typescript-eslint/parser": "^3.8.0",
"@types/semver": "^7.3.4",
"@typescript-eslint/eslint-plugin": "^4.10.0",
"@typescript-eslint/parser": "^4.10.0",
"eslint": "^5.15.0 || ^6.0.0 || ^7.0.0",
"eslint-config-prettier": "^6.11.0",
"eslint-config-prettier": "^7.0.0",
"eslint-plugin-markdown": "^1.0.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-vue-libs": "^3.0.0 || ^4.0.0",
"eslint4b": "^7.16.0",
"lerna-changelog": "^1.0.0",
"mocha": "^8.0.0",
"monaco-editor": "^0.21.2",
"nyc": "^15.0.0",

@@ -64,5 +69,6 @@ "opener": "^1.5.1",

"rimraf": "^3.0.0",
"shipjs": "^0.20.0",
"ts-node": "^8.10.2",
"typescript": "^3.9.7",
"shipjs": "^0.23.0",
"ts-node": "^9.0.0",
"typescript": "^4.0.0",
"vue-eslint-editor": "^1.1.0",
"vue-github-button": "^1.2.0",

@@ -102,4 +108,4 @@ "vuepress": "^1.5.2"

"coverage": "nyc report --reporter lcov && opener coverage/lcov-report/index.html",
"docs": "vuepress dev docs",
"docs:build": "vuepress build docs",
"docs": "npm run build && vuepress dev docs",
"docs:build": "npm run build && vuepress build docs",
"generate": "ts-node scripts/update.ts",

@@ -112,5 +118,5 @@ "lint": "eslint --ext js,ts lib scripts tests/lib docs/.vuepress --ignore-pattern \"!.*\"",

"test:debug": "mocha --require ts-node/register --inspect \"./tests/**/*.ts\"",
"test:coverage": "nyc mocha --require ts-node/register \"./tests/**/*.ts\"",
"test:coverage": "nyc mocha --require ts-node/register \"./tests/**/*.ts\" --timeout 60000",
"test:integrations": "mocha ./tests-integrations/*.js --timeout 60000"
}
}

@@ -25,3 +25,3 @@ <p align="center"><img width="143px" height="130px" src="./assets/eslint-plugin-vue-i18n.svg" alt="ESLint plugin for Vue I18n logo"></p>

Please make sure to read the [Contributing Guide](https://github.com/intlify/eslint-plugin-vue-i18n/blob/master/CONTRIBUTING.md) before making a pull request.
Please make sure to read the [Contributing Guide](https://github.com/intlify/eslint-plugin-vue-i18n/blob/master/.github/CONTRIBUTING.md) before making a pull request.

@@ -28,0 +28,0 @@ ## :copyright: License

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc