vsn 0.1.24 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/demo/demo.html +18 -7
  2. package/demo/vsn.js +1 -0
  3. package/dist/AST/ArithmeticAssignmentNode.d.ts +23 -0
  4. package/dist/AST/ArithmeticAssignmentNode.js +313 -0
  5. package/dist/AST/ArithmeticAssignmentNode.js.map +1 -0
  6. package/dist/AST/ArithmeticNode.d.ts +15 -0
  7. package/dist/AST/ArithmeticNode.js +114 -0
  8. package/dist/AST/ArithmeticNode.js.map +1 -0
  9. package/dist/AST/ArrayNode.d.ts +14 -0
  10. package/dist/AST/ArrayNode.js +114 -0
  11. package/dist/AST/ArrayNode.js.map +1 -0
  12. package/dist/AST/BlockNode.d.ts +11 -0
  13. package/dist/AST/BlockNode.js +98 -0
  14. package/dist/AST/BlockNode.js.map +1 -0
  15. package/dist/AST/BooleanLiteralNode.d.ts +5 -0
  16. package/dist/AST/BooleanLiteralNode.js +31 -0
  17. package/dist/AST/BooleanLiteralNode.js.map +1 -0
  18. package/dist/AST/ComparisonNode.d.ts +15 -0
  19. package/dist/AST/ComparisonNode.js +120 -0
  20. package/dist/AST/ComparisonNode.js.map +1 -0
  21. package/dist/AST/ConditionalNode.d.ts +13 -0
  22. package/dist/AST/ConditionalNode.js +95 -0
  23. package/dist/AST/ConditionalNode.js.map +1 -0
  24. package/dist/AST/ElementAttributeNode.d.ts +18 -0
  25. package/dist/AST/ElementAttributeNode.js +159 -0
  26. package/dist/AST/ElementAttributeNode.js.map +1 -0
  27. package/dist/AST/ElementQueryNode.d.ts +12 -0
  28. package/dist/AST/ElementQueryNode.js +111 -0
  29. package/dist/AST/ElementQueryNode.js.map +1 -0
  30. package/dist/AST/ElementStyleNode.d.ts +18 -0
  31. package/dist/AST/ElementStyleNode.js +159 -0
  32. package/dist/AST/ElementStyleNode.js.map +1 -0
  33. package/dist/AST/ForStatementNode.d.ts +17 -0
  34. package/dist/AST/ForStatementNode.js +121 -0
  35. package/dist/AST/ForStatementNode.js.map +1 -0
  36. package/dist/AST/FunctionArgumentNode.d.ts +11 -0
  37. package/dist/AST/FunctionArgumentNode.js +100 -0
  38. package/dist/AST/FunctionArgumentNode.js.map +1 -0
  39. package/dist/AST/FunctionCallNode.d.ts +13 -0
  40. package/dist/AST/FunctionCallNode.js +102 -0
  41. package/dist/AST/FunctionCallNode.js.map +1 -0
  42. package/dist/AST/IfStatementNode.d.ts +14 -0
  43. package/dist/AST/IfStatementNode.js +128 -0
  44. package/dist/AST/IfStatementNode.js.map +1 -0
  45. package/dist/AST/InNode.d.ts +15 -0
  46. package/dist/AST/InNode.js +107 -0
  47. package/dist/AST/InNode.js.map +1 -0
  48. package/dist/AST/IndexNode.d.ts +16 -0
  49. package/dist/AST/IndexNode.js +126 -0
  50. package/dist/AST/IndexNode.js.map +1 -0
  51. package/dist/AST/LiteralNode.d.ts +10 -0
  52. package/dist/AST/LiteralNode.js +74 -0
  53. package/dist/AST/LiteralNode.js.map +1 -0
  54. package/dist/AST/Node.d.ts +19 -0
  55. package/dist/AST/Node.js +117 -0
  56. package/dist/AST/Node.js.map +1 -0
  57. package/dist/AST/NotNode.d.ts +12 -0
  58. package/dist/AST/NotNode.js +103 -0
  59. package/dist/AST/NotNode.js.map +1 -0
  60. package/dist/AST/NumberLiteralNode.d.ts +5 -0
  61. package/dist/AST/NumberLiteralNode.js +36 -0
  62. package/dist/AST/NumberLiteralNode.js.map +1 -0
  63. package/dist/AST/ObjectNode.d.ts +14 -0
  64. package/dist/AST/ObjectNode.js +131 -0
  65. package/dist/AST/ObjectNode.js.map +1 -0
  66. package/dist/AST/RootScopeMemberNode.d.ts +11 -0
  67. package/dist/AST/RootScopeMemberNode.js +87 -0
  68. package/dist/AST/RootScopeMemberNode.js.map +1 -0
  69. package/dist/AST/ScopeMemberNode.d.ts +12 -0
  70. package/dist/AST/ScopeMemberNode.js +128 -0
  71. package/dist/AST/ScopeMemberNode.js.map +1 -0
  72. package/dist/AST/UnitLiteralNode.d.ts +15 -0
  73. package/dist/AST/UnitLiteralNode.js +72 -0
  74. package/dist/AST/UnitLiteralNode.js.map +1 -0
  75. package/dist/AST.d.ts +9 -61
  76. package/dist/AST.js +84 -1413
  77. package/dist/AST.js.map +1 -1
  78. package/dist/Attribute.d.ts +1 -1
  79. package/dist/Attribute.js +3 -3
  80. package/dist/Attribute.js.map +1 -1
  81. package/dist/Configuration.d.ts +1 -1
  82. package/dist/Configuration.js +4 -4
  83. package/dist/Configuration.js.map +1 -1
  84. package/dist/Controller.d.ts +12 -4
  85. package/dist/Controller.js +38 -6
  86. package/dist/Controller.js.map +1 -1
  87. package/dist/DOM/DOMObject.d.ts +1 -1
  88. package/dist/DOM/DOMObject.js +2 -2
  89. package/dist/DOM/DOMObject.js.map +1 -1
  90. package/dist/DOM.d.ts +1 -1
  91. package/dist/DOM.js +4 -4
  92. package/dist/DOM.js.map +1 -1
  93. package/dist/EventDispatcher.d.ts +29 -0
  94. package/dist/EventDispatcher.js +132 -0
  95. package/dist/EventDispatcher.js.map +1 -0
  96. package/dist/Formats.js +2 -2
  97. package/dist/Formats.js.map +1 -1
  98. package/dist/MessageList.d.ts +14 -0
  99. package/dist/MessageList.js +88 -0
  100. package/dist/MessageList.js.map +1 -0
  101. package/dist/Model/Field.d.ts +8 -0
  102. package/dist/Model/Field.js +38 -0
  103. package/dist/Model/Field.js.map +1 -0
  104. package/dist/Model.d.ts +12 -0
  105. package/dist/Model.js +61 -0
  106. package/dist/Model.js.map +1 -0
  107. package/dist/Registry.d.ts +5 -2
  108. package/dist/Registry.js +17 -16
  109. package/dist/Registry.js.map +1 -1
  110. package/dist/Scope/DynamicScopeData.d.ts +6 -0
  111. package/dist/Scope/DynamicScopeData.js +54 -0
  112. package/dist/Scope/DynamicScopeData.js.map +1 -0
  113. package/dist/Scope/QueryReference.d.ts +10 -0
  114. package/dist/Scope/QueryReference.js +103 -0
  115. package/dist/Scope/QueryReference.js.map +1 -0
  116. package/dist/Scope/ScopeData.d.ts +4 -0
  117. package/dist/Scope/ScopeData.js +40 -0
  118. package/dist/Scope/ScopeData.js.map +1 -0
  119. package/dist/Scope/ScopeDataAbstract.d.ts +22 -0
  120. package/dist/Scope/ScopeDataAbstract.js +137 -0
  121. package/dist/Scope/ScopeDataAbstract.js.map +1 -0
  122. package/dist/Scope/ScopeReference.d.ts +10 -0
  123. package/dist/Scope/ScopeReference.js +73 -0
  124. package/dist/Scope/ScopeReference.js.map +1 -0
  125. package/dist/Scope/ScopedVariableType.d.ts +6 -0
  126. package/dist/Scope/ScopedVariableType.js +14 -0
  127. package/dist/Scope/ScopedVariableType.js.map +1 -0
  128. package/dist/Scope/WrappedArray.d.ts +16 -0
  129. package/dist/Scope/WrappedArray.js +121 -0
  130. package/dist/Scope/WrappedArray.js.map +1 -0
  131. package/dist/Scope/properties/Property.d.ts +18 -0
  132. package/dist/Scope/properties/Property.js +93 -0
  133. package/dist/Scope/properties/Property.js.map +1 -0
  134. package/dist/Scope.d.ts +4 -48
  135. package/dist/Scope.js +39 -324
  136. package/dist/Scope.js.map +1 -1
  137. package/dist/SimplePromise.d.ts +42 -0
  138. package/dist/SimplePromise.js +217 -0
  139. package/dist/SimplePromise.js.map +1 -0
  140. package/dist/Tag.js +11 -5
  141. package/dist/Tag.js.map +1 -1
  142. package/dist/Types.d.ts +1 -0
  143. package/dist/Types.js +8 -1
  144. package/dist/Types.js.map +1 -1
  145. package/dist/Validators.d.ts +7 -0
  146. package/dist/Validators.js +54 -0
  147. package/dist/Validators.js.map +1 -0
  148. package/dist/attributes/Bind.js +1 -1
  149. package/dist/attributes/Bind.js.map +1 -1
  150. package/dist/attributes/JSONAttribute.js.map +1 -1
  151. package/dist/attributes/List.js +7 -7
  152. package/dist/attributes/List.js.map +1 -1
  153. package/dist/attributes/On.js +4 -1
  154. package/dist/attributes/On.js.map +1 -1
  155. package/dist/attributes/Radio.js +4 -2
  156. package/dist/attributes/Radio.js.map +1 -1
  157. package/dist/attributes/ScopeChange.js +1 -1
  158. package/dist/attributes/ScopeChange.js.map +1 -1
  159. package/dist/attributes/SetAttribute.js.map +1 -1
  160. package/dist/attributes/StandardAttribute.js +1 -1
  161. package/dist/attributes/StandardAttribute.js.map +1 -1
  162. package/dist/attributes/StyleAttribute.js +1 -1
  163. package/dist/attributes/StyleAttribute.js.map +1 -1
  164. package/dist/{Vision.d.ts → vsn.d.ts} +7 -2
  165. package/dist/{Vision.js → vsn.js} +21 -12
  166. package/dist/vsn.js.map +1 -0
  167. package/package.json +9 -13
  168. package/src/AST/ArithmeticAssignmentNode.ts +236 -0
  169. package/src/AST/ArithmeticNode.ts +52 -0
  170. package/src/AST/ArrayNode.ts +39 -0
  171. package/src/AST/BlockNode.ts +25 -0
  172. package/src/AST/BooleanLiteralNode.ts +10 -0
  173. package/src/AST/ComparisonNode.ts +57 -0
  174. package/src/AST/ConditionalNode.ts +36 -0
  175. package/src/AST/ElementAttributeNode.ts +63 -0
  176. package/src/AST/ElementQueryNode.ts +25 -0
  177. package/src/AST/ElementStyleNode.ts +63 -0
  178. package/src/AST/ForStatementNode.ts +59 -0
  179. package/src/AST/FunctionArgumentNode.ts +27 -0
  180. package/src/AST/FunctionCallNode.ts +32 -0
  181. package/src/AST/IfStatementNode.ts +67 -0
  182. package/src/AST/InNode.ts +46 -0
  183. package/src/AST/IndexNode.ts +61 -0
  184. package/src/AST/LiteralNode.ts +17 -0
  185. package/src/AST/Node.ts +71 -0
  186. package/src/AST/NotNode.ts +41 -0
  187. package/src/AST/NumberLiteralNode.ts +14 -0
  188. package/src/AST/ObjectNode.ts +55 -0
  189. package/src/AST/RootScopeMemberNode.ts +25 -0
  190. package/src/AST/ScopeMemberNode.ts +53 -0
  191. package/src/AST/UnitLiteralNode.ts +51 -0
  192. package/src/AST.ts +45 -1014
  193. package/src/Attribute.ts +2 -2
  194. package/src/Configuration.ts +3 -3
  195. package/src/Controller.ts +31 -6
  196. package/src/DOM/DOMObject.ts +1 -1
  197. package/src/DOM.ts +4 -4
  198. package/src/EventDispatcher.ts +134 -0
  199. package/src/Formats.ts +2 -2
  200. package/src/MessageList.ts +81 -0
  201. package/src/Model/Field.ts +20 -0
  202. package/src/Model.ts +43 -0
  203. package/src/Registry.ts +13 -5
  204. package/src/Scope/DynamicScopeData.ts +29 -0
  205. package/src/Scope/QueryReference.ts +29 -0
  206. package/src/Scope/ScopeData.ts +21 -0
  207. package/src/Scope/ScopeDataAbstract.ts +126 -0
  208. package/src/Scope/ScopeReference.ts +30 -0
  209. package/src/Scope/ScopedVariableType.ts +7 -0
  210. package/src/Scope/WrappedArray.ts +88 -0
  211. package/src/Scope/properties/Property.ts +79 -0
  212. package/src/Scope.ts +35 -251
  213. package/src/SimplePromise.ts +219 -0
  214. package/src/Tag.ts +9 -5
  215. package/src/Types.ts +6 -1
  216. package/src/Validators.ts +45 -0
  217. package/src/attributes/Bind.ts +3 -2
  218. package/src/attributes/JSONAttribute.ts +2 -1
  219. package/src/attributes/List.ts +4 -4
  220. package/src/attributes/On.ts +2 -0
  221. package/src/attributes/Radio.ts +5 -3
  222. package/src/attributes/ScopeChange.ts +2 -2
  223. package/src/attributes/SetAttribute.ts +2 -1
  224. package/src/attributes/StandardAttribute.ts +1 -1
  225. package/src/attributes/StyleAttribute.ts +3 -2
  226. package/src/attributes/TypeAttribute.ts +1 -1
  227. package/src/{Vision.ts → vsn.ts} +12 -5
  228. package/test/AST/ArithmeticAssignmentNode.spec.ts +47 -0
  229. package/test/AST.spec.ts +3 -2
  230. package/test/Controller.spec.ts +44 -0
  231. package/test/DOM.spec.ts +1 -1
  232. package/test/MessageList.spec.ts +101 -0
  233. package/test/Model/DataModel.spec.ts +0 -0
  234. package/test/Scope/DynamicScopeData.spec.ts +141 -0
  235. package/test/Scope.spec.ts +15 -3
  236. package/test/SimplePromise.spec.ts +271 -0
  237. package/test/Tag/TagList.spec.ts +1 -1
  238. package/test/attributes/Bind.spec.ts +5 -5
  239. package/test/attributes/JSONAttribute.spec.ts +1 -1
  240. package/test/attributes/ListItem.spec.ts +1 -1
  241. package/webpack.config.js +2 -2
  242. package/demo/vision.js +0 -1
  243. package/dist/Vision.js.map +0 -1
  244. package/main.py +0 -16
