UNPKG

next-translate-scanner

Version:

Scan next-translate code for translations and update json files.

205 lines (204 loc) 8.69 kB
"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) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const base_lexer_1 = __importDefault(require("./base-lexer")); const ts = __importStar(require("typescript")); const logger_1 = __importDefault(require("../utils/logger")); const extract_namespace_from_key_1 = __importDefault(require("../utils/extract-namespace-from-key")); const spread_options_to_entry_1 = __importDefault(require("../utils/spread-options-to-entry")); class JavascriptLexer extends base_lexer_1.default { constructor(options = {}) { super(options); this.callPattern = '(?<=^|\\s|\\.)' + this.functionPattern() + '\\(.*\\)'; } createCommentNodeParser() { const visitedComments = new Set(); return (keys, node, content) => { ts.forEachLeadingCommentRange(content, node.getFullStart(), (pos, end, kind) => { const commentId = `${pos}_${end}`; if ((kind === ts.SyntaxKind.MultiLineCommentTrivia || kind === ts.SyntaxKind.SingleLineCommentTrivia) && !visitedComments.has(commentId)) { visitedComments.add(commentId); const text = content.slice(pos, end); const commentKeys = this.commentExtractor.call(this, text); if (commentKeys) { keys.push(...commentKeys); } } }); }; } setNamespaces(keys) { if (this.defaultNS) { keys = keys.map((entry) => ({ ...entry, ns: entry.ns || this.defaultNS })); } keys.filter((entry) => { if (entry.ns) { return true; } logger_1.default.warning(`No namespace found for '${entry.key}'`); return false; }); return keys; } extract(content, filename = '__default.js') { const keys = []; const parseCommentNode = this.createCommentNodeParser(); const parseTree = (node) => { let entry = null; parseCommentNode(keys, node, content); if (node.kind === ts.SyntaxKind.TaggedTemplateExpression) { entry = this.taggedTemplateExpressionExtractor(node); } if (node.kind === ts.SyntaxKind.CallExpression) { entry = this.expressionExtractor.call(this, node); } if (entry) { keys.push(entry); } node.forEachChild(parseTree); }; const sourceFile = ts.createSourceFile(filename, content, ts.ScriptTarget.Latest); parseTree(sourceFile); return this.setNamespaces(keys); } taggedTemplateExpressionExtractor(node) { const entry = {}; const { tag, template } = node; const isTranslationFunction = (tag.text && this.functions.includes(tag.text)) || (tag.name && this.functions.includes(tag.name.text)); if (!isTranslationFunction) { return null; } if (template.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { entry.key = template.text; } else if (template.kind === ts.SyntaxKind.TemplateExpression) { logger_1.default.warning('A key that is a template string must not have any interpolations.'); return null; } (0, extract_namespace_from_key_1.default)(entry, this.nsSeparator); return entry; } expressionExtractor(node) { const entry = {}; const expression = node.expression; const nodeArguments = [...node.arguments]; if ((expression.escapedText === 'useTranslation' || expression.escapedText === 'withTranslation' || expression.escapedText === 'getT') && node.arguments.length) { const index = expression.escapedText === 'useTranslation' ? 0 : 1; const { text } = node.arguments[index]; if (text) { this.defaultNS = text; } } const isTranslationFunction = (expression.text && this.functions.includes(expression.text)) || (expression.name && this.functions.includes(expression.name.text)); if (isTranslationFunction) { const keyArgument = nodeArguments.shift(); if (!keyArgument) { return null; } if (keyArgument.kind === ts.SyntaxKind.StringLiteral || keyArgument.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { entry.key = keyArgument.text; } else if (keyArgument.kind === ts.SyntaxKind.BinaryExpression) { const concatenatedString = this.concatenateString(keyArgument); if (!concatenatedString) { logger_1.default.warning(`Key is not a string literal: ${keyArgument.text}`); return null; } entry.key = concatenatedString; } else { logger_1.default.warning(keyArgument.kind === ts.SyntaxKind.Identifier ? `Key is not a string literal: ${keyArgument.text}` : 'Key is not a string literal'); return null; } const query = nodeArguments[0]; const options = nodeArguments[1]; if (query && query.kind === ts.SyntaxKind.ObjectLiteralExpression) { try { (0, spread_options_to_entry_1.default)(entry, query); } catch (e) { logger_1.default.warning(e.message); } } if (options && options.kind === ts.SyntaxKind.ObjectLiteralExpression) { for (const p of options.properties) { if (p.initializer) { if (p.name.text === 'default') { entry.default = p.initializer.text || ''; } if (p.name.text === 'ns') { entry.ns = p.initializer.text || ''; } } } } (0, extract_namespace_from_key_1.default)(entry, this.nsSeparator); return entry; } return null; } commentExtractor(commentText) { const regexp = new RegExp(this.callPattern, 'g'); const expressions = commentText.match(regexp); if (!expressions) { return null; } const keys = []; expressions.forEach((expression) => { const expressionKeys = this.extract(expression); if (expressionKeys) { keys.push(...expressionKeys); } }); return keys; } concatenateString(binaryExpression, string = '') { if (binaryExpression.operatorToken.kind !== ts.SyntaxKind.PlusToken) { return; } if (binaryExpression.left.kind === ts.SyntaxKind.BinaryExpression) { string += this.concatenateString(binaryExpression.left, string); } else if (binaryExpression.left.kind === ts.SyntaxKind.StringLiteral) { string += binaryExpression.left.text; } else { return; } if (binaryExpression.right.kind === ts.SyntaxKind.BinaryExpression) { string += this.concatenateString(binaryExpression.right, string); } else if (binaryExpression.right.kind === ts.SyntaxKind.StringLiteral) { string += binaryExpression.right.text; } else { return; } return string; } } exports.default = JavascriptLexer;