UNPKG

@generaltranslation/gt-next-lint

Version:

ESLint plugin for General Translation Next.js integration

153 lines (152 loc) 6.7 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const require_rules_utils = require("./utils.js"); //#region src/rules/no-dynamic-jsx.ts const TRANSLATION_COMPONENTS = ["T"]; const VARIABLE_COMPONENTS = [ "Var", "DateTime", "Num", "Currency" ]; function isTranslationComponent(name) { return TRANSLATION_COMPONENTS.includes(name); } function isVariableComponent(name) { return VARIABLE_COMPONENTS.includes(name); } const noDynamicJsx = { meta: { type: "problem", docs: { description: "Detect unwrapped dynamic content in GT-Next translation components", category: "Best Practices", recommended: true, url: "https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-jsx" }, fixable: void 0, schema: [], messages: { dynamicJsx: "Dynamic content in <T> component should be wrapped in a variable component (<Var>, <DateTime>, <Num>, or <Currency>)" } }, create(context) { const state = { translationStack: 0, variableStack: 0, imports: { translationComponents: /* @__PURE__ */ new Set(), variableComponents: /* @__PURE__ */ new Set(), namespaceImports: /* @__PURE__ */ new Set(), assignedTranslationComponents: /* @__PURE__ */ new Set(), assignedVariableComponents: /* @__PURE__ */ new Set() } }; function getElementName(node) { if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.openingElement)) return null; const name = node.openingElement.name; if (!require_rules_utils.isAstNode(name)) return null; if (name.type === "JSXIdentifier") return require_rules_utils.getNodeName(name); if (name.type === "JSXMemberExpression") { const obj = name.object; const prop = name.property; if (require_rules_utils.isAstNode(obj) && require_rules_utils.isAstNode(prop) && obj.type === "JSXIdentifier" && prop.type === "JSXIdentifier") { const objectName = require_rules_utils.getNodeName(obj); const propertyName = require_rules_utils.getNodeName(prop); return objectName && propertyName ? `${objectName}.${propertyName}` : null; } } return null; } function isNamespaceTranslationComponent(elementName) { const parts = elementName.split("."); if (parts.length === 2) { const [namespace, component] = parts; return state.imports.namespaceImports.has(namespace) && isTranslationComponent(component); } return false; } function isNamespaceVariableComponent(elementName) { const parts = elementName.split("."); if (parts.length === 2) { const [namespace, component] = parts; return state.imports.namespaceImports.has(namespace) && isVariableComponent(component); } return false; } function isInsideJSXAttribute(node) { if (!require_rules_utils.isAstNode(node)) return false; let currentNode = require_rules_utils.isAstNode(node.parent) ? node.parent : null; while (currentNode) { if (currentNode.type === "JSXAttribute") return true; if (currentNode.type === "JSXElement") return false; currentNode = require_rules_utils.isAstNode(currentNode.parent) ? currentNode.parent : null; } return false; } function isComment(expression) { if (!require_rules_utils.isAstNode(expression)) return false; return expression.type === "Block" || expression.type === "Line"; } function isEmpty(expression) { if (!require_rules_utils.isAstNode(expression)) return false; return expression.type === "JSXEmptyExpression"; } return { ImportDeclaration(node) { if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.source)) return; if (node.source?.type === "Literal" && typeof node.source.value === "string") { const source = node.source.value; if (require_rules_utils.isGTModule(source)) { const specifiers = Array.isArray(node.specifiers) ? node.specifiers : []; for (const specifier of specifiers) { if (!require_rules_utils.isAstNode(specifier)) continue; if (specifier.type === "ImportSpecifier") { const importedName = require_rules_utils.getNodeName(specifier.imported) || ""; const localName = require_rules_utils.getNodeName(specifier.local) || ""; if (isTranslationComponent(importedName)) state.imports.translationComponents.add(localName); else if (isVariableComponent(importedName)) state.imports.variableComponents.add(localName); } else if (specifier.type === "ImportNamespaceSpecifier") { const localName = require_rules_utils.getNodeName(specifier.local) || ""; state.imports.namespaceImports.add(localName); } } } } }, VariableDeclarator(node) { if (require_rules_utils.isAstNode(node) && require_rules_utils.isAstNode(node.id) && require_rules_utils.isAstNode(node.init) && node.id.type === "Identifier" && node.init.type === "Identifier") { const varName = require_rules_utils.getNodeName(node.id); const assignedFrom = require_rules_utils.getNodeName(node.init); if (!varName || !assignedFrom) return; if (state.imports.translationComponents.has(assignedFrom)) state.imports.assignedTranslationComponents.add(varName); else if (state.imports.variableComponents.has(assignedFrom)) state.imports.assignedVariableComponents.add(varName); } }, JSXExpressionContainer(node) { if (!require_rules_utils.isAstNode(node)) return; if (isInsideJSXAttribute(node)) return; if (node.expression && require_rules_utils.isStringLiteral(node.expression) || isComment(node.expression) || isEmpty(node.expression)) return; let inTranslationComponent = false; let inVariableComponent = false; let currentNode = require_rules_utils.isAstNode(node.parent) ? node.parent : null; while (currentNode) { if (currentNode.type === "JSXElement") { const elementName = getElementName(currentNode); if (elementName) { if (state.imports.variableComponents.has(elementName) || state.imports.assignedVariableComponents.has(elementName) || isNamespaceVariableComponent(elementName)) { inVariableComponent = true; break; } else if (state.imports.translationComponents.has(elementName) || state.imports.assignedTranslationComponents.has(elementName) || isNamespaceTranslationComponent(elementName)) inTranslationComponent = true; } } currentNode = require_rules_utils.isAstNode(currentNode.parent) ? currentNode.parent : null; } if (inTranslationComponent && !inVariableComponent) context.report({ node, messageId: "dynamicJsx" }); } }; } }; //#endregion exports.noDynamicJsx = noDynamicJsx; //# sourceMappingURL=no-dynamic-jsx.js.map