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
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,29 @@ 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
|
-
}
|
|
239
|
-
|
|
240
|
-
if ([ScopeVariableType.Integer, ScopeVariableType.Float].indexOf(valueType) > -1 && isNaN(value)) {
|
|
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);
|
|
83
|
+
if (!this.data.hasProperty(key))
|
|
84
|
+
this.data.createProperty(key);
|
|
85
|
+
this.data[key] = value;
|
|
260
86
|
}
|
|
261
87
|
|
|
262
88
|
get keys(): string[] {
|
|
263
|
-
return
|
|
89
|
+
return this.data.keys;
|
|
264
90
|
}
|
|
265
91
|
|
|
266
92
|
has(key: string): boolean {
|
|
267
|
-
return this.
|
|
93
|
+
return this.data.hasProperty(key);
|
|
268
94
|
}
|
|
269
95
|
|
|
270
96
|
setType(key: string, type: string) {
|
|
271
|
-
this.
|
|
97
|
+
const property = this.data.getProperty(key, true);
|
|
98
|
+
property.type = type;
|
|
272
99
|
if (this.has(key))
|
|
273
100
|
this.set(key, this.get(key));
|
|
274
101
|
}
|
|
275
102
|
|
|
276
103
|
getType(key: string): string {
|
|
277
|
-
|
|
104
|
+
const property = this.data.getProperty(key);
|
|
105
|
+
return property.type;
|
|
278
106
|
}
|
|
279
107
|
|
|
280
108
|
extend(data) {
|
|
@@ -284,7 +112,7 @@ export class Scope extends EventDispatcher {
|
|
|
284
112
|
}
|
|
285
113
|
|
|
286
114
|
clear() {
|
|
287
|
-
for (const key of this.
|
|
115
|
+
for (const key of this.data.keys) {
|
|
288
116
|
if (['function', 'object'].indexOf(typeof this.get(key)) > -1) continue;
|
|
289
117
|
this.set(key, null);
|
|
290
118
|
}
|
|
@@ -296,8 +124,14 @@ export class Scope extends EventDispatcher {
|
|
|
296
124
|
}
|
|
297
125
|
|
|
298
126
|
public wrap(toWrap: any, triggerUpdates: boolean = false, updateFromWrapped: boolean = true) {
|
|
299
|
-
if (toWrap instanceof
|
|
127
|
+
if (toWrap instanceof ScopeData) {
|
|
128
|
+
if (this.data instanceof EventDispatcher) {
|
|
129
|
+
this.data.removeRelay(this);
|
|
130
|
+
this.data.deconstruct();
|
|
131
|
+
}
|
|
132
|
+
this.wrapped = toWrap;
|
|
300
133
|
this.data = toWrap;
|
|
134
|
+
this.data.addRelay(this);
|
|
301
135
|
return;
|
|
302
136
|
}
|
|
303
137
|
|
|
@@ -367,9 +201,9 @@ export class Scope extends EventDispatcher {
|
|
|
367
201
|
|
|
368
202
|
this.wrapped.get = this.get.bind(this);
|
|
369
203
|
this.wrapped.set = this.set.bind(this);
|
|
370
|
-
this.wrapped.
|
|
204
|
+
this.wrapped.on = this.on.bind(this);
|
|
371
205
|
this.wrapped.once = this.once.bind(this);
|
|
372
|
-
this.wrapped.
|
|
206
|
+
this.wrapped.off = this.off.bind(this);
|
|
373
207
|
}
|
|
374
208
|
|
|
375
209
|
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/List.ts
CHANGED
|
@@ -29,12 +29,12 @@ export class TagList extends Array<DOMObject> {
|
|
|
29
29
|
return this.map(e => e.element);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
return this
|
|
32
|
+
get first(): DOMObject {
|
|
33
|
+
return this[0];
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
return this.
|
|
36
|
+
get last(): DOMObject {
|
|
37
|
+
return this[this.length - 1];
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
removeClass(className) {
|
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')
|
|
@@ -19,7 +24,7 @@ export class Types {
|
|
|
19
24
|
|
|
20
25
|
@Registry.type('boolean')
|
|
21
26
|
public static boolean(value: string) {
|
|
22
|
-
return [0, '0', 'false', ''].indexOf(value) === -1;
|
|
27
|
+
return [0, '0', false, 'false', ''].indexOf(value) === -1;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
@Registry.type('date')
|
|
@@ -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 {
|
|
@@ -19,7 +20,7 @@ export class Bind extends Attribute {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
public async setup() {
|
|
22
|
-
this.property = this.getAttributeBinding();
|
|
23
|
+
this.property = this.getAttributeBinding(this.property);
|
|
23
24
|
const mods = this.getAttributeModifiers();
|
|
24
25
|
if (mods.length) {
|
|
25
26
|
if (mods.indexOf('from') > -1) {
|
|
@@ -90,7 +91,6 @@ export class Bind extends Attribute {
|
|
|
90
91
|
|
|
91
92
|
public mutate(mutation: MutationRecord) {
|
|
92
93
|
super.mutate(mutation);
|
|
93
|
-
|
|
94
94
|
if (!this.doUpdateFrom) return;
|
|
95
95
|
|
|
96
96
|
// Element innerText binding
|
|
@@ -8,6 +8,7 @@ export class ClassConstructor extends Attribute {
|
|
|
8
8
|
public static readonly scoped: boolean = true;
|
|
9
9
|
protected attributeKey: string;
|
|
10
10
|
protected className: string;
|
|
11
|
+
protected defaultClassName: string;
|
|
11
12
|
|
|
12
13
|
public async setup() {
|
|
13
14
|
const parentScope: Scope = this.tag.parentTag.scope;
|
|
@@ -15,7 +16,7 @@ export class ClassConstructor extends Attribute {
|
|
|
15
16
|
return;
|
|
16
17
|
|
|
17
18
|
this.attributeKey = this.getAttributeBinding();
|
|
18
|
-
this.className = this.getAttributeValue();
|
|
19
|
+
this.className = this.getAttributeValue(this.defaultClassName);
|
|
19
20
|
|
|
20
21
|
const cls = await Registry.instance.classes.get(this.className);
|
|
21
22
|
this.instantiateClass(cls);
|
|
@@ -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,15 @@ 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';
|
|
82
|
+
export {Field} from './Model/Field';
|
|
83
|
+
export {Model} from './Model';
|
|
84
|
+
export {EventDispatcher} from './EventDispatcher';
|
|
85
|
+
export {MessageList} from './MessageList';
|
|
86
|
+
export {SimplePromise} from './SimplePromise';
|
|
77
87
|
export {Tag} from './Tag';
|
|
78
88
|
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
|
+
});
|
package/test/MessageList.spec.ts
CHANGED