'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var path = _interopDefault(require('path')); var through = _interopDefault(require('through2')); var PluginError = _interopDefault(require('plugin-error')); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } var CharCodes; (function (CharCodes) { CharCodes[CharCodes["LEFT_CURLY_BRACE"] = 123] = "LEFT_CURLY_BRACE"; CharCodes[CharCodes["RIGHT_CURLY_BRACE"] = 125] = "RIGHT_CURLY_BRACE"; CharCodes[CharCodes["SINGLE_QUOTE"] = 39] = "SINGLE_QUOTE"; CharCodes[CharCodes["DOUBLE_QUOTE"] = 34] = "DOUBLE_QUOTE"; CharCodes[CharCodes["BACK_QUOTE"] = 96] = "BACK_QUOTE"; CharCodes[CharCodes["BACK_SLASH"] = 92] = "BACK_SLASH"; CharCodes[CharCodes["SLASH"] = 47] = "SLASH"; CharCodes[CharCodes["LESS_THAN"] = 60] = "LESS_THAN"; CharCodes[CharCodes["GREATER_THAN"] = 62] = "GREATER_THAN"; CharCodes[CharCodes["MINUS"] = 45] = "MINUS"; CharCodes[CharCodes["UNDER_LINE"] = 95] = "UNDER_LINE"; CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS"; CharCodes[CharCodes["EXCLAMATION"] = 33] = "EXCLAMATION"; CharCodes[CharCodes["COLON"] = 58] = "COLON"; CharCodes[CharCodes["LEFT_PAREN"] = 40] = "LEFT_PAREN"; CharCodes[CharCodes["RIGHT_PAREN"] = 41] = "RIGHT_PAREN"; CharCodes[CharCodes["DOT"] = 46] = "DOT"; CharCodes[CharCodes["ASTERISK"] = 42] = "ASTERISK"; CharCodes[CharCodes["TAB"] = 9] = "TAB"; CharCodes[CharCodes["LINE_FEED"] = 10] = "LINE_FEED"; CharCodes[CharCodes["CARRIAGE_RETURN"] = 13] = "CARRIAGE_RETURN"; CharCodes[CharCodes["SPACE"] = 32] = "SPACE"; CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A"; CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z"; CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A"; CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z"; CharCodes[CharCodes["_0"] = 48] = "_0"; CharCodes[CharCodes["_9"] = 57] = "_9"; CharCodes[CharCodes["$"] = 36] = "$"; })(CharCodes || (CharCodes = {})); var WXS_LITERAL = 'wxs'; function isWhitespace(code) { // TODO: other whitespaces return CharCodes.SPACE === code || CharCodes.TAB === code || CharCodes.LINE_FEED === code || CharCodes.CARRIAGE_RETURN === code; } function isLetter(code) { return (code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z) || // A-Z (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z) || // a-z code === CharCodes.MINUS || // - code === CharCodes.UNDER_LINE; // _ } function isNumber(code) { return code >= CharCodes._0 && code <= CharCodes._9; // 0-9 } function isValidFunctionLiteralChar(code) { return isNumber(code) || (code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z) || (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z) || code === CharCodes.UNDER_LINE || code === CharCodes.$; } var Parser = /** @class */ (function () { function Parser(source, fileName) { this.source = source; this.fileName = fileName; this.pos = 0; this.line = 1; this.column = 1; } Parser.prototype.consumeChar = function () { var ch = this.source.charCodeAt(this.pos); this.advance(); return ch; }; Parser.prototype.consumeQuoteString = function (resultRef) { if (resultRef === void 0) { resultRef = {}; } var start = this.pos; if (this.match(CharCodes.SINGLE_QUOTE) || this.match(CharCodes.DOUBLE_QUOTE) || this.match(CharCodes.BACK_QUOTE)) { var quoteType = this.consumeChar(); while (!this.eof() && !this.match(quoteType)) { if (this.match(CharCodes.BACK_SLASH) && this.match(quoteType, this.pos + 1)) { this.advance(2); } else this.advance(); } if (this.match(quoteType)) this.advance(); resultRef.result = this.source.substring(start, this.pos); return true; } return false; }; Parser.prototype.advance = function (step) { var _this = this; var _advanceOnce = function () { if (_this.source[_this.pos] === '\n') { _this.column = 1; _this.line++; } else { _this.column++; } _this.pos++; }; if (!step) { _advanceOnce(); } else { while (step-- > 0) _advanceOnce(); } }; Parser.prototype.eof = function () { return this.pos >= this.source.length; }; Parser.prototype.match = function (code, pos) { return this.source.charCodeAt(pos && pos !== -1 ? pos : this.pos) === code; }; Parser.prototype.currentChar = function () { return this.source[this.pos]; }; Parser.prototype.peekCharCode = function () { return this.source.charCodeAt(this.pos); }; Parser.prototype.consumeWhitespace = function () { this.consumeWhile(isWhitespace); }; Parser.prototype.consumeWhile = function (checkFunc) { var result = []; while (!this.eof() && checkFunc(this.source.charCodeAt(this.pos))) { var ch = this.source[this.pos]; this.advance(); result.push(ch); } return result.join(''); }; Parser.prototype.currentContext = function () { var MAX_NEXT_LINE = 2; var answer = ''; var _pos = this.pos - 1, accumulateNextLine = 0; while (_pos >= 0 && accumulateNextLine < MAX_NEXT_LINE + 2) { if (this.source[_pos] === '\n') { accumulateNextLine++; } answer = this.source[_pos] + answer; _pos--; } if (this.pos < this.source.length) { answer += this.source[this.pos]; } _pos = this.pos + 1, accumulateNextLine = 0; while (_pos < this.source.length && accumulateNextLine < MAX_NEXT_LINE) { if (this.source[_pos] === '\n') { accumulateNextLine++; } answer += this.source[_pos]; _pos++; } return answer; }; return Parser; }()); var Expression = /** @class */ (function () { function Expression(start, end, expression) { if (start === void 0) { start = 0; } if (end === void 0) { end = 0; } if (expression === void 0) { expression = ''; } this.start = start; this.end = end; this.expression = expression; } return Expression; }()); var CallExpression = /** @class */ (function (_super) { __extends(CallExpression, _super); function CallExpression(start, end, expression, functionNameStart, functionNameEnd, parameters, childFunctionExpressions) { if (start === void 0) { start = 0; } if (end === void 0) { end = 0; } if (expression === void 0) { expression = ''; } if (functionNameStart === void 0) { functionNameStart = 0; } if (functionNameEnd === void 0) { functionNameEnd = 0; } if (parameters === void 0) { parameters = ''; } if (childFunctionExpressions === void 0) { childFunctionExpressions = []; } var _this = _super.call(this, start, end, expression) || this; _this.functionNameStart = functionNameStart; _this.functionNameEnd = functionNameEnd; _this.parameters = parameters; _this.childFunctionExpressions = childFunctionExpressions; return _this; } return CallExpression; }(Expression)); /** * ExpressionParser helps parsing expressions inside wxml interpolation block */ var ExpressionParser = /** @class */ (function (_super) { __extends(ExpressionParser, _super); function ExpressionParser(source, fileName) { if (fileName === void 0) { fileName = ''; } var _this = _super.call(this, source, fileName) || this; _this.source = source; _this.fileName = fileName; _this.blockStart = -1; _this.expressions = []; _this.callExpressions = []; return _this; } ExpressionParser.prototype.parse = function () { try { var expr = this._parse(); return expr; } catch (e) { if (this.fileName) { e.message += "\nfile: " + this.fileName; } e.message += "\nline: " + this.line + ", column: " + this.column + "\n\n" + this.currentContext(); throw e; } }; ExpressionParser.prototype._parse = function () { while (!this.eof()) { if (this.match(CharCodes.LEFT_CURLY_BRACE) && this.match(CharCodes.LEFT_CURLY_BRACE, this.pos + 1)) { this.advance(2); this.enterInterpolationBlock(); // TODO: parse function calls and pass it to transfomers this.parseInterpolationExpression(); continue; } this.advance(); } return { expression: this.expressions, callExpressions: this.callExpressions }; }; /** * Parse expressions in wxml, it only cares about function calls * and ignore other expressions since it's trivial for i18n */ ExpressionParser.prototype.parseInterpolationExpression = function () { while (!this.eof()) { this.consumeQuoteString(); if (this.match(CharCodes.RIGHT_CURLY_BRACE) && this.match(CharCodes.RIGHT_CURLY_BRACE, this.pos + 1)) { var _a = this.exitInterpolationBlock(), start = _a.start, end = _a.end, block = _a.block; this.advance(2); if (end > start && start !== -1) { this.expressions.push(new Expression(start, end, block)); } return; } // maybe function call expression if (this.match(CharCodes.LEFT_PAREN)) { var start = this.isFunctionCallExpression(this.pos); if (start !== -1) { var exprs = this.parseFunctionCallExpression(start); this.callExpressions.push(exprs); continue; } } this.advance(); } }; ExpressionParser.prototype.parseObjectDecl = function () { var callFunctions = []; while (!this.eof()) { this.consumeQuoteString(); if (this.match(CharCodes.RIGHT_CURLY_BRACE)) { this.advance(); return callFunctions; } if (this.match(CharCodes.LEFT_PAREN)) { var start = this.isFunctionCallExpression(this.pos); if (start !== -1) { var expr = this.parseFunctionCallExpression(start); callFunctions.push(expr); } } if (this.match(CharCodes.LEFT_CURLY_BRACE)) { this.advance(); callFunctions.push.apply(callFunctions, __spread(this.parseObjectDecl())); continue; } this.advance(); } return callFunctions; }; ExpressionParser.prototype.parseFunctionCallExpression = function (start) { var childFunctions = []; var functionNameEnd = this.pos; if (this.consumeChar() !== CharCodes.LEFT_PAREN) { throw new Error('expected a left paren for a function call'); } while (!this.eof()) { this.consumeQuoteString(); if (this.match(CharCodes.LEFT_CURLY_BRACE)) { // JavaScript block should be ignored this.advance(); var expr = this.parseObjectDecl(); childFunctions.push.apply(childFunctions, __spread(expr)); } if (this.consumeChar() === CharCodes.RIGHT_PAREN) { break; } } return new CallExpression(start, this.pos, this.source.substring(start, functionNameEnd), start, functionNameEnd, this.source.substring(functionNameEnd + 1, this.pos - 1).trim(), childFunctions); }; ExpressionParser.prototype.enterInterpolationBlock = function () { // Already in an translation block, this must not be // valid translation block if (this.blockStart !== -1) return; this.blockStart = this.pos; }; ExpressionParser.prototype.exitInterpolationBlock = function () { var start = this.blockStart; var end = this.pos; var block = this.source.substring(start, end); this.blockStart = -1; return { start: start, end: end, block: block }; }; ExpressionParser.prototype.matchNextChar = function (code) { return this.source.charCodeAt(++this.pos) === code; }; ExpressionParser.prototype.isFunctionCallExpression = function (pos) { while (--pos >= 0) { // maybe wxs call {{ a.b() }} if (this.match(CharCodes.DOT, pos)) return -1; if (!isValidFunctionLiteralChar(this.source.charCodeAt(pos))) break; } return pos + 1; }; return ExpressionParser; }(Parser)); var parse = require('format-message-parse'); var Node = /** @class */ (function () { function Node(tagName) { this.tagName = tagName; } Node.prototype.dump = function () { return { type: this.tagName }; }; return Node; }()); var AttributeValue = /** @class */ (function () { function AttributeValue(value, start, end) { this.value = value; this.start = start; this.end = end; } return AttributeValue; }()); var Element = /** @class */ (function (_super) { __extends(Element, _super); function Element(tagName, attributes, children) { var _this = _super.call(this, tagName) || this; _this.attributes = attributes; _this.children = children; return _this; } Element.prototype.dump = function () { var e_1, _a; var attributes = {}; if (this.attributes) { try { for (var _b = __values(this.attributes), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), key = _d[0], value = _d[1]; if (value && value.value) { attributes[key] = value.value; } else { attributes[key] = null; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } var children = this.children.map(function (child) { return child.dump(); }); return { type: this.tagName, attributes: attributes, children: children }; }; return Element; }(Node)); var Text = /** @class */ (function (_super) { __extends(Text, _super); function Text(content, start, end) { var _this = _super.call(this, Text.tagName) || this; _this.content = content; _this.start = start; _this.end = end; return _this; } Text.prototype.dump = function () { return { type: this.tagName, content: this.content }; }; Text.tagName = 'text'; return Text; }(Node)); var WxmlState; (function (WxmlState) { WxmlState[WxmlState["NORMAL"] = 1] = "NORMAL"; WxmlState[WxmlState["WXS"] = 2] = "WXS"; WxmlState[WxmlState["INT"] = 4] = "INT"; })(WxmlState || (WxmlState = {})); /** * Simple wxml parser */ var WxmlParser = /** @class */ (function (_super) { __extends(WxmlParser, _super); function WxmlParser(source, fileName) { if (fileName === void 0) { fileName = ''; } var _this = _super.call(this, source, fileName) || this; _this.source = source; _this.fileName = fileName; _this.state = WxmlState.NORMAL; return _this; } WxmlParser.prototype.parse = function () { try { var nodes = this._parse(); return nodes; } catch (e) { if (this.fileName) { e.message += "\nfile: " + this.fileName; } e.message += "\nline: " + this.line + ", column: " + this.column + "\n\n" + this.currentContext(); throw e; } }; WxmlParser.prototype._parse = function () { var nodes = []; while (!this.eof()) { this.consumeWhitespace(); if (this.match(CharCodes.LESS_THAN) && this.match(CharCodes.SLASH, this.pos + 1)) { break; } // Ignore comments if (this.match(CharCodes.LESS_THAN, this.pos) && this.match(CharCodes.EXCLAMATION, this.pos + 1) && this.match(CharCodes.MINUS, this.pos + 2) && this.match(CharCodes.MINUS, this.pos + 3)) { this.advance(4); this.parseComments(); continue; } if (this.match(CharCodes.LESS_THAN)) { var node = this.parseWxmlTag(); nodes.push(node); continue; } var textNode = this.parseText(); if (textNode.content.length > 0) nodes.push(textNode); } return nodes; }; WxmlParser.prototype.parseWxmlTag = function () { if (this.consumeChar() !== CharCodes.LESS_THAN) { throw new Error('unexpected character for wxml start tag'); } this.consumeWhitespace(); var tagName = this.parseTagName(); if (!tagName || tagName.length === 0) { throw new Error("unexpected tag name " + this.currentChar()); } var attributes = this.parseAttributes(); // self-closing tag if (this.match(CharCodes.SLASH)) { this.advance(); if (this.consumeChar() !== CharCodes.GREATER_THAN) { throw new Error('unexpected character ' + this.currentChar()); } return new Element(tagName, attributes, []); } if (this.consumeChar() !== CharCodes.GREATER_THAN) { throw new Error('expected character > to close a tag'); } if (tagName.toLowerCase() === WXS_LITERAL) { this.state = WxmlState.WXS; } var childNodes = this.parse(); if (this.consumeChar() !== CharCodes.LESS_THAN) { throw new Error('expected char ' + String.fromCharCode(CharCodes.LESS_THAN) + ' but got ' + this.currentChar()); } if (this.consumeChar() !== CharCodes.SLASH) { throw new Error('expected char ' + String.fromCharCode(CharCodes.SLASH) + ' but got ' + this.currentChar()); } this.consumeWhitespace(); var endTagName = this.parseTagName(); if (endTagName !== tagName) { throw new Error("expected tag name " + tagName + " but got " + endTagName); } this.consumeWhitespace(); if (!this.match(CharCodes.GREATER_THAN)) { throw new Error('expected char ' + String.fromCharCode(CharCodes.GREATER_THAN) + ' but got ' + this.currentChar()); } this.advance(); if (tagName.toLowerCase() === WXS_LITERAL) { this.state = WxmlState.NORMAL; } return new Element(tagName, attributes, childNodes); }; WxmlParser.prototype.parseText = function () { var start = this.pos; if (this.state === WxmlState.WXS) { while (!this.eof() && !(this.match(CharCodes.LESS_THAN) && this.match(CharCodes.SLASH, this.pos + 1))) { if (!this.consumeQuoteString() && !this.consumeWXSComments()) { this.advance(); } } return new Text(this.source.substring(start, this.pos), start, this.pos); } return new Text(this.parseTextContents(), start, this.pos); }; WxmlParser.prototype.parseTextContents = function () { var result = []; while (!this.eof() && (!this.match(CharCodes.LESS_THAN) || this.state === WxmlState.INT)) { if (this.match(CharCodes.LEFT_CURLY_BRACE) && this.match(CharCodes.LEFT_CURLY_BRACE, this.pos + 1)) { this.state = WxmlState.INT; } if (this.match(CharCodes.RIGHT_CURLY_BRACE) && this.match(CharCodes.RIGHT_CURLY_BRACE, this.pos + 1)) { this.state = WxmlState.NORMAL; } var quoteStringRef = { result: '' }; if (this.consumeQuoteString(quoteStringRef)) { result.push(quoteStringRef.result); continue; } var ch = this.source[this.pos]; result.push(ch); this.advance(); } return result.join(''); }; /** * Ignore comments */ WxmlParser.prototype.parseComments = function () { while (!this.eof()) { if (this.match(CharCodes.MINUS, this.pos) && this.match(CharCodes.MINUS, this.pos + 1) && this.match(CharCodes.GREATER_THAN, this.pos + 2)) { this.advance(3); return; } this.advance(); } }; WxmlParser.prototype.parseTagName = function () { // loosy check // TODO: prevent number as first letter return this.consumeWhile(function (c) { return isLetter(c) || isNumber(c); }); }; WxmlParser.prototype.parseAttributeName = function () { // loosy check // TODO: prevent number as first letter // Note: can have colon (:) in between return this.consumeWhile(function (c) { return isLetter(c) || isNumber(c) || c === CharCodes.COLON; }); }; WxmlParser.prototype.parseAttributes = function () { var attrs = new Map(); while (!this.eof()) { this.consumeWhitespace(); if (this.match(CharCodes.SLASH) || this.match(CharCodes.GREATER_THAN)) break; if (!isLetter(this.peekCharCode()) && !this.match(CharCodes.COLON)) break; var _a = this.parseAttribute(), name = _a.name, value = _a.value; attrs.set(name, value); } return attrs; }; WxmlParser.prototype.parseAttribute = function () { var name = this.parseAttributeName(); this.consumeWhitespace(); if (!this.match(CharCodes.EQUALS)) { return { name: name, value: null }; } this.advance(); this.consumeWhitespace(); var value = this.parseAttrValue(); return { name: name, value: value }; }; WxmlParser.prototype.parseAttrValue = function () { var leftQuote = this.consumeChar(); var start = this.pos; if (leftQuote !== CharCodes.SINGLE_QUOTE && leftQuote !== CharCodes.DOUBLE_QUOTE) { throw new Error("expected char " + String.fromCharCode(CharCodes.SINGLE_QUOTE) + " or " + String.fromCharCode(CharCodes.DOUBLE_QUOTE) + " " + ("but got " + String.fromCharCode(leftQuote))); } var value = this.consumeWhile(function (ch) { return ch !== leftQuote; }); var end = this.pos; if (this.consumeChar() !== leftQuote) { throw new Error('expected char ' + String.fromCharCode(leftQuote) + ' to close an attribute'); } var attribute = new AttributeValue(value, start, end); return attribute; }; WxmlParser.prototype.consumeWXSComments = function () { if (this.match(CharCodes.SLASH) && this.match(CharCodes.SLASH, this.pos + 1)) { while (!this.eof()) { if (this.match(CharCodes.LINE_FEED)) { this.advance(); break; } if (this.match(CharCodes.CARRIAGE_RETURN) && this.match(CharCodes.LINE_FEED)) { this.advance(2); break; } // If no line end is met we should end at this point if (this.match(CharCodes.LESS_THAN) && this.match(CharCodes.SLASH, this.pos + 1)) { return false; } this.advance(); } return true; } else if (this.match(CharCodes.SLASH) && this.match(CharCodes.ASTERISK, this.pos + 1)) { while (!this.eof()) { if (this.match(CharCodes.ASTERISK) && this.match(CharCodes.SLASH, this.pos + 1)) { this.advance(2); break; } this.advance(); } return true; } return false; }; return WxmlParser; }(Parser)); var TranslationFunction; (function (TranslationFunction) { TranslationFunction["default"] = "t"; })(TranslationFunction || (TranslationFunction = {})); var I18nModuleName; (function (I18nModuleName) { I18nModuleName["default"] = "i18n"; })(I18nModuleName || (I18nModuleName = {})); var LocaleVariable; (function (LocaleVariable) { LocaleVariable["default"] = "$_locale"; })(LocaleVariable || (LocaleVariable = {})); var BLOCK_DELIMITER_START = '{{'; /** * Transform miniprogram templates (WXML) to import i18n data and transform i18n invocations * i18n data will be imported via WXS mechanism while i18n invocations will be transformed * to normal WXS calls, e.g. t(key, val) will be transformed to something like $i18n.t(key, val) */ var TranslationFunctionTransformer = /** @class */ (function () { function TranslationFunctionTransformer(translationFunctionName, i18nModuleName, currentLocaleVariableName) { if (translationFunctionName === void 0) { translationFunctionName = TranslationFunction.default; } if (i18nModuleName === void 0) { i18nModuleName = I18nModuleName.default; } if (currentLocaleVariableName === void 0) { currentLocaleVariableName = LocaleVariable.default; } this.translationFunctionName = translationFunctionName; this.i18nModuleName = i18nModuleName; this.currentLocaleVariableName = currentLocaleVariableName; this.source = ''; } /** * Given a piece of wxml source code, transform its i18n function calls into normal wxs function calls */ TranslationFunctionTransformer.prototype.transform = function (source, fileName) { if (fileName === void 0) { fileName = ''; } this.source = source; var parser = new WxmlParser(source, fileName); var nodes = parser.parse(); // Transform function call expressions in place this.transformNodes(nodes, fileName); return this.source; }; TranslationFunctionTransformer.prototype.transformNodes = function (nodes, fileName) { var e_1, _a; // walk through wxml nodes to pick up interpolation blocks for (var i = nodes.length - 1; i >= 0; i--) { var node = nodes[i]; if (node instanceof Text) { if (node.content.includes(BLOCK_DELIMITER_START)) { var _b = this.transformFunctionCallExpr(node.content, fileName), content = _b.content, transformed = _b.transformed; if (transformed) { var head = this.source.substring(0, node.start); var rear = this.source.substring(node.end); this.source = head + content + rear; } } } else if (node instanceof Element) { this.transformNodes(node.children, fileName); var attributes = this.sortAttributesByStartPos(node.attributes); try { for (var attributes_1 = (e_1 = void 0, __values(attributes)), attributes_1_1 = attributes_1.next(); !attributes_1_1.done; attributes_1_1 = attributes_1.next()) { var attrValue = attributes_1_1.value; if (attrValue && attrValue.value.includes(BLOCK_DELIMITER_START)) { var _c = this.transformFunctionCallExpr(attrValue.value, fileName), content = _c.content, transformed = _c.transformed; if (transformed) { var head = this.source.substring(0, attrValue.start); var rear = this.source.substring(attrValue.end); this.source = head + content + rear; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (attributes_1_1 && !attributes_1_1.done && (_a = attributes_1.return)) _a.call(attributes_1); } finally { if (e_1) throw e_1.error; } } } } }; TranslationFunctionTransformer.prototype.transformFunctionCallExpr = function (source, fileName) { var parser = new ExpressionParser(source, fileName); var expr = parser.parse(); return this.transformFunctionCallExprRecursively(source, expr.callExpressions); }; TranslationFunctionTransformer.prototype.transformFunctionCallExprRecursively = function (source, callExpressions) { var transformed = false; for (var i = callExpressions.length - 1; i >= 0; i--) { var callExpr = callExpressions[i]; if (callExpr.expression === this.translationFunctionName) { // Inject currentLocale variable var end = callExpr.end - 1; var localeVarDecl = callExpr.parameters.length > 0 ? ", " + this.currentLocaleVariableName : this.currentLocaleVariableName; source = source.substring(0, end) + localeVarDecl + source.substring(end); var child = this.transformFunctionCallExprRecursively(source, callExpr.childFunctionExpressions); transformed = transformed || child.transformed; source = child.content; var head = source.substring(0, callExpr.functionNameStart); var rear = source.substring(callExpr.functionNameEnd); source = head + this.i18nModuleName + '.' + TranslationFunction.default + rear; transformed = true; } } return { transformed: transformed, content: source }; }; TranslationFunctionTransformer.prototype.sortAttributesByStartPos = function (attributes) { // descendent return Array.from(attributes.values()).filter(function (a) { return !!a; }).sort(function (a, b) { return b.start - a.start; }); }; return TranslationFunctionTransformer; }()); var PLUGIN_NAME = '@miniprogram-i18n/gulp-i18n-wxml'; // Assume source folder is src var DEFAULT_WXS_PATH = path.resolve('src/i18n/locales.wxs'); var getWxsTag = function (path$$1, moduleName) { return "\n"; }; var gulpI18nWxmlTransformer = function (options) { return through.obj(function (file, _, cb) { var opts = options || { wxsPath: '', wxsModuleName: '', i18nFunctionName: '' }; var wxsPath = opts.wxsPath || DEFAULT_WXS_PATH; var wxsModuleName = opts.wxsModuleName || I18nModuleName.default; var i18nFunctionName = opts.i18nFunctionName || TranslationFunction.default; // Ignore empty file or not wxml files if (file.isNull() || path.extname(file.path) !== '.wxml') { return cb(null, file); } if (file.isStream()) { return cb(new PluginError(PLUGIN_NAME, 'Streaming data is not supported')); } // TODO: read functionn name from options var transfomer = new TranslationFunctionTransformer(i18nFunctionName, wxsModuleName); if (!file.contents) { return cb(null, file); } try { var transformedContents = transfomer.transform(file.contents.toString('utf-8'), file.path); var relativeWxsPath = path.relative(path.dirname(file.path), wxsPath); if (process.platform === 'win32') { relativeWxsPath = relativeWxsPath.replace(/\\/g, '/'); } var wxsTag = getWxsTag(relativeWxsPath, wxsModuleName); if (transformedContents.indexOf(wxsTag) !== -1) { // has already write wxs tag into wxml. file.contents = Buffer.from(transformedContents); return cb(null, file); } file.contents = Buffer.concat([Buffer.from(wxsTag), Buffer.from(transformedContents)]); } catch (err) { console.log('error:', err); return cb(new PluginError(PLUGIN_NAME, err)); } return cb(null, file); }); }; module.exports = gulpI18nWxmlTransformer;