UNPKG

eslint-plugin-lingui

Version:
122 lines 5.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.rule = exports.name = void 0; const utils_1 = require("@typescript-eslint/utils"); const create_rule_1 = require("../create-rule"); const helpers_1 = require("../helpers"); exports.name = 'require-explicit-id'; exports.rule = (0, create_rule_1.createRule)({ name: exports.name, meta: { docs: { description: "enforce 'id' property or attribute for Lingui macros", recommended: 'error', }, messages: { default: "Trans component requires an explicit 'id' attribute", missingIdCall: "Macro function call requires an explicit 'id' property", noIdInTaggedTemplate: "Tagged template literal doesn't support 'id'. Use {{ fn }}({ id: '...', message: '...' }) instead", invalidPattern: "'id' must match one of the patterns: {{ patterns }}", }, schema: [ { type: 'object', properties: { patterns: { type: 'array', items: { type: 'string', }, }, flags: { type: 'string', }, }, additionalProperties: false, }, ], type: 'problem', }, defaultOptions: [], create: function (context) { var _a; const { options: [option], } = context; const rulePatterns = (_a = option === null || option === void 0 ? void 0 : option.patterns) === null || _a === void 0 ? void 0 : _a.map((pattern) => new RegExp(pattern, option === null || option === void 0 ? void 0 : option.flags)); function validatePattern(node, idValue) { if (!(rulePatterns === null || rulePatterns === void 0 ? void 0 : rulePatterns.length)) { return; } if (!rulePatterns.some((pattern) => pattern.test(idValue))) { context.report({ node, messageId: 'invalidPattern', data: { patterns: option.patterns.join(', ') }, }); } } return { [helpers_1.LinguiTransQuery](node) { const idAttr = node.openingElement.attributes.find((attr) => attr.type === utils_1.TSESTree.AST_NODE_TYPES.JSXAttribute && attr.name.type === utils_1.TSESTree.AST_NODE_TYPES.JSXIdentifier && attr.name.name === 'id'); if (!idAttr) { context.report({ node, messageId: 'default', }); return; } // Only validate string literal values; skip complex expressions silently let idValue = null; if (idAttr.value && idAttr.value.type === utils_1.TSESTree.AST_NODE_TYPES.Literal && typeof idAttr.value.value === 'string') { idValue = idAttr.value.value; } else if (idAttr.value && idAttr.value.type === utils_1.TSESTree.AST_NODE_TYPES.JSXExpressionContainer && idAttr.value.expression.type === utils_1.TSESTree.AST_NODE_TYPES.Literal && typeof idAttr.value.expression.value === 'string') { // Handle id={"msg.hello"} the same as id="msg.hello" idValue = idAttr.value.expression.value; } if (idValue == null) { return; } validatePattern(idAttr, idValue); }, [helpers_1.LinguiTaggedTemplateExpressionMessageQuery](node) { const parent = node.parent; const fn = parent.tag.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier ? parent.tag.name : 'function'; context.report({ node: parent, messageId: 'noIdInTaggedTemplate', data: { fn }, }); }, [helpers_1.LinguiCallExpressionQuery](node) { const arg = node.arguments[0]; if (!arg || arg.type !== utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) { return; } const idProp = arg.properties.find((prop) => prop.type === utils_1.TSESTree.AST_NODE_TYPES.Property && ((prop.key.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier && prop.key.name === 'id') || (prop.key.type === utils_1.TSESTree.AST_NODE_TYPES.Literal && prop.key.value === 'id'))); if (!idProp) { context.report({ node, messageId: 'missingIdCall', }); return; } // Only validate string literal values; skip expressions silently if (idProp.value.type !== utils_1.TSESTree.AST_NODE_TYPES.Literal || typeof idProp.value.value !== 'string') { return; } validatePattern(idProp, idProp.value.value); }, }; }, }); //# sourceMappingURL=require-explicit-id.js.map