expression-parser.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. "use strict";
  2. var __extends = (this && this.__extends) || (function () {
  3. var extendStatics = function (d, b) {
  4. extendStatics = Object.setPrototypeOf ||
  5. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  6. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  7. return extendStatics(d, b);
  8. };
  9. return function (d, b) {
  10. extendStatics(d, b);
  11. function __() { this.constructor = d; }
  12. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  13. };
  14. })();
  15. var __read = (this && this.__read) || function (o, n) {
  16. var m = typeof Symbol === "function" && o[Symbol.iterator];
  17. if (!m) return o;
  18. var i = m.call(o), r, ar = [], e;
  19. try {
  20. while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
  21. }
  22. catch (error) { e = { error: error }; }
  23. finally {
  24. try {
  25. if (r && !r.done && (m = i["return"])) m.call(i);
  26. }
  27. finally { if (e) throw e.error; }
  28. }
  29. return ar;
  30. };
  31. var __spread = (this && this.__spread) || function () {
  32. for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
  33. return ar;
  34. };
  35. var __importDefault = (this && this.__importDefault) || function (mod) {
  36. return (mod && mod.__esModule) ? mod : { "default": mod };
  37. };
  38. Object.defineProperty(exports, "__esModule", { value: true });
  39. exports.CallExpression = exports.Expression = void 0;
  40. var parser_1 = __importDefault(require("./parser"));
  41. var utils_1 = require("./utils");
  42. var Expression = /** @class */ (function () {
  43. function Expression(start, end, expression) {
  44. if (start === void 0) { start = 0; }
  45. if (end === void 0) { end = 0; }
  46. if (expression === void 0) { expression = ''; }
  47. this.start = start;
  48. this.end = end;
  49. this.expression = expression;
  50. }
  51. return Expression;
  52. }());
  53. exports.Expression = Expression;
  54. var CallExpression = /** @class */ (function (_super) {
  55. __extends(CallExpression, _super);
  56. function CallExpression(start, end, expression, functionNameStart, functionNameEnd, parameters, childFunctionExpressions) {
  57. if (start === void 0) { start = 0; }
  58. if (end === void 0) { end = 0; }
  59. if (expression === void 0) { expression = ''; }
  60. if (functionNameStart === void 0) { functionNameStart = 0; }
  61. if (functionNameEnd === void 0) { functionNameEnd = 0; }
  62. if (parameters === void 0) { parameters = ''; }
  63. if (childFunctionExpressions === void 0) { childFunctionExpressions = []; }
  64. var _this = _super.call(this, start, end, expression) || this;
  65. _this.functionNameStart = functionNameStart;
  66. _this.functionNameEnd = functionNameEnd;
  67. _this.parameters = parameters;
  68. _this.childFunctionExpressions = childFunctionExpressions;
  69. return _this;
  70. }
  71. return CallExpression;
  72. }(Expression));
  73. exports.CallExpression = CallExpression;
  74. /**
  75. * ExpressionParser helps parsing expressions inside wxml interpolation block
  76. */
  77. var ExpressionParser = /** @class */ (function (_super) {
  78. __extends(ExpressionParser, _super);
  79. function ExpressionParser(source, fileName) {
  80. if (fileName === void 0) { fileName = ''; }
  81. var _this = _super.call(this, source, fileName) || this;
  82. _this.source = source;
  83. _this.fileName = fileName;
  84. _this.blockStart = -1;
  85. _this.expressions = [];
  86. _this.callExpressions = [];
  87. return _this;
  88. }
  89. ExpressionParser.prototype.parse = function () {
  90. try {
  91. var expr = this._parse();
  92. return expr;
  93. }
  94. catch (e) {
  95. if (this.fileName) {
  96. e.message += "\nfile: " + this.fileName;
  97. }
  98. e.message += "\nline: " + this.line + ", column: " + this.column + "\n\n" + this.currentContext();
  99. throw e;
  100. }
  101. };
  102. ExpressionParser.prototype._parse = function () {
  103. while (!this.eof()) {
  104. if (this.match(123 /* LEFT_CURLY_BRACE */) && this.match(123 /* LEFT_CURLY_BRACE */, this.pos + 1)) {
  105. this.advance(2);
  106. this.enterInterpolationBlock();
  107. // TODO: parse function calls and pass it to transfomers
  108. this.parseInterpolationExpression();
  109. continue;
  110. }
  111. this.advance();
  112. }
  113. return { expression: this.expressions, callExpressions: this.callExpressions };
  114. };
  115. /**
  116. * Parse expressions in wxml, it only cares about function calls
  117. * and ignore other expressions since it's trivial for i18n
  118. */
  119. ExpressionParser.prototype.parseInterpolationExpression = function () {
  120. while (!this.eof()) {
  121. this.consumeQuoteString();
  122. if (this.match(125 /* RIGHT_CURLY_BRACE */) && this.match(125 /* RIGHT_CURLY_BRACE */, this.pos + 1)) {
  123. var _a = this.exitInterpolationBlock(), start = _a.start, end = _a.end, block = _a.block;
  124. this.advance(2);
  125. if (end > start && start !== -1) {
  126. this.expressions.push(new Expression(start, end, block));
  127. }
  128. return;
  129. }
  130. // maybe function call expression
  131. if (this.match(40 /* LEFT_PAREN */)) {
  132. var start = this.isFunctionCallExpression(this.pos);
  133. if (start !== -1) {
  134. var exprs = this.parseFunctionCallExpression(start);
  135. this.callExpressions.push(exprs);
  136. continue;
  137. }
  138. }
  139. this.advance();
  140. }
  141. };
  142. ExpressionParser.prototype.parseObjectDecl = function () {
  143. var callFunctions = [];
  144. while (!this.eof()) {
  145. this.consumeQuoteString();
  146. if (this.match(125 /* RIGHT_CURLY_BRACE */)) {
  147. this.advance();
  148. return callFunctions;
  149. }
  150. if (this.match(40 /* LEFT_PAREN */)) {
  151. var start = this.isFunctionCallExpression(this.pos);
  152. if (start !== -1) {
  153. var expr = this.parseFunctionCallExpression(start);
  154. callFunctions.push(expr);
  155. }
  156. }
  157. if (this.match(123 /* LEFT_CURLY_BRACE */)) {
  158. this.advance();
  159. callFunctions.push.apply(callFunctions, __spread(this.parseObjectDecl()));
  160. continue;
  161. }
  162. this.advance();
  163. }
  164. return callFunctions;
  165. };
  166. ExpressionParser.prototype.parseFunctionCallExpression = function (start) {
  167. var childFunctions = [];
  168. var functionNameEnd = this.pos;
  169. if (this.consumeChar() !== 40 /* LEFT_PAREN */) {
  170. throw new Error('expected a left paren for a function call');
  171. }
  172. while (!this.eof()) {
  173. this.consumeQuoteString();
  174. if (this.match(123 /* LEFT_CURLY_BRACE */)) {
  175. // JavaScript block should be ignored
  176. this.advance();
  177. var expr = this.parseObjectDecl();
  178. childFunctions.push.apply(childFunctions, __spread(expr));
  179. }
  180. if (this.consumeChar() === 41 /* RIGHT_PAREN */) {
  181. break;
  182. }
  183. }
  184. return new CallExpression(start, this.pos, this.source.substring(start, functionNameEnd), start, functionNameEnd, this.source.substring(functionNameEnd + 1, this.pos - 1).trim(), childFunctions);
  185. };
  186. ExpressionParser.prototype.enterInterpolationBlock = function () {
  187. // Already in an translation block, this must not be
  188. // valid translation block
  189. if (this.blockStart !== -1)
  190. return;
  191. this.blockStart = this.pos;
  192. };
  193. ExpressionParser.prototype.exitInterpolationBlock = function () {
  194. var start = this.blockStart;
  195. var end = this.pos;
  196. var block = this.source.substring(start, end);
  197. this.blockStart = -1;
  198. return { start: start, end: end, block: block };
  199. };
  200. ExpressionParser.prototype.matchNextChar = function (code) {
  201. return this.source.charCodeAt(++this.pos) === code;
  202. };
  203. ExpressionParser.prototype.isFunctionCallExpression = function (pos) {
  204. while (--pos >= 0) {
  205. // maybe wxs call {{ a.b() }}
  206. if (this.match(46 /* DOT */, pos))
  207. return -1;
  208. if (!utils_1.isValidFunctionLiteralChar(this.source.charCodeAt(pos)))
  209. break;
  210. }
  211. return pos + 1;
  212. };
  213. return ExpressionParser;
  214. }(parser_1.default));
  215. exports.default = ExpressionParser;