vsn 0.1.44 → 0.1.45
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 +6 -2
- package/demo/markup.html +2 -0
- package/demo/vsn.js +1 -1
- package/demo/xhr.vsn +4 -0
- package/dist/AST/ArithmeticAssignmentNode.js +8 -1
- package/dist/AST/ArithmeticAssignmentNode.js.map +1 -1
- package/dist/AST/FunctionNode.d.ts +0 -0
- package/dist/AST/FunctionNode.js +1 -0
- package/dist/AST/FunctionNode.js.map +1 -0
- package/dist/AST/StringFormatNode.d.ts +18 -0
- package/dist/{attributes/ClickToggleClass.js → AST/StringFormatNode.js} +49 -49
- package/dist/AST/StringFormatNode.js.map +1 -0
- package/dist/AST/WASM/Context.d.ts +4 -0
- package/dist/AST/WASM/Context.js +18 -0
- package/dist/AST/WASM/Context.js.map +1 -0
- package/dist/AST/WASM/Function.d.ts +22 -0
- package/dist/AST/WASM/Function.js +110 -0
- package/dist/AST/WASM/Function.js.map +1 -0
- package/dist/AST/WASM/Memory.d.ts +12 -0
- package/dist/AST/WASM/Memory.js +22 -0
- package/dist/AST/WASM/Memory.js.map +1 -0
- package/dist/AST/WASM/Section.d.ts +5 -0
- package/dist/AST/WASM/Section.js +11 -0
- package/dist/AST/WASM/Section.js.map +1 -0
- package/dist/AST/WASM.d.ts +58 -0
- package/dist/AST/WASM.js +277 -0
- package/dist/AST/WASM.js.map +1 -0
- package/dist/AST/XHRNode.d.ts +15 -0
- package/dist/AST/XHRNode.js +146 -0
- package/dist/AST/XHRNode.js.map +1 -0
- package/dist/AST.d.ts +62 -55
- package/dist/AST.js +123 -83
- package/dist/AST.js.map +1 -1
- package/dist/DOM.js +39 -82
- package/dist/DOM.js.map +1 -1
- package/dist/Registry.d.ts +2 -0
- package/dist/Registry.js +13 -9
- package/dist/Registry.js.map +1 -1
- package/dist/Scope/ScopeDataAbstract.js +2 -2
- package/dist/Scope/ScopeDataAbstract.js.map +1 -1
- package/dist/Scope/properties/Property.d.ts +5 -6
- package/dist/Scope/properties/Property.js +17 -25
- package/dist/Scope/properties/Property.js.map +1 -1
- package/dist/Scope/properties/_imports.d.ts +1 -1
- package/dist/Scope/properties/_imports.js.map +1 -1
- package/dist/Tag.js +2 -11
- package/dist/Tag.js.map +1 -1
- package/dist/attributes/_imports.d.ts +0 -2
- package/dist/attributes/_imports.js +1 -5
- package/dist/attributes/_imports.js.map +1 -1
- package/dist/helpers/VisionHelper.d.ts +1 -0
- package/dist/helpers/VisionHelper.js +17 -0
- package/dist/helpers/VisionHelper.js.map +1 -1
- package/package.json +1 -1
- package/src/AST/ArithmeticAssignmentNode.ts +9 -2
- package/src/AST/FunctionNode.ts +0 -0
- package/src/AST/StringFormatNode.ts +43 -0
- package/src/AST/WASM/Context.ts +12 -0
- package/src/AST/WASM/Function.ts +67 -0
- package/src/AST/WASM/Memory.ts +21 -0
- package/src/AST/WASM/Section.ts +6 -0
- package/src/AST/WASM.ts +244 -0
- package/src/AST/XHRNode.ts +81 -0
- package/src/AST.ts +66 -31
- package/src/DOM.ts +4 -25
- package/src/Registry.ts +12 -9
- package/src/Scope/ScopeDataAbstract.ts +2 -2
- package/src/Scope/properties/Property.ts +17 -28
- package/src/Scope/properties/_imports.ts +1 -1
- package/src/Tag.ts +2 -9
- package/src/attributes/AddClassIf.ts +1 -1
- package/src/attributes/_imports.ts +0 -2
- package/src/helpers/VisionHelper.ts +13 -0
- package/test/AST/ArithmeticAssignmentNode.spec.ts +0 -2
- package/test/AST/StringFormatNode.spec.ts +12 -0
- package/test/AST/WASM.spec.ts +63 -0
- package/test/AST/XHRNode.spec.ts +10 -0
- package/test/Scope/ScopeData.spec.ts +5 -5
- package/dist/attributes/ClickRemoveClass.d.ts +0 -8
- package/dist/attributes/ClickRemoveClass.js +0 -114
- package/dist/attributes/ClickRemoveClass.js.map +0 -1
- package/dist/attributes/ClickToggleClass.d.ts +0 -8
- package/dist/attributes/ClickToggleClass.js.map +0 -1
- package/src/attributes/ClickRemoveClass.ts +0 -30
- package/src/attributes/ClickToggleClass.ts +0 -30
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {Node} from "./Node";
|
|
2
|
+
import {Token, TokenType, Tree, TreeNode} from "../AST";
|
|
3
|
+
import {Scope} from "../Scope";
|
|
4
|
+
import {DOM} from "../DOM";
|
|
5
|
+
import {Tag} from "../Tag";
|
|
6
|
+
import {ScopeDataAbstract} from "../Scope/ScopeDataAbstract";
|
|
7
|
+
|
|
8
|
+
export class XHRNode extends Node implements TreeNode {
|
|
9
|
+
constructor(
|
|
10
|
+
public readonly left: Node | null,
|
|
11
|
+
public readonly requestType: TokenType,
|
|
12
|
+
public readonly url: Node
|
|
13
|
+
) {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public getChildNodes(): Node[] {
|
|
18
|
+
const nodes = [this.url];
|
|
19
|
+
if (this.left)
|
|
20
|
+
nodes.push(this.left);
|
|
21
|
+
return nodes;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async evaluate(scope: Scope, dom: DOM, tag?: Tag) {
|
|
25
|
+
const url = await this.url.evaluate(scope, dom, tag);
|
|
26
|
+
let method: string;
|
|
27
|
+
let data = this.left ? await this.left.evaluate(scope, dom, tag) : {};
|
|
28
|
+
|
|
29
|
+
if (data instanceof Scope)
|
|
30
|
+
data = data.data;
|
|
31
|
+
|
|
32
|
+
if (data instanceof ScopeDataAbstract)
|
|
33
|
+
data = data.getData();
|
|
34
|
+
|
|
35
|
+
switch (this.requestType) {
|
|
36
|
+
case TokenType.XHR_POST:
|
|
37
|
+
method = "POST";
|
|
38
|
+
break;
|
|
39
|
+
case TokenType.XHR_PUT:
|
|
40
|
+
method = "PUT";
|
|
41
|
+
break;
|
|
42
|
+
case TokenType.XHR_DELETE:
|
|
43
|
+
method = "DELETE";
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
method = "GET";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let request = {
|
|
50
|
+
method: method
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (request.method === 'GET') {
|
|
54
|
+
|
|
55
|
+
} else {
|
|
56
|
+
request['body'] = (typeof data === "string") ? data : JSON.stringify(data);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const response = await fetch(url, request);
|
|
60
|
+
const contentType = response.headers.get('content-type');
|
|
61
|
+
if (contentType && contentType.includes('application/json')) {
|
|
62
|
+
return await response.json();
|
|
63
|
+
}
|
|
64
|
+
return await response.text();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static parse(node: Node, token: Token, tokens: Token[]): XHRNode {
|
|
68
|
+
tokens.splice(0, 1); // Consume request type
|
|
69
|
+
const url = Tree.processTokens(Tree.getNextStatementTokens(tokens, false, false, false));
|
|
70
|
+
return new XHRNode(node, token.type, url);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public static match(tokens: Token[]) {
|
|
74
|
+
return [
|
|
75
|
+
TokenType.XHR_POST,
|
|
76
|
+
TokenType.XHR_PUT,
|
|
77
|
+
TokenType.XHR_GET,
|
|
78
|
+
TokenType.XHR_DELETE,
|
|
79
|
+
].indexOf(tokens[0].type) > -1;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/AST.ts
CHANGED
|
@@ -24,6 +24,8 @@ import {ArithmeticAssignmentNode} from "./AST/ArithmeticAssignmentNode";
|
|
|
24
24
|
import {UnitLiteralNode} from "./AST/UnitLiteralNode";
|
|
25
25
|
import {BooleanLiteralNode} from "./AST/BooleanLiteralNode";
|
|
26
26
|
import {NotNode} from "./AST/NotNode";
|
|
27
|
+
import {XHRNode} from "./AST/XHRNode";
|
|
28
|
+
import {StringFormatNode} from "./AST/StringFormatNode";
|
|
27
29
|
|
|
28
30
|
function lower(str: string): string {
|
|
29
31
|
return str ? str.toLowerCase() : null;
|
|
@@ -47,6 +49,7 @@ export enum BlockType {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export enum TokenType {
|
|
52
|
+
NULL,
|
|
50
53
|
WHITESPACE,
|
|
51
54
|
TYPE_INT,
|
|
52
55
|
TYPE_UINT,
|
|
@@ -71,7 +74,8 @@ export enum TokenType {
|
|
|
71
74
|
PERIOD,
|
|
72
75
|
COMMA,
|
|
73
76
|
COLON,
|
|
74
|
-
|
|
77
|
+
SEMICOLON,
|
|
78
|
+
STRING_FORMAT,
|
|
75
79
|
STRING_LITERAL,
|
|
76
80
|
NUMBER_LITERAL,
|
|
77
81
|
BOOLEAN_LITERAL,
|
|
@@ -101,6 +105,10 @@ export enum TokenType {
|
|
|
101
105
|
ELEMENT_STYLE,
|
|
102
106
|
ELEMENT_QUERY,
|
|
103
107
|
UNIT,
|
|
108
|
+
XHR_GET,
|
|
109
|
+
XHR_POST,
|
|
110
|
+
XHR_PUT,
|
|
111
|
+
XHR_DELETE,
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
const TOKEN_PATTERNS: TokenPattern[] = [
|
|
@@ -108,6 +116,22 @@ const TOKEN_PATTERNS: TokenPattern[] = [
|
|
|
108
116
|
type: TokenType.WHITESPACE,
|
|
109
117
|
pattern: /^[\s\n\r]+/
|
|
110
118
|
},
|
|
119
|
+
{
|
|
120
|
+
type: TokenType.XHR_POST,
|
|
121
|
+
pattern: /^>>/
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: TokenType.XHR_PUT,
|
|
125
|
+
pattern: /^<>/
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: TokenType.XHR_GET,
|
|
129
|
+
pattern: /^<</
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: TokenType.XHR_DELETE,
|
|
133
|
+
pattern: /^></
|
|
134
|
+
},
|
|
111
135
|
{
|
|
112
136
|
type: TokenType.TYPE_INT,
|
|
113
137
|
pattern: /^int+/
|
|
@@ -257,9 +281,13 @@ const TOKEN_PATTERNS: TokenPattern[] = [
|
|
|
257
281
|
pattern: /^:/
|
|
258
282
|
},
|
|
259
283
|
{
|
|
260
|
-
type: TokenType.
|
|
284
|
+
type: TokenType.SEMICOLON,
|
|
261
285
|
pattern: /^;/
|
|
262
286
|
},
|
|
287
|
+
{
|
|
288
|
+
type: TokenType.STRING_FORMAT,
|
|
289
|
+
pattern: /^`([^`]*)`/
|
|
290
|
+
},
|
|
263
291
|
{
|
|
264
292
|
type: TokenType.STRING_LITERAL,
|
|
265
293
|
pattern: /^"([^"]*)"/
|
|
@@ -341,36 +369,38 @@ export const AttributableNodes = [
|
|
|
341
369
|
|
|
342
370
|
export class Tree {
|
|
343
371
|
protected static cache: { [key: string]: Node } = {};
|
|
344
|
-
protected
|
|
372
|
+
protected _root: Node;
|
|
345
373
|
|
|
346
374
|
constructor(
|
|
347
375
|
public readonly code: string
|
|
348
376
|
) {
|
|
349
377
|
if (Tree.cache[code]) {
|
|
350
|
-
this.
|
|
378
|
+
this._root = Tree.cache[code];
|
|
351
379
|
} else {
|
|
352
380
|
this.parse();
|
|
353
|
-
Tree.cache[code] = this.
|
|
381
|
+
Tree.cache[code] = this._root;
|
|
354
382
|
}
|
|
355
383
|
}
|
|
356
384
|
|
|
385
|
+
public get root(): Node { return this._root; }
|
|
386
|
+
|
|
357
387
|
public parse() {
|
|
358
388
|
const tokens = Tree.tokenize(this.code);
|
|
359
|
-
this.
|
|
389
|
+
this._root = Tree.processTokens(tokens);
|
|
360
390
|
}
|
|
361
391
|
|
|
362
392
|
async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
363
|
-
return await this.
|
|
393
|
+
return await this._root.evaluate(scope, dom, tag);
|
|
364
394
|
}
|
|
365
395
|
|
|
366
396
|
async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
367
|
-
if (!this.
|
|
397
|
+
if (!this._root.isPreparationRequired())
|
|
368
398
|
return;
|
|
369
|
-
return await this.
|
|
399
|
+
return await this._root.prepare(scope, dom, tag);
|
|
370
400
|
}
|
|
371
401
|
|
|
372
402
|
async bindToScopeChanges(scope, fnc, dom: DOM, tag: Tag = null) {
|
|
373
|
-
for (const node of this.
|
|
403
|
+
for (const node of this._root.findChildrenByTypes<ScopeMemberNode | ElementAttributeNode>([RootScopeMemberNode, ScopeMemberNode, ElementAttributeNode], 'ScopeMemberNodes')) {
|
|
374
404
|
let _scope: Scope = scope;
|
|
375
405
|
if (node instanceof ScopeMemberNode)
|
|
376
406
|
_scope = await node.scope.evaluate(scope, dom);
|
|
@@ -431,14 +461,16 @@ export class Tree {
|
|
|
431
461
|
if (count > 1000) break; // Limit to 1000 iterations while in development
|
|
432
462
|
|
|
433
463
|
if (tokens[0].type === TokenType.RETURN)
|
|
434
|
-
tokens.
|
|
464
|
+
tokens.shift()
|
|
435
465
|
|
|
436
466
|
const token: Token = tokens[0];
|
|
437
467
|
if (token.type === TokenType.NAME) {
|
|
438
468
|
node = new RootScopeMemberNode<string>(
|
|
439
469
|
new LiteralNode<string>(token.value)
|
|
440
470
|
);
|
|
441
|
-
tokens.
|
|
471
|
+
tokens.shift()
|
|
472
|
+
} else if (XHRNode.match(tokens)) {
|
|
473
|
+
node = XHRNode.parse(node, tokens[0], tokens);
|
|
442
474
|
} else if (token.type === TokenType.IF) {
|
|
443
475
|
node = IfStatementNode.parse(node, token, tokens);
|
|
444
476
|
blockNodes.push(node);
|
|
@@ -447,18 +479,20 @@ export class Tree {
|
|
|
447
479
|
node = ForStatementNode.parse(node, token, tokens);
|
|
448
480
|
blockNodes.push(node);
|
|
449
481
|
node = null;
|
|
482
|
+
} else if (StringFormatNode.match(tokens)) {
|
|
483
|
+
node = StringFormatNode.parse(node, tokens[0], tokens);
|
|
450
484
|
} else if (token.type === TokenType.STRING_LITERAL) {
|
|
451
485
|
node = new LiteralNode(token.value);
|
|
452
|
-
tokens.
|
|
486
|
+
tokens.shift()
|
|
453
487
|
} else if (token.type === TokenType.NUMBER_LITERAL) {
|
|
454
488
|
node = new NumberLiteralNode(token.value);
|
|
455
|
-
tokens.
|
|
489
|
+
tokens.shift()
|
|
456
490
|
} else if (tokens[0].type === TokenType.ELEMENT_REFERENCE) {
|
|
457
491
|
node = new ElementQueryNode(tokens[0].value, true);
|
|
458
|
-
tokens.
|
|
492
|
+
tokens.shift()
|
|
459
493
|
} else if (tokens[0].type === TokenType.ELEMENT_QUERY) {
|
|
460
494
|
node = new ElementQueryNode(tokens[0].value);
|
|
461
|
-
tokens.
|
|
495
|
+
tokens.shift()
|
|
462
496
|
} else if (tokens[0].type === TokenType.L_BRACKET) {
|
|
463
497
|
if (node) {
|
|
464
498
|
node = IndexNode.parse(node, token, tokens);
|
|
@@ -469,10 +503,10 @@ export class Tree {
|
|
|
469
503
|
node = ObjectNode.parse(node, token, tokens);
|
|
470
504
|
} else if (tokens[0].type === TokenType.ELEMENT_ATTRIBUTE) {
|
|
471
505
|
node = new ElementAttributeNode(node as any, tokens[0].value);
|
|
472
|
-
tokens.
|
|
506
|
+
tokens.shift()
|
|
473
507
|
} else if (tokens[0].type === TokenType.ELEMENT_STYLE) {
|
|
474
508
|
node = new ElementStyleNode(node as any, tokens[0].value);
|
|
475
|
-
tokens.
|
|
509
|
+
tokens.shift()
|
|
476
510
|
} else if (node !== null && token.type === TokenType.PERIOD && tokens[1].type === TokenType.NAME) {
|
|
477
511
|
node = new ScopeMemberNode(
|
|
478
512
|
node,
|
|
@@ -493,12 +527,12 @@ export class Tree {
|
|
|
493
527
|
} else {
|
|
494
528
|
node = new BlockNode(nodes);
|
|
495
529
|
}
|
|
496
|
-
} else if (tokens[0].type === TokenType.
|
|
530
|
+
} else if (tokens[0].type === TokenType.SEMICOLON) {
|
|
497
531
|
if (node) {
|
|
498
532
|
blockNodes.push(node);
|
|
499
533
|
}
|
|
500
534
|
node = null;
|
|
501
|
-
tokens.
|
|
535
|
+
tokens.shift()
|
|
502
536
|
} else if (InNode.match(tokens)) {
|
|
503
537
|
node = InNode.parse(node, token, tokens);
|
|
504
538
|
} else if (ComparisonNode.match(tokens)) {
|
|
@@ -508,16 +542,16 @@ export class Tree {
|
|
|
508
542
|
} else if (ArithmeticAssignmentNode.match(tokens)) {
|
|
509
543
|
node = ArithmeticAssignmentNode.parse(node, token, tokens);
|
|
510
544
|
} else if (tokens[0].type === TokenType.WHITESPACE) {
|
|
511
|
-
tokens.
|
|
545
|
+
tokens.shift()
|
|
512
546
|
} else if (tokens[0].type === TokenType.UNIT) {
|
|
513
547
|
node = new UnitLiteralNode(tokens[0].value);
|
|
514
|
-
tokens.
|
|
548
|
+
tokens.shift()
|
|
515
549
|
} else if (tokens[0].type === TokenType.BOOLEAN_LITERAL) {
|
|
516
550
|
node = new BooleanLiteralNode(tokens[0].value);
|
|
517
|
-
tokens.
|
|
551
|
+
tokens.shift()
|
|
518
552
|
} else if (tokens[0].type === TokenType.NULL_LITERAL) {
|
|
519
553
|
node = new LiteralNode(null);
|
|
520
|
-
tokens.
|
|
554
|
+
tokens.shift()
|
|
521
555
|
} else if (tokens[0].type === TokenType.EXCLAMATION_POINT) {
|
|
522
556
|
node = NotNode.parse(node, tokens[0], tokens);
|
|
523
557
|
} else {
|
|
@@ -583,7 +617,7 @@ export class Tree {
|
|
|
583
617
|
break;
|
|
584
618
|
default:
|
|
585
619
|
open = null;
|
|
586
|
-
close = TokenType.
|
|
620
|
+
close = TokenType.SEMICOLON;
|
|
587
621
|
openCharacter = null;
|
|
588
622
|
closeCharacter = ';';
|
|
589
623
|
break;
|
|
@@ -603,7 +637,7 @@ export class Tree {
|
|
|
603
637
|
|
|
604
638
|
// Consume opening block token
|
|
605
639
|
if (consumeOpeningToken && tokens[0].type === blockInfo.open) {
|
|
606
|
-
tokens.
|
|
640
|
+
tokens.shift()
|
|
607
641
|
}
|
|
608
642
|
|
|
609
643
|
return Tree.getTokensUntil(tokens, blockInfo.close, consumeClosingToken, includeClosingToken);
|
|
@@ -632,7 +666,7 @@ export class Tree {
|
|
|
632
666
|
}
|
|
633
667
|
|
|
634
668
|
// Consume token
|
|
635
|
-
tokens.
|
|
669
|
+
tokens.shift()
|
|
636
670
|
i--;
|
|
637
671
|
if (openBlocks === 0) {
|
|
638
672
|
if (arg.length > 0)
|
|
@@ -644,7 +678,7 @@ export class Tree {
|
|
|
644
678
|
throw Error(`Invalid Syntax, missing ${blockInfo.closeCharacter}`);
|
|
645
679
|
}
|
|
646
680
|
|
|
647
|
-
public static getTokensUntil(tokens: Token[], terminator: TokenType = TokenType.
|
|
681
|
+
public static getTokensUntil(tokens: Token[], terminator: TokenType = TokenType.SEMICOLON, consumeTerminator: boolean = true, includeTerminator: boolean = false, validIfTerminatorNotFound: boolean = false, blockInfo: IBlockInfo = null): Token[] {
|
|
648
682
|
const statementTokens: Token[] = [];
|
|
649
683
|
blockInfo = blockInfo || Tree.getBlockInfo(tokens);
|
|
650
684
|
|
|
@@ -681,8 +715,9 @@ export class Tree {
|
|
|
681
715
|
if (includeTerminator)
|
|
682
716
|
statementTokens.push(token);
|
|
683
717
|
|
|
684
|
-
if (
|
|
685
|
-
|
|
718
|
+
//if (consumeTerminator && token.type !== TokenType.SEMICOLON)
|
|
719
|
+
if ((includeTerminator || consumeTerminator) && token.type !== TokenType.SEMICOLON)
|
|
720
|
+
tokens.shift() // Consume end of block
|
|
686
721
|
break;
|
|
687
722
|
} else if (token.type === terminator && (openParens > 0 || openBraces > 0 || openBrackets > 0)) {
|
|
688
723
|
} else {
|
|
@@ -693,7 +728,7 @@ export class Tree {
|
|
|
693
728
|
}
|
|
694
729
|
|
|
695
730
|
statementTokens.push(token);
|
|
696
|
-
tokens.
|
|
731
|
+
tokens.shift() // Consume part of statement
|
|
697
732
|
i--;
|
|
698
733
|
}
|
|
699
734
|
return statementTokens;
|
package/src/DOM.ts
CHANGED
|
@@ -3,8 +3,6 @@ import {ElementHelper} from "./helpers/ElementHelper";
|
|
|
3
3
|
import {Configuration} from "./Configuration";
|
|
4
4
|
import {Tree} from "./AST";
|
|
5
5
|
import {TagList} from "./Tag/List";
|
|
6
|
-
import {benchmarkEnd, benchmarkStart} from "./Bencmark";
|
|
7
|
-
import {VisionHelper} from "./helpers/VisionHelper";
|
|
8
6
|
import {WrappedWindow} from "./DOM/WrappedWindow";
|
|
9
7
|
import {WrappedDocument} from "./DOM/WrappedDocument";
|
|
10
8
|
import {Scope} from "./Scope";
|
|
@@ -50,6 +48,8 @@ export class DOM extends EventDispatcher {
|
|
|
50
48
|
return new TagList(this.window);
|
|
51
49
|
case 'document':
|
|
52
50
|
return new TagList(this.document);
|
|
51
|
+
case 'body':
|
|
52
|
+
return new TagList(this.root);
|
|
53
53
|
default:
|
|
54
54
|
const nodes = this.querySelectorAll(selector, tag);
|
|
55
55
|
return await this.getTagsForElements(Array.from(nodes) as Element[], create);
|
|
@@ -139,7 +139,6 @@ export class DOM extends EventDispatcher {
|
|
|
139
139
|
const toBuild: HTMLElement[] = [];
|
|
140
140
|
const toSkip: HTMLElement[] = [];
|
|
141
141
|
|
|
142
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM','findElements');
|
|
143
142
|
if (ele && ele.querySelectorAll) {
|
|
144
143
|
for (const element of (Array.from(ele.querySelectorAll(`*`)) as HTMLElement[])) { // Don't build items more than once
|
|
145
144
|
if (!ElementHelper.hasVisionAttribute(element)) continue;
|
|
@@ -152,9 +151,7 @@ export class DOM extends EventDispatcher {
|
|
|
152
151
|
toBuild.push(element);
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'findElements');
|
|
156
154
|
|
|
157
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'buildTags');
|
|
158
155
|
for (const element of toBuild) {
|
|
159
156
|
if (allElements.indexOf(element) > -1) continue;
|
|
160
157
|
const tag: Tag = new Tag(element, this);
|
|
@@ -162,23 +159,17 @@ export class DOM extends EventDispatcher {
|
|
|
162
159
|
newTags.push(tag);
|
|
163
160
|
allElements.push(element as HTMLElement);
|
|
164
161
|
}
|
|
165
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'buildTags');
|
|
166
162
|
|
|
167
163
|
if (isRoot)
|
|
168
164
|
this._root = await this.getTagForElement(document.body);
|
|
169
165
|
|
|
170
166
|
// Configure, setup & execute attributes
|
|
171
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM','buildTagAttributes');
|
|
172
167
|
for (const tag of newTags)
|
|
173
168
|
await tag.buildAttributes();
|
|
174
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM','buildTagAttributes');
|
|
175
169
|
|
|
176
|
-
if (VisionHelper.inDevelopment) benchmarkStart('DOM', 'compileAttributes');
|
|
177
170
|
for (const tag of newTags)
|
|
178
171
|
await tag.compileAttributes();
|
|
179
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM','compileAttributes');
|
|
180
172
|
|
|
181
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'buildTree');
|
|
182
173
|
for (const tag of newTags) {
|
|
183
174
|
if (tag === this.root)
|
|
184
175
|
continue;
|
|
@@ -198,39 +189,27 @@ export class DOM extends EventDispatcher {
|
|
|
198
189
|
if (!foundParent)
|
|
199
190
|
console.error('Could not find parent for ', tag);
|
|
200
191
|
}
|
|
201
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'buildTree');
|
|
202
192
|
|
|
203
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'setupAttributes');
|
|
204
193
|
for (const tag of newTags)
|
|
205
194
|
await tag.setupAttributes();
|
|
206
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'setupAttributes');
|
|
207
195
|
|
|
208
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'extractAttributes');
|
|
209
196
|
for (const tag of newTags)
|
|
210
197
|
await tag.extractAttributes();
|
|
211
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'extractAttributes');
|
|
212
198
|
|
|
213
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'connectAttributes');
|
|
214
199
|
for (const tag of newTags)
|
|
215
200
|
await tag.connectAttributes();
|
|
216
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'connectAttributes');
|
|
217
201
|
|
|
218
|
-
if (VisionHelper.doBenchmark) benchmarkStart('DOM', 'finalizeTags');
|
|
219
202
|
for (const tag of newTags) {
|
|
220
203
|
await tag.finalize();
|
|
221
204
|
this.queued.splice(this.queued.indexOf(tag.element), 1);
|
|
222
205
|
}
|
|
223
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'finalizeTags');
|
|
224
206
|
|
|
225
|
-
|
|
226
|
-
for (const tag of newTags)
|
|
227
|
-
this.observer.observe(tag.element, {
|
|
207
|
+
newTags.forEach(tag => this.observer.observe(tag.element, {
|
|
228
208
|
attributes: true,
|
|
229
209
|
characterData: true,
|
|
230
210
|
childList: true,
|
|
231
211
|
subtree: true
|
|
232
|
-
});
|
|
233
|
-
if (VisionHelper.doBenchmark) benchmarkEnd('DOM', 'observeTags');
|
|
212
|
+
}));
|
|
234
213
|
|
|
235
214
|
this.dispatch('built');
|
|
236
215
|
}
|
package/src/Registry.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {VisionHelper} from "./helpers/VisionHelper";
|
|
2
1
|
import {EventDispatcher} from "./EventDispatcher";
|
|
3
2
|
import {IDeferred, IPromise, SimplePromise} from "./SimplePromise";
|
|
4
3
|
|
|
@@ -53,6 +52,7 @@ export class RegistryStore extends EventDispatcher {
|
|
|
53
52
|
|
|
54
53
|
export class Registry extends EventDispatcher {
|
|
55
54
|
protected static _instance: Registry;
|
|
55
|
+
public readonly components: RegistryStore;
|
|
56
56
|
public readonly classes: RegistryStore;
|
|
57
57
|
public readonly models: RegistryStore;
|
|
58
58
|
public readonly templates: RegistryStore;
|
|
@@ -63,15 +63,18 @@ export class Registry extends EventDispatcher {
|
|
|
63
63
|
|
|
64
64
|
constructor() {
|
|
65
65
|
super();
|
|
66
|
+
this.components = new RegistryStore();
|
|
67
|
+
this.classes = new RegistryStore();
|
|
68
|
+
this.models = new RegistryStore();
|
|
69
|
+
this.templates = new RegistryStore();
|
|
70
|
+
this.types = new RegistryStore();
|
|
71
|
+
this.validators = new RegistryStore();
|
|
72
|
+
this.formats = new RegistryStore();
|
|
73
|
+
this.attributes = new RegistryStore();
|
|
74
|
+
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.models = new RegistryStore(w['$models'] || {});
|
|
70
|
-
this.templates = new RegistryStore(w['$templates'] || {});
|
|
71
|
-
this.types = new RegistryStore(w['$types'] || {});
|
|
72
|
-
this.validators = new RegistryStore(w['$validators'] || {});
|
|
73
|
-
this.formats = new RegistryStore(w['$formats'] || {});
|
|
74
|
-
this.attributes = new RegistryStore(w['$attributes'] || {});
|
|
76
|
+
public static component(key: string = null, setup = null) {
|
|
77
|
+
return register('components', key, setup);
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
public static class(key: string = null, setup = null) {
|
|
@@ -65,7 +65,7 @@ export class ScopeDataAbstract extends EventDispatcher {
|
|
|
65
65
|
const keys = [];
|
|
66
66
|
for (const key of this.keys) {
|
|
67
67
|
const property = this.getProperty(key);
|
|
68
|
-
if (property.
|
|
68
|
+
if (property.hasLabels(tags)) {
|
|
69
69
|
keys.push(key);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -86,7 +86,7 @@ export class ScopeDataAbstract extends EventDispatcher {
|
|
|
86
86
|
propLoop: for (const key of this.getProperties()) {
|
|
87
87
|
const property = this['__'+key];
|
|
88
88
|
for (const tag of tags) {
|
|
89
|
-
if (!property.
|
|
89
|
+
if (!property.hasLabel(tag))
|
|
90
90
|
continue propLoop;
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -30,7 +30,7 @@ export interface IPropertyConfig {
|
|
|
30
30
|
type?: string;
|
|
31
31
|
default?: any;
|
|
32
32
|
validators?: TValidator[];
|
|
33
|
-
|
|
33
|
+
labels?: string[];
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export class Property<T = any> extends EventDispatcher {
|
|
@@ -41,8 +41,8 @@ export class Property<T = any> extends EventDispatcher {
|
|
|
41
41
|
constructor(value?: T, config?: IPropertyConfig) {
|
|
42
42
|
super();
|
|
43
43
|
this.config = config;
|
|
44
|
-
if (!this.config.
|
|
45
|
-
this.config.
|
|
44
|
+
if (!this.config.labels)
|
|
45
|
+
this.config.labels = [];
|
|
46
46
|
if (!this.config.validators)
|
|
47
47
|
this.config.validators = [];
|
|
48
48
|
this.type = config.type || 'any';
|
|
@@ -109,43 +109,32 @@ export class Property<T = any> extends EventDispatcher {
|
|
|
109
109
|
this.config.validators.push(validator);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
if
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const index = this.config.validators.indexOf(validator);
|
|
118
|
-
if (index != -1)
|
|
119
|
-
this.config.validators.splice(index, 1);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
addTag(tag: string) {
|
|
124
|
-
if(this.config.tags == undefined) {
|
|
125
|
-
this.config.tags = [];
|
|
112
|
+
addLabel(label: string) {
|
|
113
|
+
if(this.config.labels == undefined) {
|
|
114
|
+
this.config.labels = [];
|
|
126
115
|
}
|
|
127
|
-
if(this.config.
|
|
128
|
-
this.config.
|
|
116
|
+
if(this.config.labels.indexOf(label) == -1) {
|
|
117
|
+
this.config.labels.push(label);
|
|
129
118
|
}
|
|
130
119
|
}
|
|
131
120
|
|
|
132
|
-
|
|
133
|
-
if(this.config.
|
|
121
|
+
removeLabel(label: string) {
|
|
122
|
+
if(this.config.labels == undefined) {
|
|
134
123
|
return;
|
|
135
124
|
}
|
|
136
|
-
const index = this.config.
|
|
125
|
+
const index = this.config.labels.indexOf(label);
|
|
137
126
|
if(index != -1) {
|
|
138
|
-
this.config.
|
|
127
|
+
this.config.labels.splice(index, 1);
|
|
139
128
|
}
|
|
140
129
|
}
|
|
141
130
|
|
|
142
|
-
|
|
143
|
-
return this.config.
|
|
131
|
+
hasLabel(label: string) {
|
|
132
|
+
return this.config.labels.indexOf(label) !== -1;
|
|
144
133
|
}
|
|
145
134
|
|
|
146
|
-
|
|
147
|
-
for(const
|
|
148
|
-
if(!this.
|
|
135
|
+
hasLabels(labels: string[]) {
|
|
136
|
+
for(const label of labels) {
|
|
137
|
+
if(!this.hasLabel(label)) {
|
|
149
138
|
return false;
|
|
150
139
|
}
|
|
151
140
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {Property, property} from './Property';
|
|
1
|
+
export {Property, property, IPropertyConfig} from './Property';
|
|
2
2
|
export {ArrayProperty} from './ArrayProperty';
|
package/src/Tag.ts
CHANGED
|
@@ -72,12 +72,7 @@ export class Tag extends DOMObject {
|
|
|
72
72
|
if (this._nonDeferredAttributes.length > 0)
|
|
73
73
|
return this._nonDeferredAttributes;
|
|
74
74
|
|
|
75
|
-
const attrs: Attribute[] =
|
|
76
|
-
for (const attribute of this.attributes) {
|
|
77
|
-
if (attribute.state === AttributeState.Deferred)
|
|
78
|
-
continue;
|
|
79
|
-
attrs.push(attribute);
|
|
80
|
-
}
|
|
75
|
+
const attrs: Attribute[] = this.attributes.filter(attr => attr.state !== AttributeState.Deferred);
|
|
81
76
|
this._nonDeferredAttributes = attrs;
|
|
82
77
|
return attrs;
|
|
83
78
|
}
|
|
@@ -119,9 +114,7 @@ export class Tag extends DOMObject {
|
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
mutate(mutation: MutationRecord): void {
|
|
122
|
-
|
|
123
|
-
attr.mutate(mutation);
|
|
124
|
-
}
|
|
117
|
+
this.attributes.map(attr => attr.mutate(mutation));
|
|
125
118
|
this.dispatch('mutate', mutation);
|
|
126
119
|
}
|
|
127
120
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export {AddClassIf} from "./AddClassIf";
|
|
2
2
|
export {Bind} from "./Bind";
|
|
3
|
-
export {ClickRemoveClass} from "./ClickRemoveClass";
|
|
4
|
-
export {ClickToggleClass} from "./ClickToggleClass";
|
|
5
3
|
export {ControllerAttribute} from "./ControllerAttribute";
|
|
6
4
|
export {DisableIf} from "./DisableIf";
|
|
7
5
|
export {Exec} from "./Exec";
|
|
@@ -47,4 +47,17 @@ export class VisionHelper {
|
|
|
47
47
|
setTimeout(callback, timeout);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
public static get wasmSupport(): boolean {
|
|
52
|
+
try {
|
|
53
|
+
if (typeof WebAssembly === "object"
|
|
54
|
+
&& typeof WebAssembly.instantiate === "function") {
|
|
55
|
+
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
|
|
56
|
+
if (module instanceof WebAssembly.Module)
|
|
57
|
+
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
|
|
58
|
+
}
|
|
59
|
+
} catch (e) {
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
50
63
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {Tree} from "../../src/AST";
|
|
2
|
+
import {Scope} from "../../src/Scope";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('StringFormatNode', () => {
|
|
6
|
+
it("should format simple format strings", async () => {
|
|
7
|
+
const tree = new Tree("`Hello ${name}`");
|
|
8
|
+
const scope = new Scope();
|
|
9
|
+
scope.set("name", "World");
|
|
10
|
+
expect(await tree.evaluate(scope, null, null)).toBe("Hello World");
|
|
11
|
+
});
|
|
12
|
+
});
|