UNPKG

eslint-plugin-formatjs

Version:
104 lines (103 loc) 4.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.rule = exports.name = void 0; const tslib_1 = require("tslib"); const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser"); const magic_string_1 = tslib_1.__importDefault(require("magic-string")); const context_compat_1 = require("../context-compat"); const util_1 = require("../util"); exports.name = 'no-missing-icu-plural-one-placeholders'; function verifyAst(context, messageNode, ast) { const patches = []; _verifyAstAndReplace(ast); if (patches.length > 0) { const patchedMessage = (0, util_1.patchMessage)(messageNode, ast, content => { return patches .reduce((magicString, patch) => { switch (patch.type) { case 'prependLeft': return magicString.prependLeft(patch.index, patch.content); case 'remove': return magicString.remove(patch.start, patch.end); case 'update': return magicString.update(patch.start, patch.end, patch.content); } }, new magic_string_1.default(content)) .toString(); }); context.report({ node: messageNode, messageId: 'noMissingIcuPluralOnePlaceholders', fix: patchedMessage !== null ? fixer => fixer.replaceText(messageNode, patchedMessage) : null, }); } function _verifyAstAndReplace(ast, root = true) { for (const el of ast) { if ((0, icu_messageformat_parser_1.isPluralElement)(el) && el.options['one']) { _verifyAstAndReplace(el.options['one'].value, false); } else if ((0, icu_messageformat_parser_1.isSelectElement)(el)) { for (const { value } of Object.values(el.options)) { _verifyAstAndReplace(value, root); } } else if ((0, icu_messageformat_parser_1.isTagElement)(el)) { _verifyAstAndReplace(el.children, root); } else if (!root && (0, icu_messageformat_parser_1.isLiteralElement)(el)) { const match = el.value.match(/\b1\b/); if (match && el.location) { patches.push({ type: 'update', start: el.location.start.offset, end: el.location.end.offset, content: el.value.replace(match[0], '#'), }); } } } } } function checkNode(context, node) { const msgs = (0, util_1.extractMessages)(node); for (const [{ message: { defaultMessage }, messageNode, },] of msgs) { if (!defaultMessage || !messageNode) { continue; } verifyAst(context, messageNode, (0, icu_messageformat_parser_1.parse)(defaultMessage, { captureLocation: true })); } } exports.rule = { meta: { type: 'problem', docs: { description: 'We use `one {# item}` instead of `one {1 item}` in ICU messages as some locales use the `one` formatting for other similar numbers.', url: 'https://formatjs.github.io/docs/tooling/linter#no-explicit-icu-plural', }, fixable: 'code', messages: { noMissingIcuPluralOnePlaceholders: 'Use `one {# item}` instead of `one {1 item}` in ICU messages.', }, schema: [], }, defaultOptions: [], create(context) { const callExpressionVisitor = (node) => checkNode(context, node); const parserServices = (0, context_compat_1.getParserServices)(context); //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser if (parserServices?.defineTemplateBodyVisitor) { //@ts-expect-error return parserServices.defineTemplateBodyVisitor({ CallExpression: callExpressionVisitor, }, { CallExpression: callExpressionVisitor, }); } return { JSXOpeningElement: (node) => checkNode(context, node), CallExpression: callExpressionVisitor, }; }, };