package/src/AST.ts CHANGED
@@ -1,8 +1,29 @@
1
- import {Scope, WrappedArray} from "./Scope";
1
+ import {Scope} from "./Scope";
2
2
  import {DOM} from "./DOM";
3
- import {DOMObject} from "./DOM/DOMObject";
4
- import {TagList} from "./Tag/List";
5
3
  import {Tag} from "./Tag";
4
+ import {RootScopeMemberNode} from "./AST/RootScopeMemberNode";
5
+ import {ScopeMemberNode} from "./AST/ScopeMemberNode";
6
+ import {ElementAttributeNode} from "./AST/ElementAttributeNode";
7
+ import {Node} from "./AST/Node";
8
+ import {BlockNode} from "./AST/BlockNode";
9
+ import {LiteralNode} from "./AST/LiteralNode";
10
+ import {IfStatementNode} from "./AST/IfStatementNode";
11
+ import {ForStatementNode} from "./AST/ForStatementNode";
12
+ import {NumberLiteralNode} from "./AST/NumberLiteralNode";
13
+ import {ElementQueryNode} from "./AST/ElementQueryNode";
14
+ import {IndexNode} from "./AST/IndexNode";
15
+ import {ArrayNode} from "./AST/ArrayNode";
16
+ import {ObjectNode} from "./AST/ObjectNode";
17
+ import {ElementStyleNode} from "./AST/ElementStyleNode";
18
+ import {FunctionCallNode} from "./AST/FunctionCallNode";
19
+ import {FunctionArgumentNode} from "./AST/FunctionArgumentNode";
20
+ import {InNode} from "./AST/InNode";
21
+ import {ComparisonNode} from "./AST/ComparisonNode";
22
+ import {ArithmeticNode} from "./AST/ArithmeticNode";
23
+ import {ArithmeticAssignmentNode} from "./AST/ArithmeticAssignmentNode";
24
+ import {UnitLiteralNode} from "./AST/UnitLiteralNode";
25
+ import {BooleanLiteralNode} from "./AST/BooleanLiteralNode";
26
+ import {NotNode} from "./AST/NotNode";
6
27
 
