vsn 0.1.57 → 0.1.60
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 +5 -2
- package/demo/vsn.js +2 -2
- package/demo/xhr.html +17 -0
- package/dist/AST/ArithmeticAssignmentNode.d.ts +2 -1
- package/dist/AST/ArithmeticAssignmentNode.js +20 -18
- package/dist/AST/ArithmeticAssignmentNode.js.map +1 -1
- package/dist/AST/FunctionCallNode.js +13 -8
- package/dist/AST/FunctionCallNode.js.map +1 -1
- package/dist/AST/FunctionNode.d.ts +7 -8
- package/dist/AST/FunctionNode.js +53 -9
- package/dist/AST/FunctionNode.js.map +1 -1
- package/dist/AST.d.ts +47 -46
- package/dist/AST.js +57 -46
- package/dist/AST.js.map +1 -1
- package/dist/Scope.d.ts +1 -0
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/Tag.js +3 -4
- package/dist/Tag.js.map +1 -1
- package/dist/attributes/Exec.d.ts +1 -0
- package/dist/attributes/Exec.js +8 -1
- package/dist/attributes/Exec.js.map +1 -1
- package/dist/attributes/RootAttribute.js +3 -0
- package/dist/attributes/RootAttribute.js.map +1 -1
- package/dist/attributes/ScriptAttribute.d.ts +4 -0
- package/dist/attributes/ScriptAttribute.js +45 -0
- package/dist/attributes/ScriptAttribute.js.map +1 -0
- package/dist/attributes/_imports.d.ts +1 -0
- package/dist/attributes/_imports.js +3 -1
- package/dist/attributes/_imports.js.map +1 -1
- package/dist/vsn.js +1 -1
- package/dist/vsn.min.js +2 -2
- package/package.json +1 -1
- package/src/AST/ArithmeticAssignmentNode.ts +19 -17
- package/src/AST/FunctionCallNode.ts +7 -1
- package/src/AST/FunctionNode.ts +30 -10
- package/src/AST.ts +10 -0
- package/src/Scope.ts +6 -0
- package/src/Tag.ts +3 -5
- package/src/attributes/Exec.ts +5 -1
- package/src/attributes/RootAttribute.ts +3 -0
- package/src/attributes/ScriptAttribute.ts +9 -0
- package/src/attributes/_imports.ts +1 -0
- package/src/vsn.ts +1 -1
- package/test/AST/FunctionNode.spec.ts +14 -0
- package/demo/xhr.vsn +0 -4
package/package.json
CHANGED
|
@@ -59,7 +59,7 @@ export class ArithmeticAssignmentNode extends Node implements TreeNode {
|
|
|
59
59
|
const values = [];
|
|
60
60
|
for (let localScope of scopes) {
|
|
61
61
|
if (localScope instanceof DOMObject) {
|
|
62
|
-
await this.handleDOMObject(name, dom, localScope, tag);
|
|
62
|
+
await this.handleDOMObject(name, dom, scope, localScope, tag);
|
|
63
63
|
} else {
|
|
64
64
|
if (localScope['$wrapped'] && localScope['$scope']) {
|
|
65
65
|
localScope = localScope['$scope'];
|
|
@@ -68,16 +68,7 @@ export class ArithmeticAssignmentNode extends Node implements TreeNode {
|
|
|
68
68
|
// We get the values from the passed scope, but set the value on the local scope
|
|
69
69
|
let left: number | Array<any> | string = await this.left.evaluate(scope, dom, tag);
|
|
70
70
|
let right: number | Array<any> | string = await this.right.evaluate(scope, dom, tag);
|
|
71
|
-
|
|
72
|
-
if (left instanceof Array) {
|
|
73
|
-
left = this.handleArray(name, left, right, localScope);
|
|
74
|
-
} else if ((left as any) instanceof UnitLiteral || right instanceof UnitLiteral) {
|
|
75
|
-
left = this.handleUnit(name, left, right, localScope);
|
|
76
|
-
} else if (Number.isFinite(left)) {
|
|
77
|
-
left = this.handleNumber(name, left, right, localScope);
|
|
78
|
-
} else {
|
|
79
|
-
left = this.handleString(name, left, right, localScope);
|
|
80
|
-
}
|
|
71
|
+
left = this.handle(name, left, right, localScope);
|
|
81
72
|
|
|
82
73
|
values.push(left);
|
|
83
74
|
}
|
|
@@ -85,6 +76,20 @@ export class ArithmeticAssignmentNode extends Node implements TreeNode {
|
|
|
85
76
|
return values.length > 1 ? values : values[0];
|
|
86
77
|
}
|
|
87
78
|
|
|
79
|
+
public handle(name, left, right, localScope) {
|
|
80
|
+
if (left instanceof Array) {
|
|
81
|
+
left = this.handleArray(name, left, right, localScope);
|
|
82
|
+
} else if ((left as any) instanceof UnitLiteral || right instanceof UnitLiteral) {
|
|
83
|
+
left = this.handleUnit(name, left, right, localScope);
|
|
84
|
+
} else if (Number.isFinite(left)) {
|
|
85
|
+
left = this.handleNumber(name, left, right, localScope);
|
|
86
|
+
} else {
|
|
87
|
+
left = this.handleString(name, left, right, localScope);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return left;
|
|
91
|
+
}
|
|
92
|
+
|
|
88
93
|
public handleNumber(key, left, right, scope) {
|
|
89
94
|
if (right !== null && !Number.isFinite(right))
|
|
90
95
|
right = parseFloat(`${right}`);
|
|
@@ -167,13 +172,10 @@ export class ArithmeticAssignmentNode extends Node implements TreeNode {
|
|
|
167
172
|
return left;
|
|
168
173
|
}
|
|
169
174
|
|
|
170
|
-
public async handleDOMObject(key: string, dom: DOM, domObject: DOMObject, tag: Tag) {
|
|
175
|
+
public async handleDOMObject(key: string, dom: DOM, scope: Scope, domObject: DOMObject, tag: Tag) {
|
|
171
176
|
let left = domObject.scope.get(key);
|
|
172
|
-
let right: number | Array<any> | string = await this.right.evaluate(
|
|
173
|
-
|
|
174
|
-
return this.handleArray(key, left, right, domObject.scope);
|
|
175
|
-
|
|
176
|
-
return this.handleString(key, left, right, domObject.scope);
|
|
177
|
+
let right: number | Array<any> | string = await this.right.evaluate(scope, dom, tag);
|
|
178
|
+
return this.handle(key, left, right, domObject.scope);
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
public handleArray(key, left, right, scope) {
|
|
@@ -5,6 +5,7 @@ import {TreeNode} from "../AST";
|
|
|
5
5
|
import {Node} from "./Node";
|
|
6
6
|
import {FunctionArgumentNode} from "./FunctionArgumentNode";
|
|
7
7
|
import {ScopeMemberNode} from "./ScopeMemberNode";
|
|
8
|
+
import {FunctionNode} from "./FunctionNode";
|
|
8
9
|
|
|
9
10
|
export class FunctionCallNode<T = any> extends Node implements TreeNode {
|
|
10
11
|
constructor(
|
|
@@ -27,6 +28,11 @@ export class FunctionCallNode<T = any> extends Node implements TreeNode {
|
|
|
27
28
|
functionScope = await this.fnc.scope.evaluate(scope, dom, tag);
|
|
28
29
|
}
|
|
29
30
|
const values = await this.args.evaluate(scope, dom, tag);
|
|
30
|
-
|
|
31
|
+
const func = await this.fnc.evaluate(scope, dom, tag);
|
|
32
|
+
if (func instanceof FunctionNode) {
|
|
33
|
+
return (await func.evaluate(functionScope, dom, tag) as any)(...values);
|
|
34
|
+
} else {
|
|
35
|
+
return func.call(functionScope.wrapped || functionScope, ...values);
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
}
|
package/src/AST/FunctionNode.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {Scope} from "../Scope";
|
|
2
2
|
import {DOM} from "../DOM";
|
|
3
3
|
import {Tag} from "../Tag";
|
|
4
|
-
import {Token, TreeNode} from "../AST";
|
|
4
|
+
import {Token, Tree, TreeNode} from "../AST";
|
|
5
5
|
import {Node} from "./Node";
|
|
6
|
-
import {
|
|
7
|
-
import {RootScopeMemberNode} from "./RootScopeMemberNode";
|
|
8
|
-
import {ScopeMemberNode} from "./ScopeMemberNode";
|
|
6
|
+
import {BlockNode} from "./BlockNode";
|
|
9
7
|
|
|
10
8
|
export class FunctionNode extends Node implements TreeNode {
|
|
9
|
+
protected requiresPrep: boolean = true;
|
|
10
|
+
|
|
11
11
|
constructor(
|
|
12
|
-
public readonly name:
|
|
13
|
-
public readonly
|
|
14
|
-
public readonly block:
|
|
12
|
+
public readonly name: string,
|
|
13
|
+
public readonly args: string[],
|
|
14
|
+
public readonly block: BlockNode
|
|
15
15
|
) {
|
|
16
16
|
super();
|
|
17
17
|
}
|
|
@@ -22,10 +22,30 @@ export class FunctionNode extends Node implements TreeNode {
|
|
|
22
22
|
];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
public async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
26
|
-
|
|
25
|
+
public async prepare(scope: Scope, dom: DOM, tag: Tag = null): Promise<void> {
|
|
26
|
+
scope.set(this.name, this);
|
|
27
|
+
await super.prepare(scope, dom, tag);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
|
|
31
|
+
return async (...args) => {
|
|
32
|
+
const functionScope = new Scope(scope);
|
|
33
|
+
for (const arg of this.args) {
|
|
34
|
+
functionScope.set(arg, args.shift());
|
|
35
|
+
}
|
|
36
|
+
return await this.block.evaluate(functionScope, dom, tag);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
27
39
|
|
|
28
40
|
public static parse(lastNode, token, tokens: Token[]): FunctionNode {
|
|
29
|
-
|
|
41
|
+
tokens.shift(); // skip 'func'
|
|
42
|
+
const name = tokens.shift();
|
|
43
|
+
const argTokens = Tree.getBlockTokens(tokens);
|
|
44
|
+
const funcArgs: string[] = [];
|
|
45
|
+
for (const t of argTokens) {
|
|
46
|
+
funcArgs.push(t[0].value);
|
|
47
|
+
}
|
|
48
|
+
const block = Tree.processTokens(Tree.getBlockTokens(tokens, null)[0]);
|
|
49
|
+
return new FunctionNode(name.value, funcArgs, block);
|
|
30
50
|
}
|
|
31
51
|
}
|
package/src/AST.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {BooleanLiteralNode} from "./AST/BooleanLiteralNode";
|
|
|
26
26
|
import {NotNode} from "./AST/NotNode";
|
|
27
27
|
import {XHRNode} from "./AST/XHRNode";
|
|
28
28
|
import {StringFormatNode} from "./AST/StringFormatNode";
|
|
29
|
+
import {FunctionNode} from "./AST/FunctionNode";
|
|
29
30
|
|
|
30
31
|
function lower(str: string): string {
|
|
31
32
|
return str ? str.toLowerCase() : null;
|
|
@@ -65,6 +66,7 @@ export enum TokenType {
|
|
|
65
66
|
IF,
|
|
66
67
|
ELSE_IF,
|
|
67
68
|
ELSE,
|
|
69
|
+
FUNC,
|
|
68
70
|
NAME,
|
|
69
71
|
L_BRACE,
|
|
70
72
|
R_BRACE,
|
|
@@ -194,6 +196,10 @@ const TOKEN_PATTERNS: TokenPattern[] = [
|
|
|
194
196
|
type: TokenType.ELSE,
|
|
195
197
|
pattern: /^else\s?(?=\{)/
|
|
196
198
|
},
|
|
199
|
+
{
|
|
200
|
+
type: TokenType.FUNC,
|
|
201
|
+
pattern: /^func\s/
|
|
202
|
+
},
|
|
197
203
|
{
|
|
198
204
|
type: TokenType.ELEMENT_ATTRIBUTE,
|
|
199
205
|
pattern: /^\.?@[-_a-zA-Z0-9]*/
|
|
@@ -482,6 +488,10 @@ export class Tree {
|
|
|
482
488
|
node = ForStatementNode.parse(node, token, tokens);
|
|
483
489
|
blockNodes.push(node);
|
|
484
490
|
node = null;
|
|
491
|
+
} else if (token.type === TokenType.FUNC) {
|
|
492
|
+
node = FunctionNode.parse(node, token, tokens);
|
|
493
|
+
blockNodes.push(node);
|
|
494
|
+
node = null;
|
|
485
495
|
} else if (StringFormatNode.match(tokens)) {
|
|
486
496
|
node = StringFormatNode.parse(node, tokens[0], tokens);
|
|
487
497
|
} else if (token.type === TokenType.STRING_LITERAL) {
|
package/src/Scope.ts
CHANGED
package/src/Tag.ts
CHANGED
|
@@ -271,7 +271,7 @@ export class Tag extends DOMObject {
|
|
|
271
271
|
return this._scope;
|
|
272
272
|
|
|
273
273
|
if (this.uniqueScope)
|
|
274
|
-
return this.createScope();
|
|
274
|
+
return this.createScope(true);
|
|
275
275
|
|
|
276
276
|
if (!!this.parentTag)
|
|
277
277
|
return this.parentTag.scope;
|
|
@@ -601,18 +601,16 @@ export class Tag extends DOMObject {
|
|
|
601
601
|
public createScope(force: boolean = false): Scope {
|
|
602
602
|
// Standard attribute requires a unique scope
|
|
603
603
|
// @todo: Does this cause any issues with attribute bindings on the parent scope prior to having its own scope? hmm...
|
|
604
|
-
if (
|
|
604
|
+
if (!this._scope && (force || this.uniqueScope)) {
|
|
605
605
|
this._uniqueScope = true;
|
|
606
606
|
this._scope = new Scope();
|
|
607
607
|
|
|
608
608
|
if (this.parentTag) {
|
|
609
609
|
this.scope.parentScope = this.parentTag.scope;
|
|
610
610
|
}
|
|
611
|
-
|
|
612
|
-
return this._scope;
|
|
613
611
|
}
|
|
614
612
|
|
|
615
|
-
return
|
|
613
|
+
return this._scope;
|
|
616
614
|
}
|
|
617
615
|
|
|
618
616
|
async watchAttribute(attributeName: string) {
|
package/src/attributes/Exec.ts
CHANGED
|
@@ -7,8 +7,12 @@ export class Exec extends Attribute {
|
|
|
7
7
|
public static readonly canDefer: boolean = false;
|
|
8
8
|
protected tree: Tree;
|
|
9
9
|
|
|
10
|
+
public get code() {
|
|
11
|
+
return this.getAttributeValue();
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
public async compile() {
|
|
11
|
-
this.tree = new Tree(this.
|
|
15
|
+
this.tree = new Tree(this.code);
|
|
12
16
|
await this.tree.prepare(this.tag.scope, this.tag.dom, this.tag);
|
|
13
17
|
await super.compile();
|
|
14
18
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {Attribute} from "../Attribute";
|
|
2
2
|
import {VisionHelper} from "../helpers/VisionHelper";
|
|
3
3
|
import {Registry} from "../Registry";
|
|
4
|
+
import {Scope} from "../Scope";
|
|
4
5
|
|
|
5
6
|
@Registry.attribute('vsn-root')
|
|
6
7
|
export class RootAttribute extends Attribute {
|
|
@@ -9,6 +10,8 @@ export class RootAttribute extends Attribute {
|
|
|
9
10
|
|
|
10
11
|
public async setup() {
|
|
11
12
|
this.tag.scope.set('$mobile', VisionHelper.isMobile());
|
|
13
|
+
if (console && !this.tag.scope.get('console'))
|
|
14
|
+
this.tag.scope.set('console', Scope.fromObject(console));
|
|
12
15
|
await super.setup();
|
|
13
16
|
}
|
|
14
17
|
}
|
|
@@ -19,6 +19,7 @@ export {Referenced} from "./Referenced";
|
|
|
19
19
|
export {RootAttribute} from "./RootAttribute";
|
|
20
20
|
export {ScopeAttribute} from "./ScopeAttribute";
|
|
21
21
|
export {ScopeChange} from "./ScopeChange";
|
|
22
|
+
export {ScriptAttribute} from "./ScriptAttribute";
|
|
22
23
|
export {SetAttribute} from "./SetAttribute";
|
|
23
24
|
export {StandardAttribute} from "./StandardAttribute";
|
|
24
25
|
export {StyleAttribute} from "./StyleAttribute";
|
package/src/vsn.ts
CHANGED
|
@@ -55,7 +55,7 @@ export class Vision extends EventDispatcher {
|
|
|
55
55
|
await this._dom.buildFrom(document, true);
|
|
56
56
|
const now = (new Date()).getTime();
|
|
57
57
|
const setupTime = now - startTime;
|
|
58
|
-
console.
|
|
58
|
+
console.info(`Took ${setupTime}ms to start up VisionJS. https://www.vsnjs.com/`, window ? `v${window['VSN_VERSION']}` : null);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public static get instance() {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Tree} from "../../src/AST";
|
|
2
|
+
import {Scope} from "../../src/Scope";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('FunctionNode', () => {
|
|
6
|
+
it("properly define a simple function", async () => {
|
|
7
|
+
const tree = new Tree(`func add(a, b) { return a + b; }; add(1, 2);`);
|
|
8
|
+
const scope = new Scope();
|
|
9
|
+
await tree.prepare(scope, null, null);
|
|
10
|
+
expect(scope.get('add')).toBeDefined();
|
|
11
|
+
const v = await tree.evaluate(scope, null, null);
|
|
12
|
+
expect(v).toBe(3);
|
|
13
|
+
});
|
|
14
|
+
});
|
package/demo/xhr.vsn
DELETED