vsn 0.1.27 → 0.1.30
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.
- package/demo/vsn.js +1 -1
- package/dist/AST/ArithmeticAssignmentNode.d.ts +23 -0
- package/dist/AST/ArithmeticAssignmentNode.js +324 -0
- package/dist/AST/ArithmeticAssignmentNode.js.map +1 -0
- package/dist/AST/ArithmeticNode.d.ts +15 -0
- package/dist/AST/ArithmeticNode.js +114 -0
- package/dist/AST/ArithmeticNode.js.map +1 -0
- package/dist/AST/ArrayNode.d.ts +14 -0
- package/dist/AST/ArrayNode.js +114 -0
- package/dist/AST/ArrayNode.js.map +1 -0
- package/dist/AST/BlockNode.d.ts +11 -0
- package/dist/AST/BlockNode.js +98 -0
- package/dist/AST/BlockNode.js.map +1 -0
- package/dist/AST/BooleanLiteralNode.d.ts +5 -0
- package/dist/{Model/Collection.js → AST/BooleanLiteralNode.js} +12 -18
- package/dist/AST/BooleanLiteralNode.js.map +1 -0
- package/dist/AST/ComparisonNode.d.ts +15 -0
- package/dist/AST/ComparisonNode.js +120 -0
- package/dist/AST/ComparisonNode.js.map +1 -0
- package/dist/AST/ConditionalNode.d.ts +13 -0
- package/dist/AST/ConditionalNode.js +95 -0
- package/dist/AST/ConditionalNode.js.map +1 -0
- package/dist/AST/ElementAttributeNode.d.ts +18 -0
- package/dist/AST/ElementAttributeNode.js +159 -0
- package/dist/AST/ElementAttributeNode.js.map +1 -0
- package/dist/AST/ElementQueryNode.d.ts +13 -0
- package/dist/AST/ElementQueryNode.js +116 -0
- package/dist/AST/ElementQueryNode.js.map +1 -0
- package/dist/AST/ElementStyleNode.d.ts +18 -0
- package/dist/AST/ElementStyleNode.js +159 -0
- package/dist/AST/ElementStyleNode.js.map +1 -0
- package/dist/AST/ForStatementNode.d.ts +17 -0
- package/dist/AST/ForStatementNode.js +121 -0
- package/dist/AST/ForStatementNode.js.map +1 -0
- package/dist/AST/FunctionArgumentNode.d.ts +11 -0
- package/dist/AST/FunctionArgumentNode.js +100 -0
- package/dist/AST/FunctionArgumentNode.js.map +1 -0
- package/dist/AST/FunctionCallNode.d.ts +13 -0
- package/dist/AST/FunctionCallNode.js +102 -0
- package/dist/AST/FunctionCallNode.js.map +1 -0
- package/dist/AST/IfStatementNode.d.ts +14 -0
- package/dist/AST/IfStatementNode.js +128 -0
- package/dist/AST/IfStatementNode.js.map +1 -0
- package/dist/AST/InNode.d.ts +15 -0
- package/dist/AST/InNode.js +107 -0
- package/dist/AST/InNode.js.map +1 -0
- package/dist/AST/IndexNode.d.ts +16 -0
- package/dist/AST/IndexNode.js +126 -0
- package/dist/AST/IndexNode.js.map +1 -0
- package/dist/AST/LiteralNode.d.ts +10 -0
- package/dist/AST/LiteralNode.js +74 -0
- package/dist/AST/LiteralNode.js.map +1 -0
- package/dist/AST/Node.d.ts +19 -0
- package/dist/AST/Node.js +117 -0
- package/dist/AST/Node.js.map +1 -0
- package/dist/AST/NotNode.d.ts +12 -0
- package/dist/AST/NotNode.js +103 -0
- package/dist/AST/NotNode.js.map +1 -0
- package/dist/AST/NumberLiteralNode.d.ts +5 -0
- package/dist/{Model/fields/EmailField.js → AST/NumberLiteralNode.js} +17 -17
- package/dist/AST/NumberLiteralNode.js.map +1 -0
- package/dist/AST/ObjectNode.d.ts +14 -0
- package/dist/AST/ObjectNode.js +131 -0
- package/dist/AST/ObjectNode.js.map +1 -0
- package/dist/AST/RootScopeMemberNode.d.ts +11 -0
- package/dist/AST/RootScopeMemberNode.js +87 -0
- package/dist/AST/RootScopeMemberNode.js.map +1 -0
- package/dist/AST/ScopeMemberNode.d.ts +12 -0
- package/dist/AST/ScopeMemberNode.js +134 -0
- package/dist/AST/ScopeMemberNode.js.map +1 -0
- package/dist/AST/UnitLiteralNode.d.ts +15 -0
- package/dist/AST/UnitLiteralNode.js +72 -0
- package/dist/AST/UnitLiteralNode.js.map +1 -0
- package/dist/AST.d.ts +7 -60
- package/dist/AST.js +74 -1493
- package/dist/AST.js.map +1 -1
- package/dist/Controller.d.ts +4 -2
- package/dist/Controller.js +10 -2
- package/dist/Controller.js.map +1 -1
- package/dist/EventDispatcher.d.ts +4 -1
- package/dist/EventDispatcher.js +27 -12
- package/dist/EventDispatcher.js.map +1 -1
- package/dist/MessageList.d.ts +2 -1
- package/dist/MessageList.js +9 -1
- package/dist/MessageList.js.map +1 -1
- package/dist/Model/Field.d.ts +8 -0
- package/dist/Model/{fields/StringField.js → Field.js} +19 -24
- package/dist/Model/Field.js.map +1 -0
- package/dist/Model.d.ts +5 -4
- package/dist/Model.js +7 -18
- package/dist/Model.js.map +1 -1
- package/dist/Registry.d.ts +3 -0
- package/dist/Registry.js +11 -0
- package/dist/Registry.js.map +1 -1
- package/dist/Scope/DynamicScopeData.d.ts +6 -0
- package/dist/{Model/DataModel.js → Scope/DynamicScopeData.js} +15 -17
- package/dist/Scope/DynamicScopeData.js.map +1 -0
- package/dist/Scope/QueryReference.d.ts +10 -0
- package/dist/Scope/QueryReference.js +103 -0
- package/dist/Scope/QueryReference.js.map +1 -0
- package/dist/Scope/ScopeData.d.ts +4 -0
- package/dist/Scope/ScopeData.js +40 -0
- package/dist/Scope/ScopeData.js.map +1 -0
- package/dist/Scope/ScopeDataAbstract.d.ts +22 -0
- package/dist/Scope/ScopeDataAbstract.js +138 -0
- package/dist/Scope/ScopeDataAbstract.js.map +1 -0
- package/dist/Scope/ScopeReference.d.ts +10 -0
- package/dist/Scope/ScopeReference.js +73 -0
- package/dist/Scope/ScopeReference.js.map +1 -0
- package/dist/Scope/ScopedVariableType.d.ts +6 -0
- package/dist/Scope/ScopedVariableType.js +14 -0
- package/dist/Scope/ScopedVariableType.js.map +1 -0
- package/dist/Scope/WrappedArray.d.ts +16 -0
- package/dist/Scope/WrappedArray.js +121 -0
- package/dist/Scope/WrappedArray.js.map +1 -0
- package/dist/Scope/properties/Property.d.ts +18 -0
- package/dist/Scope/properties/Property.js +93 -0
- package/dist/Scope/properties/Property.js.map +1 -0
- package/dist/Scope.d.ts +4 -45
- package/dist/Scope.js +31 -266
- package/dist/Scope.js.map +1 -1
- package/dist/SimplePromise.d.ts +2 -2
- package/dist/SimplePromise.js.map +1 -1
- package/dist/Tag/List.d.ts +2 -2
- package/dist/Tag/List.js +14 -6
- package/dist/Tag/List.js.map +1 -1
- package/dist/Tag.js +1 -1
- package/dist/Tag.js.map +1 -1
- package/dist/Types.d.ts +1 -0
- package/dist/Types.js +8 -2
- package/dist/Types.js.map +1 -1
- package/dist/Validators.d.ts +7 -0
- package/dist/Validators.js +54 -0
- package/dist/Validators.js.map +1 -0
- package/dist/attributes/Bind.js +1 -1
- package/dist/attributes/Bind.js.map +1 -1
- package/dist/attributes/ClassConstructor.d.ts +1 -0
- package/dist/attributes/ClassConstructor.js +1 -1
- package/dist/attributes/ClassConstructor.js.map +1 -1
- package/dist/attributes/JSONAttribute.js.map +1 -1
- package/dist/attributes/List.js +4 -4
- package/dist/attributes/List.js.map +1 -1
- package/dist/attributes/Radio.js.map +1 -1
- package/dist/attributes/SetAttribute.js.map +1 -1
- package/dist/attributes/StyleAttribute.js.map +1 -1
- package/dist/vsn.d.ts +9 -1
- package/dist/vsn.js +24 -9
- package/dist/vsn.js.map +1 -1
- package/package.json +1 -1
- package/src/AST/ArithmeticAssignmentNode.ts +243 -0
- package/src/AST/ArithmeticNode.ts +52 -0
- package/src/AST/ArrayNode.ts +39 -0
- package/src/AST/BlockNode.ts +25 -0
- package/src/AST/BooleanLiteralNode.ts +10 -0
- package/src/AST/ComparisonNode.ts +57 -0
- package/src/AST/ConditionalNode.ts +36 -0
- package/src/AST/ElementAttributeNode.ts +63 -0
- package/src/AST/ElementQueryNode.ts +27 -0
- package/src/AST/ElementStyleNode.ts +63 -0
- package/src/AST/ForStatementNode.ts +59 -0
- package/src/AST/FunctionArgumentNode.ts +27 -0
- package/src/AST/FunctionCallNode.ts +32 -0
- package/src/AST/IfStatementNode.ts +67 -0
- package/src/AST/InNode.ts +46 -0
- package/src/AST/IndexNode.ts +61 -0
- package/src/AST/LiteralNode.ts +17 -0
- package/src/AST/Node.ts +71 -0
- package/src/AST/NotNode.ts +41 -0
- package/src/AST/NumberLiteralNode.ts +14 -0
- package/src/AST/ObjectNode.ts +55 -0
- package/src/AST/RootScopeMemberNode.ts +25 -0
- package/src/AST/ScopeMemberNode.ts +58 -0
- package/src/AST/UnitLiteralNode.ts +51 -0
- package/src/AST.ts +34 -1094
- package/src/Controller.ts +10 -2
- package/src/EventDispatcher.ts +29 -12
- package/src/MessageList.ts +5 -1
- package/src/Model/Field.ts +20 -0
- package/src/Model.ts +8 -22
- package/src/Registry.ts +10 -0
- package/src/{Model/DataModel.ts → Scope/DynamicScopeData.ts} +8 -10
- package/src/Scope/QueryReference.ts +29 -0
- package/src/Scope/ScopeData.ts +21 -0
- package/src/Scope/ScopeDataAbstract.ts +127 -0
- package/src/Scope/ScopeReference.ts +30 -0
- package/src/Scope/ScopedVariableType.ts +7 -0
- package/src/Scope/WrappedArray.ts +88 -0
- package/src/Scope/properties/Property.ts +79 -0
- package/src/Scope.ts +28 -194
- package/src/SimplePromise.ts +2 -2
- package/src/Tag/List.ts +4 -4
- package/src/Tag.ts +1 -1
- package/src/Types.ts +7 -2
- package/src/Validators.ts +45 -0
- package/src/attributes/Bind.ts +3 -3
- package/src/attributes/ClassConstructor.ts +2 -1
- package/src/attributes/JSONAttribute.ts +2 -1
- package/src/attributes/List.ts +1 -1
- package/src/attributes/Radio.ts +2 -1
- package/src/attributes/ScopeChange.ts +1 -1
- package/src/attributes/SetAttribute.ts +2 -1
- package/src/attributes/StyleAttribute.ts +2 -1
- package/src/attributes/TypeAttribute.ts +1 -1
- package/src/vsn.ts +14 -4
- package/test/AST/ArithmeticAssignmentNode.spec.ts +47 -0
- package/test/AST.spec.ts +2 -2
- package/test/Controller.spec.ts +44 -0
- package/test/MessageList.spec.ts +1 -1
- package/test/Model/DataModel.spec.ts +0 -141
- package/test/Scope/DynamicScopeData.spec.ts +141 -0
- package/test/Scope.spec.ts +13 -1
- package/test/Tag/TagList.spec.ts +1 -1
- package/dist/Model/Collection.d.ts +0 -5
- package/dist/Model/Collection.js.map +0 -1
- package/dist/Model/DataModel.d.ts +0 -6
- package/dist/Model/DataModel.js.map +0 -1
- package/dist/Model/ModelAbstract.d.ts +0 -20
- package/dist/Model/ModelAbstract.js +0 -122
- package/dist/Model/ModelAbstract.js.map +0 -1
- package/dist/Model/fields/BooleanField.d.ts +0 -5
- package/dist/Model/fields/BooleanField.js +0 -43
- package/dist/Model/fields/BooleanField.js.map +0 -1
- package/dist/Model/fields/EmailField.d.ts +0 -5
- package/dist/Model/fields/EmailField.js.map +0 -1
- package/dist/Model/fields/Field.d.ts +0 -13
- package/dist/Model/fields/Field.js +0 -79
- package/dist/Model/fields/Field.js.map +0 -1
- package/dist/Model/fields/FloatField.d.ts +0 -5
- package/dist/Model/fields/FloatField.js +0 -47
- package/dist/Model/fields/FloatField.js.map +0 -1
- package/dist/Model/fields/PositiveNumberField.d.ts +0 -5
- package/dist/Model/fields/PositiveNumberField.js +0 -51
- package/dist/Model/fields/PositiveNumberField.js.map +0 -1
- package/dist/Model/fields/StringField.d.ts +0 -5
- package/dist/Model/fields/StringField.js.map +0 -1
- package/src/Model/Collection.ts +0 -13
- package/src/Model/ModelAbstract.ts +0 -114
- package/src/Model/fields/BooleanField.ts +0 -16
- package/src/Model/fields/EmailField.ts +0 -12
- package/src/Model/fields/Field.ts +0 -65
- package/src/Model/fields/FloatField.ts +0 -22
- package/src/Model/fields/PositiveNumberField.ts +0 -24
- package/src/Model/fields/StringField.ts +0 -16
- package/test/Model.spec.ts +0 -306
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {DOMObject} from "../DOM/DOMObject";
|
|
5
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
6
|
+
import {Node} from "./Node";
|
|
7
|
+
import {RootScopeMemberNode} from "./RootScopeMemberNode";
|
|
8
|
+
import {ScopeMemberNode} from "./ScopeMemberNode";
|
|
9
|
+
import {ElementQueryNode} from "./ElementQueryNode";
|
|
10
|
+
import {ElementAttributeNode} from "./ElementAttributeNode";
|
|
11
|
+
import {ElementStyleNode} from "./ElementStyleNode";
|
|
12
|
+
import {UnitLiteral} from "./UnitLiteralNode";
|
|
13
|
+
import {Controller} from "../vsn";
|
|
14
|
+
|
|
15
|
+
export class ArithmeticAssignmentNode extends Node implements TreeNode {
|
|
16
|
+
constructor(
|
|
17
|
+
public readonly left: RootScopeMemberNode | ScopeMemberNode,
|
|
18
|
+
public readonly right: TreeNode,
|
|
19
|
+
public readonly type: TokenType
|
|
20
|
+
) {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected _getChildNodes(): Node[] {
|
|
25
|
+
return [
|
|
26
|
+
this.left as Node,
|
|
27
|
+
this.right as Node
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
32
|
+
let scopes = [];
|
|
33
|
+
const name: string = await this.left.name.evaluate(scope, dom, tag);
|
|
34
|
+
if (this.left instanceof ScopeMemberNode) {
|
|
35
|
+
const inner = await this.left.scope.evaluate(scope, dom, tag);
|
|
36
|
+
if (this.left.scope instanceof ElementQueryNode) {
|
|
37
|
+
if (this.left.scope.first) {
|
|
38
|
+
scopes.push(inner);
|
|
39
|
+
} else {
|
|
40
|
+
scopes.push(...inner);
|
|
41
|
+
}
|
|
42
|
+
} else if (inner instanceof Scope) {
|
|
43
|
+
scopes.push(inner);
|
|
44
|
+
} else if (inner instanceof Controller) {
|
|
45
|
+
scopes.push(inner.scope);
|
|
46
|
+
} else {
|
|
47
|
+
scopes.push(scope)
|
|
48
|
+
}
|
|
49
|
+
} else if ((this.left instanceof ElementAttributeNode || this.left instanceof ElementStyleNode) && this.left.elementRef) {
|
|
50
|
+
const elements = await this.left.elementRef.evaluate(scope, dom, tag);
|
|
51
|
+
if (this.left.elementRef.first) {
|
|
52
|
+
scopes.push(elements);
|
|
53
|
+
} else {
|
|
54
|
+
scopes = elements;
|
|
55
|
+
}
|
|
56
|
+
} else
|
|
57
|
+
scopes.push(scope);
|
|
58
|
+
|
|
59
|
+
const values = [];
|
|
60
|
+
for (let localScope of scopes) {
|
|
61
|
+
if (localScope instanceof DOMObject) {
|
|
62
|
+
await this.handleDOMObject(name, dom, localScope, tag);
|
|
63
|
+
} else {
|
|
64
|
+
if (localScope['$wrapped'] && localScope['$scope']) {
|
|
65
|
+
localScope = localScope['$scope'];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// We get the values from the passed scope, but set the value on the local scope
|
|
69
|
+
let left: number | Array<any> | string = await this.left.evaluate(scope, dom, tag);
|
|
70
|
+
let right: number | Array<any> | string = await this.right.evaluate(scope, dom, tag);
|
|
71
|
+
|
|
72
|
+
if (left instanceof Array) {
|
|
73
|
+
left = this.handleArray(name, left, right, localScope);
|
|
74
|
+
} else if ((left as any) instanceof UnitLiteral || right instanceof UnitLiteral) {
|
|
75
|
+
left = this.handleUnit(name, left, right, localScope);
|
|
76
|
+
} else if (Number.isFinite(left)) {
|
|
77
|
+
left = this.handleNumber(name, left, right, localScope);
|
|
78
|
+
} else {
|
|
79
|
+
left = this.handleString(name, left, right, localScope);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
values.push(left);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return values.length > 1 ? values : values[0];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public handleNumber(key, left, right, scope) {
|
|
89
|
+
if (right !== null && !Number.isFinite(right))
|
|
90
|
+
right = parseFloat(`${right}`);
|
|
91
|
+
|
|
92
|
+
left = left as number;
|
|
93
|
+
right = right as number;
|
|
94
|
+
|
|
95
|
+
switch (this.type) {
|
|
96
|
+
case TokenType.ASSIGN:
|
|
97
|
+
left = right;
|
|
98
|
+
break;
|
|
99
|
+
case TokenType.ADD_ASSIGN:
|
|
100
|
+
left += right;
|
|
101
|
+
break;
|
|
102
|
+
case TokenType.SUBTRACT_ASSIGN:
|
|
103
|
+
left -= right;
|
|
104
|
+
break;
|
|
105
|
+
case TokenType.MULTIPLY_ASSIGN:
|
|
106
|
+
left *= right;
|
|
107
|
+
break;
|
|
108
|
+
case TokenType.DIVIDE_ASSIGN:
|
|
109
|
+
left /= right;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
scope.set(key, left);
|
|
113
|
+
return left;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public handleString(key, left, right, scope) {
|
|
117
|
+
switch (this.type) {
|
|
118
|
+
case TokenType.ASSIGN:
|
|
119
|
+
left = right;
|
|
120
|
+
break;
|
|
121
|
+
case TokenType.ADD_ASSIGN:
|
|
122
|
+
left = `${left}${right}`;
|
|
123
|
+
break;
|
|
124
|
+
case TokenType.SUBTRACT_ASSIGN:
|
|
125
|
+
left.replace(right, '');
|
|
126
|
+
break;
|
|
127
|
+
case TokenType.MULTIPLY_ASSIGN:
|
|
128
|
+
left *= right;
|
|
129
|
+
break;
|
|
130
|
+
case TokenType.DIVIDE_ASSIGN:
|
|
131
|
+
left /= right;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
scope.set(key, left);
|
|
135
|
+
return left;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public handleUnit(key, left, right, scope) {
|
|
139
|
+
if (!(left instanceof UnitLiteral)) {
|
|
140
|
+
left = new UnitLiteral(left);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!(right instanceof UnitLiteral)) {
|
|
144
|
+
right = new UnitLiteral(right);
|
|
145
|
+
}
|
|
146
|
+
const unit = left.unit || right.unit || 'px';
|
|
147
|
+
|
|
148
|
+
switch (this.type) {
|
|
149
|
+
case TokenType.ASSIGN:
|
|
150
|
+
left = right;
|
|
151
|
+
break;
|
|
152
|
+
case TokenType.ADD_ASSIGN:
|
|
153
|
+
left = new UnitLiteral(`${left.amount+right.amount}${unit}`);
|
|
154
|
+
break;
|
|
155
|
+
case TokenType.SUBTRACT_ASSIGN:
|
|
156
|
+
left = new UnitLiteral(`${left.amount-right.amount}${unit}`);
|
|
157
|
+
break;
|
|
158
|
+
case TokenType.MULTIPLY_ASSIGN:
|
|
159
|
+
left = new UnitLiteral(`${left.amount*right.amount}${unit}`);
|
|
160
|
+
break;
|
|
161
|
+
case TokenType.DIVIDE_ASSIGN:
|
|
162
|
+
left = new UnitLiteral(`${left.amount/right.amount}${unit}`);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
scope.set(key, left);
|
|
167
|
+
return left;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public async handleDOMObject(key: string, dom: DOM, domObject: DOMObject, tag: Tag) {
|
|
171
|
+
let left = domObject.scope.get(key);
|
|
172
|
+
let right: number | Array<any> | string = await this.right.evaluate(domObject.scope, dom, tag);
|
|
173
|
+
if (left instanceof Array)
|
|
174
|
+
return this.handleArray(key, left, right, domObject.scope);
|
|
175
|
+
|
|
176
|
+
return this.handleString(key, left, right, domObject.scope);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public handleArray(key, left, right, scope) {
|
|
180
|
+
if (!(right instanceof Array))
|
|
181
|
+
right = [right];
|
|
182
|
+
switch (this.type) {
|
|
183
|
+
case TokenType.ASSIGN:
|
|
184
|
+
left.splice(0, left.length);
|
|
185
|
+
left.push(...right);
|
|
186
|
+
break;
|
|
187
|
+
case TokenType.ADD_ASSIGN:
|
|
188
|
+
left.push(...right);
|
|
189
|
+
break;
|
|
190
|
+
case TokenType.SUBTRACT_ASSIGN:
|
|
191
|
+
for (let i = left.length - 1; i >= 0; i--) {
|
|
192
|
+
if (right.indexOf(left[i]) > -1) {
|
|
193
|
+
left.splice(i, 1);
|
|
194
|
+
i++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
case TokenType.TILDE:
|
|
199
|
+
for (const toggle of right) {
|
|
200
|
+
const index = left.indexOf(toggle);
|
|
201
|
+
if (index > -1) {
|
|
202
|
+
left.splice(index, 1);
|
|
203
|
+
} else {
|
|
204
|
+
left.push(toggle);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/*
|
|
211
|
+
We have to trigger a change manually here. Setting the variable on the scope with an array won't trigger
|
|
212
|
+
it since we are modifying values inside of the array instance.
|
|
213
|
+
*/
|
|
214
|
+
scope.dispatch(`change:${key}`);
|
|
215
|
+
|
|
216
|
+
return left;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public static match(tokens: Token[]): boolean {
|
|
220
|
+
return [
|
|
221
|
+
TokenType.ASSIGN,
|
|
222
|
+
TokenType.ADD_ASSIGN,
|
|
223
|
+
TokenType.SUBTRACT_ASSIGN,
|
|
224
|
+
TokenType.MULTIPLY_ASSIGN,
|
|
225
|
+
TokenType.DIVIDE_ASSIGN,
|
|
226
|
+
TokenType.TILDE,
|
|
227
|
+
].indexOf(tokens[0].type) > -1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public static parse(lastNode: any, token, tokens: Token[]): ArithmeticAssignmentNode {
|
|
231
|
+
if (!(lastNode instanceof RootScopeMemberNode) && !(lastNode instanceof ScopeMemberNode) && !(lastNode instanceof ElementAttributeNode) && !(lastNode instanceof ElementStyleNode)) {
|
|
232
|
+
throw SyntaxError(`Invalid assignment syntax near ${Tree.toCode(tokens.splice(0, 10))}`);
|
|
233
|
+
}
|
|
234
|
+
tokens.splice(0, 1); // consume =
|
|
235
|
+
const assignmentTokens: Token[] = Tree.getNextStatementTokens(tokens, false, false, true);
|
|
236
|
+
|
|
237
|
+
return new ArithmeticAssignmentNode(
|
|
238
|
+
lastNode as RootScopeMemberNode,
|
|
239
|
+
Tree.processTokens(assignmentTokens),
|
|
240
|
+
token.type
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
|
|
7
|
+
export class ArithmeticNode extends Node implements TreeNode {
|
|
8
|
+
constructor(
|
|
9
|
+
public readonly left: TreeNode,
|
|
10
|
+
public readonly right: TreeNode,
|
|
11
|
+
public readonly type: TokenType
|
|
12
|
+
) {
|
|
13
|
+
super();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected _getChildNodes(): Node[] {
|
|
17
|
+
return [
|
|
18
|
+
this.left as Node,
|
|
19
|
+
this.right as Node
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
24
|
+
const left: any = await this.left.evaluate(scope, dom, tag);
|
|
25
|
+
const right: any = await this.right.evaluate(scope, dom, tag);
|
|
26
|
+
|
|
27
|
+
switch (this.type) {
|
|
28
|
+
case TokenType.ADD:
|
|
29
|
+
return left + right;
|
|
30
|
+
case TokenType.SUBTRACT:
|
|
31
|
+
return left - right;
|
|
32
|
+
case TokenType.MULTIPLY:
|
|
33
|
+
return left * right;
|
|
34
|
+
case TokenType.DIVIDE:
|
|
35
|
+
return left / right;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static match(tokens: Token[]): boolean {
|
|
40
|
+
return [
|
|
41
|
+
TokenType.ADD,
|
|
42
|
+
TokenType.SUBTRACT,
|
|
43
|
+
TokenType.MULTIPLY,
|
|
44
|
+
TokenType.DIVIDE
|
|
45
|
+
].indexOf(tokens[0].type) > -1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static parse(lastNode, token, tokens: Token[]) {
|
|
49
|
+
tokens.splice(0, 1); // Remove arithmetic operator
|
|
50
|
+
return new ArithmeticNode(lastNode, Tree.processTokens(Tree.getNextStatementTokens(tokens)), token.type)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {WrappedArray} from "../Scope/WrappedArray";
|
|
5
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
6
|
+
import {Node} from "./Node";
|
|
7
|
+
|
|
8
|
+
export class ArrayNode extends Node implements TreeNode {
|
|
9
|
+
constructor(
|
|
10
|
+
public readonly values: Node[]
|
|
11
|
+
) {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected _getChildNodes(): Node[] {
|
|
16
|
+
return new Array(...this.values);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
20
|
+
const arr: WrappedArray<any> = new WrappedArray();
|
|
21
|
+
for (const val of this.values) {
|
|
22
|
+
arr.push(await val.evaluate(scope, dom, tag));
|
|
23
|
+
}
|
|
24
|
+
return arr;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static match(tokens: Token[]): boolean {
|
|
28
|
+
return tokens[0].type === TokenType.L_BRACKET;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static parse(lastNode, token, tokens: Token[]): ArrayNode {
|
|
32
|
+
const valueTokens: Token[][] = Tree.getBlockTokens(tokens);
|
|
33
|
+
const values: Node[] = [];
|
|
34
|
+
for (const arg of valueTokens) {
|
|
35
|
+
values.push(Tree.processTokens(arg));
|
|
36
|
+
}
|
|
37
|
+
return new ArrayNode(values);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
|
|
7
|
+
export class BlockNode extends Node implements TreeNode {
|
|
8
|
+
constructor(
|
|
9
|
+
public readonly statements: Node[]
|
|
10
|
+
) {
|
|
11
|
+
super();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected _getChildNodes(): Node[] {
|
|
15
|
+
return [...(this.statements as Node[])];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
19
|
+
let returnValue: any = null;
|
|
20
|
+
for (let i = 0; i < this.statements.length; i++) {
|
|
21
|
+
returnValue = await this.statements[i].evaluate(scope, dom, tag);
|
|
22
|
+
}
|
|
23
|
+
return returnValue;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
|
|
7
|
+
export class ComparisonNode extends Node implements TreeNode {
|
|
8
|
+
constructor(
|
|
9
|
+
public readonly left: Node,
|
|
10
|
+
public readonly right: Node,
|
|
11
|
+
public readonly type: TokenType
|
|
12
|
+
) {
|
|
13
|
+
super();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected _getChildNodes(): Node[] {
|
|
17
|
+
return [
|
|
18
|
+
this.left as Node,
|
|
19
|
+
this.right as Node
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
24
|
+
const left: any = await this.left.evaluate(scope, dom, tag);
|
|
25
|
+
const right: any = await this.right.evaluate(scope, dom, tag);
|
|
26
|
+
switch (this.type) {
|
|
27
|
+
case TokenType.EQUALS:
|
|
28
|
+
return left === right;
|
|
29
|
+
case TokenType.NOT_EQUALS:
|
|
30
|
+
return left !== right;
|
|
31
|
+
case TokenType.GREATER_THAN:
|
|
32
|
+
return left > right;
|
|
33
|
+
case TokenType.LESS_THAN:
|
|
34
|
+
return left < right;
|
|
35
|
+
case TokenType.GREATER_THAN_EQUAL:
|
|
36
|
+
return left >= right;
|
|
37
|
+
case TokenType.LESS_THAN_EQUAL:
|
|
38
|
+
return left <= right;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static match(tokens: Token[]): boolean {
|
|
43
|
+
return [
|
|
44
|
+
TokenType.EQUALS,
|
|
45
|
+
TokenType.NOT_EQUALS,
|
|
46
|
+
TokenType.GREATER_THAN,
|
|
47
|
+
TokenType.LESS_THAN,
|
|
48
|
+
TokenType.GREATER_THAN_EQUAL,
|
|
49
|
+
TokenType.LESS_THAN_EQUAL
|
|
50
|
+
].indexOf(tokens[0].type) > -1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public static parse(lastNode, token, tokens: Token[]) {
|
|
54
|
+
tokens.splice(0, 1); // Remove comparison operator
|
|
55
|
+
return new ComparisonNode(lastNode, Tree.processTokens(Tree.getNextStatementTokens(tokens)), token.type)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {WrappedArray} from "../Scope/WrappedArray";
|
|
5
|
+
import {TreeNode} from "../AST";
|
|
6
|
+
import {BlockNode} from "./BlockNode";
|
|
7
|
+
import {Node} from "./Node";
|
|
8
|
+
|
|
9
|
+
export class ConditionalNode extends Node implements TreeNode {
|
|
10
|
+
constructor(
|
|
11
|
+
public readonly condition: Node,
|
|
12
|
+
public readonly block: BlockNode
|
|
13
|
+
) {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
protected _getChildNodes(): Node[] {
|
|
18
|
+
return [
|
|
19
|
+
this.condition as Node,
|
|
20
|
+
this.block as Node
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
25
|
+
const condition = await this.condition.evaluate(scope, dom, tag);
|
|
26
|
+
let evaluation = false;
|
|
27
|
+
|
|
28
|
+
if (condition instanceof WrappedArray) {
|
|
29
|
+
evaluation = condition.length > 0;
|
|
30
|
+
} else {
|
|
31
|
+
evaluation = !!condition;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return evaluation;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {TagList} from "../Tag/List";
|
|
5
|
+
import {TreeNode} from "../AST";
|
|
6
|
+
import {Node} from "./Node";
|
|
7
|
+
import {ElementQueryNode} from "./ElementQueryNode";
|
|
8
|
+
import {LiteralNode} from "./LiteralNode";
|
|
9
|
+
|
|
10
|
+
export class ElementAttributeNode extends Node implements TreeNode {
|
|
11
|
+
protected requiresPrep: boolean = true;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly elementRef: ElementQueryNode | null,
|
|
15
|
+
public readonly attr: string
|
|
16
|
+
) {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public get name(): LiteralNode<string> {
|
|
21
|
+
return new LiteralNode<string>(`@${this.attributeName}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected _getChildNodes(): Node[] {
|
|
25
|
+
let nodes = [];
|
|
26
|
+
if (this.elementRef)
|
|
27
|
+
nodes.push(this.elementRef)
|
|
28
|
+
return nodes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get attributeName(): string {
|
|
32
|
+
if (this.attr.startsWith('.'))
|
|
33
|
+
return this.attr.substring(2);
|
|
34
|
+
return this.attr.substring(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
38
|
+
let tags: TagList;
|
|
39
|
+
if (this.elementRef) {
|
|
40
|
+
tags = await this.elementRef.evaluate(scope, dom, tag, true);
|
|
41
|
+
} else if (tag) {
|
|
42
|
+
tags = new TagList(tag)
|
|
43
|
+
} else {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (tags.length === 1)
|
|
48
|
+
return tags[0].scope.get(`@${this.attributeName}`);
|
|
49
|
+
|
|
50
|
+
return tags.map((tag) => tag.scope.get(`@${this.attributeName}`));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
54
|
+
if (this.elementRef) {
|
|
55
|
+
await this.elementRef.prepare(scope, dom, tag);
|
|
56
|
+
const tags: TagList = await this.elementRef.evaluate(scope, dom, tag, true);
|
|
57
|
+
for (const t of tags)
|
|
58
|
+
await t.watchAttribute(this.attributeName);
|
|
59
|
+
} else if(tag) {
|
|
60
|
+
await tag.watchAttribute(this.attributeName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
|
|
7
|
+
export class ElementQueryNode extends Node implements TreeNode {
|
|
8
|
+
protected requiresPrep: boolean = true;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
public readonly query: string,
|
|
12
|
+
public readonly first: boolean = false
|
|
13
|
+
) {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async evaluate(scope: Scope, dom: DOM, tag: Tag = null, forceList: boolean = false): Promise<any> {
|
|
18
|
+
tag = tag || await dom.getTagForScope(scope);
|
|
19
|
+
const elements = await dom.get(this.query, true, tag);
|
|
20
|
+
return this.first && !forceList ? elements[0] : elements;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
24
|
+
tag = tag || await dom.getTagForScope(scope);
|
|
25
|
+
await dom.get(this.query, true, tag);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {TagList} from "../Tag/List";
|
|
5
|
+
import {TreeNode} from "../AST";
|
|
6
|
+
import {Node} from "./Node";
|
|
7
|
+
import {ElementQueryNode} from "./ElementQueryNode";
|
|
8
|
+
import {LiteralNode} from "./LiteralNode";
|
|
9
|
+
|
|
10
|
+
export class ElementStyleNode extends Node implements TreeNode {
|
|
11
|
+
protected requiresPrep: boolean = true;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
public readonly elementRef: ElementQueryNode | null,
|
|
15
|
+
public readonly attr: string
|
|
16
|
+
) {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public get name(): LiteralNode<string> {
|
|
21
|
+
return new LiteralNode<string>(`$${this.attributeName}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected _getChildNodes(): Node[] {
|
|
25
|
+
let nodes = [];
|
|
26
|
+
if (this.elementRef)
|
|
27
|
+
nodes.push(this.elementRef)
|
|
28
|
+
return nodes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get attributeName(): string {
|
|
32
|
+
if (this.attr.startsWith('.'))
|
|
33
|
+
return this.attr.substring(2);
|
|
34
|
+
return this.attr.substring(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
38
|
+
let tags: TagList;
|
|
39
|
+
if (this.elementRef) {
|
|
40
|
+
tags = await this.elementRef.evaluate(scope, dom, tag, true);
|
|
41
|
+
} else if (tag) {
|
|
42
|
+
tags = new TagList(tag)
|
|
43
|
+
} else {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (tags.length === 1)
|
|
48
|
+
return tags[0].scope.get(`$${this.attributeName}`);
|
|
49
|
+
|
|
50
|
+
return tags.map((tag) => tag.scope.get(`$${this.attributeName}`));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
54
|
+
if (this.elementRef) {
|
|
55
|
+
await this.elementRef.prepare(scope, dom, tag);
|
|
56
|
+
const tags: TagList = await this.elementRef.evaluate(scope, dom, tag, true);
|
|
57
|
+
for (const t of tags)
|
|
58
|
+
await t.watchStyle(this.attributeName);
|
|
59
|
+
} else if(tag) {
|
|
60
|
+
await tag.watchStyle(this.attributeName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
import {LiteralNode} from "./LiteralNode";
|
|
7
|
+
import {RootScopeMemberNode} from "./RootScopeMemberNode";
|
|
8
|
+
import {ScopeMemberNode} from "./ScopeMemberNode";
|
|
9
|
+
|
|
10
|
+
export class ForStatementNode extends Node implements TreeNode {
|
|
11
|
+
constructor(
|
|
12
|
+
public readonly variable: LiteralNode<string>,
|
|
13
|
+
public readonly list: RootScopeMemberNode | ScopeMemberNode,
|
|
14
|
+
public readonly block: RootScopeMemberNode | ScopeMemberNode,
|
|
15
|
+
) {
|
|
16
|
+
super();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected _getChildNodes(): Node[] {
|
|
20
|
+
return [
|
|
21
|
+
this.variable,
|
|
22
|
+
this.list,
|
|
23
|
+
this.block
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
28
|
+
const variable: string = await this.variable.evaluate(scope, dom, tag);
|
|
29
|
+
const list: any[] = await this.list.evaluate(scope, dom, tag);
|
|
30
|
+
for (let i = 0;i < list.length; i++) {
|
|
31
|
+
scope.set(variable, list[i]);
|
|
32
|
+
await this.block.evaluate(scope, dom, tag);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static parse(lastNode, token, tokens: Token[]): ForStatementNode {
|
|
39
|
+
if (tokens[1].type !== TokenType.L_PAREN) {
|
|
40
|
+
throw SyntaxError('Syntax error: Missing (');
|
|
41
|
+
}
|
|
42
|
+
if (tokens[3].type !== TokenType.OF) {
|
|
43
|
+
throw SyntaxError('Syntax error: Missing of');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
tokens.splice(0, 1); // consume for
|
|
47
|
+
const loopDef: Token[] = Tree.getNextStatementTokens(tokens);
|
|
48
|
+
const variableName: Token = loopDef.splice(0, 1)[0];
|
|
49
|
+
loopDef.splice(0, 1); // consume of
|
|
50
|
+
const list: TreeNode = Tree.processTokens(loopDef);
|
|
51
|
+
const block: TreeNode = Tree.processTokens(Tree.getBlockTokens(tokens, null)[0]);
|
|
52
|
+
|
|
53
|
+
return new ForStatementNode(
|
|
54
|
+
new LiteralNode<string>(variableName.value),
|
|
55
|
+
list as any,
|
|
56
|
+
block as any
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|