7
28
  function lower(str: string): string {
8
29
  return str ? str.toLowerCase() : null;
@@ -78,7 +99,8 @@ export enum TokenType {
78
99
  ELEMENT_REFERENCE,
79
100
  ELEMENT_ATTRIBUTE,
80
101
  ELEMENT_STYLE,
81
- ELEMENT_QUERY
102
+ ELEMENT_QUERY,
103
+ UNIT,
82
104
  }
83
105
 
84
106
  const TOKEN_PATTERNS: TokenPattern[] = [
@@ -98,6 +120,10 @@ const TOKEN_PATTERNS: TokenPattern[] = [
98
120
  type: TokenType.TYPE_FLOAT,
99
121
  pattern: /^float+/
100
122
  },
123
+ {
124
+ type: TokenType.UNIT,
125
+ pattern: /^\d+\.?\d?(?:cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)/
126
+ },
101
127
  {
102
128
  type: TokenType.TYPE_STRING,
103
129
  pattern: /^string+/
@@ -144,11 +170,11 @@ const TOKEN_PATTERNS: TokenPattern[] = [
144
170
  },
145
171
  {
146
172
  type: TokenType.ELEMENT_ATTRIBUTE,
147
- pattern: /^\.?@[_a-zA-Z0-9]*/
173
+ pattern: /^\.?@[-_a-zA-Z0-9]*/
148
174
  },
149
175
  {
150
176
  type: TokenType.ELEMENT_STYLE,
151
- pattern: /^\.?\$[a-zA-Z0-9]*/
177
+ pattern: /^\.?\$[-a-zA-Z0-9]*/
152
178
  },
153
179
  {
154
180
  type: TokenType.ELEMENT_REFERENCE,
@@ -270,7 +296,7 @@ const TOKEN_PATTERNS: TokenPattern[] = [
270
296
  type: TokenType.ADD,
271
297
  pattern: /^\+/
272
298
  },
273
- {
299
+ {
274
300
  type: TokenType.SUBTRACT,
275
301
  pattern: /^-/
276
302
  },
@@ -294,1013 +320,10 @@ const TOKEN_PATTERNS: TokenPattern[] = [
294
320
 
295
321
  export interface TreeNode<T = any> {
296
322
  evaluate(scope: Scope, dom: DOM, tag?: Tag);
297
- prepare(scope: Scope, dom: DOM, tag?: Tag);
298
- }
299
-
300
- export abstract class Node implements TreeNode {
301
- protected requiresPrep: boolean = false;
302
- protected _isPreparationRequired: boolean;
303
- protected childNodes: Node[];
304
- protected nodeCache: {[key: string]: Node[]} = {};
305
- abstract evaluate(scope: Scope, dom: DOM, tag?: Tag);
306
-
307
- isPreparationRequired(): boolean {
308
- if (this.requiresPrep)
309
- return true;
310
-
311
- if (this._isPreparationRequired !== undefined)
312
- return this._isPreparationRequired;
313
-
314
- for (const node of this.getChildNodes()) {
315
- if (node.isPreparationRequired()) {
316
- this._isPreparationRequired = true;
317
- return true;
318
- }
319
- }
320
-
321
- return false;
322
- }
323
-
324
- async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
325
- for (const node of this.getChildNodes()) {
326
- await node.prepare(scope, dom, tag);
327
- }
328
- }
329
-
330
- protected _getChildNodes(): Node[] {
331
- return [];
332
- }
333
-
334
- getChildNodes(): Node[] {
335
- if (this.childNodes === undefined) {
336
- this.childNodes = this._getChildNodes();
337
- }
338
- return this.childNodes;
339
- }
340
-
341
- findChildrenByType<T = Node>(t: any): T[] {
342
- return this.findChildrenByTypes([t]);
343
- }
344
-
345
- findChildrenByTypes<T = Node>(types: any[], cacheKey: string = null): T[] {
346
- if (cacheKey !== null && this.nodeCache[cacheKey])
347
- return this.nodeCache[cacheKey] as any;
348
-
349
- const nodes: T[] = [];
350
- for (const child of this.getChildNodes()) {
351
- for (const t of types) {
352
- if (child instanceof t)
353
- nodes.push(child as any as T);
354
- const childNodes: T[] = child.findChildrenByType<T>(t);
355
- nodes.push(...childNodes);
356
- }
357
- }
358
-
359
- if (cacheKey !== null)
360
- this.nodeCache[cacheKey] = nodes as any;
361
-
362
- return nodes;
363
- }
364
- }
365
-
366
-
367
- export class BlockNode extends Node implements TreeNode {
368
- constructor(
369
- public readonly statements: Node[]
370
- ) {
371
- super();
372
- }
373
-
374
- protected _getChildNodes(): Node[] {
375
- return [...(this.statements as Node[])];
376
- }
377
-
378
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
379
- let returnValue: any = null;
380
- for (let i = 0; i < this.statements.length; i++) {
381
- returnValue = await this.statements[i].evaluate(scope, dom, tag);
382
- }
383
- return returnValue;
384
- }
385
- }
386
-
387
- class ComparisonNode extends Node implements TreeNode {
388
- constructor(
389
- public readonly left: Node,
390
- public readonly right: Node,
391
- public readonly type: TokenType
392
- ) {
393
- super();
394
- }
395
-
396
- protected _getChildNodes(): Node[] {
397
- return [
398
- this.left as Node,
399
- this.right as Node
400
- ];
401
- }
402
-
403
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
404
- const left: any = await this.left.evaluate(scope, dom, tag);
405
- const right: any = await this.right.evaluate(scope, dom, tag);
406
- switch (this.type) {
407
- case TokenType.EQUALS:
408
- return left === right;
409
- case TokenType.NOT_EQUALS:
410
- return left !== right;
411
- case TokenType.GREATER_THAN:
412
- return left > right;
413
- case TokenType.LESS_THAN:
414
- return left < right;
415
- case TokenType.GREATER_THAN_EQUAL:
416
- return left >= right;
417
- case TokenType.LESS_THAN_EQUAL:
418
- return left <= right;
419
- }
420
- }
421
-
422
- public static match(tokens: Token[]): boolean {
423
- return [
424
- TokenType.EQUALS,
425
- TokenType.NOT_EQUALS,
426
- TokenType.GREATER_THAN,
427
- TokenType.LESS_THAN,
428
- TokenType.GREATER_THAN_EQUAL,
429
- TokenType.LESS_THAN_EQUAL
430
- ].indexOf(tokens[0].type) > -1
431
- }
432
-
433
- public static parse(lastNode, token, tokens: Token[]) {
434
- tokens.splice(0, 1); // Remove comparison operator
435
- return new ComparisonNode(lastNode, Tree.processTokens(Tree.getNextStatementTokens(tokens)), token.type)
436
- }
437
- }
438
-
439
- class ConditionalNode extends Node implements TreeNode {
440
- constructor(
441
- public readonly condition: Node,
442
- public readonly block: BlockNode
443
- ) {
444
- super();
445
- }
446
-
447
- protected _getChildNodes(): Node[] {
448
- return [
449
- this.condition as Node,
450
- this.block as Node
451
- ];
452
- }
453
-
454
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
455
- const condition = await this.condition.evaluate(scope, dom, tag);
456
- let evaluation = false;
457
-
458
- if (condition instanceof WrappedArray) {
459
- evaluation = condition.length > 0;
460
- } else {
461
- evaluation = !!condition;
462
- }
463
-
464
- return evaluation;
465
- }
466
- }
467
-
468
- class IfStatementNode extends Node implements TreeNode {
469
- constructor(
470
- protected nodes: ConditionalNode[]
471
- ) {
472
- super();
473
- }
474
-
475
- protected _getChildNodes(): Node[] {
476
- return [
477
- ...(this.nodes as Node[])
478
- ]
479
- }
480
-
481
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
482
- for (const condition of this.nodes) {
483
- const uno: boolean = await condition.evaluate(scope, dom, tag);
484
- if (uno) {
485
- return await condition.block.evaluate(scope, dom, tag);
486
- }
487
- }
488
- }
489
-
490
- public static parseConditional(tokens: Token[]): ConditionalNode {
491
- if ([
492
- TokenType.IF,
493
- TokenType.ELSE_IF
494
- ].indexOf(tokens[0].type) === -1) {
495
- throw SyntaxError('Invalid Syntax');
496
- }
497
-
498
- tokens.splice(0, 1); // consume if and else if
499
- return new ConditionalNode(
500
- Tree.processTokens(Tree.getBlockTokens(tokens, null)[0]),
501
- Tree.processTokens(Tree.getBlockTokens(tokens, null)[0])
502
- );
503
- }
504
-
505
- public static parse(lastNode, token, tokens: Token[]): IfStatementNode {
506
- if (tokens[1].type !== TokenType.L_PAREN) {
507
- throw SyntaxError('If statement needs to be followed by a condition encased in parenthesis.');
508
- }
509
- const nodes: ConditionalNode[] = [];
510
- nodes.push(IfStatementNode.parseConditional(tokens));
511
-
512
- while(tokens.length > 0 && TokenType.ELSE_IF === tokens[0].type) {
513
- nodes.push(IfStatementNode.parseConditional(tokens));
514
- }
515
-
516
- if (tokens.length > 0 && TokenType.ELSE === tokens[0].type) {
517
- tokens.splice(0, 1); // Consume else
518
- nodes.push(new ConditionalNode(
519
- new LiteralNode(true),
520
- Tree.processTokens(Tree.getBlockTokens(tokens, null)[0])
521
- ))
522
- }
523
-
524
- return new IfStatementNode(nodes);
525
- }
526
- }
527
-
528
- class ForStatementNode extends Node implements TreeNode {
529
- constructor(
530
- public readonly variable: LiteralNode<string>,
531
- public readonly list: RootScopeMemberNode | ScopeMemberNode,
532
- public readonly block: RootScopeMemberNode | ScopeMemberNode,
533
- ) {
534
- super();
535
- }
536
-
537
- protected _getChildNodes(): Node[] {
538
- return [
539
- this.variable,
540
- this.list,
541
- this.block
542
- ];
543
- }
544
-
545
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
546
- const variable: string = await this.variable.evaluate(scope, dom, tag);
547
- const list: any[] = await this.list.evaluate(scope, dom, tag);
548
- for (let i = 0;i < list.length; i++) {
549
- scope.set(variable, list[i]);
550
- await this.block.evaluate(scope, dom, tag);
551
- }
552
323
 
553
- return null;
554
- }
555
-
556
- public static parse(lastNode, token, tokens: Token[]): ForStatementNode {
557
- if (tokens[1].type !== TokenType.L_PAREN) {
558
- throw SyntaxError('Syntax error: Missing (');
559
- }
560
- if (tokens[3].type !== TokenType.OF) {
561
- throw SyntaxError('Syntax error: Missing of');
562
- }
563
-
564
- tokens.splice(0, 1); // consume for
565
- const loopDef: Token[] = Tree.getNextStatementTokens(tokens);
566
- const variableName: Token = loopDef.splice(0, 1)[0];
567
- loopDef.splice(0, 1); // consume of
568
- const list: TreeNode = Tree.processTokens(loopDef);
569
- const block: TreeNode = Tree.processTokens(Tree.getBlockTokens(tokens, null)[0]);
570
-
571
- return new ForStatementNode(
572
- new LiteralNode<string>(variableName.value),
573
- list as any,
574
- block as any
575
- );
576
- }
577
- }
578
-
579
- class NotNode extends Node implements TreeNode {
580
- constructor(
581
- public readonly toFlip: Node
582
- ) {
583
- super();
584
- }
585
-
586
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
587
- const flipping = await this.toFlip.evaluate(scope, dom, tag);
588
- return !flipping;
589
- }
590
-
591
- protected _getChildNodes(): Node[] {
592
- return [
593
- this.toFlip
594
- ];
595
- }
596
-
597
- public static parse(lastNode, token, tokens: Token[]) {
598
- tokens.splice(0, 1); // Remove not operator
599
- let containedTokens;
600
- if (tokens[0].type === TokenType.L_PAREN) {
601
- containedTokens = Tree.getNextStatementTokens(tokens);
602
- } else {
603
- containedTokens = Tree.consumeTypes(tokens, [
604
- TokenType.BOOLEAN_LITERAL,
605
- TokenType.NUMBER_LITERAL,
606
- TokenType.STRING_LITERAL,
607
- TokenType.NAME,
608
- TokenType.PERIOD
609
- ]);
610
- }
611
- return new NotNode(Tree.processTokens(containedTokens));
612
- }
613
- }
614
-
615
- class InNode extends Node implements TreeNode {
616
- constructor(
617
- public readonly left: TreeNode,
618
- public readonly right: TreeNode,
619
- public readonly flip: boolean = false
620
- ) {
621
- super();
622
- }
623
-
624
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
625
- const toCheck = await this.left.evaluate(scope, dom, tag);
626
- const array = await this.right.evaluate(scope, dom, tag);
627
-
628
- let inArray = array.indexOf(toCheck) > -1;
629
- if (this.flip)
630
- inArray = !inArray;
631
- return inArray;
632
- }
633
-
634
- protected _getChildNodes(): Node[] {
635
- return [
636
- this.left as Node,
637
- this.right as Node
638
- ];
639
- }
640
-
641
- public static match(tokens: Token[]): boolean {
642
- return tokens[0].type === TokenType.IN || (tokens[0].type === TokenType.NOT && tokens[1].type === TokenType.IN);
643
- }
644
-
645
- public static parse(lastNode, token, tokens: Token[]) {
646
- const flip: boolean = tokens[0].type === TokenType.NOT;
647
- if (flip)
648
- tokens.splice(0, 1); // consume not
649
- tokens.splice(0, 1); // consume in
650
-
651
- const containedTokens = Tree.getNextStatementTokens(tokens, false, false, true);
652
- return new InNode(lastNode, Tree.processTokens(containedTokens), flip);
653
- }
654
- }
655
-
656
- class LiteralNode<T = any> extends Node implements TreeNode {
657
- constructor(
658
- public readonly value: T
659
- ) {
660
- super();
661
- }
662
-
663
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
664
- return this.value;
665
- }
666
- }
667
-
668
- class BooleanLiteralNode extends LiteralNode<number> {
669
- constructor(
670
- public readonly value: any
671
- ) {
672
- super(value);
673
- this.value = value === 'true';
674
- }
675
- }
676
-
677
- class NumberLiteralNode extends LiteralNode<number> {
678
- constructor(
679
- public readonly value: any
680
- ) {
681
- super(value);
682
- if (this.value.indexOf('.') > -1) {
683
- this.value = parseFloat(this.value)
684
- } else {
685
- this.value = parseInt(this.value);
686
- }
687
- }
688
- }
689
-
690
-
691
- class FunctionCallNode<T = any> extends Node implements TreeNode {
692
- constructor(
693
- public readonly fnc: TreeNode<(...args: any[]) => any>,
694
- public readonly args: FunctionArgumentNode<any[]>
695
- ) {
696
- super();
697
- }
698
-
699
- protected _getChildNodes(): Node[] {
700
- return [
701
- this.fnc as Node,
702
- this.args as Node
703
- ]
704
- }
705
-
706
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
707
- let functionScope: Scope = scope;
708
- if (this.fnc instanceof ScopeMemberNode) {
709
- functionScope = await this.fnc.scope.evaluate(scope, dom, tag);
710
- }
711
- const values = await this.args.evaluate(scope, dom, tag);
712
- return (await this.fnc.evaluate(scope, dom, tag)).call(functionScope.wrapped || functionScope, ...values);
713
- }
714
- }
715
-
716
-
717
- class FunctionArgumentNode<T = any> extends Node implements TreeNode {
718
- constructor(
719
- protected args: Node[]
720
- ) {
721
- super();
722
- }
723
-
724
- protected _getChildNodes(): Node[] {
725
- return [
726
- ...(this.args as Node[])
727
- ]
728
- }
729
-
730
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
731
- const values: any[] = [];
732
- for (const arg of this.args) {
733
- values.push(await arg.evaluate(scope, dom, tag));
734
- }
735
- return values;
736
- }
737
- }
738
-
739
-
740
- class ScopeMemberNode extends Node implements TreeNode {
741
- constructor(
742
- public readonly scope: TreeNode<Scope>,
743
- public readonly name: TreeNode<string>
744
- ) {
745
- super();
746
- }
747
-
748
- protected _getChildNodes(): Node[] {
749
- return [
750
- this.scope as Node,
751
- this.name as Node
752
- ]
753
- }
754
-
755
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
756
- let scopes = [];
757
- const values = [];
758
-
759
- if (this.scope instanceof ElementQueryNode) {
760
- scopes = await this.scope.evaluate(scope, dom, tag);
761
- } else {
762
- const evalScope = await this.scope.evaluate(scope, dom, tag)
763
- if (evalScope instanceof TagList) {
764
- scopes = evalScope;
765
- } else {
766
- scopes.push(evalScope);
767
- }
768
- }
769
-
770
- for (let parent of scopes) {
771
- if (parent instanceof DOMObject)
772
- parent = parent.scope;
773
-
774
- if (!parent) {
775
- throw Error(`Cannot access "${await this.name.evaluate(scope, dom, tag)}" of undefined.`);
776
- }
777
- const name = await this.name.evaluate(scope, dom, tag);
778
- const value: any = parent.get(name, false);
779
- values.push(value instanceof Scope && value.wrapped || value);
780
- }
781
- return values.length === 1 ? values[0] : values;
782
- }
783
- }
784
-
785
-
786
- class RootScopeMemberNode<T = any> extends Node implements TreeNode {
787
- constructor(
788
- public readonly name: TreeNode<string>
789
- ) {
790
- super();
791
- }
792
-
793
- protected _getChildNodes(): Node[] {
794
- return [
795
- this.name as Node
796
- ]
797
- }
798
-
799
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
800
- const name = await this.name.evaluate(scope, dom, tag);
801
- const value = scope.get(name);
802
- return value instanceof Scope && value.wrapped || value;
803
- }
804
- }
805
-
806
- class ArithmeticNode extends Node implements TreeNode {
807
- constructor(
808
- public readonly left: TreeNode,
809
- public readonly right: TreeNode,
810
- public readonly type: TokenType
811
- ) {
812
- super();
813
- }
814
-
815
- protected _getChildNodes(): Node[] {
816
- return [
817
- this.left as Node,
818
- this.right as Node
819
- ]
820
- }
821
-
822
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
823
- const left: any = await this.left.evaluate(scope, dom, tag);
824
- const right: any = await this.right.evaluate(scope, dom, tag);
825
-
826
- switch (this.type) {
827
- case TokenType.ADD:
828
- return left + right;
829
- case TokenType.SUBTRACT:
830
- return left - right;
831
- case TokenType.MULTIPLY:
832
- return left * right;
833
- case TokenType.DIVIDE:
834
- return left / right;
835
- }
836
- }
837
-
838
- public static match(tokens: Token[]): boolean {
839
- return [
840
- TokenType.ADD,
841
- TokenType.SUBTRACT,
842
- TokenType.MULTIPLY,
843
- TokenType.DIVIDE
844
- ].indexOf(tokens[0].type) > -1
845
- }
846
-
847
- public static parse(lastNode, token, tokens: Token[]) {
848
- tokens.splice(0, 1); // Remove arithmetic operator
849
- return new ArithmeticNode(lastNode, Tree.processTokens(Tree.getNextStatementTokens(tokens)), token.type)
850
- }
851
- }
852
-
853
- class ArithmeticAssignmentNode extends Node implements TreeNode {
854
- constructor(
855
- public readonly left: RootScopeMemberNode,
856
- public readonly right: TreeNode,
857
- public readonly type: TokenType
858
- ) {
859
- super();
860
- }
861
-
862
- protected _getChildNodes(): Node[] {
863
- return [
864
- this.left as Node,
865
- this.right as Node
866
- ]
867
- }
868
-
869
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
870
- let scopes = [];
871
- const name: string = await this.left.name.evaluate(scope, dom, tag);
872
-
873
- if (this.left instanceof ScopeMemberNode) {
874
- const inner = await this.left.scope.evaluate(scope, dom, tag);
875
- if (this.left.scope instanceof ElementQueryNode) {
876
- scopes.push(...inner);
877
- } else {
878
- scopes.push(inner);
879
- }
880
- } else if ((this.left instanceof ElementAttributeNode || this.left instanceof ElementStyleNode) && this.left.elementRef) {
881
- scopes = await this.left.elementRef.evaluate(scope, dom, tag);
882
- } else
883
- scopes.push(scope);
884
-
885
- const values = [];
886
- for (let localScope of scopes) {
887
- if (localScope instanceof DOMObject) {
888
- await this.handleDOMObject(name, dom, localScope, tag);
889
- } else {
890
- if (localScope['$wrapped'] && localScope['$scope'])
891
- localScope = localScope['$scope'];
892
-
893
- let left: number | Array<any> | string = await this.left.evaluate(localScope, dom, tag);
894
- let right: number | Array<any> | string = await this.right.evaluate(localScope, dom, tag);
895
-
896
- if (left instanceof Array) {
897
- left = this.handleArray(name, left, right, localScope);
898
- } else if (Number.isFinite(left)) {
899
- left = this.handleNumber(name, left, right, localScope);
900
- } else {
901
- left = this.handleString(name, left, right, localScope);
902
- }
903
-
904
- values.push(left);
905
- }
906
- }
907
- return values.length > 1 ? values : values[0];
908
- }
909
-
910
- public handleNumber(key, left, right, scope) {
911
- if (right !== null && !Number.isFinite(right))
912
- right = parseFloat(`${right}`);
913
-
914
- left = left as number;
915
- right = right as number;
916
-
917
- switch (this.type) {
918
- case TokenType.ASSIGN:
919
- left = right;
920
- break;
921
- case TokenType.ADD_ASSIGN:
922
- left += right;
923
- break;
924
- case TokenType.SUBTRACT_ASSIGN:
925
- left -= right;
926
- break;
927
- case TokenType.MULTIPLY_ASSIGN:
928
- left *= right;
929
- break;
930
- case TokenType.DIVIDE_ASSIGN:
931
- left /= right;
932
- break;
933
- }
934
- scope.set(key, left);
935
- return left;
936
- }
937
-
938
- public handleString(key, left, right, scope) {
939
- switch (this.type) {
940
- case TokenType.ASSIGN:
941
- left = right;
942
- break;
943
- case TokenType.ADD_ASSIGN:
944
- left = `${left}${right}`;
945
- break;
946
- case TokenType.SUBTRACT_ASSIGN:
947
- left.replace(right, '');
948
- break;
949
- case TokenType.MULTIPLY_ASSIGN:
950
- left *= right;
951
- break;
952
- case TokenType.DIVIDE_ASSIGN:
953
- left /= right;
954
- break;
955
- }
956
-
957
- scope.set(key, left);
958
- return left;
959
- }
960
-
961
- public async handleDOMObject(key: string, dom: DOM, domObject: DOMObject, tag: Tag) {
962
- let left = domObject.scope.get(key);
963
- let right: number | Array<any> | string = await this.right.evaluate(domObject.scope, dom, tag);
964
- if (left instanceof Array)
965
- return this.handleArray(key, left, right, domObject.scope);
966
-
967
- return this.handleString(key, left, right, domObject.scope);
968
- }
969
-
970
- public handleArray(key, left, right, scope) {
971
- if (!(right instanceof Array))
972
- right = [right];
973
- switch (this.type) {
974
- case TokenType.ASSIGN:
975
- left.splice(0, left.length);
976
- left.push(...right);
977
- break;
978
- case TokenType.ADD_ASSIGN:
979
- left.push(...right);
980
- break;
981
- case TokenType.SUBTRACT_ASSIGN:
982
- for (let i = left.length - 1; i >= 0; i--) {
983
- if (right.indexOf(left[i]) > -1) {
984
- left.splice(i, 1);
985
- i++;
986
- }
987
- }
988
- break;
989
- case TokenType.TILDE:
990
- for (const toggle of right) {
991
- const index = left.indexOf(toggle);
992
- if (index > -1) {
993
- left.splice(index, 1);
994
- } else {
995
- left.push(toggle);
996
- }
997
- }
998
- break;
999
- }
1000
-
1001
- /*
1002
- We have to trigger a change manually here. Setting the variable on the scope with an array won't trigger
1003
- it since we are modifying values inside of the array instance.
1004
- */
1005
- scope.trigger(`change:${key}`);
1006
-
1007
- return left;
1008
- }
1009
-
1010
- public static match(tokens: Token[]): boolean {
1011
- return [
1012
- TokenType.ASSIGN,
1013
- TokenType.ADD_ASSIGN,
1014
- TokenType.SUBTRACT_ASSIGN,
1015
- TokenType.MULTIPLY_ASSIGN,
1016
- TokenType.DIVIDE_ASSIGN,
1017
- TokenType.TILDE,
1018
- ].indexOf(tokens[0].type) > -1;
1019
- }
1020
-
1021
- public static parse(lastNode: any, token, tokens: Token[]): ArithmeticAssignmentNode {
1022
- if (!(lastNode instanceof RootScopeMemberNode) && !(lastNode instanceof ScopeMemberNode) && !(lastNode instanceof ElementAttributeNode) && !(lastNode instanceof ElementStyleNode)) {
1023
- throw SyntaxError(`Invalid assignment syntax near ${Tree.toCode(tokens.splice(0, 10))}`);
1024
- }
1025
- tokens.splice(0, 1); // consume =
1026
- const assignmentTokens: Token[] = Tree.getNextStatementTokens(tokens, false, false, true);
1027
-
1028
- return new ArithmeticAssignmentNode(
1029
- lastNode as RootScopeMemberNode,
1030
- Tree.processTokens(assignmentTokens),
1031
- token.type
1032
- );
1033
- }
1034
- }
1035
-
1036
- class IndexNode extends Node implements TreeNode {
1037
- constructor(
1038
- public readonly object: Node,
1039
- public readonly index: Node,
1040
- public readonly indexTwo: Node = null
1041
- ) {
1042
- super();
1043
- }
1044
-
1045
- protected _getChildNodes(): Node[] {
1046
- const children = [
1047
- this.object,
1048
- this.index
1049
- ];
1050
- if (this.indexTwo)
1051
- children.push(this.indexTwo);
1052
-
1053
- return children;
1054
- }
1055
-
1056
- public negativeIndex(obj: any[], index: number | string): number | string {
1057
- if (Number.isFinite(index) && index < 0)
1058
- return obj.length + (index as number);
1059
- return index;
1060
- }
1061
-
1062
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1063
- const obj = await this.object.evaluate(scope, dom, tag);
1064
- const index: string | number = this.negativeIndex(obj, await this.index.evaluate(scope, dom, tag));
1065
-
1066
- if (Number.isFinite(index) && this.indexTwo) {
1067
- const indexTwo: number = this.negativeIndex(obj, await this.indexTwo.evaluate(scope, dom, tag)) as number;
1068
- const values = [];
1069
- for (let i: number = index as number; i <= indexTwo; i++) {
1070
- values.push(obj[i]);
1071
- }
1072
- return values;
1073
- } else {
1074
- return (obj)[index];
1075
- }
1076
- }
1077
-
1078
- public static match(tokens: Token[]): boolean {
1079
- return tokens[0].type === TokenType.L_BRACKET;
1080
- }
1081
-
1082
- public static parse(lastNode, token, tokens: Token[]): IndexNode {
1083
- const valueTokens: Token[][] = Tree.getBlockTokens(tokens, TokenType.COLON);
1084
- const values: Node[] = [];
1085
- for (const arg of valueTokens) {
1086
- values.push(Tree.processTokens(arg));
1087
- }
1088
- return new IndexNode(lastNode, values[0], values.length > 1 && values[1]);
1089
- }
1090
- }
1091
-
1092
- class ArrayNode extends Node implements TreeNode {
1093
- constructor(
1094
- public readonly values: Node[]
1095
- ) {
1096
- super();
1097
- }
1098
-
1099
- protected _getChildNodes(): Node[] {
1100
- return new Array(...this.values);
1101
- }
1102
-
1103
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1104
- const arr: WrappedArray<any> = new WrappedArray();
1105
- for (const val of this.values) {
1106
- arr.push(await val.evaluate(scope, dom, tag));
1107
- }
1108
- return arr;
1109
- }
1110
-
1111
- public static match(tokens: Token[]): boolean {
1112
- return tokens[0].type === TokenType.L_BRACKET;
1113
- }
1114
-
1115
- public static parse(lastNode, token, tokens: Token[]): ArrayNode {
1116
- const valueTokens: Token[][] = Tree.getBlockTokens(tokens);
1117
- const values: Node[] = [];
1118
- for (const arg of valueTokens) {
1119
- values.push(Tree.processTokens(arg));
1120
- }
1121
- return new ArrayNode(values);
1122
- }
1123
- }
1124
-
1125
- class ObjectNode extends Node implements TreeNode {
1126
- constructor(
1127
- public readonly keys: Node[],
1128
- public readonly values: Node[]
1129
- ) {
1130
- super();
1131
- }
1132
-
1133
- protected _getChildNodes(): Node[] {
1134
- return new Array(...this.values);
1135
- }
1136
-
1137
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1138
- const obj: Scope = new Scope();
1139
- for (let i = 0; i < this.values.length; i++) {
1140
- const key = this.keys[i];
1141
- const val = this.values[i];
1142
- obj.set(await key.evaluate(scope, dom, tag), await val.evaluate(scope, dom, tag));
1143
- }
1144
- return obj;
1145
- }
1146
-
1147
- public static match(tokens: Token[]): boolean {
1148
- return tokens[0].type === TokenType.L_BRACE;
1149
- }
1150
-
1151
- public static parse(lastNode, token, tokens: Token[]): ObjectNode {
1152
- const valueTokens: Token[] = Tree.getNextStatementTokens(tokens);
1153
- const keys: Node[] = [];
1154
- const values: Node[] = [];
1155
-
1156
- while (valueTokens.length > 0) {
1157
- const key: Token[] = Tree.getTokensUntil(valueTokens, TokenType.COLON, false);
1158
- if (valueTokens[0].type !== TokenType.COLON)
1159
- throw Error('Invalid object literal syntax. Expecting :');
1160
- valueTokens.splice(0, 1); // Consume :
1161
- const val: Token[] = Tree.getTokensUntil(valueTokens, TokenType.COMMA, true, false, true, {
1162
- type: BlockType.STATEMENT,
1163
- open: null,
1164
- close: null,
1165
- openCharacter: null,
1166
- closeCharacter: null
1167
- });
1168
- keys.push(Tree.processTokens(key));
1169
- values.push(Tree.processTokens(val));
1170
- }
1171
- return new ObjectNode(keys, values);
1172
- }
1173
- }
1174
-
1175
- class ElementQueryNode extends Node implements TreeNode {
1176
- protected requiresPrep: boolean = true;
1177
-
1178
- constructor(
1179
- public readonly query: string
1180
- ) {
1181
- super();
1182
- }
1183
-
1184
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1185
- tag = tag || await dom.getTagForScope(scope);
1186
- return await dom.get(this.query, true, tag);
1187
- }
1188
-
1189
- async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
1190
- tag = tag || await dom.getTagForScope(scope);
1191
- await dom.get(this.query, true, tag);
1192
- }
1193
- }
1194
-
1195
- class ElementAttributeNode extends Node implements TreeNode {
1196
- protected requiresPrep: boolean = true;
1197
-
1198
- constructor(
1199
- public readonly elementRef: ElementQueryNode | null,
1200
- public readonly attr: string
1201
- ) {
1202
- super();
1203
- }
1204
-
1205
- public get name(): LiteralNode<string> {
1206
- return new LiteralNode<string>(`@${this.attributeName}`);
1207
- }
1208
-
1209
- protected _getChildNodes(): Node[] {
1210
- let nodes = [];
1211
- if (this.elementRef)
1212
- nodes.push(this.elementRef)
1213
- return nodes;
1214
- }
1215
-
1216
- get attributeName(): string {
1217
- if (this.attr.startsWith('.'))
1218
- return this.attr.substring(2);
1219
- return this.attr.substring(1);
1220
- }
1221
-
1222
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1223
- let tags: TagList;
1224
- if (this.elementRef) {
1225
- tags = await this.elementRef.evaluate(scope, dom, tag);
1226
- } else if (tag) {
1227
- tags = new TagList(tag)
1228
- } else {
1229
- return;
1230
- }
1231
-
1232
- if (tags.length === 1)
1233
- return tags[0].scope.get(`@${this.attributeName}`);
1234
-
1235
- return tags.map((tag) => tag.scope.get(`@${this.attributeName}`));
1236
- }
1237
-
1238
- async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
1239
- if (this.elementRef) {
1240
- await this.elementRef.prepare(scope, dom, tag);
1241
- const tags: TagList = await this.elementRef.evaluate(scope, dom, tag);
1242
- for (const t of tags)
1243
- await t.watchAttribute(this.attributeName);
1244
- } else if(tag) {
1245
- await tag.watchAttribute(this.attributeName);
1246
- }
1247
- }
324
+ prepare(scope: Scope, dom: DOM, tag?: Tag);
1248
325
  }
