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.
Files changed (46) hide show
  1. package/demo/demo.html +5 -2
  2. package/demo/vsn.js +2 -2
  3. package/demo/xhr.html +17 -0
  4. package/dist/AST/ArithmeticAssignmentNode.d.ts +2 -1
  5. package/dist/AST/ArithmeticAssignmentNode.js +20 -18
  6. package/dist/AST/ArithmeticAssignmentNode.js.map +1 -1
  7. package/dist/AST/FunctionCallNode.js +13 -8
  8. package/dist/AST/FunctionCallNode.js.map +1 -1
  9. package/dist/AST/FunctionNode.d.ts +7 -8
  10. package/dist/AST/FunctionNode.js +53 -9
  11. package/dist/AST/FunctionNode.js.map +1 -1
  12. package/dist/AST.d.ts +47 -46
  13. package/dist/AST.js +57 -46
  14. package/dist/AST.js.map +1 -1
  15. package/dist/Scope.d.ts +1 -0
  16. package/dist/Scope.js +5 -0
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/Tag.js +3 -4
  19. package/dist/Tag.js.map +1 -1
  20. package/dist/attributes/Exec.d.ts +1 -0
  21. package/dist/attributes/Exec.js +8 -1
  22. package/dist/attributes/Exec.js.map +1 -1
  23. package/dist/attributes/RootAttribute.js +3 -0
  24. package/dist/attributes/RootAttribute.js.map +1 -1
  25. package/dist/attributes/ScriptAttribute.d.ts +4 -0
  26. package/dist/attributes/ScriptAttribute.js +45 -0
  27. package/dist/attributes/ScriptAttribute.js.map +1 -0
  28. package/dist/attributes/_imports.d.ts +1 -0
  29. package/dist/attributes/_imports.js +3 -1
  30. package/dist/attributes/_imports.js.map +1 -1
  31. package/dist/vsn.js +1 -1
  32. package/dist/vsn.min.js +2 -2
  33. package/package.json +1 -1
  34. package/src/AST/ArithmeticAssignmentNode.ts +19 -17
  35. package/src/AST/FunctionCallNode.ts +7 -1
  36. package/src/AST/FunctionNode.ts +30 -10
  37. package/src/AST.ts +10 -0
  38. package/src/Scope.ts +6 -0
  39. package/src/Tag.ts +3 -5
  40. package/src/attributes/Exec.ts +5 -1
  41. package/src/attributes/RootAttribute.ts +3 -0
  42. package/src/attributes/ScriptAttribute.ts +9 -0
  43. package/src/attributes/_imports.ts +1 -0
  44. package/src/vsn.ts +1 -1
  45. package/test/AST/FunctionNode.spec.ts +14 -0
  46. package/demo/xhr.vsn +0 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vsn",
3
- "version": "0.1.57",
3
+ "version": "0.1.60",
4
4
  "description": "SEO Friendly Javascript/Typescript Framework",
5
5
  "keywords": [
6
6
  "framework",
@@ -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(domObject.scope, dom, tag);
173
- if (left instanceof Array)
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
- return (await this.fnc.evaluate(scope, dom, tag)).call(functionScope.wrapped || functionScope, ...values);
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
  }
@@ -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 {LiteralNode} from "./LiteralNode";
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: LiteralNode<string>,
13
- public readonly variables: LiteralNode<string>[],
14
- public readonly block: RootScopeMemberNode | ScopeMemberNode,
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
- public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {}
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
- return new FunctionNode(null, null, null);
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
@@ -220,4 +220,10 @@ export class Scope extends EventDispatcher {
220
220
  delete toUnwrap[field];
221
221
  }
222
222
  }
223
+
224
+ public static fromObject(obj, parentScope?: Scope): Scope {
225
+ const scope = new Scope(parentScope);
226
+ scope.wrap(obj);
227
+ return scope;
228
+ }
223
229
  }
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 ((!this.uniqueScope && force) || this.uniqueScope) {
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 null;
613
+ return this._scope;
616
614
  }
617
615
 
618
616
  async watchAttribute(attributeName: string) {
@@ -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.getAttributeValue());
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
  }
@@ -0,0 +1,9 @@
1
+ import {Registry} from "../Registry";
2
+ import {Exec} from "./Exec";
3
+
4
+ @Registry.attribute('vsn-script')
5
+ export class ScriptAttribute extends Exec {
6
+ public get code() {
7
+ return this.tag.element.innerText;
8
+ }
9
+ }
@@ -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.warn(`Took ${setupTime}ms to start up VisionJS. https://www.vsnjs.com/`, window ? `v${window['VSN_VERSION']}` : null);
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
@@ -1,4 +0,0 @@
1
- <component>
2
- <script></script>
3
- <template></template>
4
- </component>