wxml-parser.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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 __values = (this && this.__values) || function(o) {
  16. var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
  17. if (m) return m.call(o);
  18. if (o && typeof o.length === "number") return {
  19. next: function () {
  20. if (o && i >= o.length) o = void 0;
  21. return { value: o && o[i++], done: !o };
  22. }
  23. };
  24. throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
  25. };
  26. var __read = (this && this.__read) || function (o, n) {
  27. var m = typeof Symbol === "function" && o[Symbol.iterator];
  28. if (!m) return o;
  29. var i = m.call(o), r, ar = [], e;
  30. try {
  31. while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
  32. }
  33. catch (error) { e = { error: error }; }
  34. finally {
  35. try {
  36. if (r && !r.done && (m = i["return"])) m.call(i);
  37. }
  38. finally { if (e) throw e.error; }
  39. }
  40. return ar;
  41. };
  42. var __importDefault = (this && this.__importDefault) || function (mod) {
  43. return (mod && mod.__esModule) ? mod : { "default": mod };
  44. };
  45. Object.defineProperty(exports, "__esModule", { value: true });
  46. exports.Text = exports.Element = exports.AttributeValue = exports.Node = void 0;
  47. var types_1 = require("./types");
  48. var parser_1 = __importDefault(require("./parser"));
  49. var utils_1 = require("./utils");
  50. var Node = /** @class */ (function () {
  51. function Node(tagName) {
  52. this.tagName = tagName;
  53. }
  54. Node.prototype.dump = function () {
  55. return { type: this.tagName };
  56. };
  57. return Node;
  58. }());
  59. exports.Node = Node;
  60. var AttributeValue = /** @class */ (function () {
  61. function AttributeValue(value, start, end) {
  62. this.value = value;
  63. this.start = start;
  64. this.end = end;
  65. }
  66. return AttributeValue;
  67. }());
  68. exports.AttributeValue = AttributeValue;
  69. var Element = /** @class */ (function (_super) {
  70. __extends(Element, _super);
  71. function Element(tagName, attributes, children) {
  72. var _this = _super.call(this, tagName) || this;
  73. _this.attributes = attributes;
  74. _this.children = children;
  75. return _this;
  76. }
  77. Element.prototype.dump = function () {
  78. var e_1, _a;
  79. var attributes = {};
  80. if (this.attributes) {
  81. try {
  82. for (var _b = __values(this.attributes), _c = _b.next(); !_c.done; _c = _b.next()) {
  83. var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
  84. if (value && value.value) {
  85. attributes[key] = value.value;
  86. }
  87. else {
  88. attributes[key] = null;
  89. }
  90. }
  91. }
  92. catch (e_1_1) { e_1 = { error: e_1_1 }; }
  93. finally {
  94. try {
  95. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  96. }
  97. finally { if (e_1) throw e_1.error; }
  98. }
  99. }
  100. var children = this.children.map(function (child) { return child.dump(); });
  101. return { type: this.tagName, attributes: attributes, children: children };
  102. };
  103. return Element;
  104. }(Node));
  105. exports.Element = Element;
  106. var Text = /** @class */ (function (_super) {
  107. __extends(Text, _super);
  108. function Text(content, start, end) {
  109. var _this = _super.call(this, Text.tagName) || this;
  110. _this.content = content;
  111. _this.start = start;
  112. _this.end = end;
  113. return _this;
  114. }
  115. Text.prototype.dump = function () {
  116. return { type: this.tagName, content: this.content };
  117. };
  118. Text.tagName = 'text';
  119. return Text;
  120. }(Node));
  121. exports.Text = Text;
  122. /**
  123. * Simple wxml parser
  124. */
  125. var WxmlParser = /** @class */ (function (_super) {
  126. __extends(WxmlParser, _super);
  127. function WxmlParser(source, fileName) {
  128. if (fileName === void 0) { fileName = ''; }
  129. var _this = _super.call(this, source, fileName) || this;
  130. _this.source = source;
  131. _this.fileName = fileName;
  132. _this.state = 1 /* NORMAL */;
  133. return _this;
  134. }
  135. WxmlParser.prototype.parse = function () {
  136. try {
  137. var nodes = this._parse();
  138. return nodes;
  139. }
  140. catch (e) {
  141. if (this.fileName) {
  142. e.message += "\nfile: " + this.fileName;
  143. }
  144. e.message += "\nline: " + this.line + ", column: " + this.column + "\n\n" + this.currentContext();
  145. throw e;
  146. }
  147. };
  148. WxmlParser.prototype._parse = function () {
  149. var nodes = [];
  150. while (!this.eof()) {
  151. this.consumeWhitespace();
  152. if (this.match(60 /* LESS_THAN */) && this.match(47 /* SLASH */, this.pos + 1)) {
  153. break;
  154. }
  155. // Ignore comments
  156. if (this.match(60 /* LESS_THAN */, this.pos) &&
  157. this.match(33 /* EXCLAMATION */, this.pos + 1) &&
  158. this.match(45 /* MINUS */, this.pos + 2) &&
  159. this.match(45 /* MINUS */, this.pos + 3)) {
  160. this.advance(4);
  161. this.parseComments();
  162. continue;
  163. }
  164. if (this.match(60 /* LESS_THAN */)) {
  165. var node = this.parseWxmlTag();
  166. nodes.push(node);
  167. continue;
  168. }
  169. var textNode = this.parseText();
  170. if (textNode.content.length > 0)
  171. nodes.push(textNode);
  172. }
  173. return nodes;
  174. };
  175. WxmlParser.prototype.parseWxmlTag = function () {
  176. if (this.consumeChar() !== 60 /* LESS_THAN */) {
  177. throw new Error('unexpected character for wxml start tag');
  178. }
  179. this.consumeWhitespace();
  180. var tagName = this.parseTagName();
  181. if (!tagName || tagName.length === 0) {
  182. throw new Error("unexpected tag name " + this.currentChar());
  183. }
  184. var attributes = this.parseAttributes();
  185. // self-closing tag
  186. if (this.match(47 /* SLASH */)) {
  187. this.advance();
  188. if (this.consumeChar() !== 62 /* GREATER_THAN */) {
  189. throw new Error('unexpected character ' + this.currentChar());
  190. }
  191. return new Element(tagName, attributes, []);
  192. }
  193. if (this.consumeChar() !== 62 /* GREATER_THAN */) {
  194. throw new Error('expected character > to close a tag');
  195. }
  196. if (tagName.toLowerCase() === types_1.WXS_LITERAL) {
  197. this.state = 2 /* WXS */;
  198. }
  199. var childNodes = this.parse();
  200. if (this.consumeChar() !== 60 /* LESS_THAN */) {
  201. throw new Error('expected char ' + String.fromCharCode(60 /* LESS_THAN */) + ' but got ' + this.currentChar());
  202. }
  203. if (this.consumeChar() !== 47 /* SLASH */) {
  204. throw new Error('expected char ' + String.fromCharCode(47 /* SLASH */) + ' but got ' + this.currentChar());
  205. }
  206. this.consumeWhitespace();
  207. var endTagName = this.parseTagName();
  208. if (endTagName !== tagName) {
  209. throw new Error("expected tag name " + tagName + " but got " + endTagName);
  210. }
  211. this.consumeWhitespace();
  212. if (!this.match(62 /* GREATER_THAN */)) {
  213. throw new Error('expected char ' + String.fromCharCode(62 /* GREATER_THAN */) + ' but got ' + this.currentChar());
  214. }
  215. this.advance();
  216. if (tagName.toLowerCase() === types_1.WXS_LITERAL) {
  217. this.state = 1 /* NORMAL */;
  218. }
  219. return new Element(tagName, attributes, childNodes);
  220. };
  221. WxmlParser.prototype.parseText = function () {
  222. var start = this.pos;
  223. if (this.state === 2 /* WXS */) {
  224. while (!this.eof() && !(this.match(60 /* LESS_THAN */) && this.match(47 /* SLASH */, this.pos + 1))) {
  225. if (!this.consumeQuoteString() && !this.consumeWXSComments()) {
  226. this.advance();
  227. }
  228. }
  229. return new Text(this.source.substring(start, this.pos), start, this.pos);
  230. }
  231. return new Text(this.parseTextContents(), start, this.pos);
  232. };
  233. WxmlParser.prototype.parseTextContents = function () {
  234. var result = [];
  235. while (!this.eof() && (!this.match(60 /* LESS_THAN */) || this.state === 4 /* INT */)) {
  236. if (this.match(123 /* LEFT_CURLY_BRACE */) && this.match(123 /* LEFT_CURLY_BRACE */, this.pos + 1)) {
  237. this.state = 4 /* INT */;
  238. }
  239. if (this.match(125 /* RIGHT_CURLY_BRACE */) && this.match(125 /* RIGHT_CURLY_BRACE */, this.pos + 1)) {
  240. this.state = 1 /* NORMAL */;
  241. }
  242. var quoteStringRef = { result: '' };
  243. if (this.consumeQuoteString(quoteStringRef)) {
  244. result.push(quoteStringRef.result);
  245. continue;
  246. }
  247. var ch = this.source[this.pos];
  248. result.push(ch);
  249. this.advance();
  250. }
  251. return result.join('');
  252. };
  253. /**
  254. * Ignore comments
  255. */
  256. WxmlParser.prototype.parseComments = function () {
  257. while (!this.eof()) {
  258. if (this.match(45 /* MINUS */, this.pos) &&
  259. this.match(45 /* MINUS */, this.pos + 1) &&
  260. this.match(62 /* GREATER_THAN */, this.pos + 2)) {
  261. this.advance(3);
  262. return;
  263. }
  264. this.advance();
  265. }
  266. };
  267. WxmlParser.prototype.parseTagName = function () {
  268. // loosy check
  269. // TODO: prevent number as first letter
  270. return this.consumeWhile(function (c) { return utils_1.isLetter(c) || utils_1.isNumber(c); });
  271. };
  272. WxmlParser.prototype.parseAttributeName = function () {
  273. // loosy check
  274. // TODO: prevent number as first letter
  275. // Note: can have colon (:) in between
  276. return this.consumeWhile(function (c) { return utils_1.isLetter(c) || utils_1.isNumber(c) || c === 58 /* COLON */; });
  277. };
  278. WxmlParser.prototype.parseAttributes = function () {
  279. var attrs = new Map();
  280. while (!this.eof()) {
  281. this.consumeWhitespace();
  282. if (this.match(47 /* SLASH */) || this.match(62 /* GREATER_THAN */))
  283. break;
  284. if (!utils_1.isLetter(this.peekCharCode()) && !this.match(58 /* COLON */))
  285. break;
  286. var _a = this.parseAttribute(), name = _a.name, value = _a.value;
  287. attrs.set(name, value);
  288. }
  289. return attrs;
  290. };
  291. WxmlParser.prototype.parseAttribute = function () {
  292. var name = this.parseAttributeName();
  293. this.consumeWhitespace();
  294. if (!this.match(61 /* EQUALS */)) {
  295. return { name: name, value: null };
  296. }
  297. this.advance();
  298. this.consumeWhitespace();
  299. var value = this.parseAttrValue();
  300. return { name: name, value: value };
  301. };
  302. WxmlParser.prototype.parseAttrValue = function () {
  303. var leftQuote = this.consumeChar();
  304. var start = this.pos;
  305. if (leftQuote !== 39 /* SINGLE_QUOTE */ && leftQuote !== 34 /* DOUBLE_QUOTE */) {
  306. throw new Error("expected char " + String.fromCharCode(39 /* SINGLE_QUOTE */) + " or " + String.fromCharCode(34 /* DOUBLE_QUOTE */) + " " +
  307. ("but got " + String.fromCharCode(leftQuote)));
  308. }
  309. var value = this.consumeWhile(function (ch) { return ch !== leftQuote; });
  310. var end = this.pos;
  311. if (this.consumeChar() !== leftQuote) {
  312. throw new Error('expected char ' + String.fromCharCode(leftQuote) + ' to close an attribute');
  313. }
  314. var attribute = new AttributeValue(value, start, end);
  315. return attribute;
  316. };
  317. WxmlParser.prototype.consumeWXSComments = function () {
  318. if (this.match(47 /* SLASH */) && this.match(47 /* SLASH */, this.pos + 1)) {
  319. while (!this.eof()) {
  320. if (this.match(10 /* LINE_FEED */)) {
  321. this.advance();
  322. break;
  323. }
  324. if (this.match(13 /* CARRIAGE_RETURN */) && this.match(10 /* LINE_FEED */)) {
  325. this.advance(2);
  326. break;
  327. }
  328. // If no line end is met we should end at this point
  329. if (this.match(60 /* LESS_THAN */) && this.match(47 /* SLASH */, this.pos + 1)) {
  330. return false;
  331. }
  332. this.advance();
  333. }
  334. return true;
  335. }
  336. else if (this.match(47 /* SLASH */) && this.match(42 /* ASTERISK */, this.pos + 1)) {
  337. while (!this.eof()) {
  338. if (this.match(42 /* ASTERISK */) && this.match(47 /* SLASH */, this.pos + 1)) {
  339. this.advance(2);
  340. break;
  341. }
  342. this.advance();
  343. }
  344. return true;
  345. }
  346. return false;
  347. };
  348. return WxmlParser;
  349. }(parser_1.default));
  350. exports.default = WxmlParser;