1 | "use strict";
|
2 | var isArray = Array.isArray;
|
3 | var ok = require("assert").ok;
|
4 |
|
5 | var Node = require("./ast/Node");
|
6 | var Program = require("./ast/Program");
|
7 | var TemplateRoot = require("./ast/TemplateRoot");
|
8 | var FunctionDeclaration = require("./ast/FunctionDeclaration");
|
9 | var FunctionCall = require("./ast/FunctionCall");
|
10 | var Literal = require("./ast/Literal");
|
11 | var Identifier = require("./ast/Identifier");
|
12 | var Comment = require("./ast/Comment");
|
13 | var If = require("./ast/If");
|
14 | var ElseIf = require("./ast/ElseIf");
|
15 | var Else = require("./ast/Else");
|
16 | var Assignment = require("./ast/Assignment");
|
17 | var BinaryExpression = require("./ast/BinaryExpression");
|
18 | var LogicalExpression = require("./ast/LogicalExpression");
|
19 | var Vars = require("./ast/Vars");
|
20 | var Return = require("./ast/Return");
|
21 | var HtmlElement = require("./ast/HtmlElement");
|
22 | var Html = require("./ast/Html");
|
23 | var Text = require("./ast/Text");
|
24 | var ForEach = require("./ast/ForEach");
|
25 | var ForEachProp = require("./ast/ForEachProp");
|
26 | var ForRange = require("./ast/ForRange");
|
27 | var HtmlComment = require("./ast/HtmlComment");
|
28 | var SelfInvokingFunction = require("./ast/SelfInvokingFunction");
|
29 | var ForStatement = require("./ast/ForStatement");
|
30 | var UpdateExpression = require("./ast/UpdateExpression");
|
31 | var UnaryExpression = require("./ast/UnaryExpression");
|
32 | var MemberExpression = require("./ast/MemberExpression");
|
33 | var Code = require("./ast/Code");
|
34 | var Macro = require("./ast/Macro");
|
35 | var ConditionalExpression = require("./ast/ConditionalExpression");
|
36 | var NewExpression = require("./ast/NewExpression");
|
37 | var ObjectExpression = require("./ast/ObjectExpression");
|
38 | var ArrayExpression = require("./ast/ArrayExpression");
|
39 | var Property = require("./ast/Property");
|
40 | var VariableDeclarator = require("./ast/VariableDeclarator");
|
41 | var ThisExpression = require("./ast/ThisExpression");
|
42 | var TemplateLiteral = require("./ast/TemplateLiteral");
|
43 | var Expression = require("./ast/Expression");
|
44 | var Scriptlet = require("./ast/Scriptlet");
|
45 | var ContainerNode = require("./ast/ContainerNode");
|
46 | var WhileStatement = require("./ast/WhileStatement");
|
47 | var DocumentType = require("./ast/DocumentType");
|
48 | var Declaration = require("./ast/Declaration");
|
49 | var SequenceExpression = require("./ast/SequenceExpression");
|
50 | var CustomTag = require("./ast/CustomTag");
|
51 |
|
52 | var parseExpression = require("./util/parseExpression");
|
53 | var parseStatement = require("./util/parseStatement");
|
54 | var parseJavaScriptArgs = require("./util/parseJavaScriptArgs");
|
55 | var parseJavaScriptParams = require("./util/parseJavaScriptParams");
|
56 | var isValidJavaScriptIdentifier = require("./util/isValidJavaScriptIdentifier");
|
57 |
|
58 | var DEFAULT_BUILDER;
|
59 |
|
60 | function makeNode(arg) {
|
61 | if (typeof arg === "string") {
|
62 | return parseExpression(arg, DEFAULT_BUILDER);
|
63 | } else if (arg instanceof Node) {
|
64 | return arg;
|
65 | } else if (arg == null) {
|
66 | return undefined;
|
67 | } else if (Array.isArray(arg)) {
|
68 | return arg.map(arg => {
|
69 | return makeNode(arg);
|
70 | });
|
71 | } else {
|
72 | throw new Error(
|
73 | "Argument should be a string or Node or null. Actual: " + arg
|
74 | );
|
75 | }
|
76 | }
|
77 |
|
78 | var literalNull = new Literal({ value: null });
|
79 | var literalUndefined = new Literal({ value: undefined });
|
80 | var literalTrue = new Literal({ value: true });
|
81 | var literalFalse = new Literal({ value: false });
|
82 | var identifierOut = new Identifier({ name: "out" });
|
83 | var identifierRequire = new Identifier({ name: "require" });
|
84 |
|
85 | class Builder {
|
86 | arrayExpression(elements) {
|
87 | if (elements) {
|
88 | if (!isArray(elements)) {
|
89 | elements = [elements];
|
90 | }
|
91 |
|
92 | for (var i = 0; i < elements.length; i++) {
|
93 | elements[i] = makeNode(elements[i]);
|
94 | }
|
95 | } else {
|
96 | elements = [];
|
97 | }
|
98 |
|
99 | return new ArrayExpression({ elements });
|
100 | }
|
101 |
|
102 | assignment(left, right, operator) {
|
103 | if (operator == null) {
|
104 | operator = "=";
|
105 | }
|
106 | left = makeNode(left);
|
107 | right = makeNode(right);
|
108 | return new Assignment({ left, right, operator });
|
109 | }
|
110 |
|
111 | binaryExpression(left, operator, right) {
|
112 | left = makeNode(left);
|
113 | right = makeNode(right);
|
114 | return new BinaryExpression({ left, operator, right });
|
115 | }
|
116 |
|
117 | sequenceExpression(expressions) {
|
118 | expressions = makeNode(expressions);
|
119 | return new SequenceExpression({ expressions });
|
120 | }
|
121 |
|
122 | code(value) {
|
123 | return new Code({ value });
|
124 | }
|
125 |
|
126 | computedMemberExpression(object, property) {
|
127 | object = makeNode(object);
|
128 | property = makeNode(property);
|
129 | let computed = true;
|
130 |
|
131 | return new MemberExpression({ object, property, computed });
|
132 | }
|
133 |
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | concat(args) {
|
141 | var prev;
|
142 | let operator = "+";
|
143 | args = Array.isArray(args)
|
144 | ? args
|
145 | : Array.prototype.slice.call(arguments, 0);
|
146 |
|
147 | for (var i = 1; i < args.length; i++) {
|
148 | var left;
|
149 | var right = makeNode(args[i]);
|
150 | if (i === 1) {
|
151 | left = makeNode(args[i - 1]);
|
152 | } else {
|
153 | left = prev;
|
154 | }
|
155 |
|
156 | prev = new BinaryExpression({ left, operator, right });
|
157 | }
|
158 |
|
159 | return prev;
|
160 | }
|
161 |
|
162 | conditionalExpression(test, consequent, alternate) {
|
163 | return new ConditionalExpression({ test, consequent, alternate });
|
164 | }
|
165 |
|
166 | containerNode(type, codeGenerator) {
|
167 | if (typeof type === "function") {
|
168 | codeGenerator = arguments[0];
|
169 | type = "ContainerNode";
|
170 | }
|
171 |
|
172 | var node = new ContainerNode(type);
|
173 | if (codeGenerator) {
|
174 | node.setCodeGenerator(codeGenerator);
|
175 | }
|
176 | return node;
|
177 | }
|
178 |
|
179 | customTag(el, tagDef) {
|
180 | return new CustomTag(el, tagDef);
|
181 | }
|
182 |
|
183 | declaration(declaration) {
|
184 | return new Declaration({ declaration });
|
185 | }
|
186 |
|
187 | documentType(documentType) {
|
188 | return new DocumentType({ documentType });
|
189 | }
|
190 |
|
191 | elseStatement(body) {
|
192 | return new Else({ body });
|
193 | }
|
194 |
|
195 | elseIfStatement(test, body, elseStatement) {
|
196 | test = makeNode(test);
|
197 |
|
198 | return new ElseIf({ test, body, else: elseStatement });
|
199 | }
|
200 |
|
201 | expression(value, ast) {
|
202 | return new Expression({ value, ast });
|
203 | }
|
204 |
|
205 | forEach(params, ofExpression, body) {
|
206 | return new ForEach(
|
207 | arguments.length === 1
|
208 | ? params
|
209 | : {
|
210 | params: makeNode(params),
|
211 | of: makeNode(ofExpression),
|
212 | body
|
213 | }
|
214 | );
|
215 | }
|
216 |
|
217 | forEachProp(params, inExpression, body) {
|
218 | return new ForEachProp(
|
219 | arguments.length === 1
|
220 | ? params
|
221 | : {
|
222 | params: makeNode(params),
|
223 | in: makeNode(inExpression),
|
224 | body
|
225 | }
|
226 | );
|
227 | }
|
228 |
|
229 | forRange(params, from, to, step, body) {
|
230 | return new ForRange(
|
231 | arguments.length === 1
|
232 | ? params
|
233 | : {
|
234 | params: makeNode(params),
|
235 | from: makeNode(from),
|
236 | to: makeNode(to),
|
237 | step: makeNode(step),
|
238 | body
|
239 | }
|
240 | );
|
241 | }
|
242 |
|
243 | forStatement(init, test, update, body) {
|
244 | if (arguments.length === 1) {
|
245 | var def = arguments[0];
|
246 | return new ForStatement(def);
|
247 | } else {
|
248 | init = makeNode(init);
|
249 | test = makeNode(test);
|
250 | update = makeNode(update);
|
251 | return new ForStatement({ init, test, update, body });
|
252 | }
|
253 | }
|
254 |
|
255 | functionCall(callee, args) {
|
256 | callee = makeNode(callee);
|
257 |
|
258 | if (args) {
|
259 | if (!isArray(args)) {
|
260 | throw new Error('"args" should be an array');
|
261 | }
|
262 |
|
263 | for (var i = 0; i < args.length; i++) {
|
264 | args[i] = makeNode(args[i]);
|
265 | }
|
266 | } else {
|
267 | args = [];
|
268 | }
|
269 |
|
270 | return new FunctionCall({ callee, args });
|
271 | }
|
272 |
|
273 | functionDeclaration(name, params, body) {
|
274 | return new FunctionDeclaration({ name, params, body });
|
275 | }
|
276 |
|
277 | html(argument) {
|
278 | argument = makeNode(argument);
|
279 |
|
280 | return new Html({ argument });
|
281 | }
|
282 |
|
283 | htmlComment(comment) {
|
284 | return new HtmlComment({ comment });
|
285 | }
|
286 |
|
287 | comment(comment) {
|
288 | return new Comment({ comment });
|
289 | }
|
290 |
|
291 | htmlElement(tagName, attributes, body, argument, openTagOnly, selfClosed) {
|
292 | if (typeof tagName === "object" && !(tagName instanceof Node)) {
|
293 | let def = arguments[0];
|
294 | return new HtmlElement(def);
|
295 | } else {
|
296 | return new HtmlElement({
|
297 | tagName,
|
298 | attributes,
|
299 | body,
|
300 | argument,
|
301 | openTagOnly,
|
302 | selfClosed
|
303 | });
|
304 | }
|
305 | }
|
306 |
|
307 | htmlLiteral(htmlCode) {
|
308 | var argument = new Literal({ value: htmlCode });
|
309 | return new Html({ argument });
|
310 | }
|
311 |
|
312 | identifier(name) {
|
313 | ok(typeof name === "string", '"name" should be a string');
|
314 |
|
315 | if (!isValidJavaScriptIdentifier(name)) {
|
316 | var error = new Error("Invalid JavaScript identifier: " + name);
|
317 | error.code = "INVALID_IDENTIFIER";
|
318 | throw error;
|
319 | }
|
320 | return new Identifier({ name });
|
321 | }
|
322 |
|
323 | identifierOut() {
|
324 | return identifierOut;
|
325 | }
|
326 |
|
327 | ifStatement(test, body, elseStatement) {
|
328 | test = makeNode(test);
|
329 |
|
330 | return new If({ test, body, else: elseStatement });
|
331 | }
|
332 |
|
333 | literal(value) {
|
334 | return new Literal({ value });
|
335 | }
|
336 |
|
337 | literalFalse() {
|
338 | return literalFalse;
|
339 | }
|
340 |
|
341 | literalNull() {
|
342 | return literalNull;
|
343 | }
|
344 |
|
345 | literalTrue() {
|
346 | return literalTrue;
|
347 | }
|
348 |
|
349 | literalUndefined() {
|
350 | return literalUndefined;
|
351 | }
|
352 |
|
353 | logicalExpression(left, operator, right) {
|
354 | left = makeNode(left);
|
355 | right = makeNode(right);
|
356 | return new LogicalExpression({ left, operator, right });
|
357 | }
|
358 |
|
359 | macro(name, params, body) {
|
360 | return new Macro({ name, params, body });
|
361 | }
|
362 |
|
363 | memberExpression(object, property, computed) {
|
364 | object = makeNode(object);
|
365 | property = makeNode(property);
|
366 |
|
367 | return new MemberExpression({ object, property, computed });
|
368 | }
|
369 |
|
370 | moduleExports(value) {
|
371 | let object = new Identifier({ name: "module" });
|
372 | let property = new Identifier({ name: "exports" });
|
373 |
|
374 | var moduleExports = new MemberExpression({ object, property });
|
375 |
|
376 | if (value) {
|
377 | return new Assignment({
|
378 | left: moduleExports,
|
379 | right: value,
|
380 | operator: "="
|
381 | });
|
382 | } else {
|
383 | return moduleExports;
|
384 | }
|
385 | }
|
386 |
|
387 | negate(argument) {
|
388 | argument = makeNode(argument);
|
389 |
|
390 | var operator = "!";
|
391 | var prefix = true;
|
392 | return new UnaryExpression({ argument, operator, prefix });
|
393 | }
|
394 |
|
395 | newExpression(callee, args) {
|
396 | callee = makeNode(callee);
|
397 |
|
398 | if (args) {
|
399 | if (!isArray(args)) {
|
400 | args = [args];
|
401 | }
|
402 |
|
403 | for (var i = 0; i < args.length; i++) {
|
404 | args[i] = makeNode(args[i]);
|
405 | }
|
406 | } else {
|
407 | args = [];
|
408 | }
|
409 |
|
410 | return new NewExpression({ callee, args });
|
411 | }
|
412 |
|
413 | node(type, generateCode) {
|
414 | if (typeof type === "function") {
|
415 | generateCode = arguments[0];
|
416 | type = "Node";
|
417 | }
|
418 |
|
419 | var node = new Node(type);
|
420 | if (generateCode) {
|
421 | node.setCodeGenerator(generateCode);
|
422 | }
|
423 | return node;
|
424 | }
|
425 |
|
426 | objectExpression(properties) {
|
427 | if (properties) {
|
428 | if (isArray(properties)) {
|
429 | for (var i = 0; i < properties.length; i++) {
|
430 | let prop = properties[i];
|
431 | prop.value = makeNode(prop.value);
|
432 | }
|
433 | } else {
|
434 | let propertiesObject = properties;
|
435 | properties = Object.keys(propertiesObject).map(key => {
|
436 | let value = propertiesObject[key];
|
437 | if (!(value instanceof Node)) {
|
438 | value = value = new Literal({ value });
|
439 | }
|
440 |
|
441 | key = new Literal({ value: key });
|
442 |
|
443 | let property = new Property({ key, value });
|
444 | return property;
|
445 | });
|
446 | }
|
447 | } else {
|
448 | properties = [];
|
449 | }
|
450 |
|
451 | return new ObjectExpression({ properties });
|
452 | }
|
453 |
|
454 | parseExpression(str) {
|
455 | ok(typeof str === "string", '"str" should be a string expression');
|
456 | var parsed = parseExpression(str, DEFAULT_BUILDER);
|
457 | return parsed;
|
458 | }
|
459 |
|
460 | parseJavaScriptArgs(args) {
|
461 | ok(typeof args === "string", '"args" should be a string');
|
462 | return parseJavaScriptArgs(args, DEFAULT_BUILDER);
|
463 | }
|
464 |
|
465 | parseJavaScriptParams(params) {
|
466 | ok(typeof params === "string", '"params" should be a string');
|
467 | return parseJavaScriptParams(params, DEFAULT_BUILDER);
|
468 | }
|
469 |
|
470 | parseStatement(str) {
|
471 | ok(typeof str === "string", '"str" should be a string expression');
|
472 | var parsed = parseStatement(str, DEFAULT_BUILDER);
|
473 | return parsed;
|
474 | }
|
475 |
|
476 | replacePlaceholderEscapeFuncs(node) {
|
477 | return node;
|
478 | }
|
479 |
|
480 | program(body) {
|
481 | return new Program({ body });
|
482 | }
|
483 |
|
484 | property(key, value, computed) {
|
485 | key = makeNode(key);
|
486 | value = makeNode(value);
|
487 | computed = computed === true;
|
488 |
|
489 | return new Property({ key, value, computed });
|
490 | }
|
491 |
|
492 | renderBodyFunction(body, params) {
|
493 | if (!params) {
|
494 | params = [new Identifier({ name: "out" })];
|
495 | }
|
496 | return new FunctionDeclaration({ name: null, params, body });
|
497 | }
|
498 |
|
499 | require(path) {
|
500 | path = makeNode(path);
|
501 |
|
502 | let callee = identifierRequire;
|
503 | let args = [path];
|
504 | return new FunctionCall({ callee, args });
|
505 | }
|
506 |
|
507 | requireResolve(path) {
|
508 | path = makeNode(path);
|
509 |
|
510 | let callee = new MemberExpression({
|
511 | object: new Identifier({ name: "require" }),
|
512 | property: new Identifier({ name: "resolve" })
|
513 | });
|
514 |
|
515 | let args = [path];
|
516 | return new FunctionCall({ callee, args });
|
517 | }
|
518 |
|
519 | returnStatement(argument) {
|
520 | argument = makeNode(argument);
|
521 |
|
522 | return new Return({ argument });
|
523 | }
|
524 |
|
525 | scriptlet(scriptlet) {
|
526 | return new Scriptlet({
|
527 | code: scriptlet.value,
|
528 | tag: scriptlet.tag,
|
529 | block: scriptlet.block
|
530 | });
|
531 | }
|
532 |
|
533 | selfInvokingFunction(params, args, body) {
|
534 | if (arguments.length === 1) {
|
535 | body = arguments[0];
|
536 | params = null;
|
537 | args = null;
|
538 | }
|
539 |
|
540 | return new SelfInvokingFunction({ params, args, body });
|
541 | }
|
542 |
|
543 | strictEquality(left, right) {
|
544 | left = makeNode(left);
|
545 | right = makeNode(right);
|
546 |
|
547 | var operator = "===";
|
548 | return new BinaryExpression({ left, right, operator });
|
549 | }
|
550 |
|
551 | templateLiteral(quasis, expressions) {
|
552 | return new TemplateLiteral({ quasis, expressions });
|
553 | }
|
554 |
|
555 | templateRoot(body) {
|
556 | return new TemplateRoot({ body });
|
557 | }
|
558 |
|
559 | text(argument, escape, preserveWhitespace) {
|
560 | if (typeof argument === "object" && !(argument instanceof Node)) {
|
561 | var def = arguments[0];
|
562 | return new Text(def);
|
563 | }
|
564 | argument = makeNode(argument);
|
565 |
|
566 | return new Text({ argument, escape, preserveWhitespace });
|
567 | }
|
568 |
|
569 | thisExpression() {
|
570 | return new ThisExpression();
|
571 | }
|
572 |
|
573 | unaryExpression(argument, operator, prefix) {
|
574 | argument = makeNode(argument);
|
575 |
|
576 | return new UnaryExpression({ argument, operator, prefix });
|
577 | }
|
578 |
|
579 | updateExpression(argument, operator, prefix) {
|
580 | argument = makeNode(argument);
|
581 | return new UpdateExpression({ argument, operator, prefix });
|
582 | }
|
583 |
|
584 | variableDeclarator(id, init) {
|
585 | if (typeof id === "string") {
|
586 | id = new Identifier({ name: id });
|
587 | }
|
588 | if (init) {
|
589 | init = makeNode(init);
|
590 | }
|
591 |
|
592 | return new VariableDeclarator({ id, init });
|
593 | }
|
594 |
|
595 | var(id, init, kind) {
|
596 | if (!kind) {
|
597 | kind = "var";
|
598 | }
|
599 |
|
600 | id = makeNode(id);
|
601 | init = makeNode(init);
|
602 |
|
603 | var declarations = [new VariableDeclarator({ id, init })];
|
604 |
|
605 | return new Vars({ declarations, kind });
|
606 | }
|
607 |
|
608 | vars(declarations, kind) {
|
609 | if (declarations) {
|
610 | if (Array.isArray(declarations)) {
|
611 | for (let i = 0; i < declarations.length; i++) {
|
612 | var declaration = declarations[i];
|
613 | if (!declaration) {
|
614 | throw new Error("Invalid variable declaration");
|
615 | }
|
616 | if (typeof declaration === "string") {
|
617 | declarations[i] = new VariableDeclarator({
|
618 | id: new Identifier({ name: declaration })
|
619 | });
|
620 | } else if (declaration instanceof Identifier) {
|
621 | declarations[i] = new VariableDeclarator({
|
622 | id: declaration
|
623 | });
|
624 | } else if (typeof declaration === "object") {
|
625 | if (!(declaration instanceof VariableDeclarator)) {
|
626 | let id = declaration.id;
|
627 | let init = declaration.init;
|
628 |
|
629 | if (typeof id === "string") {
|
630 | id = new Identifier({ name: id });
|
631 | }
|
632 |
|
633 | if (!id) {
|
634 | throw new Error("Invalid variable declaration");
|
635 | }
|
636 |
|
637 | if (init) {
|
638 | init = makeNode(init);
|
639 | }
|
640 |
|
641 | declarations[i] = new VariableDeclarator({
|
642 | id,
|
643 | init
|
644 | });
|
645 | }
|
646 | }
|
647 | }
|
648 | } else if (typeof declarations === "object") {
|
649 |
|
650 | declarations = Object.keys(declarations).map(key => {
|
651 | let id = new Identifier({ name: key });
|
652 | let init = makeNode(declarations[key]);
|
653 | return new VariableDeclarator({ id, init });
|
654 | });
|
655 | }
|
656 | }
|
657 |
|
658 | return new Vars({ declarations, kind });
|
659 | }
|
660 |
|
661 | whileStatement(test, body) {
|
662 | return new WhileStatement({ test, body });
|
663 | }
|
664 | }
|
665 |
|
666 | DEFAULT_BUILDER = new Builder();
|
667 |
|
668 | Builder.DEFAULT_BUILDER = DEFAULT_BUILDER;
|
669 |
|
670 | module.exports = Builder;
|