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.
Files changed (244) hide show
  1. package/demo/vsn.js +1 -1
  2. package/dist/AST/ArithmeticAssignmentNode.d.ts +23 -0
  3. package/dist/AST/ArithmeticAssignmentNode.js +324 -0
  4. package/dist/AST/ArithmeticAssignmentNode.js.map +1 -0
  5. package/dist/AST/ArithmeticNode.d.ts +15 -0
  6. package/dist/AST/ArithmeticNode.js +114 -0
  7. package/dist/AST/ArithmeticNode.js.map +1 -0
  8. package/dist/AST/ArrayNode.d.ts +14 -0
  9. package/dist/AST/ArrayNode.js +114 -0
  10. package/dist/AST/ArrayNode.js.map +1 -0
  11. package/dist/AST/BlockNode.d.ts +11 -0
  12. package/dist/AST/BlockNode.js +98 -0
  13. package/dist/AST/BlockNode.js.map +1 -0
  14. package/dist/AST/BooleanLiteralNode.d.ts +5 -0
  15. package/dist/{Model/Collection.js → AST/BooleanLiteralNode.js} +12 -18
  16. package/dist/AST/BooleanLiteralNode.js.map +1 -0
  17. package/dist/AST/ComparisonNode.d.ts +15 -0
  18. package/dist/AST/ComparisonNode.js +120 -0
  19. package/dist/AST/ComparisonNode.js.map +1 -0
  20. package/dist/AST/ConditionalNode.d.ts +13 -0
  21. package/dist/AST/ConditionalNode.js +95 -0
  22. package/dist/AST/ConditionalNode.js.map +1 -0
  23. package/dist/AST/ElementAttributeNode.d.ts +18 -0
  24. package/dist/AST/ElementAttributeNode.js +159 -0
  25. package/dist/AST/ElementAttributeNode.js.map +1 -0
  26. package/dist/AST/ElementQueryNode.d.ts +13 -0
  27. package/dist/AST/ElementQueryNode.js +116 -0
  28. package/dist/AST/ElementQueryNode.js.map +1 -0
  29. package/dist/AST/ElementStyleNode.d.ts +18 -0
  30. package/dist/AST/ElementStyleNode.js +159 -0
  31. package/dist/AST/ElementStyleNode.js.map +1 -0
  32. package/dist/AST/ForStatementNode.d.ts +17 -0
  33. package/dist/AST/ForStatementNode.js +121 -0
  34. package/dist/AST/ForStatementNode.js.map +1 -0
  35. package/dist/AST/FunctionArgumentNode.d.ts +11 -0
  36. package/dist/AST/FunctionArgumentNode.js +100 -0
  37. package/dist/AST/FunctionArgumentNode.js.map +1 -0
  38. package/dist/AST/FunctionCallNode.d.ts +13 -0
  39. package/dist/AST/FunctionCallNode.js +102 -0
  40. package/dist/AST/FunctionCallNode.js.map +1 -0
  41. package/dist/AST/IfStatementNode.d.ts +14 -0
  42. package/dist/AST/IfStatementNode.js +128 -0
  43. package/dist/AST/IfStatementNode.js.map +1 -0
  44. package/dist/AST/InNode.d.ts +15 -0
  45. package/dist/AST/InNode.js +107 -0
  46. package/dist/AST/InNode.js.map +1 -0
  47. package/dist/AST/IndexNode.d.ts +16 -0
  48. package/dist/AST/IndexNode.js +126 -0
  49. package/dist/AST/IndexNode.js.map +1 -0
  50. package/dist/AST/LiteralNode.d.ts +10 -0
  51. package/dist/AST/LiteralNode.js +74 -0
  52. package/dist/AST/LiteralNode.js.map +1 -0
  53. package/dist/AST/Node.d.ts +19 -0
  54. package/dist/AST/Node.js +117 -0
  55. package/dist/AST/Node.js.map +1 -0
  56. package/dist/AST/NotNode.d.ts +12 -0
  57. package/dist/AST/NotNode.js +103 -0
  58. package/dist/AST/NotNode.js.map +1 -0
  59. package/dist/AST/NumberLiteralNode.d.ts +5 -0
  60. package/dist/{Model/fields/EmailField.js → AST/NumberLiteralNode.js} +17 -17
  61. package/dist/AST/NumberLiteralNode.js.map +1 -0
  62. package/dist/AST/ObjectNode.d.ts +14 -0
  63. package/dist/AST/ObjectNode.js +131 -0
  64. package/dist/AST/ObjectNode.js.map +1 -0
  65. package/dist/AST/RootScopeMemberNode.d.ts +11 -0
  66. package/dist/AST/RootScopeMemberNode.js +87 -0
  67. package/dist/AST/RootScopeMemberNode.js.map +1 -0
  68. package/dist/AST/ScopeMemberNode.d.ts +12 -0
  69. package/dist/AST/ScopeMemberNode.js +134 -0
  70. package/dist/AST/ScopeMemberNode.js.map +1 -0
  71. package/dist/AST/UnitLiteralNode.d.ts +15 -0
  72. package/dist/AST/UnitLiteralNode.js +72 -0
  73. package/dist/AST/UnitLiteralNode.js.map +1 -0
  74. package/dist/AST.d.ts +7 -60
  75. package/dist/AST.js +74 -1493
  76. package/dist/AST.js.map +1 -1
  77. package/dist/Controller.d.ts +4 -2
  78. package/dist/Controller.js +10 -2
  79. package/dist/Controller.js.map +1 -1
  80. package/dist/EventDispatcher.d.ts +4 -1
  81. package/dist/EventDispatcher.js +27 -12
  82. package/dist/EventDispatcher.js.map +1 -1
  83. package/dist/MessageList.d.ts +2 -1
  84. package/dist/MessageList.js +9 -1
  85. package/dist/MessageList.js.map +1 -1
  86. package/dist/Model/Field.d.ts +8 -0
  87. package/dist/Model/{fields/StringField.js → Field.js} +19 -24
  88. package/dist/Model/Field.js.map +1 -0
  89. package/dist/Model.d.ts +5 -4
  90. package/dist/Model.js +7 -18
  91. package/dist/Model.js.map +1 -1
  92. package/dist/Registry.d.ts +3 -0
  93. package/dist/Registry.js +11 -0
  94. package/dist/Registry.js.map +1 -1
  95. package/dist/Scope/DynamicScopeData.d.ts +6 -0
  96. package/dist/{Model/DataModel.js → Scope/DynamicScopeData.js} +15 -17
  97. package/dist/Scope/DynamicScopeData.js.map +1 -0
  98. package/dist/Scope/QueryReference.d.ts +10 -0
  99. package/dist/Scope/QueryReference.js +103 -0
  100. package/dist/Scope/QueryReference.js.map +1 -0
  101. package/dist/Scope/ScopeData.d.ts +4 -0
  102. package/dist/Scope/ScopeData.js +40 -0
  103. package/dist/Scope/ScopeData.js.map +1 -0
  104. package/dist/Scope/ScopeDataAbstract.d.ts +22 -0
  105. package/dist/Scope/ScopeDataAbstract.js +138 -0
  106. package/dist/Scope/ScopeDataAbstract.js.map +1 -0
  107. package/dist/Scope/ScopeReference.d.ts +10 -0
  108. package/dist/Scope/ScopeReference.js +73 -0
  109. package/dist/Scope/ScopeReference.js.map +1 -0
  110. package/dist/Scope/ScopedVariableType.d.ts +6 -0
  111. package/dist/Scope/ScopedVariableType.js +14 -0
  112. package/dist/Scope/ScopedVariableType.js.map +1 -0
  113. package/dist/Scope/WrappedArray.d.ts +16 -0
  114. package/dist/Scope/WrappedArray.js +121 -0
  115. package/dist/Scope/WrappedArray.js.map +1 -0
  116. package/dist/Scope/properties/Property.d.ts +18 -0
  117. package/dist/Scope/properties/Property.js +93 -0
  118. package/dist/Scope/properties/Property.js.map +1 -0
  119. package/dist/Scope.d.ts +4 -45
  120. package/dist/Scope.js +31 -266
  121. package/dist/Scope.js.map +1 -1
  122. package/dist/SimplePromise.d.ts +2 -2
  123. package/dist/SimplePromise.js.map +1 -1
  124. package/dist/Tag/List.d.ts +2 -2
  125. package/dist/Tag/List.js +14 -6
  126. package/dist/Tag/List.js.map +1 -1
  127. package/dist/Tag.js +1 -1
  128. package/dist/Tag.js.map +1 -1
  129. package/dist/Types.d.ts +1 -0
  130. package/dist/Types.js +8 -2
  131. package/dist/Types.js.map +1 -1
  132. package/dist/Validators.d.ts +7 -0
  133. package/dist/Validators.js +54 -0
  134. package/dist/Validators.js.map +1 -0
  135. package/dist/attributes/Bind.js +1 -1
  136. package/dist/attributes/Bind.js.map +1 -1
  137. package/dist/attributes/ClassConstructor.d.ts +1 -0
  138. package/dist/attributes/ClassConstructor.js +1 -1
  139. package/dist/attributes/ClassConstructor.js.map +1 -1
  140. package/dist/attributes/JSONAttribute.js.map +1 -1
  141. package/dist/attributes/List.js +4 -4
  142. package/dist/attributes/List.js.map +1 -1
  143. package/dist/attributes/Radio.js.map +1 -1
  144. package/dist/attributes/SetAttribute.js.map +1 -1
  145. package/dist/attributes/StyleAttribute.js.map +1 -1
  146. package/dist/vsn.d.ts +9 -1
  147. package/dist/vsn.js +24 -9
  148. package/dist/vsn.js.map +1 -1
  149. package/package.json +1 -1
  150. package/src/AST/ArithmeticAssignmentNode.ts +243 -0
  151. package/src/AST/ArithmeticNode.ts +52 -0
  152. package/src/AST/ArrayNode.ts +39 -0
  153. package/src/AST/BlockNode.ts +25 -0
  154. package/src/AST/BooleanLiteralNode.ts +10 -0
  155. package/src/AST/ComparisonNode.ts +57 -0
  156. package/src/AST/ConditionalNode.ts +36 -0
  157. package/src/AST/ElementAttributeNode.ts +63 -0
  158. package/src/AST/ElementQueryNode.ts +27 -0
  159. package/src/AST/ElementStyleNode.ts +63 -0
  160. package/src/AST/ForStatementNode.ts +59 -0
  161. package/src/AST/FunctionArgumentNode.ts +27 -0
  162. package/src/AST/FunctionCallNode.ts +32 -0
  163. package/src/AST/IfStatementNode.ts +67 -0
  164. package/src/AST/InNode.ts +46 -0
  165. package/src/AST/IndexNode.ts +61 -0
  166. package/src/AST/LiteralNode.ts +17 -0
  167. package/src/AST/Node.ts +71 -0
  168. package/src/AST/NotNode.ts +41 -0
  169. package/src/AST/NumberLiteralNode.ts +14 -0
  170. package/src/AST/ObjectNode.ts +55 -0
  171. package/src/AST/RootScopeMemberNode.ts +25 -0
  172. package/src/AST/ScopeMemberNode.ts +58 -0
  173. package/src/AST/UnitLiteralNode.ts +51 -0
  174. package/src/AST.ts +34 -1094
  175. package/src/Controller.ts +10 -2
  176. package/src/EventDispatcher.ts +29 -12
  177. package/src/MessageList.ts +5 -1
  178. package/src/Model/Field.ts +20 -0
  179. package/src/Model.ts +8 -22
  180. package/src/Registry.ts +10 -0
  181. package/src/{Model/DataModel.ts → Scope/DynamicScopeData.ts} +8 -10
  182. package/src/Scope/QueryReference.ts +29 -0
  183. package/src/Scope/ScopeData.ts +21 -0
  184. package/src/Scope/ScopeDataAbstract.ts +127 -0
  185. package/src/Scope/ScopeReference.ts +30 -0
  186. package/src/Scope/ScopedVariableType.ts +7 -0
  187. package/src/Scope/WrappedArray.ts +88 -0
  188. package/src/Scope/properties/Property.ts +79 -0
  189. package/src/Scope.ts +28 -194
  190. package/src/SimplePromise.ts +2 -2
  191. package/src/Tag/List.ts +4 -4
  192. package/src/Tag.ts +1 -1
  193. package/src/Types.ts +7 -2
  194. package/src/Validators.ts +45 -0
  195. package/src/attributes/Bind.ts +3 -3
  196. package/src/attributes/ClassConstructor.ts +2 -1
  197. package/src/attributes/JSONAttribute.ts +2 -1
  198. package/src/attributes/List.ts +1 -1
  199. package/src/attributes/Radio.ts +2 -1
  200. package/src/attributes/ScopeChange.ts +1 -1
  201. package/src/attributes/SetAttribute.ts +2 -1
  202. package/src/attributes/StyleAttribute.ts +2 -1
  203. package/src/attributes/TypeAttribute.ts +1 -1
  204. package/src/vsn.ts +14 -4
  205. package/test/AST/ArithmeticAssignmentNode.spec.ts +47 -0
  206. package/test/AST.spec.ts +2 -2
  207. package/test/Controller.spec.ts +44 -0
  208. package/test/MessageList.spec.ts +1 -1
  209. package/test/Model/DataModel.spec.ts +0 -141
  210. package/test/Scope/DynamicScopeData.spec.ts +141 -0
  211. package/test/Scope.spec.ts +13 -1
  212. package/test/Tag/TagList.spec.ts +1 -1
  213. package/dist/Model/Collection.d.ts +0 -5
  214. package/dist/Model/Collection.js.map +0 -1
  215. package/dist/Model/DataModel.d.ts +0 -6
  216. package/dist/Model/DataModel.js.map +0 -1
  217. package/dist/Model/ModelAbstract.d.ts +0 -20
  218. package/dist/Model/ModelAbstract.js +0 -122
  219. package/dist/Model/ModelAbstract.js.map +0 -1
  220. package/dist/Model/fields/BooleanField.d.ts +0 -5
  221. package/dist/Model/fields/BooleanField.js +0 -43
  222. package/dist/Model/fields/BooleanField.js.map +0 -1
  223. package/dist/Model/fields/EmailField.d.ts +0 -5
  224. package/dist/Model/fields/EmailField.js.map +0 -1
  225. package/dist/Model/fields/Field.d.ts +0 -13
  226. package/dist/Model/fields/Field.js +0 -79
  227. package/dist/Model/fields/Field.js.map +0 -1
  228. package/dist/Model/fields/FloatField.d.ts +0 -5
  229. package/dist/Model/fields/FloatField.js +0 -47
  230. package/dist/Model/fields/FloatField.js.map +0 -1
  231. package/dist/Model/fields/PositiveNumberField.d.ts +0 -5
  232. package/dist/Model/fields/PositiveNumberField.js +0 -51
  233. package/dist/Model/fields/PositiveNumberField.js.map +0 -1
  234. package/dist/Model/fields/StringField.d.ts +0 -5
  235. package/dist/Model/fields/StringField.js.map +0 -1
  236. package/src/Model/Collection.ts +0 -13
  237. package/src/Model/ModelAbstract.ts +0 -114
  238. package/src/Model/fields/BooleanField.ts +0 -16
  239. package/src/Model/fields/EmailField.ts +0 -12
  240. package/src/Model/fields/Field.ts +0 -65
  241. package/src/Model/fields/FloatField.ts +0 -22
  242. package/src/Model/fields/PositiveNumberField.ts +0 -24
  243. package/src/Model/fields/StringField.ts +0 -16
  244. package/test/Model.spec.ts +0 -306
