all repos — h3 @ 56a6ad8b0ffac6a74a0f4624bb5ae08230b29f59

A tiny, extremely minimalist JavaScript microframework.

Added tests; fixes
h3rald h3rald@h3rald.com
Sat, 18 Apr 2020 15:57:38 +0200
commit

56a6ad8b0ffac6a74a0f4624bb5ae08230b29f59

parent

2f4713a643d593d6f57929d1a86b524c20a1f845

4 files changed, 74 insertions(+), 36 deletions(-)

jump to
M __tests__/h3.js__tests__/h3.js

@@ -2,6 +2,7 @@ // TODO: Rewrite

const h3 = require("../h3.js").default; describe("h3", () => { + it("should expose an equal method to check object/array/function equality", () => { expect(h3.equal({}, {})).toBeTruthy(); expect(h3.equal([], [])).toBeTruthy();

@@ -88,6 +89,30 @@ value: undefined,

}); }); + it("should throw an error when invalid arguments are supplied", () => { + const empty = () => h3(); + const invalid1st = () => h3(1); + const invalid1st2 = () => h3(1, {}); + const invalid1st3 = () => h3(1, {}, []); + const invalid2nd = () => h3("div", 1); + const invalid2nd2 = () => h3("div", true, []); + const invalid2nd3 = () => h3("div", null, []); + expect(empty).toThrowError(/No arguments passed/); + expect(invalid1st).toThrowError(/Invalid first argument/); + expect(invalid1st2).toThrowError(/Invalid first argument/); + expect(invalid1st3).toThrowError(/Invalid first argument/); + expect(invalid2nd).toThrowError(/second argument of a VNode constructor/); + expect(invalid2nd2).toThrowError(/Invalid second argument/); + expect(invalid2nd3).toThrowError(/Invalid second argument/); + }); + + it("should support the creation of elements with a single, non-array child", () => { + const vnode1 = h3("div", () => "test"); + const vnode2 = h3("div", () => h3("span")); + expect(vnode1.children[0].value).toEqual("test"); + expect(vnode2.children[0].type).toEqual("span"); + }); + it("should support the creation of nodes with a single child node", () => { const result = { type: "div",

@@ -100,7 +125,8 @@ classList: [],

data: {}, eventListeners: {}, id: undefined, - key: undefined, + $key: undefined, + $html: undefined, style: undefined, value: "test", },

@@ -110,7 +136,8 @@ classList: [],

data: {}, eventListeners: {}, id: undefined, - key: undefined, + $key: undefined, + $html: undefined, style: undefined, value: undefined, };

@@ -249,7 +276,9 @@ });

}); it("should support the creation of virtual node elements with element children and classes", () => { - expect(h3("div.test", ["a", h3("span", ["test1"]), () => h3("span", ["test2"])])).toEqual({ + expect( + h3("div.test", ["a", h3("span", ["test1"]), () => h3("span", ["test2"])]) + ).toEqual({ attributes: {}, type: "div", children: [
M docs/js/h3.jsdocs/js/h3.js

@@ -1,4 +1,3 @@

-// Basic object equality const equal = (obj1, obj2) => { if ( (obj1 === null && obj2 === null) ||

@@ -58,7 +57,6 @@ const selectorRegex = /^([a-z0-9:_=-]+)(#[a-z0-9:_=-]+)?(\..+)?$/i;

// Virtual Node Implementation with HyperScript-like syntax class VNode { - constructor(...args) { this.type = undefined; this.attributes = {};

@@ -79,7 +77,10 @@ let vnode = args[0];

if (typeof vnode === "string") { // Assume empty element this.processSelector(vnode); - } else if (typeof vnode === "object" && vnode !== null) { + } else if ( + typeof vnode === "function" || + (typeof vnode === "object" && vnode !== null) + ) { // Text node if (vnode.type === "#text") { this.type = "#text";

@@ -100,16 +101,15 @@ "[VNode] Invalid first argument provided to VNode constructor."

); } this.processSelector(selector); - this.children = []; if (typeof data === "string") { // Assume single child text node - this.type = "#text"; - this.value = data; + this.children = [new VNode({ type: "#text", value: data })]; return; } - if (typeof data !== "object" || data === null) { + if (typeof data !== "function" && (typeof data !== "object" || data === null)) { + console.log(data); throw new Error( - "[VNode] The second argument of a VNode constructor must be an object or a string." + "[VNode] The second argument of a VNode constructor must be an object, an array or a string." ); } if (Array.isArray(data)) {

@@ -200,8 +200,11 @@ if (arg instanceof VNode) {

return arg; } if (arg instanceof Function) { - const vnode = arg(); - if (typeof vnode !== VNode) { + let vnode = arg(); + if (typeof vnode === "string") { + vnode = new VNode({ type: "#text", value: vnode }); + } + if (!(vnode instanceof VNode)) { throw new Error("[VNode] Function argument does not return a VNode"); } return vnode;

@@ -217,7 +220,7 @@ this.children = children.map((c) => {

if (typeof c === "string") { return new VNode({ type: "#text", value: c }); } - if (typeof c === "object" && c !== null) { + if (typeof c === "function" || (typeof c === "object" && c !== null)) { return this.processVNodeObject(c); } throw new Error(`[VNode] Specified child is not a VNode: ${c}`);
M example/assets/js/h3.jsexample/assets/js/h3.js

@@ -1,4 +1,3 @@

-// Basic object equality const equal = (obj1, obj2) => { if ( (obj1 === null && obj2 === null) ||

@@ -58,7 +57,6 @@ const selectorRegex = /^([a-z0-9:_=-]+)(#[a-z0-9:_=-]+)?(\..+)?$/i;

// Virtual Node Implementation with HyperScript-like syntax class VNode { - constructor(...args) { this.type = undefined; this.attributes = {};

@@ -79,7 +77,10 @@ let vnode = args[0];

if (typeof vnode === "string") { // Assume empty element this.processSelector(vnode); - } else if (typeof vnode === "object" && vnode !== null) { + } else if ( + typeof vnode === "function" || + (typeof vnode === "object" && vnode !== null) + ) { // Text node if (vnode.type === "#text") { this.type = "#text";

@@ -100,16 +101,15 @@ "[VNode] Invalid first argument provided to VNode constructor."

); } this.processSelector(selector); - this.children = []; if (typeof data === "string") { // Assume single child text node - this.type = "#text"; - this.value = data; + this.children = [new VNode({ type: "#text", value: data })]; return; } - if (typeof data !== "object" || data === null) { + if (typeof data !== "function" && (typeof data !== "object" || data === null)) { + console.log(data); throw new Error( - "[VNode] The second argument of a VNode constructor must be an object or a string." + "[VNode] The second argument of a VNode constructor must be an object, an array or a string." ); } if (Array.isArray(data)) {

@@ -200,8 +200,11 @@ if (arg instanceof VNode) {

return arg; } if (arg instanceof Function) { - const vnode = arg(); - if (typeof vnode !== VNode) { + let vnode = arg(); + if (typeof vnode === "string") { + vnode = new VNode({ type: "#text", value: vnode }); + } + if (!(vnode instanceof VNode)) { throw new Error("[VNode] Function argument does not return a VNode"); } return vnode;

@@ -217,7 +220,7 @@ this.children = children.map((c) => {

if (typeof c === "string") { return new VNode({ type: "#text", value: c }); } - if (typeof c === "object" && c !== null) { + if (typeof c === "function" || (typeof c === "object" && c !== null)) { return this.processVNodeObject(c); } throw new Error(`[VNode] Specified child is not a VNode: ${c}`);
M h3.jsh3.js

@@ -1,4 +1,3 @@

-// Basic object equality const equal = (obj1, obj2) => { if ( (obj1 === null && obj2 === null) ||

@@ -58,7 +57,6 @@ const selectorRegex = /^([a-z0-9:_=-]+)(#[a-z0-9:_=-]+)?(\..+)?$/i;

// Virtual Node Implementation with HyperScript-like syntax class VNode { - constructor(...args) { this.type = undefined; this.attributes = {};

@@ -79,7 +77,10 @@ let vnode = args[0];

if (typeof vnode === "string") { // Assume empty element this.processSelector(vnode); - } else if (typeof vnode === "object" && vnode !== null) { + } else if ( + typeof vnode === "function" || + (typeof vnode === "object" && vnode !== null) + ) { // Text node if (vnode.type === "#text") { this.type = "#text";

@@ -100,16 +101,15 @@ "[VNode] Invalid first argument provided to VNode constructor."

); } this.processSelector(selector); - this.children = []; if (typeof data === "string") { // Assume single child text node - this.type = "#text"; - this.value = data; + this.children = [new VNode({ type: "#text", value: data })]; return; } - if (typeof data !== "object" || data === null) { + if (typeof data !== "function" && (typeof data !== "object" || data === null)) { + console.log(data); throw new Error( - "[VNode] The second argument of a VNode constructor must be an object or a string." + "[VNode] The second argument of a VNode constructor must be an object, an array or a string." ); } if (Array.isArray(data)) {

@@ -200,8 +200,11 @@ if (arg instanceof VNode) {

return arg; } if (arg instanceof Function) { - const vnode = arg(); - if (typeof vnode !== VNode) { + let vnode = arg(); + if (typeof vnode === "string") { + vnode = new VNode({ type: "#text", value: vnode }); + } + if (!(vnode instanceof VNode)) { throw new Error("[VNode] Function argument does not return a VNode"); } return vnode;

@@ -217,7 +220,7 @@ this.children = children.map((c) => {

if (typeof c === "string") { return new VNode({ type: "#text", value: c }); } - if (typeof c === "object" && c !== null) { + if (typeof c === "function" || (typeof c === "object" && c !== null)) { return this.processVNodeObject(c); } throw new Error(`[VNode] Specified child is not a VNode: ${c}`);