vsn 0.1.27 → 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.
- package/demo/demo.html +2 -0
- package/demo/vsn.js +1 -1
- package/dist/AST/ArithmeticAssignmentNode.d.ts +23 -0
- package/dist/AST/ArithmeticAssignmentNode.js +313 -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 +12 -0
- package/dist/AST/ElementQueryNode.js +111 -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 +128 -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/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 +4 -3
- package/dist/Model.js +6 -17
- 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} +17 -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 +137 -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.js +1 -1
- package/dist/Tag.js.map +1 -1
- package/dist/Types.d.ts +1 -0
- package/dist/Types.js +8 -1
- 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.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 +4 -1
- package/dist/vsn.js +14 -9
- package/dist/vsn.js.map +1 -1
- package/package.json +1 -1
- package/src/AST/ArithmeticAssignmentNode.ts +236 -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 +25 -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 +53 -0
- package/src/AST/UnitLiteralNode.ts +51 -0
- package/src/AST.ts +33 -1093
- package/src/Controller.ts +10 -2
- package/src/EventDispatcher.ts +29 -12
- package/src/Model/Field.ts +20 -0
- package/src/Model.ts +7 -21
- package/src/Registry.ts +10 -0
- package/src/Scope/DynamicScopeData.ts +29 -0
- package/src/Scope/QueryReference.ts +29 -0
- package/src/Scope/ScopeData.ts +21 -0
- package/src/Scope/ScopeDataAbstract.ts +126 -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 -193
- package/src/SimplePromise.ts +2 -2
- package/src/Tag.ts +1 -1
- package/src/Types.ts +6 -1
- package/src/Validators.ts +45 -0
- package/src/attributes/Bind.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 +9 -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/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/DataModel.ts +0 -29
- 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
package/src/Scope.ts
CHANGED
|
@@ -1,162 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import {EventDispatcher} from "./EventDispatcher";
|
|
2
|
+
import {ScopeReference} from "./Scope/ScopeReference";
|
|
3
|
+
import {QueryReference} from "./Scope/QueryReference";
|
|
4
|
+
import {WrappedArray} from "./Scope/WrappedArray";
|
|
5
|
+
import {ScopeData} from "./Scope/ScopeData";
|
|
6
|
+
import {DynamicScopeData} from "./Scope/DynamicScopeData";
|
|
6
7
|
|
|
7
|
-
export class ScopeReference {
|
|
8
|
-
private _scope: Scope;
|
|
9
|
-
private _key: string;
|
|
10
|
-
private _value: any;
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
scope: Scope = null,
|
|
14
|
-
key: string = null,
|
|
15
|
-
value: any = null
|
|
16
|
-
) {
|
|
17
|
-
this._scope = scope;
|
|
18
|
-
this._key = key;
|
|
19
|
-
this._value = value;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public async getScope() {
|
|
23
|
-
return this._scope;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public async getKey() {
|
|
27
|
-
return this._key;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public async getValue() {
|
|
31
|
-
return this._value;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class QueryReference extends ScopeReference {
|
|
36
|
-
constructor(
|
|
37
|
-
public readonly path: string,
|
|
38
|
-
public readonly scope: Scope
|
|
39
|
-
) {
|
|
40
|
-
super();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public async getScope() {
|
|
44
|
-
let parts: string[] = this.path.split('.');
|
|
45
|
-
parts = parts.splice(0, parts.length - 1);
|
|
46
|
-
const qResult = await DOM.instance.eval(parts.join('.'));
|
|
47
|
-
return qResult.length === 1 ? qResult[0].scope : qResult.map((dobj) => dobj.scope);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public async getKey() {
|
|
51
|
-
const parts: string[] = this.path.split('.');
|
|
52
|
-
return parts[parts.length - 1];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public async getValue() {
|
|
56
|
-
return await DOM.instance.eval(this.path);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export class ScopeVariableType {
|
|
61
|
-
public static readonly Integer: string = 'integer';
|
|
62
|
-
public static readonly Float: string = 'float';
|
|
63
|
-
public static readonly Boolean: string = 'boolean';
|
|
64
|
-
public static readonly String: string = 'string';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export class WrappedArray<T> extends Array<T> {
|
|
68
|
-
private dispatcher: EventDispatcher;
|
|
69
|
-
public readonly $wrapped: boolean = true;
|
|
70
|
-
|
|
71
|
-
constructor(...items: T[]) {
|
|
72
|
-
super(...items);
|
|
73
|
-
Object.setPrototypeOf(this, WrappedArray.prototype);
|
|
74
|
-
this.dispatcher = new EventDispatcher();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
dispatch(event: string, ...args: any[]) {
|
|
78
|
-
this.dispatcher.dispatch(event, ...args);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
on(event: string, callback: EventDispatcherCallback) {
|
|
82
|
-
this.dispatcher.on(event, callback);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
off(event: string, key?: number) {
|
|
86
|
-
this.dispatcher.off(event, key);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
once(event: string, callback: EventDispatcherCallback) {
|
|
90
|
-
this.dispatcher.once(event, callback);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
push(...items: T[]): number {
|
|
94
|
-
const num: number = super.push(...items);
|
|
95
|
-
|
|
96
|
-
this.dispatch('push', ...items);
|
|
97
|
-
this.dispatch('change', {
|
|
98
|
-
'added': items
|
|
99
|
-
});
|
|
100
|
-
for (const item of items) {
|
|
101
|
-
this.dispatch('add', item);
|
|
102
|
-
}
|
|
103
|
-
return num;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
splice(start: number, deleteCount?: number): T[] {
|
|
107
|
-
const removed: T[] = super.splice(start, deleteCount);
|
|
108
|
-
|
|
109
|
-
this.dispatch('change', {
|
|
110
|
-
'removed': removed
|
|
111
|
-
});
|
|
112
|
-
for (const item of removed) {
|
|
113
|
-
this.dispatch('remove', item);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return removed;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get(key: string) {
|
|
120
|
-
const keys: string[] = [
|
|
121
|
-
'length'
|
|
122
|
-
];
|
|
123
|
-
return keys.indexOf(key) > -1 ? this[key] : undefined;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get length(): number {
|
|
127
|
-
let c: number = 0;
|
|
128
|
-
for (const item of this) {
|
|
129
|
-
c += 1;
|
|
130
|
-
}
|
|
131
|
-
return c;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
set length(num: number) {
|
|
135
|
-
this.setLength(num);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
setLength(num: number) {
|
|
139
|
-
let c: number = 0;
|
|
140
|
-
const toRemove: T[] = [];
|
|
141
|
-
for (const item of this) {
|
|
142
|
-
c += 1;
|
|
143
|
-
if (c >= num) {
|
|
144
|
-
toRemove.push(item);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
for (const item of toRemove) {
|
|
149
|
-
this.splice(this.indexOf(item), 1);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
8
|
|
|
154
9
|
export class Scope extends EventDispatcher {
|
|
155
10
|
public wrapped: any;
|
|
156
|
-
protected data:
|
|
157
|
-
protected types: {[key: string]: string;} = {};
|
|
11
|
+
protected data: ScopeData;
|
|
158
12
|
protected children: Scope[];
|
|
159
|
-
protected _keys: string[];
|
|
160
13
|
protected _parentScope: Scope;
|
|
161
14
|
|
|
162
15
|
constructor(
|
|
@@ -166,8 +19,8 @@ export class Scope extends EventDispatcher {
|
|
|
166
19
|
if (parent)
|
|
167
20
|
this.parentScope = parent;
|
|
168
21
|
this.children = [];
|
|
169
|
-
this.data = new
|
|
170
|
-
this.
|
|
22
|
+
this.data = new DynamicScopeData({});
|
|
23
|
+
this.data.addRelay(this);
|
|
171
24
|
}
|
|
172
25
|
|
|
173
26
|
public get parentScope(): Scope {
|
|
@@ -227,54 +80,30 @@ export class Scope extends EventDispatcher {
|
|
|
227
80
|
}
|
|
228
81
|
|
|
229
82
|
set(key: string, value: any) {
|
|
230
|
-
if (this.data
|
|
231
|
-
this.data.
|
|
232
|
-
|
|
233
|
-
if (typeof value === 'string') {
|
|
234
|
-
const valueType = this.getType(key);
|
|
235
|
-
const caster = Registry.instance.types.getSynchronous(valueType);
|
|
236
|
-
if (caster) {
|
|
237
|
-
value = caster(value);
|
|
238
|
-
}
|
|
83
|
+
if (!this.data.hasProperty(key))
|
|
84
|
+
this.data.createProperty(key);
|
|
239
85
|
|
|
240
|
-
|
|
241
|
-
value = null;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (this.data[key] !== value) {
|
|
246
|
-
const previousValue = this.data[key];
|
|
247
|
-
this.data[key] = value;
|
|
248
|
-
const event = {
|
|
249
|
-
value: value,
|
|
250
|
-
previousValue: previousValue,
|
|
251
|
-
key: key
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
this.dispatch(`change:${key}`, event);
|
|
255
|
-
this.dispatch('change', key, event);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (this._keys.indexOf(key) === -1)
|
|
259
|
-
this._keys.push(key);
|
|
86
|
+
this.data[key] = value;
|
|
260
87
|
}
|
|
261
88
|
|
|
262
89
|
get keys(): string[] {
|
|
263
|
-
return
|
|
90
|
+
return this.data.keys;
|
|
264
91
|
}
|
|
265
92
|
|
|
266
93
|
has(key: string): boolean {
|
|
267
|
-
return this.
|
|
94
|
+
return this.data.hasProperty(key);
|
|
268
95
|
}
|
|
269
96
|
|
|
270
97
|
setType(key: string, type: string) {
|
|
271
|
-
this.
|
|
98
|
+
const property = this.data.getProperty(key, true);
|
|
99
|
+
property.type = type;
|
|
272
100
|
if (this.has(key))
|
|
273
101
|
this.set(key, this.get(key));
|
|
274
102
|
}
|
|
275
103
|
|
|
276
104
|
getType(key: string): string {
|
|
277
|
-
|
|
105
|
+
const property = this.data.getProperty(key);
|
|
106
|
+
return property.type;
|
|
278
107
|
}
|
|
279
108
|
|
|
280
109
|
extend(data) {
|
|
@@ -284,7 +113,7 @@ export class Scope extends EventDispatcher {
|
|
|
284
113
|
}
|
|
285
114
|
|
|
286
115
|
clear() {
|
|
287
|
-
for (const key of this.
|
|
116
|
+
for (const key of this.data.keys) {
|
|
288
117
|
if (['function', 'object'].indexOf(typeof this.get(key)) > -1) continue;
|
|
289
118
|
this.set(key, null);
|
|
290
119
|
}
|
|
@@ -296,8 +125,14 @@ export class Scope extends EventDispatcher {
|
|
|
296
125
|
}
|
|
297
126
|
|
|
298
127
|
public wrap(toWrap: any, triggerUpdates: boolean = false, updateFromWrapped: boolean = true) {
|
|
299
|
-
if (toWrap instanceof
|
|
128
|
+
if (toWrap instanceof ScopeData) {
|
|
129
|
+
if (this.data instanceof EventDispatcher) {
|
|
130
|
+
this.data.removeRelay(this);
|
|
131
|
+
this.data.deconstruct();
|
|
132
|
+
}
|
|
133
|
+
this.wrapped = toWrap;
|
|
300
134
|
this.data = toWrap;
|
|
135
|
+
this.data.addRelay(this);
|
|
301
136
|
return;
|
|
302
137
|
}
|
|
303
138
|
|
|
@@ -367,9 +202,9 @@ export class Scope extends EventDispatcher {
|
|
|
367
202
|
|
|
368
203
|
this.wrapped.get = this.get.bind(this);
|
|
369
204
|
this.wrapped.set = this.set.bind(this);
|
|
370
|
-
this.wrapped.
|
|
205
|
+
this.wrapped.on = this.on.bind(this);
|
|
371
206
|
this.wrapped.once = this.once.bind(this);
|
|
372
|
-
this.wrapped.
|
|
207
|
+
this.wrapped.off = this.off.bind(this);
|
|
373
208
|
}
|
|
374
209
|
|
|
375
210
|
public unwrap(): void {
|
package/src/SimplePromise.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {EventDispatcher} from "./EventDispatcher";
|
|
|
3
3
|
export interface IDeferred<T> {
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
promise: SimplePromise<T>;
|
|
6
|
-
resolve(result
|
|
6
|
+
resolve(result?: T): void;
|
|
7
7
|
reject(reason: string): void;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -67,7 +67,7 @@ export class SimplePromise<T> extends EventDispatcher implements IPromise<T> {
|
|
|
67
67
|
* promise will be fulfilled with the value. Generally, if you don't know if a value is a promise or not,
|
|
68
68
|
* Promise.resolve(value) it instead and work with the return value as a promise.
|
|
69
69
|
*/
|
|
70
|
-
public static resolve<T>(result
|
|
70
|
+
public static resolve<T>(result?: T): IPromise<T> {
|
|
71
71
|
return new SimplePromise<T>((resolve: TResolve<T>): void => {
|
|
72
72
|
if (result instanceof SimplePromise) {
|
|
73
73
|
result.then((innerResult: T) => {
|
package/src/Tag.ts
CHANGED
|
@@ -254,11 +254,11 @@ export class Tag extends DOMObject {
|
|
|
254
254
|
if (obj instanceof Controller) {
|
|
255
255
|
obj.init(this.scope, this, this.element);
|
|
256
256
|
} else {
|
|
257
|
-
this.scope.wrap(obj, triggerUpdates, updateFromWrapped);
|
|
258
257
|
obj['$scope'] = this.scope;
|
|
259
258
|
obj['$tag'] = this;
|
|
260
259
|
obj['$el'] = this.element;
|
|
261
260
|
}
|
|
261
|
+
this.scope.wrap(obj, triggerUpdates, updateFromWrapped);
|
|
262
262
|
return obj;
|
|
263
263
|
}
|
|
264
264
|
|
package/src/Types.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import {Registry} from "./Registry";
|
|
2
2
|
|
|
3
3
|
export class Types {
|
|
4
|
+
@Registry.type('any')
|
|
5
|
+
public static any(value: any): any {
|
|
6
|
+
return value as any;
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
@Registry.type('string')
|
|
5
10
|
public static string(value: string) {
|
|
6
|
-
return value
|
|
11
|
+
return `${value}`;
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
@Registry.type('integer')
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {Registry} from "./Registry";
|
|
2
|
+
|
|
3
|
+
export class Validators {
|
|
4
|
+
public static readonly _emailRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
|
5
|
+
|
|
6
|
+
@Registry.validator('email')
|
|
7
|
+
public static email(value: any): string[] {
|
|
8
|
+
const errors: string[] = [];
|
|
9
|
+
|
|
10
|
+
if(value != null && !this._emailRegex.test(value))
|
|
11
|
+
errors.push('Please enter a valid email address');
|
|
12
|
+
|
|
13
|
+
return errors;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Registry.validator('required')
|
|
17
|
+
public static required(value: any): string[] {
|
|
18
|
+
const errors: string[] = [];
|
|
19
|
+
|
|
20
|
+
if(value == null || value.length == 0)
|
|
21
|
+
errors.push('This field is required');
|
|
22
|
+
|
|
23
|
+
return errors;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Registry.validator('positive')
|
|
27
|
+
public static positive(value: any): string[] {
|
|
28
|
+
const errors: string[] = [];
|
|
29
|
+
|
|
30
|
+
if(value != null && value < 0)
|
|
31
|
+
errors.push('Please enter a positive number');
|
|
32
|
+
|
|
33
|
+
return errors;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Registry.validator('negative')
|
|
37
|
+
public static negative(value: any): string[] {
|
|
38
|
+
const errors: string[] = [];
|
|
39
|
+
|
|
40
|
+
if(value != null && value > 0)
|
|
41
|
+
errors.push('Please enter a negative number');
|
|
42
|
+
|
|
43
|
+
return errors;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/attributes/Bind.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {Scope
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
2
|
import {Attribute} from "../Attribute";
|
|
3
3
|
import {Tree} from "../AST";
|
|
4
4
|
import {Registry} from "../Registry";
|
|
5
|
+
import {ScopeReference} from "../Scope/ScopeReference";
|
|
5
6
|
|
|
6
7
|
@Registry.attribute('vsn-bind')
|
|
7
8
|
export class Bind extends Attribute {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {Registry} from "../Registry";
|
|
2
2
|
import {Attribute} from "../Attribute";
|
|
3
|
-
import {Scope
|
|
3
|
+
import {Scope} from "../Scope";
|
|
4
|
+
import {ScopeReference} from "../Scope/ScopeReference";
|
|
4
5
|
|
|
5
6
|
@Registry.attribute('vsn-json')
|
|
6
7
|
export class JSONAttribute extends Attribute {
|
package/src/attributes/List.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Attribute} from "../Attribute";
|
|
2
2
|
import {Tag} from "../Tag";
|
|
3
|
-
import {WrappedArray} from "../Scope";
|
|
3
|
+
import {WrappedArray} from "../Scope/WrappedArray";
|
|
4
4
|
import {Tree} from "../AST";
|
|
5
5
|
import {ElementHelper} from "../helpers/ElementHelper";
|
|
6
6
|
import {Registry} from "../Registry";
|
package/src/attributes/Radio.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {Scope
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
2
|
import {Attribute} from "../Attribute";
|
|
3
3
|
import {Registry} from "../Registry";
|
|
4
|
+
import {ScopeReference} from "../Scope/ScopeReference";
|
|
4
5
|
|
|
5
6
|
@Registry.attribute('vsn-set')
|
|
6
7
|
export class SetAttribute extends Attribute {
|
package/src/vsn.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {DOM} from "./DOM";
|
|
2
|
-
import {WrappedArray} from "./Scope";
|
|
2
|
+
import {WrappedArray} from "./Scope/WrappedArray";
|
|
3
3
|
import {Registry} from "./Registry";
|
|
4
4
|
import "./Types";
|
|
5
5
|
import "./Formats";
|
|
@@ -8,7 +8,9 @@ import {VisionHelper} from "./helpers/VisionHelper";
|
|
|
8
8
|
import {Tree} from "./AST";
|
|
9
9
|
import {Query} from "./Query";
|
|
10
10
|
import {EventDispatcher} from "./EventDispatcher";
|
|
11
|
-
import {
|
|
11
|
+
import {DynamicScopeData} from "./Scope/DynamicScopeData";
|
|
12
|
+
import {Controller} from "./Controller";
|
|
13
|
+
import {property} from "./Scope/properties/Property";
|
|
12
14
|
|
|
13
15
|
export class Vision extends EventDispatcher {
|
|
14
16
|
protected static _instance: Vision;
|
|
@@ -28,7 +30,7 @@ export class Vision extends EventDispatcher {
|
|
|
28
30
|
}
|
|
29
31
|
this.registry.classes.register('Object', Object);
|
|
30
32
|
this.registry.classes.register('WrappedArray', WrappedArray);
|
|
31
|
-
this.registry.classes.register('
|
|
33
|
+
this.registry.classes.register('Data', DynamicScopeData);
|
|
32
34
|
|
|
33
35
|
if (VisionHelper.window) {
|
|
34
36
|
window['Vision'] = Vision;
|
|
@@ -72,7 +74,10 @@ export * from './Registry';
|
|
|
72
74
|
export * from './Attribute';
|
|
73
75
|
export * from './AST';
|
|
74
76
|
export {DOM} from './DOM';
|
|
75
|
-
export {
|
|
77
|
+
export {Scope} from './Scope';
|
|
78
|
+
export {ScopeReference} from './Scope/ScopeReference';
|
|
79
|
+
export {WrappedArray} from './Scope/WrappedArray';
|
|
76
80
|
export {Controller} from './Controller';
|
|
81
|
+
export {Property, property} from './Scope/properties/Property';
|
|
77
82
|
export {Tag} from './Tag';
|
|
78
83
|
export const vision: Vision = Vision.instance;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {SimplePromise} from "../../src/SimplePromise";
|
|
2
|
+
import {DOM} from "../../src/DOM";
|
|
3
|
+
import {Tree} from "../../src/AST";
|
|
4
|
+
import {Scope} from "../../src/Scope";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
describe('ArithmeticAssignmentNode', () => {
|
|
8
|
+
it("should support simple arithmetic with numbers", async () => {
|
|
9
|
+
const tree = new Tree(`
|
|
10
|
+
a = 1;
|
|
11
|
+
a += 10;
|
|
12
|
+
b = a + 1;
|
|
13
|
+
b -= 10;
|
|
14
|
+
c = a + 1;
|
|
15
|
+
c /= 2;
|
|
16
|
+
d = a + 1;
|
|
17
|
+
d *= 2;
|
|
18
|
+
`);
|
|
19
|
+
const scope = new Scope();
|
|
20
|
+
await tree.evaluate(scope, null, null);
|
|
21
|
+
expect(scope.get("a")).toBe(11);
|
|
22
|
+
expect(scope.get("b")).toBe(2);
|
|
23
|
+
expect(scope.get("c")).toBe(6);
|
|
24
|
+
expect(scope.get("d")).toBe(24);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should support simple arithmetic with numbers inside nested objects", async () => {
|
|
28
|
+
const tree = new Tree(`
|
|
29
|
+
z = {};
|
|
30
|
+
a = 100;
|
|
31
|
+
z.z = {};
|
|
32
|
+
z.z.a = 10;
|
|
33
|
+
z.a = 1;
|
|
34
|
+
z.b = 15;
|
|
35
|
+
z.a += z.z.a;
|
|
36
|
+
z.b *= a + z.a + z.b;
|
|
37
|
+
z.z.b = z.z.a + z.a;
|
|
38
|
+
z.z.b *= z.z.a;
|
|
39
|
+
`);
|
|
40
|
+
const scope = new Scope();
|
|
41
|
+
await tree.evaluate(scope, null, null);
|
|
42
|
+
expect(await Tree.apply('z.z.a', scope, null, null)).toBe(10);
|
|
43
|
+
expect(await Tree.apply('z.a', scope, null, null)).toBe(11);
|
|
44
|
+
expect(await Tree.apply('z.b', scope, null, null)).toBe(1890);
|
|
45
|
+
expect(await Tree.apply('z.z.b', scope, null, null)).toBe(210);
|
|
46
|
+
});
|
|
47
|
+
});
|
package/test/AST.spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import {Scope
|
|
1
|
+
import {WrappedArray} from '../src/Scope/WrappedArray';
|
|
2
|
+
import {Scope} from "../src/Scope";
|
|
3
3
|
import {Tree} from "../src/AST";
|
|
4
4
|
import {DOM} from "../src/DOM";
|
|
5
5
|
import {IDeferred, SimplePromise} from "../src/SimplePromise";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {Controller} from '../src/Controller';
|
|
2
|
+
import {DOM} from "../src/DOM";
|
|
3
|
+
import {SimplePromise} from "../src/SimplePromise";
|
|
4
|
+
import {Registry} from "../src/Registry";
|
|
5
|
+
import {property} from "../src/Scope/properties/Property";
|
|
6
|
+
import {Property} from "../src/vsn";
|
|
7
|
+
|
|
8
|
+
@Registry.controller('ControllerTestController')
|
|
9
|
+
class TestController extends Controller {
|
|
10
|
+
@property()
|
|
11
|
+
public test: string;
|
|
12
|
+
|
|
13
|
+
@property(Property, {
|
|
14
|
+
type: 'integer',
|
|
15
|
+
min: 0,
|
|
16
|
+
max: 100,
|
|
17
|
+
validators: [
|
|
18
|
+
'positive',
|
|
19
|
+
]
|
|
20
|
+
})
|
|
21
|
+
public positive_integer: number;
|
|
22
|
+
|
|
23
|
+
isValid(): boolean {
|
|
24
|
+
return this.test === 'test';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('Controller', () => {
|
|
29
|
+
it("methods should be callable from vsn-script", async () => {
|
|
30
|
+
document.body.innerHTML = `
|
|
31
|
+
<div vsn-controller:test="ControllerTestController" vsn-set:test.test="notTest" vsn-bind="test.test"></div>
|
|
32
|
+
`;
|
|
33
|
+
const dom = new DOM(document);
|
|
34
|
+
const deferred = SimplePromise.defer();
|
|
35
|
+
dom.once('built', async () => {
|
|
36
|
+
expect(await dom.eval('test.test')).toBe('notTest');
|
|
37
|
+
expect(await dom.eval('test.isValid()')).toBe(false);
|
|
38
|
+
await dom.eval('test.test = "test"');
|
|
39
|
+
expect(await dom.eval('test.isValid()')).toBe(true);
|
|
40
|
+
deferred.resolve();
|
|
41
|
+
});
|
|
42
|
+
await deferred.promise;
|
|
43
|
+
});
|
|
44
|
+
});
|