package/src/Scope.ts CHANGED
@@ -1,162 +1,15 @@
1
- import {Registry} from "./Registry";
2
- import {DOM} from "./DOM";
3
- import {EventDispatcher, EventDispatcherCallback} from "./EventDispatcher";
4
- import {DataModel} from "./Model/DataModel";
5
- import {Model} from "./Model";
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: DataModel;
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 DataModel({});
170
- this._keys = [];
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[key] === undefined)
231
- this.data.createField(key);
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 [...this._keys];
89
+ return this.data.keys;
264
90
  }
265
91
 
266
92
  has(key: string): boolean {
267
- return this._keys.indexOf(key) > -1;
93
+ return this.data.hasProperty(key);
268
94
  }
269
95
 
270
96
  setType(key: string, type: string) {
271
- this.types[key] = type;
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
- return this.types[key] || ScopeVariableType.String;
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._keys) {
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 Model) {
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.bind = this.on.bind(this);
204
+ this.wrapped.on = this.on.bind(this);
371
205
  this.wrapped.once = this.once.bind(this);
372
- this.wrapped.unbind = this.off.bind(this);
206
+ this.wrapped.off = this.off.bind(this);
373
207
  }
374
208
 
375
209
  public unwrap(): void {
@@ -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: T): void;
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: T): IPromise<T> {
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
- next() {
33
- return this.map(e => e.element.nextElementSibling).filter(e => e != null)
32
+ get first(): DOMObject {
33
+ return this[0];
34
34
  }
35
35
 
36
- prev() {
37
- return this.map(e => e.element.previousElementSibling).filter(e => e != null)
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
+ }
@@ -1,7 +1,8 @@
1
- import {Scope, ScopeReference} from "../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, ScopeReference} from "../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 {
@@ -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";
@@ -1,6 +1,7 @@
1
1
  import {Registry} from "../Registry";
2
2
  import {Attribute} from "../Attribute";
3
- import {Scope, ScopeReference} from "../Scope";
3
+ import {Scope} from "../Scope";
4
+ import {ScopeReference} from "../Scope/ScopeReference";
4
5
 
5
6
 
6
7
  @Registry.attribute('vsn-radio')
@@ -1,6 +1,6 @@
1
1
  import {Attribute} from "../Attribute";
2
2
  import {Tree} from "../AST";
3
- import {ScopeReference} from "../Scope";
3
+ import {ScopeReference} from "../Scope/ScopeReference";
4
4
  import {Registry} from "../Registry";
5
5
 
6
6
  @Registry.attribute('vsn-scope-change')
@@ -1,6 +1,7 @@
1
- import {Scope, ScopeReference} from "../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 {
@@ -1,6 +1,7 @@
1
1
  import {Registry} from "../Registry";
2
2
  import {Attribute} from "../Attribute";
3
- import {Scope, ScopeReference} from "../Scope";
3
+ import {Scope} from "../Scope";
4
+ import {ScopeReference} from "../Scope/ScopeReference";
4
5
 
5
6
 
6
7
  @Registry.attribute('vsn-styles')
@@ -1,5 +1,5 @@
1
1
  import {Attribute} from "../Attribute";
2
- import {ScopeReference} from "../Scope";
2
+ import {ScopeReference} from "../Scope/ScopeReference";
3
3
  import {Registry} from "../Registry";
4
4
 
5
5
  @Registry.attribute('vsn-type')
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 {DataModel} from "./Model/DataModel";
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('DataModel', DataModel);
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 {WrappedArray, Scope, ScopeReference} from './Scope';
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, WrappedArray} from "../src/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
+ });
@@ -1,4 +1,4 @@
1
- import MessageList from "../src/MessageList";
1
+ import {MessageList} from "../src/MessageList";
2
2
 
3
3
  describe('MessageList', () => {
4
4
  it("should reset properly", () => {