1249
326
 
1250
- class ElementStyleNode extends Node implements TreeNode {
1251
- protected requiresPrep: boolean = true;
1252
-
1253
- constructor(
1254
- public readonly elementRef: ElementQueryNode | null,
1255
- public readonly attr: string
1256
- ) {
1257
- super();
1258
- }
1259
-
1260
- public get name(): LiteralNode<string> {
1261
- return new LiteralNode<string>(`$${this.attributeName}`);
1262
- }
1263
-
1264
- protected _getChildNodes(): Node[] {
1265
- let nodes = [];
1266
- if (this.elementRef)
1267
- nodes.push(this.elementRef)
1268
- return nodes;
1269
- }
1270
-
1271
- get attributeName(): string {
1272
- if (this.attr.startsWith('.'))
1273
- return this.attr.substring(2);
1274
- return this.attr.substring(1);
1275
- }
1276
-
1277
- async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
1278
- let tags: TagList;
1279
- if (this.elementRef) {
1280
- tags = await this.elementRef.evaluate(scope, dom, tag);
1281
- } else if (tag) {
1282
- tags = new TagList(tag)
1283
- } else {
1284
- return;
1285
- }
1286
-
1287
- if (tags.length === 1)
1288
- return tags[0].scope.get(`$${this.attributeName}`);
1289
-
1290
- return tags.map((tag) => tag.scope.get(`$${this.attributeName}`));
1291
- }
1292
-
1293
- async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
1294
- if (this.elementRef) {
1295
- await this.elementRef.prepare(scope, dom, tag);
1296
- const tags: TagList = await this.elementRef.evaluate(scope, dom, tag);
1297
- for (const t of tags)
1298
- await t.watchStyle(this.attributeName);
1299
- } else if(tag) {
1300
- await tag.watchStyle(this.attributeName);
1301
- }
1302
- }
1303
- }
1304
327
 
1305
328
  export interface IBlockInfo {
1306
329
  type: BlockType,
@@ -1317,7 +340,7 @@ export const AttributableNodes = [
1317
340
  ];
1318
341
 
1319
342
  export class Tree {
1320
- protected static cache: {[key: string]: Node} = {};
343
+ protected static cache: { [key: string]: Node } = {};
1321
344
  protected rootNode: Node;
1322
345
 
1323
346
  constructor(
@@ -1356,7 +379,7 @@ export class Tree {
1356
379
  }
1357
380
 
1358
381
  const name = await node.name.evaluate(scope, dom, tag);
1359
- _scope.bind(`change:${name}`, fnc);
382
+ _scope.on(`change:${name}`, fnc);
1360
383
  }
1361
384
  }
1362
385
 
@@ -1486,6 +509,9 @@ export class Tree {
1486
509
  node = ArithmeticAssignmentNode.parse(node, token, tokens);
1487
510
  } else if (tokens[0].type === TokenType.WHITESPACE) {
1488
511
  tokens.splice(0, 1);
512
+ } else if (tokens[0].type === TokenType.UNIT) {
513
+ node = new UnitLiteralNode(tokens[0].value);
514
+ tokens.splice(0, 1);
1489
515
  } else if (tokens[0].type === TokenType.BOOLEAN_LITERAL) {
1490
516
  node = new BooleanLiteralNode(tokens[0].value);
1491
517
  tokens.splice(0, 1);
@@ -1536,7 +562,7 @@ export class Tree {
1536
562
  let openCharacter: string;
1537
563
  let closeCharacter: string;
1538
564
 
1539
- switch(blockType) {
565
+ switch (blockType) {
1540
566
  case BlockType.PAREN:
1541
567
  open = TokenType.L_PAREN;
1542
568
  close = TokenType.R_PAREN;
@@ -1686,4 +712,9 @@ export class Tree {
1686
712
  tokens.splice(0, matching.length);
1687
713
  return matching;
1688
714
  }
715
+
716
+ static async apply(code: string, scope: Scope, dom: DOM, tag: Tag) {
717
+ const t = new Tree(code);
718
+ return await t.evaluate(scope, dom, tag);
719
+ }
1689
720
  }