diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 112254d..0000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,31 +0,0 @@ -version: '2' # required to adjust maintainability checks -checks: - argument-count: - config: - threshold: 10 - complex-logic: - config: - threshold: 4 - file-lines: - config: - threshold: 500 - method-complexity: - enabled: false - method-count: - config: - threshold: 20 - method-lines: - config: - threshold: 250 - nested-control-flow: - config: - threshold: 6 - return-statements: - config: - threshold: 4 -exclude_patterns: - - 'dist' - - 'test*' - - 'rollup*' - - 'plugins/node.js' - - 'tmp' diff --git a/.eslintrc b/.eslintrc index 26a21bd..8a7d0de 100644 --- a/.eslintrc +++ b/.eslintrc @@ -30,11 +30,11 @@ 2, { "anonymous": "always", "named": "never" } ], - "space-in-parens": 2, + "space-in-parens": 0, "space-infix-ops": 2, "space-unary-ops": 2, "vars-on-top": 2, - "wrap-iife": 2, + "wrap-iife": 0, "semi": [2, "always"], "indent": [ 2, @@ -46,7 +46,7 @@ "valid-jsdoc": 2, "no-var": "error", "no-undef": 0, - "no-unused-vars":"warn", + "no-unused-vars": "warn", "no-multi-spaces": "error", "no-multiple-empty-lines": "error", "one-var": "off", diff --git a/.size-snapshot.json b/.size-snapshot.json index 631e6dd..f4a2192 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -5,7 +5,7 @@ "gzipped": 2075 }, "valyrian.min.js": { - "bundled": 12953, + "bundled": 13481, "minified": 5030, "gzipped": 2068 } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3ae5246..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: node_js - -node_js: - - lts/* - -install: - - yarn - -script: - - yarn test - -after_success: yarn coverage diff --git a/dist/valyrian.min.js.map b/dist/valyrian.min.js.map index 455dfbc..72b3e72 100644 --- a/dist/valyrian.min.js.map +++ b/dist/valyrian.min.js.map @@ -1 +1 @@ -{"version":3,"file":"valyrian.min.js","sources":["../lib/index.js"],"sourcesContent":["\n//eslint-disable-next-line max-lines-per-function\nfunction valyrian() {\n let UND = void 0;\n let oncreate = 'oncreate';\n let onupdate = 'onupdate';\n let onremove = 'onremove';\n let onbeforeupdate = 'onbeforeupdate';\n let functionstr = 'function';\n let once = 'v-once';\n let isArray = Array.isArray;\n let mainNode;\n let oldMainNode;\n let mountedComponent;\n let directives = {};\n\n function Vnode(name, props, children) {\n this.props = props || {};\n this.children = children;\n this.name = name;\n };\n\n function TextVnode(dom) {\n this.dom = dom;\n }\n TextVnode.prototype = {\n props: {},\n children: []\n };\n\n let emptyNode = new TextVnode();\n\n function createElement(tag, isSVG) {\n return isSVG ?\n document.createElementNS('http://www.w3.org/2000/svg', tag) :\n document.createElement(tag);\n }\n\n function lifecycleCall(vnode, methodName, oldNode) {\n if (vnode.props[methodName]) {\n return vnode.props[methodName](vnode, oldNode);\n }\n }\n\n function callRemove(vnode) {\n if (vnode instanceof Vnode) {\n for (let i = 0, l = vnode.children.length; i < l; i++) {\n callRemove(vnode.children[i]);\n }\n\n vnode.props[onremove] && vnode.props[onremove](vnode);\n }\n }\n\n\n function v(tagOrComponent, props, ...children) {\n return new Vnode(tagOrComponent, props, children);\n };\n\n v.isNode = typeof window === 'undefined';\n\n // Hydrates the current dom before mount\n v.domToVnode = dom => {\n if (dom.nodeType === 3) {\n return new TextVnode(dom);\n }\n\n if (dom.nodeType === 1) {\n let props = {};\n [].forEach.call(dom.attributes, (prop) => props[prop.nodeName] = prop.nodeValue);\n\n let vnode = new Vnode(\n dom.nodeName,\n props,\n []\n );\n vnode.dom = dom;\n\n for (let i = 0, l = dom.childNodes.length; i < l; i++) {\n let childVnode = v.domToVnode(dom.childNodes[i]);\n childVnode && vnode.children.push(childVnode);\n }\n return vnode;\n }\n };\n\n v.trust = (htmlString) => {\n let div = createElement('div');\n div.innerHTML = htmlString.trim();\n\n return [].map.call(div.childNodes, (item) => v.domToVnode(item));\n };\n\n // Plugin system\n let plugins = new Map();\n v.usePlugin = (plugin, options) => !plugins.has(plugin) && plugins.set(plugin, true) && plugin(v, options);\n\n v.reservedWords = [\n \"key\",\n once,\n oncreate,\n onbeforeupdate,\n onupdate,\n onremove,\n \"data\"\n ];\n\n let attachedListeners = {};\n function eventListener(e) {\n let dom = e.target;\n let name = `__on${e.type}`;\n while (dom) {\n if (dom[name]) {\n dom[name](e, dom);\n if (!e.defaultPrevented) {\n v.update();\n }\n return;\n }\n dom = dom.parentNode;\n }\n };\n\n v.updateProperty = (name, newNode, oldNode) => {\n if (name in newNode.props) {\n let value = newNode.props[name];\n\n if (v.reservedWords.indexOf(name) !== -1) {\n if (directives[name]) {\n directives[name](value, newNode, oldNode);\n }\n } else if (typeof value === functionstr) {\n name = `__${name}`;\n if (!attachedListeners[name]) {\n document.addEventListener(name.slice(4), eventListener);\n attachedListeners[name] = true;\n };\n newNode.dom[name] = value;\n } else if (name in newNode.dom && !newNode.isSVG) {\n if (newNode.dom[name] !== value) {\n newNode.dom[name] = value;\n }\n } else if (!oldNode || value !== oldNode.props[name]) {\n newNode.dom.setAttribute(name, value);\n }\n }\n };\n\n function updateProps(newNode, oldNode) {\n for (let name in newNode.props) {\n v.updateProperty(name, newNode, oldNode);\n }\n }\n\n function removeProps(newNode, oldNode) {\n for (let name in oldNode.props) {\n if (v.reservedWords.indexOf(name) === -1 && name in newNode.props === false && typeof oldNode.props[name] !== functionstr) {\n if (name in newNode.dom) {\n newNode.dom[name] = UND;\n } else {\n newNode.dom.removeAttribute(name);\n }\n }\n }\n }\n\n function moveDom(dom, $parent, oldDom) {\n if (dom !== oldDom) {\n oldDom ?\n $parent.replaceChild(dom, oldDom) :\n $parent.appendChild(dom);\n }\n }\n\n function removeVnode(vnode) {\n callRemove(vnode);\n vnode.dom && vnode.dom.parentNode && vnode.dom.parentNode.removeChild(vnode.dom);\n }\n\n function updateKeyedNode($parent, newNode, compareNode, newIndex) {\n let oldDom = $parent.childNodes[newIndex];\n // Moved or updated\n if (compareNode.dom) {\n newNode.dom = compareNode.dom;\n if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, compareNode) === false) {\n newNode.children = compareNode.children;\n moveDom(newNode.dom, $parent, oldDom);\n } else {\n removeProps(newNode, compareNode);\n updateProps(newNode, compareNode);\n moveDom(newNode.dom, $parent, oldDom);\n lifecycleCall(newNode, v.isMounted ? onupdate : oncreate, compareNode);\n patch(newNode, compareNode);\n }\n } else {\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n moveDom(newNode.dom, $parent, oldDom);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n }\n }\n\n let vnodesToCleanup = [];\n\n v.onCleanup = callback => {\n let parentVnode = v.current.parentVnode;\n if (!parentVnode.onCleanup) {\n parentVnode.onCleanup = [];\n }\n\n parentVnode.onCleanup.push(callback);\n\n if (vnodesToCleanup.indexOf(parentVnode) === -1) {\n vnodesToCleanup.push(parentVnode);\n }\n };\n\n function cleanupVnodes() {\n for (let l = vnodesToCleanup.length; l--;) {\n for (let callback of vnodesToCleanup[l].onCleanup) {\n callback();\n }\n }\n vnodesToCleanup = [];\n }\n\n v.current = {\n parentVnode: UND,\n oldParentVnode: UND,\n component: UND\n };\n\n // eslint-disable-next-line complexity,sonarjs/cognitive-complexity\n function patch(parentNode, oldParentNode) {\n let newTree = isArray(parentNode.children) ? parentNode.children : [parentNode.children];\n let oldTree = oldParentNode.children;\n v.current.parentVnode = parentNode;\n v.current.oldParentVnode = oldParentNode;\n\n // Flatten children\n for (let i = 0; i < newTree.length; i++) {\n let childVnode = newTree[i];\n\n if (isArray(childVnode)) {\n newTree.splice(i--, 1, ...childVnode);\n } else if (childVnode instanceof Vnode) {\n if (typeof childVnode.name === 'string') {\n childVnode.isSVG = parentNode.isSVG || childVnode.name === 'svg';\n } else {\n v.current.component = childVnode;\n newTree.splice(i--, 1, ...[(childVnode.name.view || childVnode.name).call(childVnode.name, childVnode.props, ...childVnode.children)]);\n }\n } else if (childVnode === null || childVnode === UND) {\n newTree.splice(i--, 1);\n }\n }\n\n if (newTree.length === 0) {\n if (oldTree.length > 0) {\n let i = oldTree.length;\n while (i--) {\n callRemove(oldTree[i]);\n }\n parentNode.dom.textContent = '';\n }\n\n // Is keyed list\n } else if (oldTree.length && newTree[0] instanceof Vnode && newTree[0].props.key) {\n let oldKeys = oldTree.map(vnode => vnode.props.key);\n let newKeys = newTree.map(vnode => vnode.props.key);\n\n for (let i = 0, l = newKeys.length; i < l; i++) {\n let key = newKeys[i];\n let newNode = newTree[i];\n\n // Updated: Same key\n if (key === oldKeys[i]) {\n oldTree[i].processed = true;\n updateKeyedNode(parentNode.dom, newNode, oldTree[i], i);\n } else {\n let oldIndex = oldKeys.indexOf(key);\n let newIndex = i >= oldKeys.length ? UND : i;\n\n // Moved: Key exists in old keys\n if (oldIndex !== -1) {\n oldTree[oldIndex].processed = true;\n updateKeyedNode(parentNode.dom, newNode, oldTree[oldIndex], newIndex);\n // Added: Key does not exists in old keys\n } else {\n updateKeyedNode(parentNode.dom, newNode, emptyNode, newIndex);\n }\n }\n }\n\n // Delete unprocessed old keys\n let l = oldTree.length;\n\n while (l--) {\n !oldTree[l].processed && removeVnode(oldTree[l]);\n }\n\n // Not keyed list or first render so use the simple algorithm\n } else {\n let i = oldTree.length;\n let l = newTree.length;\n\n // Remove deleted nodes\n while (i-- > l) {\n removeVnode(oldTree[i]);\n }\n\n for (i = 0; i < l; i++) {\n let newNode = newTree[i];\n let oldNode = oldTree[i];\n // Is vnode\n if (newNode instanceof Vnode) {\n if (!oldNode) {\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n parentNode.dom.appendChild(newNode.dom);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n } else {\n if (newNode.name === oldNode.name) {\n newNode.dom = oldNode.dom;\n if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, oldNode) === false) {\n newNode.children = oldNode.children;\n } else {\n removeProps(newNode, oldNode);\n updateProps(newNode, oldNode);\n lifecycleCall(newNode, v.isMounted ? onupdate : oncreate, oldNode);\n patch(newNode, oldNode);\n }\n } else {\n callRemove(oldNode);\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n parentNode.dom.replaceChild(newNode.dom, parentNode.dom.childNodes[i]);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n }\n }\n\n } else {\n let dom;\n\n // If we are getting a TextVnode could be from the domToVnode method\n let value = newNode.dom ? newNode.dom.nodeValue : String(newNode);\n\n if (oldNode instanceof TextVnode) {\n dom = oldNode.dom;\n if (value !== dom.nodeValue) {\n dom.nodeValue = value;\n }\n } else {\n dom = document.createTextNode(value);\n if (!oldNode) {\n parentNode.dom.appendChild(dom);\n } else {\n callRemove(oldNode);\n parentNode.dom.replaceChild(dom, oldNode.dom);\n }\n }\n newTree[i] = new TextVnode(dom);\n }\n }\n }\n\n parentNode.children = newTree;\n };\n\n v.update = (props, ...children) => {\n if (mainNode) {\n if (mountedComponent) {\n cleanupVnodes();\n oldMainNode = mainNode;\n mainNode = new Vnode(mainNode.name, mainNode.props, [v(mountedComponent, props, ...children)]);\n mainNode.dom = oldMainNode.dom;\n mainNode.isSVG = mainNode.name === 'svg';\n patch(mainNode, oldMainNode);\n v.isMounted = true;\n }\n\n return v.isNode && mainNode.dom.innerHTML;\n }\n };\n\n v.mount = (container, component, props, ...children) => {\n let mainContainer = v.isNode\n ? createElement('div')\n : typeof container === 'string'\n ? document.querySelectorAll(container)[0]\n : container;\n\n mainNode = v.domToVnode(mainContainer);\n mountedComponent = component;\n\n return v.update(props, ...children);\n };\n\n v.unMount = () => {\n mountedComponent = () => '';\n let result = v.update();\n mountedComponent = UND;\n v.isMounted = false;\n return result;\n };\n\n v.directive = (directive, handler) => {\n let directiveName = `v-${directive}`;\n if (v.reservedWords.indexOf(directiveName) === -1) {\n v.reservedWords.push(directiveName);\n directives[directiveName] = handler;\n }\n };\n\n let hideDirective = (test) => (bool, vnode, oldnode) => {\n let value = test ? bool : !bool;\n if (value) {\n let newdom = document.createTextNode('');\n if (oldnode && oldnode.dom && oldnode.dom.parentNode) {\n callRemove(oldnode);\n oldnode.dom.parentNode.replaceChild(newdom, oldnode.dom);\n }\n vnode.name = '';\n vnode.children = [];\n vnode.props = {};\n vnode.dom = newdom;\n }\n };\n\n let targetMap = new WeakMap();\n\n v.directive('if', hideDirective(false));\n v.directive('unless', hideDirective(true));\n v.directive('for', (set, vnode) => vnode.children = set.map(vnode.children[0]));\n v.directive('show', (bool, vnode) => vnode.dom.style.display = bool ? '' : 'none');\n v.directive('class', (classes, vnode) => {\n for (let name in classes) {\n vnode.dom.classList.toggle(name, classes[name]);\n }\n });\n v.directive('html', (html, vnode) => vnode.children = v.trust(html));\n\n\n return v;\n}\n\nconst v = valyrian();\nv.newInstance = valyrian;\n\n(v.isNode ? global : window).v = v;\n"],"names":["valyrian","mainNode","oldMainNode","mountedComponent","UND","isArray","Array","directives","Vnode","name","props","children","this","TextVnode","dom","prototype","emptyNode","createElement","tag","isSVG","document","createElementNS","lifecycleCall","vnode","methodName","oldNode","callRemove","i","l","length","v","tagOrComponent","isNode","window","domToVnode","nodeType","forEach","call","attributes","prop","nodeName","nodeValue","childNodes","childVnode","push","trust","htmlString","div","innerHTML","trim","map","item","plugins","Map","usePlugin","plugin","options","has","set","reservedWords","attachedListeners","eventListener","e","target","type","defaultPrevented","update","parentNode","updateProps","newNode","updateProperty","removeProps","indexOf","removeAttribute","moveDom","$parent","oldDom","replaceChild","appendChild","removeVnode","removeChild","updateKeyedNode","compareNode","newIndex","isMounted","patch","value","addEventListener","slice","setAttribute","vnodesToCleanup","oldParentNode","newTree","oldTree","current","parentVnode","oldParentVnode","splice","component","view","textContent","key","oldKeys","newKeys","processed","oldIndex","String","createTextNode","onCleanup","callback","cleanupVnodes","mount","container","mainContainer","querySelectorAll","unMount","result","directive","handler","directiveName","hideDirective","test","bool","oldnode","newdom","style","display","classes","classList","toggle","html","newInstance","global"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"valyrian.min.js","sources":["../lib/index.js"],"sourcesContent":["\n//eslint-disable-next-line max-lines-per-function\nfunction valyrian() {\n let UND = void 0;\n let oncreate = 'oncreate';\n let onupdate = 'onupdate';\n let onremove = 'onremove';\n let onbeforeupdate = 'onbeforeupdate';\n let functionstr = 'function';\n let once = 'v-once';\n let isArray = Array.isArray;\n let mainNode;\n let oldMainNode;\n let mountedComponent;\n let directives = {};\n\n function Vnode(name, props, children) {\n this.props = props || {};\n this.children = children;\n this.name = name;\n };\n\n function TextVnode(dom) {\n this.dom = dom;\n }\n TextVnode.prototype = {\n props: {},\n children: []\n };\n\n let emptyNode = new TextVnode();\n\n function createElement(tag, isSVG) {\n return isSVG ?\n document.createElementNS('http://www.w3.org/2000/svg', tag) :\n document.createElement(tag);\n }\n\n function lifecycleCall(vnode, methodName, oldNode) {\n if (vnode.props[methodName]) {\n return vnode.props[methodName](vnode, oldNode);\n }\n }\n\n function callRemove(vnode) {\n if (vnode instanceof Vnode) {\n for (let i = 0, l = vnode.children.length; i < l; i++) {\n callRemove(vnode.children[i]);\n }\n\n vnode.props[onremove] && vnode.props[onremove](vnode);\n }\n }\n\n\n function v(tagOrComponent, props, ...children) {\n return new Vnode(tagOrComponent, props, children);\n };\n\n v.isNode = typeof window === 'undefined';\n\n // Hydrates the current dom before mount\n v.domToVnode = dom => {\n if (dom.nodeType === 3) {\n return new TextVnode(dom);\n }\n\n if (dom.nodeType === 1) {\n let props = {};\n [].forEach.call(dom.attributes, (prop) => props[prop.nodeName] = prop.nodeValue);\n\n let vnode = new Vnode(\n dom.nodeName,\n props,\n []\n );\n vnode.dom = dom;\n\n for (let i = 0, l = dom.childNodes.length; i < l; i++) {\n let childVnode = v.domToVnode(dom.childNodes[i]);\n childVnode && vnode.children.push(childVnode);\n }\n return vnode;\n }\n };\n\n v.trust = (htmlString) => {\n let div = createElement('div');\n div.innerHTML = htmlString.trim();\n\n return [].map.call(div.childNodes, (item) => v.domToVnode(item));\n };\n\n // Plugin system\n let plugins = new Map();\n v.usePlugin = (plugin, options) => !plugins.has(plugin) && plugins.set(plugin, true) && plugin(v, options);\n\n v.reservedWords = [\n \"key\",\n once,\n oncreate,\n onbeforeupdate,\n onupdate,\n onremove,\n \"data\"\n ];\n\n let attachedListeners = {};\n function eventListener(e) {\n let dom = e.target;\n let name = `__on${e.type}`;\n while (dom) {\n if (dom[name]) {\n dom[name](e, dom);\n if (!e.defaultPrevented) {\n v.update();\n }\n return;\n }\n dom = dom.parentNode;\n }\n };\n\n v.updateProperty = (name, newNode, oldNode) => {\n if (name in newNode.props) {\n let value = newNode.props[name];\n if (v.reservedWords.indexOf(name) !== -1) {\n if (directives[name]) {\n directives[name](value, newNode, oldNode);\n }\n } else if (typeof value === functionstr) {\n name = `__${name}`;\n if (!attachedListeners[name]) {\n document.addEventListener(name.slice(4), eventListener);\n attachedListeners[name] = true;\n };\n newNode.dom[name] = value;\n } else if (name in newNode.dom && !newNode.isSVG) {\n if (newNode.dom[name] !== value) {\n newNode.dom[name] = value;\n }\n } else if (!oldNode || value !== oldNode.props[name]) {\n newNode.dom.setAttribute(name, value);\n }\n }\n };\n\n function updateProps(newNode, oldNode) {\n for (let name in newNode.props) {\n v.updateProperty(name, newNode, oldNode);\n }\n }\n\n function removeProps(newNode, oldNode) {\n for (let name in oldNode.props) {\n if (v.reservedWords.indexOf(name) === -1 && name in newNode.props === false && typeof oldNode.props[name] !== functionstr) {\n if (name in newNode.dom) {\n newNode.dom[name] = UND;\n } else {\n newNode.dom.removeAttribute(name);\n }\n }\n }\n }\n\n function moveDom(dom, $parent, oldDom) {\n if (dom !== oldDom) {\n oldDom ?\n $parent.replaceChild(dom, oldDom) :\n $parent.appendChild(dom);\n }\n }\n\n function removeVnode(vnode) {\n callRemove(vnode);\n vnode.dom && vnode.dom.parentNode && vnode.dom.parentNode.removeChild(vnode.dom);\n }\n\n function updateKeyedNode($parent, newNode, compareNode, newIndex) {\n let oldDom = $parent.childNodes[newIndex];\n // Moved or updated\n if (compareNode.dom) {\n newNode.dom = compareNode.dom;\n if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, compareNode) === false) {\n newNode.children = compareNode.children;\n moveDom(newNode.dom, $parent, oldDom);\n } else {\n removeProps(newNode, compareNode);\n updateProps(newNode, compareNode);\n moveDom(newNode.dom, $parent, oldDom);\n lifecycleCall(newNode, v.isMounted ? onupdate : oncreate, compareNode);\n patch(newNode, compareNode);\n }\n } else {\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n moveDom(newNode.dom, $parent, oldDom);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n }\n }\n\n let vnodesToCleanup = [];\n\n v.onCleanup = callback => {\n let parentVnode = v.current.parentVnode;\n if (!parentVnode.onCleanup) {\n parentVnode.onCleanup = [];\n }\n\n parentVnode.onCleanup.push(callback);\n\n if (vnodesToCleanup.indexOf(parentVnode) === -1) {\n vnodesToCleanup.push(parentVnode);\n }\n };\n\n function cleanupVnodes() {\n for (let l = vnodesToCleanup.length; l--;) {\n for (let callback of vnodesToCleanup[l].onCleanup) {\n callback();\n }\n }\n vnodesToCleanup = [];\n }\n\n v.current = {\n parentVnode: UND,\n oldParentVnode: UND,\n component: UND\n };\n\n // eslint-disable-next-line complexity,sonarjs/cognitive-complexity\n function patch(parentNode, oldParentNode) {\n let newTree = isArray(parentNode.children) ? parentNode.children : [parentNode.children];\n let oldTree = oldParentNode.children;\n v.current.parentVnode = parentNode;\n v.current.oldParentVnode = oldParentNode;\n\n // Flatten children\n for (let i = 0; i < newTree.length; i++) {\n let childVnode = newTree[i];\n\n if (isArray(childVnode)) {\n newTree.splice(i--, 1, ...childVnode);\n } else if (childVnode instanceof Vnode) {\n if (typeof childVnode.name === 'string') {\n childVnode.isSVG = parentNode.isSVG || childVnode.name === 'svg';\n } else {\n v.current.component = childVnode;\n newTree.splice(i--, 1, ...[(childVnode.name.view || childVnode.name).call(childVnode.name, childVnode.props, ...childVnode.children)]);\n }\n } else if (childVnode === null || childVnode === UND) {\n newTree.splice(i--, 1);\n }\n }\n\n if (newTree.length === 0) {\n if (oldTree.length > 0) {\n let i = oldTree.length;\n while (i--) {\n callRemove(oldTree[i]);\n }\n parentNode.dom.textContent = '';\n }\n\n // Is keyed list\n } else if (oldTree.length && newTree[0] instanceof Vnode && newTree[0].props.key) {\n let oldKeys = oldTree.map(vnode => vnode.props.key);\n let newKeys = newTree.map(vnode => vnode.props.key);\n\n for (let i = 0, l = newKeys.length; i < l; i++) {\n let key = newKeys[i];\n let newNode = newTree[i];\n\n // Updated: Same key\n if (key === oldKeys[i]) {\n oldTree[i].processed = true;\n updateKeyedNode(parentNode.dom, newNode, oldTree[i], i);\n } else {\n let oldIndex = oldKeys.indexOf(key);\n let newIndex = i >= oldKeys.length ? UND : i;\n\n // Moved: Key exists in old keys\n if (oldIndex !== -1) {\n oldTree[oldIndex].processed = true;\n updateKeyedNode(parentNode.dom, newNode, oldTree[oldIndex], newIndex);\n // Added: Key does not exists in old keys\n } else {\n updateKeyedNode(parentNode.dom, newNode, emptyNode, newIndex);\n }\n }\n }\n\n // Delete unprocessed old keys\n let l = oldTree.length;\n\n while (l--) {\n !oldTree[l].processed && removeVnode(oldTree[l]);\n }\n\n // Not keyed list or first render so use the simple algorithm\n } else {\n let i = oldTree.length;\n let l = newTree.length;\n\n // Remove deleted nodes\n while (i-- > l) {\n removeVnode(oldTree[i]);\n }\n\n for (i = 0; i < l; i++) {\n let newNode = newTree[i];\n let oldNode = oldTree[i];\n // Is vnode\n if (newNode instanceof Vnode) {\n if (!oldNode) {\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n parentNode.dom.appendChild(newNode.dom);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n } else {\n if (newNode.name === oldNode.name) {\n newNode.dom = oldNode.dom;\n if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, oldNode) === false) {\n newNode.children = oldNode.children;\n } else {\n removeProps(newNode, oldNode);\n updateProps(newNode, oldNode);\n lifecycleCall(newNode, v.isMounted ? onupdate : oncreate, oldNode);\n patch(newNode, oldNode);\n }\n } else {\n callRemove(oldNode);\n newNode.dom = createElement(newNode.name, newNode.isSVG);\n updateProps(newNode);\n parentNode.dom.replaceChild(newNode.dom, parentNode.dom.childNodes[i]);\n lifecycleCall(newNode, oncreate);\n patch(newNode, emptyNode);\n }\n }\n\n } else {\n let dom;\n\n // If we are getting a TextVnode could be from the domToVnode method\n let value = newNode.dom ? newNode.dom.nodeValue : String(newNode);\n\n if (oldNode instanceof TextVnode) {\n dom = oldNode.dom;\n if (value !== dom.nodeValue) {\n dom.nodeValue = value;\n }\n } else {\n dom = document.createTextNode(value);\n if (!oldNode) {\n parentNode.dom.appendChild(dom);\n } else {\n callRemove(oldNode);\n parentNode.dom.replaceChild(dom, oldNode.dom);\n }\n }\n newTree[i] = new TextVnode(dom);\n }\n }\n }\n\n parentNode.children = newTree;\n };\n\n v.update = (props, ...children) => {\n if (mainNode) {\n if (mountedComponent) {\n cleanupVnodes();\n oldMainNode = mainNode;\n mainNode = new Vnode(mainNode.name, mainNode.props, [v(mountedComponent, props, ...children)]);\n mainNode.dom = oldMainNode.dom;\n mainNode.isSVG = mainNode.name === 'svg';\n patch(mainNode, oldMainNode);\n v.isMounted = true;\n }\n\n return v.isNode && mainNode.dom.innerHTML;\n }\n };\n\n v.mount = (container, component, props, ...children) => {\n let mainContainer = v.isNode\n ? createElement('div')\n : typeof container === 'string'\n ? document.querySelectorAll(container)[0]\n : container;\n\n mainNode = v.domToVnode(mainContainer);\n mountedComponent = component;\n\n return v.update(props, ...children);\n };\n\n v.unMount = () => {\n mountedComponent = () => '';\n let result = v.update();\n mountedComponent = UND;\n v.isMounted = false;\n return result;\n };\n\n v.directive = (directive, handler) => {\n let directiveName = `v-${directive}`;\n if (v.reservedWords.indexOf(directiveName) === -1) {\n v.reservedWords.push(directiveName);\n directives[directiveName] = handler;\n }\n };\n\n let hideDirective = (test) => (bool, vnode, oldnode) => {\n let value = test ? bool : !bool;\n if (value) {\n let newdom = document.createTextNode('');\n if (oldnode && oldnode.dom && oldnode.dom.parentNode) {\n callRemove(oldnode);\n oldnode.dom.parentNode.replaceChild(newdom, oldnode.dom);\n }\n vnode.name = '';\n vnode.children = [];\n vnode.props = {};\n vnode.dom = newdom;\n }\n };\n\n v.directive('if', hideDirective(false));\n v.directive('unless', hideDirective(true));\n v.directive('for', (set, vnode) => vnode.children = set.map(vnode.children[0]));\n v.directive('show', (bool, vnode) => vnode.dom.style.display = bool ? '' : 'none');\n v.directive('class', (classes, vnode) => {\n for (let name in classes) {\n vnode.dom.classList.toggle(name, classes[name]);\n }\n });\n v.directive('html', (html, vnode) => vnode.children = v.trust(html));\n\n return v;\n}\n\nconst v = valyrian();\nv.newInstance = valyrian;\n\n(v.isNode ? global : window).v = v;\n"],"names":["valyrian","mainNode","oldMainNode","mountedComponent","UND","oncreate","onupdate","onremove","onbeforeupdate","functionstr","once","isArray","Array","directives","Vnode","name","props","children","this","TextVnode","dom","prototype","emptyNode","createElement","tag","isSVG","document","createElementNS","lifecycleCall","vnode","methodName","oldNode","callRemove","i","l","length","v","tagOrComponent","isNode","window","domToVnode","nodeType","forEach","call","attributes","prop","nodeName","nodeValue","childNodes","childVnode","push","trust","htmlString","div","innerHTML","trim","map","item","plugins","Map","usePlugin","plugin","options","has","set","reservedWords","attachedListeners","eventListener","e","target","type","defaultPrevented","update","parentNode","updateProps","newNode","updateProperty","removeProps","indexOf","removeAttribute","moveDom","$parent","oldDom","replaceChild","appendChild","removeVnode","removeChild","updateKeyedNode","compareNode","newIndex","isMounted","patch","value","addEventListener","slice","setAttribute","vnodesToCleanup","oldParentNode","newTree","oldTree","current","parentVnode","oldParentVnode","splice","component","view","textContent","key","oldKeys","newKeys","processed","oldIndex","String","createTextNode","onCleanup","callback","cleanupVnodes","mount","container","mainContainer","querySelectorAll","unMount","result","directive","handler","directiveName","hideDirective","test","bool","oldnode","newdom","style","display","classes","classList","toggle","html","newInstance","global"],"mappings":"yBAEA,SAASA,IACP,IAQIC,EACAC,EACAC,EAVAC,OAAM,EACNC,EAAW,WACXC,EAAW,WACXC,EAAW,WACXC,EAAiB,iBACjBC,EAAc,WACdC,EAAO,SACPC,EAAUC,MAAMD,QAIhBE,EAAa,GAEjB,SAASC,EAAMC,EAAMC,EAAOC,GAC1BC,KAAKF,MAAQA,GAAS,GACtBE,KAAKD,SAAWA,EAChBC,KAAKH,KAAOA,EAGd,SAASI,EAAUC,GACjBF,KAAKE,IAAMA,EAEbD,EAAUE,UAAY,CACpBL,MAAO,GACPC,SAAU,IAGZ,IAAIK,EAAY,IAAIH,EAEpB,SAASI,EAAcC,EAAKC,GAC1B,OAAOA,EACLC,SAASC,gBAAgB,6BAA8BH,GACvDE,SAASH,cAAcC,GAG3B,SAASI,EAAcC,EAAOC,EAAYC,GACxC,GAAIF,EAAMb,MAAMc,GACd,OAAOD,EAAMb,MAAMc,GAAYD,EAAOE,GAI1C,SAASC,EAAWH,GAClB,GAAIA,aAAiBf,EAAO,CAC1B,IAAK,IAAImB,EAAI,EAAGC,EAAIL,EAAMZ,SAASkB,OAAQF,EAAIC,EAAGD,IAChDD,EAAWH,EAAMZ,SAASgB,IAG5BJ,EAAMb,MAAc,UAAKa,EAAMb,MAAc,SAAEa,IAKnD,SAASO,EAAEC,EAAgBrB,KAAUC,GACnC,OAAO,IAAIH,EAAMuB,EAAgBrB,EAAOC,GAG1CmB,EAAEE,OAA2B,oBAAXC,OAGlBH,EAAEI,WAAapB,IACb,GAAqB,IAAjBA,EAAIqB,SACN,OAAO,IAAItB,EAAUC,GAGvB,GAAqB,IAAjBA,EAAIqB,SAAgB,CACtB,IAAIzB,EAAQ,GACZ,GAAG0B,QAAQC,KAAKvB,EAAIwB,WAAaC,GAAS7B,EAAM6B,EAAKC,UAAYD,EAAKE,WAEtE,IAAIlB,EAAQ,IAAIf,EACdM,EAAI0B,SACJ9B,EACA,IAEFa,EAAMT,IAAMA,EAEZ,IAAK,IAAIa,EAAI,EAAGC,EAAId,EAAI4B,WAAWb,OAAQF,EAAIC,EAAGD,IAAK,CACrD,IAAIgB,EAAab,EAAEI,WAAWpB,EAAI4B,WAAWf,IAC7CgB,GAAcpB,EAAMZ,SAASiC,KAAKD,GAEpC,OAAOpB,IAIXO,EAAEe,MAASC,IACT,IAAIC,EAAM9B,EAAc,OAGxB,OAFA8B,EAAIC,UAAYF,EAAWG,OAEpB,GAAGC,IAAIb,KAAKU,EAAIL,WAAaS,GAASrB,EAAEI,WAAWiB,KAI5D,IAAIC,EAAU,IAAIC,IAClBvB,EAAEwB,UAAY,CAACC,EAAQC,KAAaJ,EAAQK,IAAIF,IAAWH,EAAQM,IAAIH,GAAQ,IAASA,EAAOzB,EAAG0B,GAElG1B,EAAE6B,cAAgB,CAChB,MACAvD,EACAL,EACAG,EACAF,EACAC,EACA,QAGF,IAAI2D,EAAoB,GACxB,SAASC,EAAcC,GACrB,IAAIhD,EAAMgD,EAAEC,OACRtD,EAAO,OAAOqD,EAAEE,KACpB,KAAOlD,GAAK,CACV,GAAIA,EAAIL,GAKN,OAJAK,EAAIL,GAAMqD,EAAGhD,QACRgD,EAAEG,kBACLnC,EAAEoC,UAINpD,EAAMA,EAAIqD,YA4Bd,SAASC,EAAYC,EAAS5C,GAC5B,IAAK,IAAIhB,KAAQ4D,EAAQ3D,MACvBoB,EAAEwC,eAAe7D,EAAM4D,EAAS5C,GAIpC,SAAS8C,EAAYF,EAAS5C,GAC5B,IAAK,IAAIhB,KAAQgB,EAAQf,OACgB,IAAnCoB,EAAE6B,cAAca,QAAQ/D,IAAgBA,KAAQ4D,EAAQ3D,QAAU,UAAgBe,EAAQf,MAAMD,KAAUN,IACxGM,KAAQ4D,EAAQvD,IAClBuD,EAAQvD,IAAIL,GAAQX,EAEpBuE,EAAQvD,IAAI2D,gBAAgBhE,IAMpC,SAASiE,EAAQ5D,EAAK6D,EAASC,GACzB9D,IAAQ8D,IACVA,EACED,EAAQE,aAAa/D,EAAK8D,GAC1BD,EAAQG,YAAYhE,IAI1B,SAASiE,EAAYxD,GACnBG,EAAWH,GACXA,EAAMT,KAAOS,EAAMT,IAAIqD,YAAc5C,EAAMT,IAAIqD,WAAWa,YAAYzD,EAAMT,KAG9E,SAASmE,EAAgBN,EAASN,EAASa,EAAaC,GACtD,IAAIP,EAASD,EAAQjC,WAAWyC,GAE5BD,EAAYpE,KACduD,EAAQvD,IAAMoE,EAAYpE,IACtBuD,EAAQ3D,MAAMN,KAAiE,IAAxDkB,EAAc+C,EAASnE,EAAgBgF,IAChEb,EAAQ1D,SAAWuE,EAAYvE,SAC/B+D,EAAQL,EAAQvD,IAAK6D,EAASC,KAE9BL,EAAYF,EAASa,GACrBd,EAAYC,EAASa,GACrBR,EAAQL,EAAQvD,IAAK6D,EAASC,GAC9BtD,EAAc+C,EAASvC,EAAEsD,UAAYpF,EAAWD,EAAUmF,GAC1DG,EAAMhB,EAASa,MAGjBb,EAAQvD,IAAMG,EAAcoD,EAAQ5D,KAAM4D,EAAQlD,OAClDiD,EAAYC,GACZK,EAAQL,EAAQvD,IAAK6D,EAASC,GAC9BtD,EAAc+C,EAAStE,GACvBsF,EAAMhB,EAASrD,IA3EnBc,EAAEwC,eAAiB,CAAC7D,EAAM4D,EAAS5C,KACjC,GAAIhB,KAAQ4D,EAAQ3D,MAAO,CACzB,IAAI4E,EAAQjB,EAAQ3D,MAAMD,IACa,IAAnCqB,EAAE6B,cAAca,QAAQ/D,GACtBF,EAAWE,IACbF,EAAWE,GAAM6E,EAAOjB,EAAS5C,UAEnB6D,IAAUnF,GAErByD,EADLnD,EAAO,KAAKA,KAEVW,SAASmE,iBAAiB9E,EAAK+E,MAAM,GAAI3B,GACzCD,EAAkBnD,IAAQ,GAE5B4D,EAAQvD,IAAIL,GAAQ6E,GACX7E,KAAQ4D,EAAQvD,MAAQuD,EAAQlD,MACrCkD,EAAQvD,IAAIL,KAAU6E,IACxBjB,EAAQvD,IAAIL,GAAQ6E,GAEZ7D,GAAW6D,IAAU7D,EAAQf,MAAMD,IAC7C4D,EAAQvD,IAAI2E,aAAahF,EAAM6E,KA4DrC,IAAII,EAAkB,GA+BtB,SAASL,EAAMlB,EAAYwB,GACzB,IAAIC,EAAUvF,EAAQ8D,EAAWxD,UAAYwD,EAAWxD,SAAW,CAACwD,EAAWxD,UAC3EkF,EAAUF,EAAchF,SAC5BmB,EAAEgE,QAAQC,YAAc5B,EACxBrC,EAAEgE,QAAQE,eAAiBL,EAG3B,IAAK,IAAIhE,EAAI,EAAGA,EAAIiE,EAAQ/D,OAAQF,IAAK,CACvC,IAAIgB,EAAaiD,EAAQjE,GAErBtB,EAAQsC,GACViD,EAAQK,OAAOtE,IAAK,KAAMgB,GACjBA,aAAsBnC,EACA,iBAApBmC,EAAWlC,KACpBkC,EAAWxB,MAAQgD,EAAWhD,OAA6B,QAApBwB,EAAWlC,MAElDqB,EAAEgE,QAAQI,UAAYvD,EACtBiD,EAAQK,OAAOtE,IAAK,GAAQgB,EAAWlC,KAAK0F,MAAQxD,EAAWlC,MAAM4B,KAAKM,EAAWlC,KAAMkC,EAAWjC,SAAUiC,EAAWhC,YAErG,OAAfgC,GAAuBA,IAAe7C,GAC/C8F,EAAQK,OAAOtE,IAAK,GAIxB,GAAuB,IAAnBiE,EAAQ/D,QACV,GAAIgE,EAAQhE,OAAS,EAAG,CACtB,IAAIF,EAAIkE,EAAQhE,OAChB,KAAOF,KACLD,EAAWmE,EAAQlE,IAErBwC,EAAWrD,IAAIsF,YAAc,SAI1B,GAAIP,EAAQhE,QAAU+D,EAAQ,aAAcpF,GAASoF,EAAQ,GAAGlF,MAAM2F,IAAK,CAChF,IAAIC,EAAUT,EAAQ3C,IAAI3B,GAASA,EAAMb,MAAM2F,KAC3CE,EAAUX,EAAQ1C,IAAI3B,GAASA,EAAMb,MAAM2F,KAE/C,IAAK,IAAI1E,EAAI,EAAGC,EAAI2E,EAAQ1E,OAAQF,EAAIC,EAAGD,IAAK,CAC9C,IAAI0E,EAAME,EAAQ5E,GACd0C,EAAUuB,EAAQjE,GAGtB,GAAI0E,IAAQC,EAAQ3E,GAClBkE,EAAQlE,GAAG6E,WAAY,EACvBvB,EAAgBd,EAAWrD,IAAKuD,EAASwB,EAAQlE,GAAIA,OAChD,CACL,IAAI8E,EAAWH,EAAQ9B,QAAQ6B,GAC3BlB,EAAWxD,GAAK2E,EAAQzE,OAAS/B,EAAM6B,GAGzB,IAAd8E,GACFZ,EAAQY,GAAUD,WAAY,EAC9BvB,EAAgBd,EAAWrD,IAAKuD,EAASwB,EAAQY,GAAWtB,IAG5DF,EAAgBd,EAAWrD,IAAKuD,EAASrD,EAAWmE,IAM1D,IAAIvD,EAAIiE,EAAQhE,OAEhB,KAAOD,MACJiE,EAAQjE,GAAG4E,WAAazB,EAAYc,EAAQjE,QAI1C,CACL,IAAID,EAAIkE,EAAQhE,OACZD,EAAIgE,EAAQ/D,OAGhB,KAAOF,KAAMC,GACXmD,EAAYc,EAAQlE,IAGtB,IAAKA,EAAI,EAAGA,EAAIC,EAAGD,IAAK,CACtB,IAAI0C,EAAUuB,EAAQjE,GAClBF,EAAUoE,EAAQlE,GAEtB,GAAI0C,aAAmB7D,EAChBiB,EAOC4C,EAAQ5D,OAASgB,EAAQhB,MAC3B4D,EAAQvD,IAAMW,EAAQX,IAClBuD,EAAQ3D,MAAMN,KAA6D,IAApDkB,EAAc+C,EAASnE,EAAgBuB,GAChE4C,EAAQ1D,SAAWc,EAAQd,UAE3B4D,EAAYF,EAAS5C,GACrB2C,EAAYC,EAAS5C,GACrBH,EAAc+C,EAASvC,EAAEsD,UAAYpF,EAAWD,EAAU0B,GAC1D4D,EAAMhB,EAAS5C,MAGjBC,EAAWD,GACX4C,EAAQvD,IAAMG,EAAcoD,EAAQ5D,KAAM4D,EAAQlD,OAClDiD,EAAYC,GACZF,EAAWrD,IAAI+D,aAAaR,EAAQvD,IAAKqD,EAAWrD,IAAI4B,WAAWf,IACnEL,EAAc+C,EAAStE,GACvBsF,EAAMhB,EAASrD,KAtBjBqD,EAAQvD,IAAMG,EAAcoD,EAAQ5D,KAAM4D,EAAQlD,OAClDiD,EAAYC,GACZF,EAAWrD,IAAIgE,YAAYT,EAAQvD,KACnCQ,EAAc+C,EAAStE,GACvBsF,EAAMhB,EAASrD,QAsBZ,CACL,IAAIF,EAGAwE,EAAQjB,EAAQvD,IAAMuD,EAAQvD,IAAI2B,UAAYiE,OAAOrC,GAErD5C,aAAmBZ,GACrBC,EAAMW,EAAQX,IACVwE,IAAUxE,EAAI2B,YAChB3B,EAAI2B,UAAY6C,KAGlBxE,EAAMM,SAASuF,eAAerB,GACzB7D,GAGHC,EAAWD,GACX0C,EAAWrD,IAAI+D,aAAa/D,EAAKW,EAAQX,MAHzCqD,EAAWrD,IAAIgE,YAAYhE,IAM/B8E,EAAQjE,GAAK,IAAId,EAAUC,KAKjCqD,EAAWxD,SAAWiF,EApKxB9D,EAAE8E,UAAYC,IACZ,IAAId,EAAcjE,EAAEgE,QAAQC,YACvBA,EAAYa,YACfb,EAAYa,UAAY,IAG1Bb,EAAYa,UAAUhE,KAAKiE,IAEmB,IAA1CnB,EAAgBlB,QAAQuB,IAC1BL,EAAgB9C,KAAKmD,IAazBjE,EAAEgE,QAAU,CACVC,YAAajG,EACbkG,eAAgBlG,EAChBoG,UAAWpG,GA8IbgC,EAAEoC,OAAS,CAACxD,KAAUC,KACpB,GAAIhB,EAWF,OAVIE,KA5JR,WACE,IAAK,IAAI+B,EAAI8D,EAAgB7D,OAAQD,KACnC,IAAK,IAAIiF,KAAYnB,EAAgB9D,GAAGgF,UACtCC,IAGJnB,EAAkB,GAuJdoB,GACAlH,EAAcD,EACdA,EAAW,IAAIa,EAAMb,EAASc,KAAMd,EAASe,MAAO,CAACoB,EAAEjC,EAAkBa,KAAUC,KACnFhB,EAASmB,IAAMlB,EAAYkB,IAC3BnB,EAASwB,MAA0B,QAAlBxB,EAASc,KAC1B4E,EAAM1F,EAAUC,GAChBkC,EAAEsD,WAAY,GAGTtD,EAAEE,QAAUrC,EAASmB,IAAIkC,WAIpClB,EAAEiF,MAAQ,CAACC,EAAWd,EAAWxF,KAAUC,KACzC,IAAIsG,EAAgBnF,EAAEE,OAClBf,EAAc,OACO,iBAAd+F,EACL5F,SAAS8F,iBAAiBF,GAAW,GACrCA,EAKN,OAHArH,EAAWmC,EAAEI,WAAW+E,GACxBpH,EAAmBqG,EAEZpE,EAAEoC,OAAOxD,KAAUC,IAG5BmB,EAAEqF,QAAU,KACVtH,EAAmB,IAAM,GACzB,IAAIuH,EAAStF,EAAEoC,SAGf,OAFArE,EAAmBC,EACnBgC,EAAEsD,WAAY,EACPgC,GAGTtF,EAAEuF,UAAY,CAACA,EAAWC,KACxB,IAAIC,EAAgB,KAAKF,GACuB,IAA5CvF,EAAE6B,cAAca,QAAQ+C,KAC1BzF,EAAE6B,cAAcf,KAAK2E,GACrBhH,EAAWgH,GAAiBD,IAIhC,IAAIE,EAAiBC,GAAS,CAACC,EAAMnG,EAAOoG,KAE1C,GADYF,EAAOC,GAAQA,EAChB,CACT,IAAIE,EAASxG,SAASuF,eAAe,IACjCgB,GAAWA,EAAQ7G,KAAO6G,EAAQ7G,IAAIqD,aACxCzC,EAAWiG,GACXA,EAAQ7G,IAAIqD,WAAWU,aAAa+C,EAAQD,EAAQ7G,MAEtDS,EAAMd,KAAO,GACbc,EAAMZ,SAAW,GACjBY,EAAMb,MAAQ,GACda,EAAMT,IAAM8G,IAehB,OAXA9F,EAAEuF,UAAU,KAAMG,GAAc,IAChC1F,EAAEuF,UAAU,SAAUG,GAAc,IACpC1F,EAAEuF,UAAU,MAAO,CAAC3D,EAAKnC,IAAUA,EAAMZ,SAAW+C,EAAIR,IAAI3B,EAAMZ,SAAS,KAC3EmB,EAAEuF,UAAU,OAAQ,CAACK,EAAMnG,IAAUA,EAAMT,IAAI+G,MAAMC,QAAUJ,EAAO,GAAK,QAC3E5F,EAAEuF,UAAU,QAAS,CAACU,EAASxG,KAC7B,IAAK,IAAId,KAAQsH,EACfxG,EAAMT,IAAIkH,UAAUC,OAAOxH,EAAMsH,EAAQtH,MAG7CqB,EAAEuF,UAAU,OAAQ,CAACa,EAAM3G,IAAUA,EAAMZ,SAAWmB,EAAEe,MAAMqF,IAEvDpG,EAGT,MAAMA,EAAIpC,IACVoC,EAAEqG,YAAczI,GAEfoC,EAAEE,OAASoG,OAASnG,QAAQH,EAAIA"} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 959274c..4c9ded6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,13 +1,12 @@ - //eslint-disable-next-line max-lines-per-function function valyrian() { let UND = void 0; - let oncreate = 'oncreate'; - let onupdate = 'onupdate'; - let onremove = 'onremove'; - let onbeforeupdate = 'onbeforeupdate'; - let functionstr = 'function'; - let once = 'v-once'; + let oncreate = "oncreate"; + let onupdate = "onupdate"; + let onremove = "onremove"; + let onbeforeupdate = "onbeforeupdate"; + let functionstr = "function"; + let once = "v-once"; let isArray = Array.isArray; let mainNode; let oldMainNode; @@ -18,7 +17,7 @@ function valyrian() { this.props = props || {}; this.children = children; this.name = name; - }; + } function TextVnode(dom) { this.dom = dom; @@ -31,9 +30,9 @@ function valyrian() { let emptyNode = new TextVnode(); function createElement(tag, isSVG) { - return isSVG ? - document.createElementNS('http://www.w3.org/2000/svg', tag) : - document.createElement(tag); + return isSVG + ? document.createElementNS("http://www.w3.org/2000/svg", tag) + : document.createElement(tag); } function lifecycleCall(vnode, methodName, oldNode) { @@ -52,28 +51,26 @@ function valyrian() { } } - function v(tagOrComponent, props, ...children) { return new Vnode(tagOrComponent, props, children); - }; + } - v.isNode = typeof window === 'undefined'; + v.isNode = typeof window === "undefined"; // Hydrates the current dom before mount - v.domToVnode = dom => { + v.domToVnode = (dom) => { if (dom.nodeType === 3) { return new TextVnode(dom); } if (dom.nodeType === 1) { let props = {}; - [].forEach.call(dom.attributes, (prop) => props[prop.nodeName] = prop.nodeValue); - - let vnode = new Vnode( - dom.nodeName, - props, - [] + [].forEach.call( + dom.attributes, + (prop) => (props[prop.nodeName] = prop.nodeValue) ); + + let vnode = new Vnode(dom.nodeName, props, []); vnode.dom = dom; for (let i = 0, l = dom.childNodes.length; i < l; i++) { @@ -85,7 +82,7 @@ function valyrian() { }; v.trust = (htmlString) => { - let div = createElement('div'); + let div = createElement("div"); div.innerHTML = htmlString.trim(); return [].map.call(div.childNodes, (item) => v.domToVnode(item)); @@ -93,7 +90,8 @@ function valyrian() { // Plugin system let plugins = new Map(); - v.usePlugin = (plugin, options) => !plugins.has(plugin) && plugins.set(plugin, true) && plugin(v, options); + v.usePlugin = (plugin, options) => + !plugins.has(plugin) && plugins.set(plugin, true) && plugin(v, options); v.reservedWords = [ "key", @@ -119,7 +117,7 @@ function valyrian() { } dom = dom.parentNode; } - }; + } v.updateProperty = (name, newNode, oldNode) => { if (name in newNode.props) { @@ -133,7 +131,7 @@ function valyrian() { if (!attachedListeners[name]) { document.addEventListener(name.slice(4), eventListener); attachedListeners[name] = true; - }; + } newNode.dom[name] = value; } else if (name in newNode.dom && !newNode.isSVG) { if (newNode.dom[name] !== value) { @@ -153,7 +151,11 @@ function valyrian() { function removeProps(newNode, oldNode) { for (let name in oldNode.props) { - if (v.reservedWords.indexOf(name) === -1 && name in newNode.props === false && typeof oldNode.props[name] !== functionstr) { + if ( + v.reservedWords.indexOf(name) === -1 && + name in newNode.props === false && + typeof oldNode.props[name] !== functionstr + ) { if (name in newNode.dom) { newNode.dom[name] = UND; } else { @@ -165,15 +167,15 @@ function valyrian() { function moveDom(dom, $parent, oldDom) { if (dom !== oldDom) { - oldDom ? - $parent.replaceChild(dom, oldDom) : - $parent.appendChild(dom); + oldDom ? $parent.replaceChild(dom, oldDom) : $parent.appendChild(dom); } } function removeVnode(vnode) { callRemove(vnode); - vnode.dom && vnode.dom.parentNode && vnode.dom.parentNode.removeChild(vnode.dom); + vnode.dom && + vnode.dom.parentNode && + vnode.dom.parentNode.removeChild(vnode.dom); } function updateKeyedNode($parent, newNode, compareNode, newIndex) { @@ -181,7 +183,10 @@ function valyrian() { // Moved or updated if (compareNode.dom) { newNode.dom = compareNode.dom; - if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, compareNode) === false) { + if ( + newNode.props[once] || + lifecycleCall(newNode, onbeforeupdate, compareNode) === false + ) { newNode.children = compareNode.children; moveDom(newNode.dom, $parent, oldDom); } else { @@ -202,7 +207,7 @@ function valyrian() { let vnodesToCleanup = []; - v.onCleanup = callback => { + v.onCleanup = (callback) => { let parentVnode = v.current.parentVnode; if (!parentVnode.onCleanup) { parentVnode.onCleanup = []; @@ -216,7 +221,7 @@ function valyrian() { }; function cleanupVnodes() { - for (let l = vnodesToCleanup.length; l--;) { + for (let l = vnodesToCleanup.length; l--; ) { for (let callback of vnodesToCleanup[l].onCleanup) { callback(); } @@ -232,7 +237,9 @@ function valyrian() { // eslint-disable-next-line complexity,sonarjs/cognitive-complexity function patch(parentNode, oldParentNode) { - let newTree = isArray(parentNode.children) ? parentNode.children : [parentNode.children]; + let newTree = isArray(parentNode.children) + ? parentNode.children + : [parentNode.children]; let oldTree = oldParentNode.children; v.current.parentVnode = parentNode; v.current.oldParentVnode = oldParentNode; @@ -244,11 +251,21 @@ function valyrian() { if (isArray(childVnode)) { newTree.splice(i--, 1, ...childVnode); } else if (childVnode instanceof Vnode) { - if (typeof childVnode.name === 'string') { - childVnode.isSVG = parentNode.isSVG || childVnode.name === 'svg'; + if (typeof childVnode.name === "string") { + childVnode.isSVG = parentNode.isSVG || childVnode.name === "svg"; } else { v.current.component = childVnode; - newTree.splice(i--, 1, ...[(childVnode.name.view || childVnode.name).call(childVnode.name, childVnode.props, ...childVnode.children)]); + newTree.splice( + i--, + 1, + ...[ + (childVnode.name.view || childVnode.name).call( + childVnode.name, + childVnode.props, + ...childVnode.children + ) + ] + ); } } else if (childVnode === null || childVnode === UND) { newTree.splice(i--, 1); @@ -261,13 +278,17 @@ function valyrian() { while (i--) { callRemove(oldTree[i]); } - parentNode.dom.textContent = ''; + parentNode.dom.textContent = ""; } - // Is keyed list - } else if (oldTree.length && newTree[0] instanceof Vnode && newTree[0].props.key) { - let oldKeys = oldTree.map(vnode => vnode.props.key); - let newKeys = newTree.map(vnode => vnode.props.key); + // Is keyed list + } else if ( + oldTree.length && + newTree[0] instanceof Vnode && + newTree[0].props.key + ) { + let oldKeys = oldTree.map((vnode) => vnode.props.key); + let newKeys = newTree.map((vnode) => vnode.props.key); for (let i = 0, l = newKeys.length; i < l; i++) { let key = newKeys[i]; @@ -284,8 +305,13 @@ function valyrian() { // Moved: Key exists in old keys if (oldIndex !== -1) { oldTree[oldIndex].processed = true; - updateKeyedNode(parentNode.dom, newNode, oldTree[oldIndex], newIndex); - // Added: Key does not exists in old keys + updateKeyedNode( + parentNode.dom, + newNode, + oldTree[oldIndex], + newIndex + ); + // Added: Key does not exists in old keys } else { updateKeyedNode(parentNode.dom, newNode, emptyNode, newIndex); } @@ -299,7 +325,7 @@ function valyrian() { !oldTree[l].processed && removeVnode(oldTree[l]); } - // Not keyed list or first render so use the simple algorithm + // Not keyed list or first render so use the simple algorithm } else { let i = oldTree.length; let l = newTree.length; @@ -323,24 +349,33 @@ function valyrian() { } else { if (newNode.name === oldNode.name) { newNode.dom = oldNode.dom; - if (newNode.props[once] || lifecycleCall(newNode, onbeforeupdate, oldNode) === false) { + if ( + newNode.props[once] || + lifecycleCall(newNode, onbeforeupdate, oldNode) === false + ) { newNode.children = oldNode.children; } else { removeProps(newNode, oldNode); updateProps(newNode, oldNode); - lifecycleCall(newNode, v.isMounted ? onupdate : oncreate, oldNode); + lifecycleCall( + newNode, + v.isMounted ? onupdate : oncreate, + oldNode + ); patch(newNode, oldNode); } } else { callRemove(oldNode); newNode.dom = createElement(newNode.name, newNode.isSVG); updateProps(newNode); - parentNode.dom.replaceChild(newNode.dom, parentNode.dom.childNodes[i]); + parentNode.dom.replaceChild( + newNode.dom, + parentNode.dom.childNodes[i] + ); lifecycleCall(newNode, oncreate); patch(newNode, emptyNode); } } - } else { let dom; @@ -367,16 +402,18 @@ function valyrian() { } parentNode.children = newTree; - }; + } v.update = (props, ...children) => { if (mainNode) { if (mountedComponent) { cleanupVnodes(); oldMainNode = mainNode; - mainNode = new Vnode(mainNode.name, mainNode.props, [v(mountedComponent, props, ...children)]); + mainNode = new Vnode(mainNode.name, mainNode.props, [ + v(mountedComponent, props, ...children) + ]); mainNode.dom = oldMainNode.dom; - mainNode.isSVG = mainNode.name === 'svg'; + mainNode.isSVG = mainNode.name === "svg"; patch(mainNode, oldMainNode); v.isMounted = true; } @@ -387,10 +424,10 @@ function valyrian() { v.mount = (container, component, props, ...children) => { let mainContainer = v.isNode - ? createElement('div') - : typeof container === 'string' - ? document.querySelectorAll(container)[0] - : container; + ? createElement("div") + : typeof container === "string" + ? document.querySelectorAll(container)[0] + : container; mainNode = v.domToVnode(mainContainer); mountedComponent = component; @@ -399,7 +436,7 @@ function valyrian() { }; v.unMount = () => { - mountedComponent = () => ''; + mountedComponent = () => ""; let result = v.update(); mountedComponent = UND; v.isMounted = false; @@ -417,28 +454,34 @@ function valyrian() { let hideDirective = (test) => (bool, vnode, oldnode) => { let value = test ? bool : !bool; if (value) { - let newdom = document.createTextNode(''); + let newdom = document.createTextNode(""); if (oldnode && oldnode.dom && oldnode.dom.parentNode) { callRemove(oldnode); oldnode.dom.parentNode.replaceChild(newdom, oldnode.dom); } - vnode.name = ''; + vnode.name = ""; vnode.children = []; vnode.props = {}; vnode.dom = newdom; } }; - v.directive('if', hideDirective(false)); - v.directive('unless', hideDirective(true)); - v.directive('for', (set, vnode) => vnode.children = set.map(vnode.children[0])); - v.directive('show', (bool, vnode) => vnode.dom.style.display = bool ? '' : 'none'); - v.directive('class', (classes, vnode) => { + v.directive("if", hideDirective(false)); + v.directive("unless", hideDirective(true)); + v.directive( + "for", + (set, vnode) => (vnode.children = set.map(vnode.children[0])) + ); + v.directive( + "show", + (bool, vnode) => (vnode.dom.style.display = bool ? "" : "none") + ); + v.directive("class", (classes, vnode) => { for (let name in classes) { vnode.dom.classList.toggle(name, classes[name]); } }); - v.directive('html', (html, vnode) => vnode.children = v.trust(html)); + v.directive("html", (html, vnode) => (vnode.children = v.trust(html))); return v; } diff --git a/package.json b/package.json index 9953dad..598f7da 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ }, "scripts": { "dev:source": "cross-env NODE_ENV=development node rollupSource.js", - "dev:scratchpad": "cross-env NODE_ENV=development nodemon -w ./test -w ./lib -w ./plugins -w ./scratchpad.js --exec 'mocha --timeout 10000 --slow 0 --require @babel/register --require esm \"scratchpad.js\"'", "dev:test": "cross-env NODE_ENV=development nodemon -w ./test -w ./lib -w ./plugins --exec 'mocha --bail --timeout 10000 --slow 0 --require @babel/register \"test/**/*_test.js\"'", "dev:test:nyc": "cross-env NODE_ENV=development nodemon -w ./test -w ./lib -w ./plugins --exec 'nyc --reporter=text --reporter=lcov mocha --timeout 10000 --slow 0 --require @babel/register \"test/**/*_test.js\"'", "build": "yarn build:source && yarn remark", diff --git a/plugins/hooks.js b/plugins/hooks.js index c5443aa..4fbdb01 100644 --- a/plugins/hooks.js +++ b/plugins/hooks.js @@ -1,11 +1,11 @@ let plugin = function (v) { let UND; - v.createHook = function ({name, init, update, response}) { + v.createHook = function ({ name, init, update, response }) { name = `use${name.charAt(0).toUpperCase()}${name.slice(1).toLowerCase()}`; if (!v[name]) { v[name] = (...args) => { - let {component, parentVnode, oldParentVnode} = v.current; + let { component, parentVnode, oldParentVnode } = v.current; if (parentVnode.components === UND) { parentVnode.components = []; @@ -16,16 +16,27 @@ let plugin = function (v) { } let hook; - let oldComponentNode = oldParentVnode.components && oldParentVnode.components[parentVnode.components.length - 1]; - let oldMethod = oldComponentNode && ('view' in oldComponentNode.name ? oldComponentNode.name.view : oldComponentNode.name); - let currentMethod = 'view' in component.name ? component.name.view : component.name; + let oldComponentNode = + oldParentVnode.components && + oldParentVnode.components[parentVnode.components.length - 1]; + let oldMethod = + oldComponentNode && + ("view" in oldComponentNode.name + ? oldComponentNode.name.view + : oldComponentNode.name); + let currentMethod = + "view" in component.name ? component.name.view : component.name; if (component.hooks === UND) { component.hooks = []; } let hookIndex = component.hooks.length; - if (oldMethod === currentMethod && 'hooks' in oldComponentNode && oldComponentNode.hooks[hookIndex] !== UND) { + if ( + oldMethod === currentMethod && + "hooks" in oldComponentNode && + oldComponentNode.hooks[hookIndex] !== UND + ) { component.hooks = oldComponentNode.hooks; hook = oldComponentNode.hooks[hookIndex]; if (update) { @@ -45,24 +56,24 @@ let plugin = function (v) { function createStateHook(value) { let state = value; - let setState = value => state = value; + let setState = (value) => (state = value); let stateObj = Object.create(null); - stateObj.toJSON = stateObj.toString = stateObj.valueOf = () => typeof state === 'function' ? state() : state; + stateObj.toJSON = stateObj.toString = stateObj.valueOf = () => + typeof state === "function" ? state() : state; return [stateObj, setState]; } v.createHook({ - name: 'state', + name: "state", init: (initial) => createStateHook(initial), response: (hook) => hook }); - // Effect hook function callHook(hook, changes) { - let {prev} = hook; + let { prev } = hook; if (!changes) { hook.onCleanup = hook.effect(); } else if (changes.length > 0) { @@ -75,20 +86,19 @@ let plugin = function (v) { } } - if (typeof hook.onCleanup === 'function') { + if (typeof hook.onCleanup === "function") { v.onCleanup(hook.onCleanup); } } v.createHook({ - name: 'effect', + name: "effect", init: (effect, changes) => { - let hook = {effect, prev: changes}; + let hook = { effect, prev: changes }; callHook(hook); return hook; }, update: (hook, effect, changes) => callHook(hook, changes) }); - }; plugin.default = plugin; diff --git a/plugins/node.js b/plugins/node.js index 9560ffa..2a408fa 100644 --- a/plugins/node.js +++ b/plugins/node.js @@ -1,20 +1,19 @@ -let fs = require('fs'); -let path = require('path'); +let fs = require("fs"); +let path = require("path"); -let CleanCSS = require('clean-css'); -let {PurgeCSS} = require('purgecss'); -let fetch = require('node-fetch'); -let FormData = require('form-data'); +let CleanCSS = require("clean-css"); +let { PurgeCSS } = require("purgecss"); +let fetch = require("node-fetch"); +let FormData = require("form-data"); -let {Document, parseHtml} = require('./utils/dom'); -let treeAdapter = require('./utils/tree-adapter'); -let requestPlugin = require('./request'); +let { Document, parseHtml } = require("./utils/dom"); +let treeAdapter = require("./utils/tree-adapter"); +let requestPlugin = require("./request"); global.fetch = fetch; global.FormData = FormData; global.document = new Document(); - let errorHandler = (resolve, reject) => (err) => { if (err) { return reject(err); @@ -24,28 +23,29 @@ let errorHandler = (resolve, reject) => (err) => { }; function fileMethodFactory() { - let prop = ''; + let prop = ""; return function (file) { if (!file) { return prop; } - let contents = ''; - if (typeof file === 'string') { - contents = fs.readFileSync(file, 'utf8'); + let contents = ""; + if (typeof file === "string") { + contents = fs.readFileSync(file, "utf8"); } - if (typeof file === 'object' && 'raw' in file) { + if (typeof file === "object" && "raw" in file) { contents = file.raw; } - return prop += contents; + prop += contents; + return prop; }; } function inline(...args) { return args.map((item) => { - let ext = item.split('.').pop(); + let ext = item.split(".").pop(); if (!inline[ext]) { inline[ext] = fileMethodFactory(); } @@ -57,7 +57,7 @@ inline.css = fileMethodFactory(); inline.js = fileMethodFactory(); inline.uncss = (function () { - let prop = ''; + let prop = ""; return function (renderedHtml, options = {}) { if (!renderedHtml) { return prop; @@ -78,19 +78,20 @@ inline.uncss = (function () { let contents = html.map((item) => { return { raw: item, - extension: 'html' + extension: "html" }; }); let purgecss = new PurgeCSS(); let output = await purgecss.purge({ content: contents, - css: [{raw: opt.raw}], + css: [{ raw: opt.raw }], fontFace: true, keyframes: true, variables: true, whitelistPatterns: opt.ignore, - defaultExtractor: (content) => content.match(/[A-Za-z0-9-_/:@]*[A-Za-z0-9-_/]+/g) || [], + defaultExtractor: (content) => + content.match(/[A-Za-z0-9-_/:@]*[A-Za-z0-9-_/]+/g) || [], ...opt.purgecssOptions }); @@ -103,14 +104,14 @@ inline.uncss = (function () { level: { 1: { // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false` - roundingPrecision: 'all=3', - specialComments: 'none' // denotes a number of /*! ... */ comments preserved; defaults to `all` + roundingPrecision: "all=3", + specialComments: "none" // denotes a number of /*! ... */ comments preserved; defaults to `all` }, 2: { restructureRules: true // controls rule restructuring; defaults to false } }, - compatibility: 'ie11', + compatibility: "ie11", ...opt.cleanCssOptions }).minify(prop).styles; @@ -119,38 +120,38 @@ inline.uncss = (function () { return asyncMethod(); }; -}()); +})(); function sw(file, options = {}) { - let swfiletemplate = path.resolve(__dirname, './node.sw.tpl.js'); - let swTpl = fs.readFileSync(swfiletemplate, 'utf8'); + let swfiletemplate = path.resolve(__dirname, "./node.sw.tpl.js"); + let swTpl = fs.readFileSync(swfiletemplate, "utf8"); let opt = Object.assign( { - version: 'v1::', - name: 'Valyrian.js', - urls: ['/'], + version: "v1::", + name: "Valyrian.js", + urls: ["/"], debug: false }, options ); let contents = swTpl - .replace('v1::', 'v' + opt.version + '::') - .replace('Valyrian.js', opt.name) + .replace("v1::", "v" + opt.version + "::") + .replace("Valyrian.js", opt.name) .replace("['/']", '["' + opt.urls.join('","') + '"]'); if (!opt.debug) { - contents = contents.replace('console.log', '() => {}'); + contents = contents.replace("console.log", "() => {}"); } return new Promise((resolve, reject) => { - fs.writeFile(file, contents, 'utf8', errorHandler(resolve, reject)); + fs.writeFile(file, contents, "utf8", errorHandler(resolve, reject)); }); } function parseDom(childNodes, depth = 1) { - let spaces = ''; + let spaces = ""; for (let i = 0; i < depth; i++) { - spaces += ' '; + spaces += " "; } return childNodes @@ -170,10 +171,10 @@ function parseDom(childNodes, depth = 1) { } str += JSON.stringify(attrs); } else { - str += '{}'; + str += "{}"; } - str += ', ['; + str += ", ["; if (item.childNodes && item.childNodes.length > 0) { str += `${parseDom(item.childNodes, depth + 1)}\n${spaces}`; } @@ -182,23 +183,23 @@ function parseDom(childNodes, depth = 1) { return str; } }) - .join(','); + .join(","); } function htmlToHyperscript(html) { - return `[${parseDom(parseHtml(html, {treeAdapter}))}\n]`; + return `[${parseDom(parseHtml(html, { treeAdapter }))}\n]`; } function icons(source, configuration = {}) { - let favicons = require('favicons'), + let favicons = require("favicons"), options = Object.assign({}, icons.options, configuration); if (options.iconsPath) { - options.iconsPath = options.iconsPath.replace(/\/$/gi, '') + '/'; + options.iconsPath = options.iconsPath.replace(/\/$/gi, "") + "/"; } if (options.linksViewPath) { - options.linksViewPath = options.linksViewPath.replace(/\/$/gi, '') + '/'; + options.linksViewPath = options.linksViewPath.replace(/\/$/gi, "") + "/"; } async function processResponse(response, options) { @@ -232,7 +233,7 @@ function icons(source, configuration = {}) { if (options.linksViewPath) { let html = ` function Links(){ - return ${htmlToHyperscript(response.html.join(''))}; + return ${htmlToHyperscript(response.html.join(""))}; } Links.default = Links; @@ -241,7 +242,11 @@ module.exports = Links; promises.push( new Promise((resolve, reject) => { - fs.writeFile(`${options.linksViewPath}/links.js`, html, errorHandler(resolve, reject)); + fs.writeFile( + `${options.linksViewPath}/links.js`, + html, + errorHandler(resolve, reject) + ); }) ); } @@ -252,9 +257,9 @@ module.exports = Links; return new Promise((resolve, reject) => { favicons(source, options, (err, response) => { if (err) { - process.stdout.write(err.status + '\n'); // HTTP error code (e.g. `200`) or `null` - process.stdout.write(err.name + '\n'); // Error name e.g. "API Error" - process.stdout.write(err.message + '\n'); // Error description e.g. "An unknown error has occurred" + process.stdout.write(err.status + "\n"); // HTTP error code (e.g. `200`) or `null` + process.stdout.write(err.name + "\n"); // Error name e.g. "API Error" + process.stdout.write(err.message + "\n"); // Error description e.g. "An unknown error has occurred" return reject(err); } @@ -273,19 +278,19 @@ icons.options = { linksViewPath: null, // Path to the generated links file // favicons options - path: '', // Path for overriding default icons path. `string` + path: "", // Path for overriding default icons path. `string` appName: null, // Your application's name. `string` appDescription: null, // Your application's description. `string` developerName: null, // Your (or your developer's) name. `string` developerURL: null, - dir: 'auto', - lang: 'en-US', - background: '#fff', // Background colour for flattened icons. `string` - theme_color: '#fff', - display: 'standalone', // Android display: "browser" or "standalone". `string` - orientation: 'any', // Android orientation: "any" "portrait" or "landscape". `string` - start_url: '/', // Android start application's URL. `string` - version: '1.0', // Your application's version number. `number` + dir: "auto", + lang: "en-US", + background: "#fff", // Background colour for flattened icons. `string` + theme_color: "#fff", + display: "standalone", // Android display: "browser" or "standalone". `string` + orientation: "any", // Android orientation: "any" "portrait" or "landscape". `string` + start_url: "/", // Android start application's URL. `string` + version: "1.0", // Your application's version number. `number` logging: false, // Print logs to console? `boolean` icons: { android: true, // Create Android homescreen icon. `boolean` diff --git a/plugins/node.sw.tpl.js b/plugins/node.sw.tpl.js index ba318c5..e4a475d 100644 --- a/plugins/node.sw.tpl.js +++ b/plugins/node.sw.tpl.js @@ -47,9 +47,7 @@ async function fetchRequest(event) { return cachedResponse; } } catch (error) { - Log( - "WORKER: cache request failed.", error - ); + Log("WORKER: cache request failed.", error); } Log( @@ -90,7 +88,8 @@ self.addEventListener("fetch", (event) => { self.addEventListener("install", (event) => { Log("WORKER: Version install", cacheName); event.waitUntil( - caches.open(cacheName) + caches + .open(cacheName) .then((cache) => cache.addAll(config.urls)) // IMPORTANT: `skipWaiting()` forces the waiting ServiceWorker to become the // active ServiceWorker, triggering the `onactivate` event. @@ -104,12 +103,14 @@ self.addEventListener("install", (event) => { // got refreshed. Since we call `skipWaiting()` in `oninstall`, `onactivate` is // called immediately. self.addEventListener("activate", (event) => { - self.clients.matchAll({ - includeUncontrolled: true - }).then((clientList) => { - urls = clientList.map(client => client.url); - Log('WORKER: Matching clients:', urls.join(', ')); - }); + self.clients + .matchAll({ + includeUncontrolled: true + }) + .then((clientList) => { + urls = clientList.map((client) => client.url); + Log("WORKER: Matching clients:", urls.join(", ")); + }); event.waitUntil( caches diff --git a/plugins/request.js b/plugins/request.js index d8a00ed..f87bdf3 100644 --- a/plugins/request.js +++ b/plugins/request.js @@ -1,9 +1,9 @@ let plugin = function (v) { - let Request = function (baseUrl = '', options = {}) { - let url = baseUrl.replace(/\/$/gi, '').trim(), + let Request = function (baseUrl = "", options = {}) { + let url = baseUrl.replace(/\/$/gi, "").trim(), opts = Object.assign( { - methods: ['get', 'post', 'put', 'patch', 'delete'] + methods: ["get", "post", "put", "patch", "delete"] }, options ), @@ -13,15 +13,15 @@ let plugin = function (v) { let e = encodeURIComponent; return Object.keys(obj) .map((p) => { - let k = prefix ? prefix + '[' + p + ']' : p; + let k = prefix ? prefix + "[" + p + "]" : p; - if (typeof obj[p] === 'object') { + if (typeof obj[p] === "object") { return serialize(obj[p], k); } - return e(k) + '=' + e(obj[p]); + return e(k) + "=" + e(obj[p]); }) - .join('&'); + .join("&"); } async function request(method, url, data, options = {}) { @@ -36,22 +36,23 @@ let plugin = function (v) { ); if (!opts.headers.Accept) { - opts.headers.Accept = 'application/json'; + opts.headers.Accept = "application/json"; } let acceptType = opts.headers.Accept; - let contentType = opts.headers['Content-Type'] || opts.headers['content-type'] || ''; + let contentType = + opts.headers["Content-Type"] || opts.headers["content-type"] || ""; if (opts.methods.indexOf(method) === -1) { - throw new Error('Method not allowed'); + throw new Error("Method not allowed"); } if (data) { - if (opts.method === 'get' && typeof data === 'object') { - url += '?' + serialize(data); + if (opts.method === "get" && typeof data === "object") { + url += "?" + serialize(data); } - if (opts.method !== 'get') { + if (opts.method !== "get") { if (/json/gi.test(contentType)) { opts.body = JSON.stringify(data); } else { @@ -95,16 +96,13 @@ let plugin = function (v) { parseUrl = function (url) { let u = /^https?/gi.test(url) ? url - : (request.urls.base + url) - .trim() - .replace(/^\/\//gi, '/') - .trim(); + : (request.urls.base + url).trim().replace(/^\/\//gi, "/").trim(); - if (v.isNode && typeof request.urls.node === 'string') { - request.urls.node = request.urls.node.replace(/\/$/gi, '').trim(); + if (v.isNode && typeof request.urls.node === "string") { + request.urls.node = request.urls.node.replace(/\/$/gi, "").trim(); - if (typeof request.urls.api === 'string') { - request.urls.api = request.urls.api.replace(/\/$/gi, '').trim(); + if (typeof request.urls.api === "string") { + request.urls.api = request.urls.api.replace(/\/$/gi, "").trim(); u = u.replace(request.urls.api, request.urls.node); } @@ -126,7 +124,11 @@ let plugin = function (v) { request.urls.base = url; request.options = opts; - opts.methods.forEach((method) => (request[method] = (url, data, options) => request(method, url, data, options))); + opts.methods.forEach( + (method) => + (request[method] = (url, data, options) => + request(method, url, data, options)) + ); return request; }; diff --git a/plugins/router.js b/plugins/router.js index 5520fbd..92bbfc8 100644 --- a/plugins/router.js +++ b/plugins/router.js @@ -1,5 +1,3 @@ - - let plugin = function (v) { function flat(array) { return Array.isArray(array) ? array.flat(Infinity) : [array]; @@ -10,7 +8,7 @@ let plugin = function (v) { return; } - let realpath = path.replace(/(\S)(\/+)$/, '$1'); + let realpath = path.replace(/(\S)(\/+)$/, "$1"); // Find the express like params let params = realpath.match(/:(\w+)?/gi) || []; @@ -20,27 +18,25 @@ let plugin = function (v) { params[i] = params[i].slice(1); } - let regexpPath = '^' + realpath - .replace(/:(\w+)/gi, '([^\\/\\s]+)') - + '$'; + let regexpPath = "^" + realpath.replace(/:(\w+)/gi, "([^\\/\\s]+)") + "$"; router.paths.push({ method, path: realpath, middlewares: flat(middlewares), params, - regexp: new RegExp(regexpPath, 'i') + regexp: new RegExp(regexpPath, "i") }); }; function parseQuery(queryParts) { - let parts = queryParts ? queryParts.split('&', 20) : []; + let parts = queryParts ? queryParts.split("&", 20) : []; let query = {}; let i = 0; let nameValue; for (; i < parts.length; i++) { - nameValue = parts[i].split('=', 2); + nameValue = parts[i].split("=", 2); query[nameValue[0]] = nameValue[1]; } @@ -57,7 +53,7 @@ let plugin = function (v) { let params = {}; let matches = []; router.params = {}; - router.path = ''; + router.path = ""; router.matches = []; // Search for middlewares @@ -80,7 +76,7 @@ let plugin = function (v) { matches.push(match.shift()); } - if (item.method === 'get') { + if (item.method === "get") { router.path = item.path; break; } @@ -109,7 +105,7 @@ let plugin = function (v) { response = await middlewares[i](req, response); if (response !== undefined) { - if (!response.view && typeof response === 'function') { + if (!response.view && typeof response === "function") { response.view = response; } @@ -126,11 +122,11 @@ let plugin = function (v) { const router = { paths: [], get(path, ...args) { - addPath(router, 'get', path, args); + addPath(router, "get", path, args); return router; }, use(...args) { - let path = typeof args[0] === 'string' ? args.shift() : '/'; + let path = typeof args[0] === "string" ? args.shift() : "/"; let i; let k; let subrouter; @@ -139,12 +135,12 @@ let plugin = function (v) { for (i = 0; i < args.length; i++) { subrouter = args[i]; - if (typeof subrouter === 'function') { - addPath(router, 'use', `${path}.*`, [subrouter]); + if (typeof subrouter === "function") { + addPath(router, "use", `${path}.*`, [subrouter]); } else if (subrouter.paths) { for (k = 0; k < subrouter.paths.length; k++) { item = subrouter.paths[k]; - subpath = `${path}${item.path}`.replace(/^\/\//, '/'); + subpath = `${path}${item.path}`.replace(/^\/\//, "/"); addPath(router, item.method, subpath, item.middlewares); } } @@ -153,7 +149,7 @@ let plugin = function (v) { return router; }, async go(path) { - let parts = path.split('?', 2); + let parts = path.split("?", 2); let urlParts = parts[0]; let queryParts = parts[1]; router.url = path; @@ -210,16 +206,16 @@ let plugin = function (v) { function onPopStateGoToRoute() { v.routes.go(document.location.pathname); } - window.addEventListener('popstate', onPopStateGoToRoute, false); + window.addEventListener("popstate", onPopStateGoToRoute, false); onPopStateGoToRoute(); } } }; - v.routes.url = ''; + v.routes.url = ""; v.routes.params = {}; v.routes.query = {}; - v.routes.path = ''; + v.routes.path = ""; v.routes.matches = []; v.routes.go = function (...args) { @@ -228,19 +224,19 @@ let plugin = function (v) { if (args[0]) { let arg = args[0]; - let viewMethod = 'view' in Object(arg) ? arg.view : arg; + let viewMethod = "view" in Object(arg) ? arg.view : arg; - if (typeof viewMethod === 'function') { + if (typeof viewMethod === "function") { parentComponent = args.shift(); } } - if (typeof args[0] === 'string') { + if (typeof args[0] === "string") { url = args.shift(); } if (!url) { - throw new Error('v.router.url.required'); + throw new Error("v.router.url.required"); } return runRoute(parentComponent, url, args); @@ -249,24 +245,21 @@ let plugin = function (v) { v.routes.get = function () { let routes = []; mainRouter.paths.forEach((path) => { - if (path.method === 'get') { + if (path.method === "get") { routes.push(path.path); } }); return routes; }; - v.directive('route', (url, vnode, oldnode) => { + v.directive("route", (url, vnode, oldnode) => { vnode.props.href = url; vnode.props.onclick = (e) => { - if (typeof url === 'string' && url.length > 0) { - if (url.charAt(0) !== '/') { - let current = v.routes.current - .split('?', 2) - .shift() - .split('/'); + if (typeof url === "string" && url.length > 0) { + if (url.charAt(0) !== "/") { + let current = v.routes.current.split("?", 2).shift().split("/"); current.pop(); - url = `${current.join('/')}/${url}`; + url = `${current.join("/")}/${url}`; } v.routes.go(url); @@ -274,10 +267,9 @@ let plugin = function (v) { e.preventDefault(); }; - v.updateProperty('href', vnode, oldnode); - v.updateProperty('onclick', vnode, oldnode); + v.updateProperty("href", vnode, oldnode); + v.updateProperty("onclick", vnode, oldnode); }); - }; plugin.default = plugin; diff --git a/plugins/signals.js b/plugins/signals.js index 876ca64..2dce708 100644 --- a/plugins/signals.js +++ b/plugins/signals.js @@ -2,7 +2,7 @@ let plugin = function (v) { let signals = new Map(); function makeUnsubscribe(subscriptions, computed, handler, cleanup) { - if (typeof cleanup === 'function') { + if (typeof cleanup === "function") { computed.cleanup = cleanup; } computed.unsubscribe = () => { @@ -12,7 +12,7 @@ let plugin = function (v) { } function createGetter(signal, subscriptions, getters, nameOrHandler, getter) { - if (typeof nameOrHandler === 'function') { + if (typeof nameOrHandler === "function") { if (subscriptions.has(nameOrHandler) === false) { let computed = v.Signal(() => nameOrHandler(signal.value)); let cleanup = computed(); // Execute to register itself @@ -24,7 +24,7 @@ let plugin = function (v) { } if (nameOrHandler in getters) { - throw new Error('Named computed already exists.'); + throw new Error("Named computed already exists."); } getters[nameOrHandler] = getter; @@ -32,7 +32,7 @@ let plugin = function (v) { // eslint-disable-next-line sonarjs/cognitive-complexity v.Signal = function (value, key) { - if (typeof key !== 'undefined' && signals.has(key)) { + if (typeof key !== "undefined" && signals.has(key)) { let signal = signals.get(key); signal.cleanup(); return signal; @@ -43,64 +43,81 @@ let plugin = function (v) { let forceUpdate = false; - let signal = new Proxy(function (valOrPath, handler) { - if (typeof valOrPath === 'undefined') { - return signal.value; - } else if (typeof valOrPath === 'function') { - return createGetter(signal, subscriptions, getters, valOrPath); - } else if (typeof valOrPath === 'string' && typeof handler !== 'undefined') { - let parsed = valOrPath.split('.'); - let result = signal.value; - let next; - while (parsed.length) { - next = parsed.shift(); - if (parsed.length > 0) { - if (typeof result[next] !== 'object') { - result[next] = {}; + let signal = new Proxy( + function (valOrPath, handler) { + if (typeof valOrPath === "undefined") { + return signal.value; + } else if (typeof valOrPath === "function") { + return createGetter(signal, subscriptions, getters, valOrPath); + } else if ( + typeof valOrPath === "string" && + typeof handler !== "undefined" + ) { + let parsed = valOrPath.split("."); + let result = signal.value; + let next; + while (parsed.length) { + next = parsed.shift(); + if (parsed.length > 0) { + if (typeof result[next] !== "object") { + result[next] = {}; + } + result = result[next]; + } else { + result[next] = + typeof handler === "function" ? handler(result[next]) : handler; } - result = result[next]; - } else { - result[next] = typeof handler === 'function' ? handler(result[next]) : handler; } + forceUpdate = true; + signal.value = signal.value; + } else { + signal.value = valOrPath; } - forceUpdate = true; - signal.value = signal.value; - } else { - signal.value = valOrPath; - } - }, { - set(state, prop, val) { - if (prop === 'value' || prop === 'unsubscribe' || prop === 'cleanup') { - let old = state[prop]; - state[prop] = val; - if (prop === 'value' && (forceUpdate || val !== old)) { - forceUpdate = false; - for (let [handler, computed] of subscriptions) { - computed.cleanup(); - let cleanup = handler(val); - makeUnsubscribe(subscriptions, computed, handler, cleanup); + }, + { + set(state, prop, val) { + if ( + prop === "value" || + prop === "unsubscribe" || + prop === "cleanup" + ) { + let old = state[prop]; + state[prop] = val; + if (prop === "value" && (forceUpdate || val !== old)) { + forceUpdate = false; + for (let [handler, computed] of subscriptions) { + computed.cleanup(); + let cleanup = handler(val); + makeUnsubscribe(subscriptions, computed, handler, cleanup); + } } + return true; + } + }, + get(state, prop) { + if (prop === "value") { + return typeof state.value === "function" + ? state.value() + : state.value; } - return true; - } - }, - get(state, prop) { - if (prop === 'value') { - return typeof state.value === 'function' ? state.value() : state.value; - } - if (prop === 'cleanup' || prop === 'unsubscribe' || prop === 'getter') { - return state[prop]; - } + if ( + prop === "cleanup" || + prop === "unsubscribe" || + prop === "getter" + ) { + return state[prop]; + } - if (prop in getters) { - return getters[prop](state.value); + if (prop in getters) { + return getters[prop](state.value); + } } } - }); + ); Object.defineProperties(signal, { - value: {value, writable: true, enumerable: true}, + value: { value, writable: true, enumerable: true }, cleanup: { value() { for (let [handler, computed] of subscriptions) { @@ -118,13 +135,12 @@ let plugin = function (v) { } }); - if (typeof key !== 'undefined') { + if (typeof key !== "undefined") { signals.set(key, signal); } return signal; }; - }; plugin.default = plugin; diff --git a/plugins/store.js b/plugins/store.js index e265f5a..12084c9 100644 --- a/plugins/store.js +++ b/plugins/store.js @@ -1,13 +1,12 @@ let plugin = function (v) { - function keyExists(objectname, object, key) { if (key in object === false) { throw new Error(`The ${objectname} "${key}" does not exists.`); } - }; + } function deepFreeze(obj) { - if (typeof obj === 'object' && obj !== null && !Object.isFrozen(obj)) { + if (typeof obj === "object" && obj !== null && !Object.isFrozen(obj)) { if (Array.isArray(obj)) { for (let i = 0, l = obj.length; i < l; i++) { deepFreeze(obj[i]); @@ -21,18 +20,23 @@ let plugin = function (v) { } return obj; - }; + } - v.Store = function ({ state = {}, getters = {}, actions = {}, mutations = {} } = {}) { + v.Store = function ({ + state = {}, + getters = {}, + actions = {}, + mutations = {} + } = {}) { let frozen = true; function isUnfrozen() { if (frozen) { - throw new Error('You need to commit a mutation to change the state'); + throw new Error("You need to commit a mutation to change the state"); } - }; + } - let localState = typeof state === 'function' ? state() : state; + let localState = typeof state === "function" ? state() : state; this.state = new Proxy(localState || {}, { get: (state, prop) => deepFreeze(state[prop]), @@ -53,12 +57,13 @@ let plugin = function (v) { try { return getters[getter](this.state, this.getters); } catch (e) { + // Getters should fail silently } } }); this.commit = (mutation, ...args) => { - keyExists('mutation', mutations, mutation); + keyExists("mutation", mutations, mutation); frozen = false; mutations[mutation](this.state, ...args); frozen = true; @@ -66,12 +71,13 @@ let plugin = function (v) { }; this.dispatch = (action, ...args) => { - keyExists('action', actions, action); + keyExists("action", actions, action); return Promise.resolve(actions[action](this, ...args)); }; }; - v.useStore = (store) => v.$store = store instanceof v.Store ? store : new v.Store(store); + v.useStore = (store) => + (v.$store = store instanceof v.Store ? store : new v.Store(store)); }; plugin.default = plugin; diff --git a/plugins/sw.js b/plugins/sw.js index 0c45f1d..6a3120b 100644 --- a/plugins/sw.js +++ b/plugins/sw.js @@ -1,8 +1,7 @@ let plugin = function (v) { if (!v.isNode) { v.sw = async function (file = v.sw.file, options = v.sw.options) { - await navigator.serviceWorker - .register(file, options); + await navigator.serviceWorker.register(file, options); v.sw.ready = true; v.sw.file = file; @@ -11,8 +10,8 @@ let plugin = function (v) { }; v.sw.ready = false; - v.sw.file = '/sw.js'; - v.sw.options = { scope: '/' }; + v.sw.file = "/sw.js"; + v.sw.options = { scope: "/" }; } }; diff --git a/plugins/utils/dom.js b/plugins/utils/dom.js index de78539..3386aa3 100644 --- a/plugins/utils/dom.js +++ b/plugins/utils/dom.js @@ -1,19 +1,21 @@ -'use strict'; +"use strict"; -const parse5 = require('parse5'); +const parse5 = require("parse5"); -const parseAttributes = exports.parseAttributes = function (attributes) { +const parseAttributes = (exports.parseAttributes = function (attributes) { let attrs = []; for (let i = 0, l = attributes.length; i < l; i++) { attrs.push({ - nodeName: (attributes[i].prefix ? attributes[i].prefix + ':' : '') + attributes[i].name, + nodeName: + (attributes[i].prefix ? attributes[i].prefix + ":" : "") + + attributes[i].name, nodeValue: attributes[i].value }); } return attrs; -}; +}); -const parseHtml = exports.parseHtml = function (html, options = {}) { +const parseHtml = (exports.parseHtml = function (html, options = {}) { let returnHtml = /^)/i.test(html); let returnBody = /^)/i.test(html); let returnHead = /^)/i.test(html); @@ -35,13 +37,13 @@ const parseHtml = exports.parseHtml = function (html, options = {}) { } return parse5.parseFragment(html, options).childNodes; -}; +}); function generateDom(tree) { let childNodes = []; for (let i = 0, l = tree.length; i < l; i++) { let node = tree[i]; - if (node.nodeName === '#text') { + if (node.nodeName === "#text") { childNodes.push(new Text(node.value)); } else { let element = new Element(1, node.nodeName); @@ -76,33 +78,35 @@ function splice(arr, item, add, byValue) { } function createAttributeFilter(name) { - return o => toLower(o.nodeName) === toLower(name); + return (o) => toLower(o.nodeName) === toLower(name); } function isChildNode(node, child) { - let index = node.childNodes ? findWhere(node.childNodes, child, true, true) : -1; + let index = node.childNodes + ? findWhere(node.childNodes, child, true, true) + : -1; if (index === -1) { - throw new Error('The node is not child of this element'); + throw new Error("The node is not child of this element"); } return true; } let selfClosingTags = [ - 'area', - 'base', - 'br', - 'col', - 'embed', - 'hr', - 'img', - 'input', - 'link', - 'meta', - 'param', - 'source', - 'track', - 'wbr', - '!doctype' + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "meta", + "param", + "source", + "track", + "wbr", + "!doctype" ]; function serialize(dom) { @@ -110,13 +114,18 @@ function serialize(dom) { return dom.textContent; } else if (dom.nodeType === 1) { let name = toLower(dom.nodeName); - let str = '<' + name; + let str = "<" + name; for (let i = 0, l = dom.attributes.length; i < l; i++) { - str += ' ' + dom.attributes[i].nodeName + '="' + dom.attributes[i].nodeValue + '"'; + str += + " " + + dom.attributes[i].nodeName + + '="' + + dom.attributes[i].nodeValue + + '"'; } if (selfClosingTags.indexOf(name) === -1) { - str += '>'; + str += ">"; if (dom.childNodes && dom.childNodes.length > 0) { for (let i = 0, l = dom.childNodes.length; i < l; i++) { let child = serialize(dom.childNodes[i]); @@ -125,9 +134,9 @@ function serialize(dom) { } } } - str += ''; + str += ""; } else { - str += '/>'; + str += "/>"; } return str; @@ -139,7 +148,7 @@ class Node { this.nodeType = nodeType; this.nodeName = toLower(nodeName); this.childNodes = []; - this.nodeValue = ''; + this.nodeValue = ""; } appendChild(child) { this.insertBefore(child); @@ -179,7 +188,7 @@ exports.Node = Node; class Text extends Node { constructor(text) { - super(3, '#text'); + super(3, "#text"); this.textContent = text; } set textContent(text) { @@ -197,37 +206,44 @@ class Element extends Node { this.attributes = []; this.attachedListeners = {}; let updateStyles = (state) => { - let str = ''; + let str = ""; for (let key in state) { let value = state[key]; - if (typeof value !== 'undefined' && value !== null && String(value).length > 0) { + if ( + typeof value !== "undefined" && + value !== null && + String(value).length > 0 + ) { str += `${key}: ${state[key]};`; } } if (str.length === 0) { - this.removeAttribute('style'); + this.removeAttribute("style"); } else { - this.setAttribute('style', str); + this.setAttribute("style", str); } }; - this.style = new Proxy({}, { - get: (state, prop) => state[prop], - set: (state, prop, value) => { - state[prop] = value; - updateStyles(state); - return true; - }, - deleteProperty: (state, prop) => { - delete state[prop]; - updateStyles(state); - return true; + this.style = new Proxy( + {}, + { + get: (state, prop) => state[prop], + set: (state, prop, value) => { + state[prop] = value; + updateStyles(state); + return true; + }, + deleteProperty: (state, prop) => { + delete state[prop]; + updateStyles(state); + return true; + } } - }); + ); this.classList = { toggle: (item, force) => { if (item) { - let classes = (this.getAttribute('class') || '').split(' '); + let classes = (this.getAttribute("class") || "").split(" "); let itemIndex = classes.indexOf(item); if (force && itemIndex === -1) { classes.push(item); @@ -237,29 +253,38 @@ class Element extends Node { classes.splice(itemIndex, 1); } - let final = classes.join(' ').trim(); + let final = classes.join(" ").trim(); if (final.length) { - this.setAttribute('class', classes.join(' ').trim()); + this.setAttribute("class", classes.join(" ").trim()); } else { - this.removeAttribute('class'); + this.removeAttribute("class"); } } } }; - } setAttribute(name, value) { - let attr = findWhere(this.attributes, createAttributeFilter(name), false, false); + let attr = findWhere( + this.attributes, + createAttributeFilter(name), + false, + false + ); if (!attr) { - this.attributes.push(attr = { nodeName: name, nodeValue: value }); + this.attributes.push((attr = { nodeName: name, nodeValue: value })); } else { attr.nodeValue = value; } } getAttribute(name) { - let attr = findWhere(this.attributes, createAttributeFilter(name), false, false); + let attr = findWhere( + this.attributes, + createAttributeFilter(name), + false, + false + ); return attr && attr.nodeValue; } @@ -268,7 +293,10 @@ class Element extends Node { } addEventListener(type, handler) { - (this.attachedListeners[toLower(type)] || (this.attachedListeners[toLower(type)] = [])).push(handler); + ( + this.attachedListeners[toLower(type)] || + (this.attachedListeners[toLower(type)] = []) + ).push(handler); } removeEventListener(type, handler) { @@ -276,33 +304,36 @@ class Element extends Node { } dispatchEvent(event) { - let t = event.target = this, + let t = (event.target = this), c = event.cancelable, - l, i; + l, + i; do { event.currentTarget = t; l = t.attachedListeners && t.attachedListeners[toLower(event.type)]; if (l) { - for (i = l.length; i--;) { + for (i = l.length; i--; ) { if ((l[i].call(t, event) === false || event._end) && c) { event.defaultPrevented = true; } } } } while (event.bubbles && !(c && event._stop) && (t = t.parentNode)); - return l != null; + return l !== null; } set textContent(text) { this.nodeValue = String(text); - this.childNodes = this.nodeValue.trim().length ? [new Text(this.nodeValue)] : []; + this.childNodes = this.nodeValue.trim().length + ? [new Text(this.nodeValue)] + : []; } get textContent() { return this.nodeValue; } get innerHTML() { - let str = ''; + let str = ""; for (let i = 0, l = this.childNodes.length; i < l; i++) { str += serialize(this.childNodes[i]); } @@ -310,7 +341,7 @@ class Element extends Node { } set innerHTML(html) { - this.textContent = ''; + this.textContent = ""; let childNodes = generateDom(parseHtml(html)); for (let i = 0, l = childNodes.length; i < l; i++) { this.appendChild(childNodes[i]); @@ -325,7 +356,7 @@ exports.Element = Element; class Document extends Element { constructor() { - super(9, '#document'); + super(9, "#document"); } createElement(type) { diff --git a/plugins/utils/tree-adapter.js b/plugins/utils/tree-adapter.js index f0fd403..38335b2 100644 --- a/plugins/utils/tree-adapter.js +++ b/plugins/utils/tree-adapter.js @@ -1,12 +1,12 @@ -'use strict'; +"use strict"; -const { DOCUMENT_MODE } = require('parse5/lib/common/html'); +const { DOCUMENT_MODE } = require("parse5/lib/common/html"); -const {Element, Text, Document, parseAttributes} = require('./dom'); +const { Element, Text, Document, parseAttributes } = require("./dom"); exports.createDocumentFragment = function () { return { - nodeName: '#document-fragment', + nodeName: "#document-fragment", childNodes: [] }; }; @@ -22,8 +22,8 @@ exports.createElement = function (tagName, namespaceURI, attributes) { exports.createCommentNode = function (data) { return { - nodeName: '#comment', - data: data, + nodeName: "#comment", + data, parentNode: null }; }; @@ -40,7 +40,11 @@ const appendChild = (exports.appendChild = function (parentNode, newNode) { newNode.parentNode = parentNode; }); -const insertBefore = (exports.insertBefore = function (parentNode, newNode, referenceNode) { +const insertBefore = (exports.insertBefore = function ( + parentNode, + newNode, + referenceNode +) { const insertionIdx = parentNode.childNodes.indexOf(referenceNode); parentNode.childNodes.splice(insertionIdx, 0, newNode); @@ -66,7 +70,7 @@ exports.setDocumentType = function (document, name, publicId, systemId) { let doctypeNode = null; for (let i = 0; i < document.childNodes.length; i++) { - if (document.childNodes[i].nodeName === '#documentType') { + if (document.childNodes[i].nodeName === "#documentType") { doctypeNode = document.childNodes[i]; break; } @@ -77,12 +81,12 @@ exports.setDocumentType = function (document, name, publicId, systemId) { doctypeNode.publicId = publicId; doctypeNode.systemId = systemId; } else { - let element = new Element(10, '!DOCTYPE'); - element.nodeName = '!DOCTYPE'; + let element = new Element(10, "!DOCTYPE"); + element.nodeName = "!DOCTYPE"; element.publicId = publicId; element.systemId = systemId; element.name = name; - element.attributes = [{nodeName: 'html', nodeValue: true}]; + element.attributes = [{ nodeName: "html", nodeValue: true }]; appendChild(document, element); } @@ -109,7 +113,7 @@ exports.insertText = function (parentNode, text) { if (parentNode.childNodes.length) { const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1]; - if (prevNode.nodeName === '#text') { + if (prevNode.nodeName === "#text") { prevNode.value += text; prevNode.nodeValue += text; return; @@ -120,9 +124,10 @@ exports.insertText = function (parentNode, text) { }; exports.insertTextBefore = function (parentNode, text, referenceNode) { - const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1]; + const prevNode = + parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1]; - if (prevNode && prevNode.nodeName === '#text') { + if (prevNode && prevNode.nodeName === "#text") { prevNode.value += text; prevNode.nodeValue += text; } else { @@ -192,15 +197,15 @@ exports.getDocumentTypeNodeSystemId = function (doctypeNode) { //Node types exports.isTextNode = function (node) { - return node.nodeName === '#text'; + return node.nodeName === "#text"; }; exports.isCommentNode = function (node) { - return node.nodeName === '#comment'; + return node.nodeName === "#comment"; }; exports.isDocumentTypeNode = function (node) { - return node.nodeName === '#documentType'; + return node.nodeName === "#documentType"; }; exports.isElementNode = function (node) { diff --git a/plugins/v-model.js b/plugins/v-model.js index ab51fa7..da12623 100644 --- a/plugins/v-model.js +++ b/plugins/v-model.js @@ -1,11 +1,11 @@ let plugin = function (v) { - v.directive('model', ([model, property, event], vnode, oldvnode) => { - if (vnode.name === 'input') { - event = event || 'oninput'; + v.directive("model", ([model, property, event], vnode, oldvnode) => { + if (vnode.name === "input") { + event = event || "oninput"; switch (vnode.props.type) { - case 'checkbox': { + case "checkbox": { if (Array.isArray(model[property])) { - vnode.props[event] = e => { + vnode.props[event] = (e) => { let val = e.target.value; let idx = model[property].indexOf(val); if (idx === -1) { @@ -16,7 +16,7 @@ let plugin = function (v) { }; vnode.props.checked = model[property].indexOf(vnode.dom.value) !== -1; - } else if ('value' in vnode.props) { + } else if ("value" in vnode.props) { vnode.props[event] = () => { if (model[property] === vnode.props.value) { model[property] = null; @@ -30,23 +30,23 @@ let plugin = function (v) { vnode.props.checked = model[property]; } - v.updateProperty('checked', vnode, oldvnode); + v.updateProperty("checked", vnode, oldvnode); break; } - case 'radio': { + case "radio": { vnode.props.checked = model[property] === vnode.dom.value; - v.updateProperty('checked', vnode, oldvnode); + v.updateProperty("checked", vnode, oldvnode); break; } default: { vnode.props.value = model[property]; - v.updateProperty('value', vnode, oldvnode); + v.updateProperty("value", vnode, oldvnode); } } - } else if (vnode.name === 'select') { - event = event || 'onclick'; + } else if (vnode.name === "select") { + event = event || "onclick"; if (vnode.props.multiple) { - vnode.props[event] = e => { + vnode.props[event] = (e) => { let val = e.target.value; if (e.ctrlKey) { let idx = model[property].indexOf(val); @@ -60,33 +60,33 @@ let plugin = function (v) { model[property].push(val); } }; - vnode.children.forEach(child => { - if (child.name === 'option') { + vnode.children.forEach((child) => { + if (child.name === "option") { let value = - 'value' in child.props + "value" in child.props ? child.props.value - : child.children.join('').trim(); + : child.children.join("").trim(); child.props.selected = model[property].indexOf(value) !== -1; } }); } else { - vnode.children.forEach(child => { - if (child.name === 'option') { + vnode.children.forEach((child) => { + if (child.name === "option") { let value = - 'value' in child.props + "value" in child.props ? child.props.value - : child.children.join('').trim(); + : child.children.join("").trim(); child.props.selected = value === model[property]; } }); } - } else if (vnode.name === 'textarea') { - event = event || 'oninput'; + } else if (vnode.name === "textarea") { + event = event || "oninput"; vnode.children = [model[property]]; } if (!vnode.props[event]) { - vnode.props[event] = e => (model[property] = e.target.value); + vnode.props[event] = (e) => (model[property] = e.target.value); } v.updateProperty(event, vnode, oldvnode); diff --git a/rollupSource.js b/rollupSource.js index 10de406..0093e92 100644 --- a/rollupSource.js +++ b/rollupSource.js @@ -1,36 +1,40 @@ -let rollup = require('rollup'); -let commonjs = require('@rollup/plugin-commonjs'); -let {nodeResolve} = require('@rollup/plugin-node-resolve'); -let includepaths = require('rollup-plugin-includepaths'); -let filesize = require('rollup-plugin-filesize'); -let progress = require('rollup-plugin-progress'); -let { string } = require('rollup-plugin-string'); -let sourcemaps = require('rollup-plugin-sourcemaps'); -let { terser } = require('rollup-plugin-terser'); -let {sizeSnapshot } = require('rollup-plugin-size-snapshot'); -let buble = require('@rollup/plugin-buble'); +let rollup = require("rollup"); +let commonjs = require("@rollup/plugin-commonjs"); +let { nodeResolve } = require("@rollup/plugin-node-resolve"); +let includepaths = require("rollup-plugin-includepaths"); +let filesize = require("rollup-plugin-filesize"); +let progress = require("rollup-plugin-progress"); +let { string } = require("rollup-plugin-string"); +let sourcemaps = require("rollup-plugin-sourcemaps"); +let { terser } = require("rollup-plugin-terser"); +let { sizeSnapshot } = require("rollup-plugin-size-snapshot"); +let buble = require("@rollup/plugin-buble"); -const argv = require('yargs').argv; -let file = argv.file || 'index'; -let distFile = file === 'index' ? 'valyrian' : file; +const argv = require("yargs").argv; +let file = argv.file || "index"; +let distFile = file === "index" ? "valyrian" : file; let inputOptions = { - input: './lib/' + file + '.js', + input: "./lib/" + file + ".js", plugins: [ progress({ clearLine: false }), - includepaths({ paths: ['./lib', './node_modules'] }), + includepaths({ paths: ["./lib", "./node_modules"] }), nodeResolve({ jsnext: true, main: true, browser: true }), string({ - include: '**/*.tpl.js' + include: "**/*.tpl.js" + }), + buble({ + jsx: "v", + transforms: { asyncAwait: false }, + target: { chrome: 71, firefox: 64, safari: 10, node: 8.7 } }), - buble({ jsx: 'v', transforms: {asyncAwait: false}, target: { chrome: 71, firefox: 64, safari: 10, node: 8.7 } }), // babel({ exclude: 'node_modules/**' }), commonjs({ - include: ['./node_modules/**'], // Default: undefined + include: ["./node_modules/**"], // Default: undefined // if false then skip sourceMap generation for CommonJS modules sourceMap: true // Default: true }), @@ -42,58 +46,60 @@ let inputOptions = { }; let outputOptions = { - file: './dist/' + distFile + '.min.js', - format: 'iife', + file: "./dist/" + distFile + ".min.js", + format: "iife", sourcemap: true, - name: 'v', + name: "v", compact: true }; -if (process.env.NODE_ENV === 'production') { +if (process.env.NODE_ENV === "production") { outputOptions.sourcemap = false; - inputOptions.plugins.push(terser({ - warnings: 'verbose', - output: { - ecma: 6 - } - })); + inputOptions.plugins.push( + terser({ + warnings: "verbose", + output: { + ecma: 6 + } + }) + ); rollup .rollup(inputOptions) .then((bundle) => bundle.write(outputOptions)) - .then(() => console.log('Bundle finished.')) + .then(() => console.log("Bundle finished.")) .catch(console.log); } -if (process.env.NODE_ENV !== 'production') { - inputOptions.plugins.push(terser({ warnings: 'verbose' })); +if (process.env.NODE_ENV !== "production") { + inputOptions.plugins.push(terser({ warnings: "verbose" })); inputOptions.output = outputOptions; inputOptions.watch = { - include: ['./lib/**'], + include: ["./lib/**"], chokidar: false }; const watch = rollup.watch(inputOptions); const stderr = console.error.bind(console); - watch.on('event', (event) => { + watch.on("event", (event) => { switch (event.code) { - case 'START': - stderr('checking rollup-watch version...'); + case "START": + stderr("checking rollup-watch version..."); break; - case 'BUNDLE_START': + case "BUNDLE_START": stderr(`bundling ${outputOptions.file}...`); break; - case 'BUNDLE_END': + case "BUNDLE_END": stderr(`${outputOptions.file} bundled in ${event.duration}ms.`); break; - case 'ERROR': + case "ERROR": stderr(`error: ${event.error}`); break; - case 'FATAL': + case "FATAL": stderr(`error: ${event.error}`); break; - case 'END': + case "END": stderr(`Watching for changes...`); break; default: diff --git a/scratchpad.js b/scratchpad.js deleted file mode 100644 index fea0341..0000000 --- a/scratchpad.js +++ /dev/null @@ -1,59 +0,0 @@ -import expect from 'expect'; -import './lib'; -import nodePlugin from './plugins/node'; -v.usePlugin(nodePlugin); - -describe.only('Hooks like pattern', () => { - - it.only('should create a simple counter', async () => { - let Counter = () => { - let [count, setState] = v.useState(0); - setState(count + 1); - console.log(count); - return
{}}>{count}
; - }; - - console.log('**************mount**************'); - let result = v.mount('div', Counter); - console.log('**************mounted**************', result); - console.log('**************update**************'); - result = v.update(); - console.log('**************updated**************', result); - - - // let component; - // let hookIndex = 0; - - // function useState(initial) { - // let hook; - - // if (component) { - // component.hooks = component.hooks || []; - // if (component.hooks && component.hooks[hookIndex]) { - // hook = component.hooks[hookIndex]; - // } else { - // hook = { - // state: initial, - // setState(value) { - // hook.state = typeof value === 'function' ? value(hook.state) : value; - // } - // }; - // component.hooks.push(hook); - // } - // } - - // return [hook.state, hook.setState]; - // } - - // function Component() { - // let [state, setState] = useState(0); - // setState(state + 1); - // console.log(state); - // } - // component = {component: Component}; - - // Component(); - // Component(); - - }); -}); diff --git a/test/directives_test.js b/test/directives_test.js index b277c58..790ef37 100644 --- a/test/directives_test.js +++ b/test/directives_test.js @@ -1,47 +1,45 @@ -import expect from 'expect'; -import faker from 'faker'; -import dayjs from 'dayjs'; -import '../lib'; -import nodePlugin from '../plugins/node'; +import expect from "expect"; +import faker from "faker"; +import dayjs from "dayjs"; +import "../lib"; +import nodePlugin from "../plugins/node"; v.usePlugin(nodePlugin); // eslint-disable-next-line max-lines-per-function -describe('Directives', () => { - - describe('Directive creation', () => { - +describe("Directives", () => { + describe("Directive creation", () => { let result; - it('should be able create a directive', () => { - let expected = 'Hello world'; - v.directive('test', (value) => result = `Hello ${value}`); - v.mount('div', () =>
); + it("should be able create a directive", () => { + let expected = "Hello world"; + v.directive("test", (value) => (result = `Hello ${value}`)); + v.mount("div", () =>
); expect(result).toEqual(expected); }); - it('should not be able overwrite a directive', () => { - let expected = 'Hello world'; - v.directive('test', () => result = 'Something else'); - v.mount('div', () =>
); + it("should not be able overwrite a directive", () => { + let expected = "Hello world"; + v.directive("test", () => (result = "Something else")); + v.mount("div", () =>
); expect(result).toEqual(expected); }); - it('should be able to get the vnode', () => { + it("should be able to get the vnode", () => { let newVnode; let oldVnode; - v.directive('test2', (v, vnode, oldvnode) => { + v.directive("test2", (v, vnode, oldvnode) => { newVnode = vnode; oldVnode = oldvnode; }); - v.mount('div', () =>
); + v.mount("div", () =>
); v.update(); expect(newVnode).toEqual({ - name: 'div', + name: "div", props: { - 'v-test2': true + "v-test2": true }, dom: expect.any(Object), children: [], @@ -49,9 +47,9 @@ describe('Directives', () => { }); expect(oldVnode).toEqual({ - name: 'div', + name: "div", props: { - 'v-test2': true + "v-test2": true }, dom: expect.any(Object), children: [], @@ -59,27 +57,31 @@ describe('Directives', () => { }); }); - it('should be able to identify if this is first render or update', () => { - v.directive('create', (placeholder, vnode, oldvnode) => { + it("should be able to identify if this is first render or update", () => { + v.directive("create", (placeholder, vnode, oldvnode) => { if (!oldvnode) { - vnode.children = ['First render, vnode created']; + vnode.children = ["First render, vnode created"]; } else { - vnode.children = ['Second render, vnode updated']; + vnode.children = ["Second render, vnode updated"]; } }); let component = () =>
; - let result = v.mount('body', component); - expect(result).toEqual('
First render, vnode created
'); + let result = v.mount("body", component); + expect(result).toEqual("
First render, vnode created
"); let result2 = v.update(); - expect(result2).toEqual('
Second render, vnode updated
'); + expect(result2).toEqual("
Second render, vnode updated
"); }); - it('should be able to modify the children of a vnode', () => { - let expected = '
Hello world
'; - v.directive('test3', (v, vnode) => vnode.children = 'Hello world'); - let result = v.mount('div', () =>
Hello John Doe
); + it("should be able to modify the children of a vnode", () => { + let expected = "
Hello world
"; + v.directive("test3", (v, vnode) => (vnode.children = "Hello world")); + let result = v.mount("div", () => ( +
+ Hello John Doe +
+ )); expect(result).toEqual(expected); }); @@ -87,63 +89,70 @@ describe('Directives', () => { * Modify properties is not guaranteed because the properties are processed by place * If the directive needs to do update previous properties you need to update the property using the v.updateProperty method */ - it('Modify properties is not guaranteed', () => { + it("Modify properties is not guaranteed", () => { let update = false; - v.directive('test4', (p, vnode, oldVnode) => { + v.directive("test4", (p, vnode, oldVnode) => { // Try to change u property - vnode.props.u = 'property changed'; + vnode.props.u = "property changed"; if (update) { - v.updateProperty('u', vnode, oldVnode); + v.updateProperty("u", vnode, oldVnode); } // Try to change x property - vnode.props.x = 'property changed'; + vnode.props.x = "property changed"; }); - let result = v.mount('div', () =>
); + let result = v.mount("div", () =>
); expect(result).toEqual('
'); v.unMount(); update = true; - let result2 = v.mount('div', () =>
); - expect(result2).toEqual('
'); + let result2 = v.mount("div", () =>
); + expect(result2).toEqual( + '
' + ); }); /** * We don't have flags as vue or ember * For this we should be able to use a directive as flag */ - it('should be able to use it as a flag', () => { - let expected = '
August 16, 2018
'; + it("should be able to use it as a flag", () => { + let expected = "
August 16, 2018
"; - let formatDate = (value) => dayjs(value).format('MMMM D, YYYY'); + let formatDate = (value) => dayjs(value).format("MMMM D, YYYY"); - v.directive('date-inline', (date, vnode) => vnode.children = formatDate(date)); - v.directive('date', (v, vnode) => vnode.children = formatDate(vnode.children[0])); + v.directive( + "date-inline", + (date, vnode) => (vnode.children = formatDate(date)) + ); + v.directive( + "date", + (v, vnode) => (vnode.children = formatDate(vnode.children[0])) + ); let date = "08-16-2018"; - let result = v.mount('div', () =>
); + let result = v.mount("div", () =>
); expect(result).toEqual(expected); - result = v.mount('div', () =>
{date}
); + result = v.mount("div", () =>
{date}
); expect(result).toEqual(expected); }); /** - * Works as a Switch statement - * It needs a set of arrays as children of the form [{case}, vnodes] - * This is not added to the base library but it shows the capabilities of valyrian directives - */ - it('v-switch example', () => { - v.directive('switch', (value, vnode) => { + * Works as a Switch statement + * It needs a set of arrays as children of the form [{case}, vnodes] + * This is not added to the base library but it shows the capabilities of valyrian directives + */ + it("v-switch example", () => { + v.directive("switch", (value, vnode) => { for (let i = 0, l = vnode.children.length; i < l; i++) { let [test, handler] = vnode.children[i]; let result = false; - result = typeof test === 'function' ? - test(value) : - value === test; + result = typeof test === "function" ? test(value) : value === test; if (result) { - vnode.children = typeof handler === 'function' ? handler(value) : handler; + vnode.children = + typeof handler === "function" ? handler(value) : handler; return; } } @@ -152,126 +161,138 @@ describe('Directives', () => { }); let name; - let component = () =>
- {['John', Hello John]} - {[(val) => val === 'John Doe', Hello John Doe]} - {['Jane', (val) => Hello {val} Doe]} -
; + let component = () => ( +
+ {["John", Hello John]} + {[(val) => val === "John Doe", Hello John Doe]} + {["Jane", (val) => Hello {val} Doe]} +
+ ); let expected; let result; // Direct equality - expected = '
Hello John
'; - name = 'John'; - result = v.mount('div', component); + expected = "
Hello John
"; + name = "John"; + result = v.mount("div", component); expect(result).toEqual(expected); // Comparison method - expected = '
Hello John Doe
'; - name = 'John Doe'; - result = v.mount('div', component); + expected = "
Hello John Doe
"; + name = "John Doe"; + result = v.mount("div", component); expect(result).toEqual(expected); // Result method - expected = '
Hello Jane Doe
'; - name = 'Jane'; - result = v.mount('div', component); + expected = "
Hello Jane Doe
"; + name = "Jane"; + result = v.mount("div", component); expect(result).toEqual(expected); // If no case return the value as children - expected = '
Hello Anonymous
'; - name = 'Hello Anonymous'; - result = v.mount('div', component); + expected = "
Hello Anonymous
"; + name = "Hello Anonymous"; + result = v.mount("div", component); expect(result).toEqual(expected); }); }); - describe('Official directives', () => { + describe("Official directives", () => { /** * v-for directive works like this * On the element set the v-for directive to an array * It needs a function as a child to process the elements of the array * Think of it as a map function that returns a list of vnodes */ - describe('v-for', () => { - - it('should create 10 list items', () => { - let items = faker.lorem.words(10).split(' '); - let expected = ''; - let result = v.mount('body', () => ); + describe("v-for", () => { + it("should create 10 list items", () => { + let items = faker.lorem.words(10).split(" "); + let expected = + ""; + let result = v.mount("body", () => ( + + )); expect(result).toEqual(expected); }); - it('should create 10 list items getting its index', () => { - let items = faker.lorem.words(10).split(' '); + it("should create 10 list items getting its index", () => { + let items = faker.lorem.words(10).split(" "); let i = 0; - let expected = ''; - let result = v.mount('body', () => ); + let expected = + ""; + let result = v.mount("body", () => ( + + )); expect(result).toEqual(expected); }); - }); /** * Works as Vue's v-if directive or ember "if" helper * It renders a vnode if the referenced value is true */ - describe('v-if', () => { - - it('should render vnode if thruthy values', () => { - let values = [ - {}, - 1, - true, - [], - "string", - new Date(), - -1 - ]; - - let expected = '
Hello world
'; - - values.forEach(value => { + describe("v-if", () => { + it("should render vnode if thruthy values", () => { + let values = [{}, 1, true, [], "string", new Date(), -1]; + + let expected = "
Hello world
"; + + values.forEach((value) => { v.unMount(); - let result = v.mount('div', () =>
Hello world
); + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); }); - it('should not render vnode with falsy values', () => { - let values = [ - false, - 0, - '', - null,, - NaN - ]; + it("should not render vnode with falsy values", () => { + let values = [false, 0, "", null, , NaN]; - let expected = '
'; + let expected = "
"; - values.forEach(value => { + values.forEach((value) => { v.unMount(); - let result = v.mount('div', () =>
Hello world
); + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); }); - it('should update oldnode', () => { + it("should update oldnode", () => { let value = true; - let expected1 = '
Hello world
'; - let expected2 = '
'; - - let result1 = v.mount('div', () =>
Hello world
); + let expected1 = "
Hello world
"; + let expected2 = "
"; + + let result1 = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result1).toEqual(expected1); value = false; let result2 = v.update(); expect(result2).toEqual(expected2); }); - }); /** @@ -281,103 +302,101 @@ describe('Directives', () => { * Works as embers "unless" helper * It renders a vnode if the referenced value is false */ - describe('v-unless', () => { - - it('should render vnode with falsy values', () => { - let values = [ - false, - 0, - '', - null,, - NaN - ]; + describe("v-unless", () => { + it("should render vnode with falsy values", () => { + let values = [false, 0, "", null, , NaN]; - let expected = '
Hello world
'; + let expected = "
Hello world
"; - values.forEach(value => { + values.forEach((value) => { v.unMount(); - let result = v.mount('div', () =>
Hello world
); + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); }); - it('should not render vnode if thruthy values', () => { - let values = [ - {}, - 1, - true, - [], - "string", - new Date(), - -1 - ]; + it("should not render vnode if thruthy values", () => { + let values = [{}, 1, true, [], "string", new Date(), -1]; - let expected = '
'; + let expected = "
"; - values.forEach(value => { + values.forEach((value) => { v.unMount(); - let result = v.mount('div', () =>
Hello world
); + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); }); - }); /** * Works as Vue's v-show directive * It renders a vnode and only changes it's display style value */ - describe('v-show', () => { - - it('should show a vnode if true', () => { + describe("v-show", () => { + it("should show a vnode if true", () => { let value = true; - let expected = '
Hello world
'; - let result = v.mount('div', () =>
Hello world
); + let expected = "
Hello world
"; + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); - it('should hide a vnode if false', () => { + it("should hide a vnode if false", () => { let value = false; - let expected = '
Hello world
'; - let result = v.mount('div', () =>
Hello world
); + let expected = + '
Hello world
'; + let result = v.mount("div", () => ( +
+ Hello world +
+ )); expect(result).toEqual(expected); }); - }); /** * v-class directive receives a object with boolean attributes to toggle classes on the dom */ - describe('v-class', () => { - - it('should toggle on a class', () => { + describe("v-class", () => { + it("should toggle on a class", () => { let classes = { world: true }; - let result = v.mount('body', () =>
); + let result = v.mount("body", () =>
); expect(result).toEqual('
'); classes.world = false; let result2 = v.update(); - expect(result2).toEqual('
'); - + expect(result2).toEqual("
"); }); - it('should toggle on a class in an element with a class attribute', () => { + it("should toggle on a class in an element with a class attribute", () => { let classes = { world: true }; - let result = v.mount('body', () =>
); + let result = v.mount("body", () => ( +
+ )); expect(result).toEqual('
'); classes.world = false; let result2 = v.update(); expect(result2).toEqual('
'); - }); }); @@ -385,19 +404,19 @@ describe('Directives', () => { * The directive v-once is used to render just once and skip all subsequent render updates * Similar to write the lifecycle onbeforeupdate={() => false} */ - describe('v-once', () => { - it('should not update the dom after first render', () => { - let Store = {hello: 'world'}; + describe("v-once", () => { + it("should not update the dom after first render", () => { + let Store = { hello: "world" }; let Component = () =>
Hello {Store.hello}
; - let result = v.mount('body', Component); - expect(result).toEqual('
Hello world
'); + let result = v.mount("body", Component); + expect(result).toEqual("
Hello world
"); // We update our store - Store.hello = 'John Doe'; + Store.hello = "John Doe"; let result2 = v.update(); - expect(result2).toEqual('
Hello world
'); + expect(result2).toEqual("
Hello world
"); }); }); @@ -406,40 +425,45 @@ describe('Directives', () => { * and it does not improve performance because Valyrian.js is already very fast with vnodes. * We can use this directive to replace the v.trust use like in this test */ - describe('v-html', () => { - it('should handle direct html render', () => { + describe("v-html", () => { + it("should handle direct html render", () => { // Using v.trust example - let Component = () =>
{v.trust('
Hello world
')}
; - let result = v.mount('body', Component); + let Component = () =>
{v.trust("
Hello world
")}
; + let result = v.mount("body", Component); - expect(result).toEqual('
Hello world
'); + expect(result).toEqual("
Hello world
"); // Unmount to clean the instance v.unMount(); // Using v-html directive let Component2 = () =>
; - let result2 = v.mount('body', Component2); + let result2 = v.mount("body", Component2); - expect(result2).toEqual('
Hello world
'); + expect(result2).toEqual("
Hello world
"); }); }); }); - // if the v-if directive resolve to false, we should not execute any other directive or attribute update like v-for - describe('use v-if with v-for', () => { - it('should use v-if with v-for directives', () => { + describe("use v-if with v-for", () => { + it("should use v-if with v-for directives", () => { let arr = [1, 2, 3, 4]; let show = true; - let component = () =>
{i => {i}}
; + let component = () => ( +
+ {(i) => {i}} +
+ ); - let result = v.mount('body', component); - expect(result).toEqual('
1234
'); + let result = v.mount("body", component); + expect(result).toEqual( + "
1234
" + ); show = false; let result2 = v.update(); - expect(result2).toEqual(''); + expect(result2).toEqual(""); }); }); @@ -447,19 +471,20 @@ describe('Directives', () => { * The data directive is used just to pass data without creating an attribute on the node. * And its main use is in the lifecycle methods to validate properties or changes */ - describe('reserved word data', () => { - it('should not render an attribute', () => { - let data = {hello: 'world'}; - let Component = () =>
oldVnode.props.data.hello !== newVnode.props.data.hello} - >
; - - let result = v.mount('body', Component); - expect(result).toEqual('
'); - }); + describe("reserved word data", () => { + it("should not render an attribute", () => { + let data = { hello: "world" }; + let Component = () => ( +
+ oldVnode.props.data.hello !== newVnode.props.data.hello + } + >
+ ); + let result = v.mount("body", Component); + expect(result).toEqual("
"); + }); }); - }); - diff --git a/test/hooks_test.js b/test/hooks_test.js index 9f18f65..e3a6831 100644 --- a/test/hooks_test.js +++ b/test/hooks_test.js @@ -1,14 +1,13 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; -import hooksPlugin from '../plugins/hooks'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; +import hooksPlugin from "../plugins/hooks"; v.usePlugin(nodePlugin); v.usePlugin(hooksPlugin); -describe('Hooks', () => { - - describe('State hook', () => { - it('should handle a component state', async () => { +describe("Hooks", () => { + describe("State hook", () => { + it("should handle a component state", async () => { v.unMount(); let Counter = () => { @@ -18,41 +17,44 @@ describe('Hooks', () => { return
{count}
; }; - let result = v.mount('div', Counter); - expect(result).toEqual('
0
'); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter); + expect(result).toEqual("
0
"); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
2
'); + expect(result).toEqual("
2
"); result = v.unMount(); }); - it('should handle subcomponents state and cleanup', async () => { + it("should handle subcomponents state and cleanup", async () => { v.unMount(); let Ok = () => { - let [ok, setOk] = v.useState('ok'); - let interval = setInterval(() => setOk('not ok'), 1000); + let [ok, setOk] = v.useState("ok"); + let interval = setInterval(() => setOk("not ok"), 1000); v.onCleanup(() => clearInterval(interval)); return
{ok}
; }; - let Counter = () => { let [count, setCount] = v.useState(0); let interval = setInterval(() => setCount(count + 1), 1000); v.onCleanup(() => clearInterval(interval)); - return
{count}
; + return ( +
+ {count} +
+ ); }; - let result = v.mount('div', Counter); - expect(result).toEqual('
0
ok
'); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter); + expect(result).toEqual("
0
ok
"); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
2
not ok
'); + expect(result).toEqual("
2
not ok
"); result = v.unMount(); }); - it('array getter-setter based state', async () => { + it("array getter-setter based state", async () => { v.unMount(); let Counter = () => { @@ -62,84 +64,83 @@ describe('Hooks', () => { return
{count}
; }; - let result = v.mount('div', Counter); - expect(result).toEqual('
0
'); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter); + expect(result).toEqual("
0
"); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
2
'); + expect(result).toEqual("
2
"); result = v.unMount(); }); }); - describe('Effect hook', () => { - - it('should call the effect at first render', () => { + describe("Effect hook", () => { + it("should call the effect at first render", () => { let count = 0; let Component = function () { v.useEffect(() => count++); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); }); - it('should call the effect at every update', () => { + it("should call the effect at every update", () => { let count = 0; let Component = function () { v.useEffect(() => count++); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); response = v.update(); - expect(response).toEqual('
2
'); + expect(response).toEqual("
2
"); }); - it('should handle cleanup', () => { + it("should handle cleanup", () => { let count = 0; let Component = function () { v.useEffect(() => { count++; - return () => count -= 2; + return () => (count -= 2); }); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); response = v.update(); - expect(response).toEqual('
0
'); + expect(response).toEqual("
0
"); }); - it('should not call the effect if the change array is passed and there are no changes', () => { + it("should not call the effect if the change array is passed and there are no changes", () => { let count = 0; let Component = function () { v.useEffect(() => count++, [0]); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); response = v.update(); - expect(response).toEqual('
1
'); + expect(response).toEqual("
1
"); }); - it('should call the effect if the change array is passed and there are changes', () => { + it("should call the effect if the change array is passed and there are changes", () => { let count = 0; let Component = function () { v.useEffect(() => count++, [count]); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); response = v.update(); - expect(response).toEqual('
2
'); + expect(response).toEqual("
2
"); }); - it('should call cleanup even if the changes array is passed and there are changes', () => { + it("should call cleanup even if the changes array is passed and there are changes", () => { let count = 0; let Component = function () { v.useEffect(() => { @@ -149,37 +150,35 @@ describe('Hooks', () => { return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); response = v.update(); - expect(response).toEqual('
3
'); + expect(response).toEqual("
3
"); response = v.update(); - expect(response).toEqual('
5
'); + expect(response).toEqual("
5
"); }); - it('should handle cleanup on unMount', () => { + it("should handle cleanup on unMount", () => { let count = 0; let Component = function () { v.useEffect(() => { count++; - return () => count -= 2; + return () => (count -= 2); }); return
{count}
; }; - let response = v.mount('body', Component); - expect(response).toEqual('
1
'); + let response = v.mount("body", Component); + expect(response).toEqual("
1
"); expect(count).toEqual(1); response = v.update(); - expect(response).toEqual('
0
'); + expect(response).toEqual("
0
"); expect(count).toEqual(0); response = v.unMount(); - expect(response).toEqual(''); + expect(response).toEqual(""); expect(count).toEqual(-2); - }); }); - }); diff --git a/test/hyperscript_test.js b/test/hyperscript_test.js index bcdc5b5..a506ea5 100644 --- a/test/hyperscript_test.js +++ b/test/hyperscript_test.js @@ -1,34 +1,32 @@ - -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; v.usePlugin(nodePlugin); -describe('Hyperscript', () => { - - it('should create a div element', () => { - expect(v('div')).toEqual({ - name: 'div', +describe("Hyperscript", () => { + it("should create a div element", () => { + expect(v("div")).toEqual({ + name: "div", props: {}, children: [] }); }); - it('should create a div element with a text child', () => { - expect(v('div', null, 'Hello')).toEqual({ - name: 'div', + it("should create a div element with a text child", () => { + expect(v("div", null, "Hello")).toEqual({ + name: "div", props: {}, - children: ['Hello'] + children: ["Hello"] }); }); - it('should create a div element with an element child', () => { - expect(v('div', null, v('span'))).toEqual({ - name: 'div', + it("should create a div element with an element child", () => { + expect(v("div", null, v("span"))).toEqual({ + name: "div", props: {}, children: [ { - name: 'span', + name: "span", props: {}, children: [] } @@ -36,88 +34,87 @@ describe('Hyperscript', () => { }); }); - it('should create a div element with comma separated children', () => { - expect(v('div', null, 'Hello ', 'world')).toEqual({ - name: 'div', + it("should create a div element with comma separated children", () => { + expect(v("div", null, "Hello ", "world")).toEqual({ + name: "div", props: {}, - children: [ - 'Hello ', - 'world' - ] + children: ["Hello ", "world"] }); }); - it('should create a div element with array of children', () => { - expect(v('div', null, ['Hello ', 'world'])).toEqual({ - name: 'div', + it("should create a div element with array of children", () => { + expect(v("div", null, ["Hello ", "world"])).toEqual({ + name: "div", props: {}, - children: [ - ['Hello ', - 'world'] - ] + children: [["Hello ", "world"]] }); }); - it('should create a div element with mixed array of children and comma separated children', () => { - expect(v('div', null, ['Hello ', 'world'], v('span', null, 'Whats up'))).toEqual({ - name: 'div', + it("should create a div element with mixed array of children and comma separated children", () => { + expect( + v("div", null, ["Hello ", "world"], v("span", null, "Whats up")) + ).toEqual({ + name: "div", props: {}, children: [ - ['Hello ', 'world'], + ["Hello ", "world"], { - name: 'span', + name: "span", props: {}, - children: ['Whats up'] + children: ["Whats up"] } ] }); }); - it('should create a div element with mixed nested arrays of children ', () => { - expect(v('div', null, ['Hello ', 'world', ['Only', ['for', 'this', ['time']]]])).toEqual({ - name: 'div', + it("should create a div element with mixed nested arrays of children ", () => { + expect( + v("div", null, ["Hello ", "world", ["Only", ["for", "this", ["time"]]]]) + ).toEqual({ + name: "div", props: {}, - children: [ - ['Hello ', 'world', ['Only', ['for', 'this', ['time']]]] - ] + children: [["Hello ", "world", ["Only", ["for", "this", ["time"]]]]] }); }); - it('should create a div element with props', () => { - expect(v('div', { id: 'unique', class: 'unique' })).toEqual({ - name: 'div', + it("should create a div element with props", () => { + expect(v("div", { id: "unique", class: "unique" })).toEqual({ + name: "div", props: { - id: 'unique', - class: 'unique' + id: "unique", + class: "unique" }, children: [] }); }); - it('should create a div element from string', () => { - expect(v.trust('
Hola mundo
')).toEqual([ - { - name: 'div', - props: { - id: 'unique', - class: 'unique' - }, - children: [{dom: expect.anything()}], - dom: expect.anything() - } - ]); + it("should create a div element from string", () => { + expect(v.trust('
Hola mundo
')).toEqual( + [ + { + name: "div", + props: { + id: "unique", + class: "unique" + }, + children: [{ dom: expect.anything() }], + dom: expect.anything() + } + ] + ); }); - it('should handle different types of data', () => { + it("should handle different types of data", () => { let date = new Date(); - expect(v('div', null, [null, 'Hello', , 1, date, { hello: 'world' }, ['Hello']])).toEqual({ - name: 'div', + expect( + v("div", null, [null, "Hello", , 1, date, { hello: "world" }, ["Hello"]]) + ).toEqual({ + name: "div", props: {}, children: [ - [null, 'Hello', undefined, 1, date, { hello: 'world' }, ['Hello']] + [null, "Hello", undefined, 1, date, { hello: "world" }, ["Hello"]] ] }); }); - }); diff --git a/test/keyed_test.js b/test/keyed_test.js index 192b56b..e3d6458 100644 --- a/test/keyed_test.js +++ b/test/keyed_test.js @@ -1,44 +1,51 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; v.usePlugin(nodePlugin); -describe('Keyed lists', () => { +describe("Keyed lists", () => { let set = [1, 2, 3, 4, 5]; let tests = [ - {name: 'Removed at the end', set: [1, 2, 3, 4]}, // Removed at the end - {name: 'Removed at the start', set: [2, 3, 4, 5]}, // Remmoved at the start - {name: 'Removed at the center', set: [1, 3, 5]}, // Removed at the center - {name: 'Added at the end', set: [1, 2, 3, 4, 5, 6]}, // Added at the end - {name: 'Added at the start', set: [6, 1, 2, 3, 4, 5]}, // Added at the start - {name: 'Added at the center', set: [1, 2, 6, 3, 4, 5]}, // Added at the center - {name: 'Reversed', set: [5, 4, 3, 2, 1]}, // Reversed - {name: 'Switch positions', set: [1, 4, 3, 2, 5]}, // Switch positions, - {name: 'Mixed positions', set: [1, 3, 2, 6, 5, 4]}, - {name: 'Replaced with undefined', set: [1, 3, 2, , 5, 4]}, - {name: 'Added, remove and replaced with undefined', set: [6, 7, 8, 9,, 10]} + { name: "Removed at the end", set: [1, 2, 3, 4] }, // Removed at the end + { name: "Removed at the start", set: [2, 3, 4, 5] }, // Remmoved at the start + { name: "Removed at the center", set: [1, 3, 5] }, // Removed at the center + { name: "Added at the end", set: [1, 2, 3, 4, 5, 6] }, // Added at the end + { name: "Added at the start", set: [6, 1, 2, 3, 4, 5] }, // Added at the start + { name: "Added at the center", set: [1, 2, 6, 3, 4, 5] }, // Added at the center + { name: "Reversed", set: [5, 4, 3, 2, 1] }, // Reversed + { name: "Switch positions", set: [1, 4, 3, 2, 5] }, // Switch positions, + { name: "Mixed positions", set: [1, 3, 2, 6, 5, 4] }, + { name: "Replaced with undefined", set: [1, 3, 2, , 5, 4] }, + { + name: "Added, remove and replaced with undefined", + set: [6, 7, 8, 9, , 10] + } ]; function getString(set) { - let str = '"; return str; } let beforeString = getString(set); - tests.forEach(test => { - it('Keyed list: ' + test.name, () => { + tests.forEach((test) => { + it("Keyed list: " + test.name, () => { let keys = [...set]; - let component = () => ; + let component = () => ( + + ); - let before = v.mount('body', component); + let before = v.mount("body", component); keys = [...test.set]; let after = v.update(); @@ -49,17 +56,21 @@ describe('Keyed lists', () => { }); }); - it('Keyed list: Replace with undefined and update with defined', () => { + it("Keyed list: Replace with undefined and update with defined", () => { let keys = [1, 2, 3, 4, 5]; - let component = () => ; + let component = () => ( + + ); - let before = v.mount('body', component); + let before = v.mount("body", component); - keys = [6, 7, 8, 9,, 10]; + keys = [6, 7, 8, 9, , 10]; let after = v.update(); let afterString = getString(keys); diff --git a/test/lifecycle_test.js b/test/lifecycle_test.js index aee854f..40038ca 100644 --- a/test/lifecycle_test.js +++ b/test/lifecycle_test.js @@ -1,10 +1,10 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; v.usePlugin(nodePlugin); -describe('Lifecycle', () => { - it('Mount and update', () => { +describe("Lifecycle", () => { + it("Mount and update", () => { let s = 1; let calls = []; @@ -14,23 +14,23 @@ describe('Lifecycle', () => { {...{ oncreate() { // After dom element is created and attached to the document - calls.push('component oncreate'); + calls.push("component oncreate"); }, onbeforeupdate() { // before dom element is updated // if you return false the update step is skipped - calls.push('component onbeforeupdate'); + calls.push("component onbeforeupdate"); }, onupdate() { // after dom element is updated - calls.push('component onupdate'); + calls.push("component onupdate"); }, onremove() { // after dom element is removed - calls.push('component onremove'); + calls.push("component onremove"); } }} > @@ -39,15 +39,15 @@ describe('Lifecycle', () => { {...{ oncreate() { // After dom element is created and attached to the document - calls.push('oncreate'); + calls.push("oncreate"); }, onupdate() { // after dom element is updated - calls.push('onupdate'); + calls.push("onupdate"); }, onremove() { // after dom element is removed - calls.push('onremove'); + calls.push("onremove"); } }} > @@ -60,13 +60,13 @@ describe('Lifecycle', () => { {(function () { let elem = []; if (s >= 0) { - for (let l = s; l--;) { + for (let l = s; l--; ) { if (l !== 4) { elem.push(
  • { - calls.push('onspanremove'); + calls.push("onspanremove"); }} > {l + 1} @@ -78,51 +78,50 @@ describe('Lifecycle', () => { } return elem; - }())} + })()} ); }; let result = []; let expectedDom = [ - '

    1

    • 1
    ', - '
      ', - '

      1

      • 1
      ', - '

      2

      • 2
      • 1
      ', - '

      1

      • 1
      ', - '

      3

      • 3
      • 2
      • 1
      ', - '
        ' + "

        1

        • 1
        ", + "
          ", + "

          1

          • 1
          ", + "

          2

          • 2
          • 1
          ", + "

          1

          • 1
          ", + "

          3

          • 3
          • 2
          • 1
          ", + "
            " ]; let expectedLifeCycleCalls = [ - 'component oncreate', - 'oncreate', - 'component onbeforeupdate', - 'component onupdate', - 'onremove', - 'onspanremove', - 'component onbeforeupdate', - 'component onupdate', - 'oncreate', - 'component onbeforeupdate', - 'component onupdate', - 'onupdate', - 'component onbeforeupdate', - 'component onupdate', - 'onupdate', - 'onspanremove', - 'component onbeforeupdate', - 'component onupdate', - 'onupdate', - 'component onbeforeupdate', - 'component onupdate', - 'onremove', - 'onspanremove', - 'onspanremove', - 'onspanremove' + "component oncreate", + "oncreate", + "component onbeforeupdate", + "component onupdate", + "onremove", + "onspanremove", + "component onbeforeupdate", + "component onupdate", + "oncreate", + "component onbeforeupdate", + "component onupdate", + "onupdate", + "component onbeforeupdate", + "component onupdate", + "onupdate", + "onspanremove", + "component onbeforeupdate", + "component onupdate", + "onupdate", + "component onbeforeupdate", + "component onupdate", + "onremove", + "onspanremove", + "onspanremove", + "onspanremove" ]; - - result.push(v.mount('body', Lifecycle)); + result.push(v.mount("body", Lifecycle)); s = 0; result.push(v.update()); s = 1; @@ -139,5 +138,4 @@ describe('Lifecycle', () => { expect(result).toEqual(expectedDom); expect(calls).toEqual(expectedLifeCycleCalls); }); - }); diff --git a/test/mount_n_update_test.js b/test/mount_n_update_test.js index 2ef6f88..e98a9b5 100644 --- a/test/mount_n_update_test.js +++ b/test/mount_n_update_test.js @@ -1,13 +1,13 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; v.usePlugin(nodePlugin); -describe('Mount and update', () => { - it('Mount and update with POJO component', () => { +describe("Mount and update", () => { + it("Mount and update with POJO component", () => { let Component = { - world: 'World', - id: 'example', + world: "World", + id: "example", view() { return
            Hello {this.world}
            ; } @@ -15,8 +15,8 @@ describe('Mount and update', () => { let result = {}; - result.before = v.mount('body', Component); - Component.world = 'John Doe'; + result.before = v.mount("body", Component); + Component.world = "John Doe"; result.after = v.update(); expect(result).toEqual({ @@ -25,17 +25,17 @@ describe('Mount and update', () => { }); }); - it('Mount and update with functional stateful component', () => { + it("Mount and update with functional stateful component", () => { let Component = function () { return
            Hello {this.world}
            ; }; - Component.world = 'World'; - Component.id = 'example'; + Component.world = "World"; + Component.id = "example"; let result = {}; - result.before = v.mount('body', Component); - Component.world = 'John Doe'; + result.before = v.mount("body", Component); + Component.world = "John Doe"; result.after = v.update(); expect(result).toEqual({ @@ -44,11 +44,11 @@ describe('Mount and update', () => { }); }); - it('Mount and update with functional stateless subcomponent', () => { + it("Mount and update with functional stateless subcomponent", () => { let SubComponent = (props) =>
            Hello {props.world}
            ; let state = { - world: 'World', - id: 'example' + world: "World", + id: "example" }; let Component = function () { return ; @@ -56,8 +56,8 @@ describe('Mount and update', () => { let result = {}; - result.before = v.mount('body', Component); - state.world = 'John Doe'; + result.before = v.mount("body", Component); + state.world = "John Doe"; result.after = v.update(); expect(result).toEqual({ @@ -66,18 +66,18 @@ describe('Mount and update', () => { }); }); - it('Handle multiple update calls', () => { + it("Handle multiple update calls", () => { let Component = { - world: 'World', - id: 'example', + world: "World", + id: "example", view() { return
            Hello {this.world}
            ; } }; let result = {}; - result.before = v.mount('body', Component); - Component.world = 'John Doe'; + result.before = v.mount("body", Component); + Component.world = "John Doe"; result.after = v.update(); result.afteragain = v.update(); @@ -88,17 +88,17 @@ describe('Mount and update', () => { }); }); - it('Antipattern: Mount and update with functional stateless component', () => { + it("Antipattern: Mount and update with functional stateless component", () => { let Component = (props) =>
            Hello {props.world}
            ; let props = { - world: 'World', - id: 'example' + world: "World", + id: "example" }; let result = {}; - result.before = v.mount('body', Component, props); - props.world = 'John Doe'; + result.before = v.mount("body", Component, props); + props.world = "John Doe"; result.after = v.update(props); expect(result).toEqual({ @@ -107,84 +107,88 @@ describe('Mount and update', () => { }); }); - it('Should update text node with dom node', () => { + it("Should update text node with dom node", () => { let text = true; - let Component = () => (text ? 'Hello world' :
            Hello world
            ); + let Component = () => (text ? "Hello world" :
            Hello world
            ); let result = {}; - result.before = v.mount('body', Component); + result.before = v.mount("body", Component); text = false; result.after = v.update(); expect(result).toEqual({ - before: 'Hello world', - after: '
            Hello world
            ' + before: "Hello world", + after: "
            Hello world
            " }); }); - it('Should update dom node with text node', () => { + it("Should update dom node with text node", () => { let text = false; - let Component = () => (text ? 'Hello world' :
            Hello world
            ); + let Component = () => (text ? "Hello world" :
            Hello world
            ); let result = {}; - result.before = v.mount('body', Component); + result.before = v.mount("body", Component); text = true; result.after = v.update(); expect(result).toEqual({ - before: '
            Hello world
            ', - after: 'Hello world' + before: "
            Hello world
            ", + after: "Hello world" }); }); - it('Should handle different types of data', () => { + it("Should handle different types of data", () => { let date = new Date(); - let Component = () => v('div', null, [null, 'Hello', , 1, date, { hello: 'world' }, ['Hello']]); - expect(v.mount('body', Component)).toEqual(`
            Hello1${date}[object Object]Hello
            `); + let Component = () => + v("div", null, [null, "Hello", , 1, date, { hello: "world" }, ["Hello"]]); + expect(v.mount("body", Component)).toEqual( + `
            Hello1${date}[object Object]Hello
            ` + ); }); - - it('Should handle svgs', () => { - // eslint-disable-next-line max-len - let svg = ''; + it("Should handle svgs", () => { + let svg = + // eslint-disable-next-line max-len + ''; let Component = () => v.trust(svg); // eslint-disable-next-line max-len - expect(v.mount('body', Component)).toEqual(svg); + expect(v.mount("body", Component)).toEqual(svg); }); - it('should fail silently if try to update before mount', () => { + it("should fail silently if try to update before mount", () => { v.unMount(); v.update(); }); - it('should handle text vnode as new node', () => { - let vnode = v.trust('Some text'); + it("should handle text vnode as new node", () => { + let vnode = v.trust("Some text"); let component = () => vnode; - let result = v.mount('body', component); + let result = v.mount("body", component); - expect(result).toEqual('Some text'); + expect(result).toEqual("Some text"); - vnode.children = ['Other text']; + vnode.children = ["Other text"]; let result2 = v.update(); - expect(result2).toEqual('Some text'); + expect(result2).toEqual("Some text"); }); - it('should handle the passing of data with the data property', () => { - let data = {foo: 'bar'}; - let onupdate = (newNode, oldNode) => expect(newNode.props.data).toEqual(oldNode.props.data); + it("should handle the passing of data with the data property", () => { + let data = { foo: "bar" }; + let onupdate = (newNode, oldNode) => + expect(newNode.props.data).toEqual(oldNode.props.data); let component = () =>
            ; - let result = v.mount('body', component); - expect(result).toEqual('
            '); + let result = v.mount("body", component); + expect(result).toEqual("
            "); let result2 = v.update(); - expect(result2).toEqual('
            '); + expect(result2).toEqual("
            "); }); - it('should create another v instance using the v.newInstance method', () => { + it("should create another v instance using the v.newInstance method", () => { // We create a new instance let v2 = v.newInstance(); @@ -192,12 +196,12 @@ describe('Mount and update', () => { let component = () => `Hello world ${count}`; // Get the first render - let result1 = v.mount('body', component); - let result2 = v2.mount('body', component); + let result1 = v.mount("body", component); + let result2 = v2.mount("body", component); // Bot updates must be equal - expect(result1).toEqual('Hello world 0'); - expect(result2).toEqual('Hello world 0'); + expect(result1).toEqual("Hello world 0"); + expect(result2).toEqual("Hello world 0"); // We increment the counter and unMount the first instance count++; @@ -208,65 +212,69 @@ describe('Mount and update', () => { let result4 = v2.update(); // For the first instance should be '' because component has been unMounted; - expect(result3).toEqual(''); + expect(result3).toEqual(""); // For the second instance should be 'Hello world 1' because it is still mounted - expect(result4).toEqual('Hello world 1'); + expect(result4).toEqual("Hello world 1"); }); - }); -describe.skip('performance test', () => { - +describe.skip("performance test", () => { let set = [1, 2, 3, 4, 5]; let tests = [ - {name: 'Removed at the end', set: [1, 2, 3, 4]}, // Removed at the end - {name: 'Removed at the start', set: [2, 3, 4, 5]}, // Remmoved at the start - {name: 'Removed at the center', set: [1, 3, 5]}, // Removed at the center - {name: 'Added at the end', set: [1, 2, 3, 4, 5, 6]}, // Added at the end - {name: 'Added at the start', set: [6, 1, 2, 3, 4, 5]}, // Added at the start - {name: 'Added at the center', set: [1, 2, 6, 3, 4, 5]}, // Added at the center - {name: 'Reversed', set: [5, 4, 3, 2, 1]}, // Reversed - {name: 'Switch positions', set: [1, 4, 3, 2, 5]}, // Switch positions, - {name: 'Mixed positions', set: [1, 3, 2, 6, 5, 4]}, - {name: 'Replaced with undefined', set: [1, 3, 2, , 5, 4]}, - {name: 'Added, remove and replaced with undefined', set: [6, 7, 8, 9,, 10]} + { name: "Removed at the end", set: [1, 2, 3, 4] }, // Removed at the end + { name: "Removed at the start", set: [2, 3, 4, 5] }, // Remmoved at the start + { name: "Removed at the center", set: [1, 3, 5] }, // Removed at the center + { name: "Added at the end", set: [1, 2, 3, 4, 5, 6] }, // Added at the end + { name: "Added at the start", set: [6, 1, 2, 3, 4, 5] }, // Added at the start + { name: "Added at the center", set: [1, 2, 6, 3, 4, 5] }, // Added at the center + { name: "Reversed", set: [5, 4, 3, 2, 1] }, // Reversed + { name: "Switch positions", set: [1, 4, 3, 2, 5] }, // Switch positions, + { name: "Mixed positions", set: [1, 3, 2, 6, 5, 4] }, + { name: "Replaced with undefined", set: [1, 3, 2, , 5, 4] }, + { + name: "Added, remove and replaced with undefined", + set: [6, 7, 8, 9, , 10] + } ]; function getString(set) { - let str = '
              '; + let str = "
                "; for (let key of set) { - str += key ? `
              • ${key}
              • ` : ''; + str += key ? `
              • ${key}
              • ` : ""; } - str += '
              '; + str += "
            "; return str; } let beforeString = getString(set); - tests.forEach(test => { - it('Render list: ' + test.name, () => { + tests.forEach((test) => { + it("Render list: " + test.name, () => { let keys = [...set]; - let component = () =>
              {keys.map(key => { - if (key) { - return
            • {key}
            • ; - }; - })}
            ; - - let before = v.mount('body', component); + let component = () => ( +
              + {keys.map((key) => { + if (key) { + return
            • {key}
            • ; + } + })} +
            + ); + + let before = v.mount("body", component); keys = [...test.set]; v.unMount(); - let after = v.mount('body', component); + let after = v.mount("body", component); let afterString = getString(test.set); expect(before).toEqual(beforeString); expect(after).toEqual(afterString); - for (let i = 100000; i--;) { + for (let i = 100000; i--; ) { v.unMount(); - v.mount('body', component); + v.mount("body", component); } }); }); - }); diff --git a/test/node_test.js b/test/node_test.js index 5d3d47d..004567c 100644 --- a/test/node_test.js +++ b/test/node_test.js @@ -1,13 +1,14 @@ -import expect from 'expect'; -import fs from 'fs'; -import '../lib'; -import nodePlugin from '../plugins/node'; -import packageJson from '../package.json'; +import expect from "expect"; +import fs from "fs"; +import "../lib"; +import nodePlugin from "../plugins/node"; +import packageJson from "../package.json"; v.usePlugin(nodePlugin); -describe('Node test', () => { - it('Get hyperscript string from html', () => { - let html = 'Hello world'; +describe("Node test", () => { + it("Get hyperscript string from html", () => { + let html = + 'Hello world'; let dom = v.htmlToHyperscript(html); @@ -18,7 +19,8 @@ describe('Node test', () => { ]) ]`); - html = 'Hello world'; + html = + 'Hello world'; dom = v.htmlToHyperscript(html); @@ -33,7 +35,8 @@ describe('Node test', () => { ]) ]`); - html = 'Hello world'; + html = + 'Hello world'; dom = v.htmlToHyperscript(html); @@ -49,7 +52,8 @@ describe('Node test', () => { ]) ]`); - html = 'Hello world'; + html = + 'Hello world'; dom = v.htmlToHyperscript(html); @@ -59,7 +63,8 @@ describe('Node test', () => { ]) ]`); - html = '
            Hello world
            '; + html = + '
            Hello world
            '; dom = v.htmlToHyperscript(html); @@ -80,40 +85,39 @@ describe('Node test', () => { ]`); }); - it('Should create a service worker file', async () => { - let file = '.tmp/sw.js'; + it("Should create a service worker file", async () => { + let file = ".tmp/sw.js"; await v.sw(file, { - name: 'Test', + name: "Test", version: packageJson.version, - urls: ['/', '/hello'] + urls: ["/", "/hello"] }); expect(fs.existsSync(file)).toBeTruthy(); - }); // NOTE: This test will take some time between 30 and 60 seconds - it('Should generate icons, manifest.json and a links component', async () => { + it("Should generate icons, manifest.json and a links component", async () => { let favicons = { - iconsPath: '.tmp/', // Path to the generated icons - linksViewPath: '.tmp/', // Path to the generated links file + iconsPath: ".tmp/", // Path to the generated icons + linksViewPath: ".tmp/", // Path to the generated links file // favicons options - path: '/icons/', // Path for overriding default icons path. `string` + path: "/icons/", // Path for overriding default icons path. `string` appName: packageJson.name, // Your application's name. `string` appShortName: packageJson.name, // Your application's short_name. `string`. Optional. If not set, appName will be used. `string` appDescription: packageJson.description, // Your application's description. `string` - developerName: 'Christian César Robledo López (Masquerade Circus)', // Your (or your developer's) name. `string` - developerURL: 'http://masquerade-circus.net', - dir: 'auto', - lang: 'en-US', - background: '#fff', // Background colour for flattened icons. `string` - theme_color: '#fff', // Theme color user for example in Android's task switcher. `string` + developerName: "Christian César Robledo López (Masquerade Circus)", // Your (or your developer's) name. `string` + developerURL: "http://masquerade-circus.net", + dir: "auto", + lang: "en-US", + background: "#fff", // Background colour for flattened icons. `string` + theme_color: "#fff", // Theme color user for example in Android's task switcher. `string` appleStatusBarStyle: "black-translucent", // Style for Apple status bar: "black-translucent", "default", "black". `string` - display: 'standalone', // Android display: "browser" or "standalone". `string` - orientation: 'any', // Android orientation: "any" "portrait" or "landscape". `string` - scope: '/', // set of URLs that the browser considers within your app - start_url: '/', // Start URL when launching the application from a device. `string` + display: "standalone", // Android display: "browser" or "standalone". `string` + orientation: "any", // Android orientation: "any" "portrait" or "landscape". `string` + scope: "/", // set of URLs that the browser considers within your app + start_url: "/", // Start URL when launching the application from a device. `string` version: packageJson.version, // Your application's version number. `number` logging: false, // Print logs to console? `boolean` pixel_art: false, // Keeps pixels "sharp" when scaling up, for pixel art. Only supported in offline mode. @@ -140,24 +144,22 @@ describe('Node test', () => { } }; - await v.icons('./assets/icon.png', favicons); - expect(fs.existsSync('.tmp/favicon.ico')).toBeTruthy(); - expect(fs.existsSync('.tmp/links.js')).toBeTruthy(); - expect(fs.existsSync('.tmp/manifest.json')).toBeTruthy(); - + await v.icons("./assets/icon.png", favicons); + expect(fs.existsSync(".tmp/favicon.ico")).toBeTruthy(); + expect(fs.existsSync(".tmp/links.js")).toBeTruthy(); + expect(fs.existsSync(".tmp/manifest.json")).toBeTruthy(); }); - it('should remove unused css', async () => { - let html = 'Hello world'; + it("should remove unused css", async () => { + let html = "Hello world"; let css = ` span{display:block;} span.hello{display: inline-block} `; - await v.inline.css({raw: css}); + await v.inline.css({ raw: css }); let cleanCss = await v.inline.uncss([html]); - expect(cleanCss).toEqual('span{display:block}'); + expect(cleanCss).toEqual("span{display:block}"); }); - }); diff --git a/test/request_test.js b/test/request_test.js index 6040285..cd2bd71 100644 --- a/test/request_test.js +++ b/test/request_test.js @@ -1,103 +1,134 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; -import requestPlugin from '../plugins/request'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; +import requestPlugin from "../plugins/request"; v.usePlugin(nodePlugin); v.usePlugin(requestPlugin); -describe('Request', () => { - it('should get', async () => { - let res = await v.request.get('https://jsonplaceholder.typicode.com/posts/1'); +describe("Request", () => { + it("should get", async () => { + let res = await v.request.get( + "https://jsonplaceholder.typicode.com/posts/1" + ); expect(res).toEqual({ userId: 1, id: 1, - title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', - body: 'quia et suscipit\n' + - 'suscipit recusandae consequuntur expedita et cum\n' + - 'reprehenderit molestiae ut ut quas totam\n' + - 'nostrum rerum est autem sunt rem eveniet architecto' + title: + "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + body: + "quia et suscipit\n" + + "suscipit recusandae consequuntur expedita et cum\n" + + "reprehenderit molestiae ut ut quas totam\n" + + "nostrum rerum est autem sunt rem eveniet architecto" }); }); - it('should post', async () => { - let res = await v.request.post('https://jsonplaceholder.typicode.com/posts', { - title: 'foo', - body: 'bar', - userId: 1 - }, { - headers: { - "Content-Type": "application/json; charset=UTF-8" + it("should post", async () => { + let res = await v.request.post( + "https://jsonplaceholder.typicode.com/posts", + { + title: "foo", + body: "bar", + userId: 1 + }, + { + headers: { + "Content-Type": "application/json; charset=UTF-8" + } } - }); + ); expect(res).toEqual({ userId: 1, id: 101, - title: 'foo', - body: 'bar' + title: "foo", + body: "bar" }); }); - it('should put', async () => { - let res = await v.request.put('https://jsonplaceholder.typicode.com/posts/1', { - id: 1, - title: 'foo', - body: 'bar', - userId: 1 - }, { - headers: { - "Content-Type": "application/json; charset=UTF-8" + it("should put", async () => { + let res = await v.request.put( + "https://jsonplaceholder.typicode.com/posts/1", + { + id: 1, + title: "foo", + body: "bar", + userId: 1 + }, + { + headers: { + "Content-Type": "application/json; charset=UTF-8" + } } - }); + ); expect(res).toEqual({ userId: 1, id: 1, - title: 'foo', - body: 'bar' + title: "foo", + body: "bar" }); }); - it('should patch', async () => { - let res = await v.request.patch('https://jsonplaceholder.typicode.com/posts/1', { - body: 'bar' - }, { - headers: { - "Content-Type": "application/json; charset=UTF-8" + it("should patch", async () => { + let res = await v.request.patch( + "https://jsonplaceholder.typicode.com/posts/1", + { + body: "bar" + }, + { + headers: { + "Content-Type": "application/json; charset=UTF-8" + } } - }); - expect(res).toEqual({ - userId: 1, - id: 1, - title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', - body: 'bar' - }, { - headers: { - "Content-Type": "application/json; charset=UTF-8" + ); + expect(res).toEqual( + { + userId: 1, + id: 1, + title: + "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + body: "bar" + }, + { + headers: { + "Content-Type": "application/json; charset=UTF-8" + } } - }); + ); }); - it('should delete', async () => { - let res = await v.request.delete('https://jsonplaceholder.typicode.com/posts/1'); + it("should delete", async () => { + let res = await v.request.delete( + "https://jsonplaceholder.typicode.com/posts/1" + ); expect(res).toEqual({}); }); - it('should serialize data', async () => { - let res = await v.request.get('https://jsonplaceholder.typicode.com/posts/', { - userId: 1 - }); + it("should serialize data", async () => { + let res = await v.request.get( + "https://jsonplaceholder.typicode.com/posts/", + { + userId: 1 + } + ); expect(res).toEqual(expect.any(Array)); expect(res.length).toEqual(10); }); - it('should resolve with full response', async () => { - let res = await v.request.get('https://jsonplaceholder.typicode.com/posts/1', null, {resolveWithFullResponse: true}); - expect(res).toEqual(expect.objectContaining({ - body: expect.any(Object), - url: 'https://jsonplaceholder.typicode.com/posts/1', - status: 200, - statusText: 'OK', - headers: expect.any(Object) - })); + it("should resolve with full response", async () => { + let res = await v.request.get( + "https://jsonplaceholder.typicode.com/posts/1", + null, + { resolveWithFullResponse: true } + ); + expect(res).toEqual( + expect.objectContaining({ + body: expect.any(Object), + url: "https://jsonplaceholder.typicode.com/posts/1", + status: 200, + statusText: "OK", + headers: expect.any(Object) + }) + ); }); }); diff --git a/test/router_test.js b/test/router_test.js index 8d5ac6d..506f891 100644 --- a/test/router_test.js +++ b/test/router_test.js @@ -1,43 +1,72 @@ import expect from "expect"; -import '../lib'; +import "../lib"; import nodePlugin from "../plugins/node"; import router from "../plugins/router"; v.usePlugin(nodePlugin); v.usePlugin(router); -describe('Router', () => { +// eslint-disable-next-line max-lines-per-function +describe("Router", () => { it("Dev test", async () => { let Component = () =>
            Hello world
            ; let router = v.Router(); router - .get('/', () => console.log('Hello 1'), () => Component) - .get('/hello', [() => console.log('Hello 2'), () => Component]) - .get('/hello/', [() => console.log('Hello 3'), () => Component]) - .get('/:hello', [() => console.log('Hello 4'), () => Component]) - .get('/hello/(.*)', [() => console.log('Hello 5'), () => Component]) - .get('/:hello/world', () => console.log('Hello 6'), [() => console.log('Hello 6')], () => Component) - .get('/hello/:world', [() => console.log('Hello 7'), () => Component], () => console.log('Hello 7')); + .get( + "/", + () => console.log("Hello 1"), + () => Component + ) + .get("/hello", [() => console.log("Hello 2"), () => Component]) + .get("/hello/", [() => console.log("Hello 3"), () => Component]) + .get("/:hello", [() => console.log("Hello 4"), () => Component]) + .get("/hello/(.*)", [() => console.log("Hello 5"), () => Component]) + .get( + "/:hello/world", + () => console.log("Hello 6"), + [() => console.log("Hello 6")], + () => Component + ) + .get( + "/hello/:world", + [() => console.log("Hello 7"), () => Component], + () => console.log("Hello 7") + ); let subrouter = v.Router(); subrouter - .get('/', () => console.log('Hello 1'), () => Component) - .get('/hello', [() => console.log('Hello 2'), () => Component]) - .get('/hello/', [() => console.log('Hello 3'), () => Component]) - .get('/:hello', [() => console.log('Hello 4'), () => Component]) - .get('/hello/(.*)', [() => console.log('Hello 5'), () => Component]) - .get('/:hello/world', () => console.log('Hello 6'), [() => console.log('Hello 6')], () => Component) - .get('/hello/:world', [() => console.log('Hello 7'), () => Component], () => console.log('Hello 7')) - .use(() => () => 'Not ok'); - - router.use('/ok', subrouter); - router.use(() => () => 'Not found'); - + .get( + "/", + () => console.log("Hello 1"), + () => Component + ) + .get("/hello", [() => console.log("Hello 2"), () => Component]) + .get("/hello/", [() => console.log("Hello 3"), () => Component]) + .get("/:hello", [() => console.log("Hello 4"), () => Component]) + .get("/hello/(.*)", [() => console.log("Hello 5"), () => Component]) + .get( + "/:hello/world", + () => console.log("Hello 6"), + [() => console.log("Hello 6")], + () => Component + ) + .get( + "/hello/:world", + [() => console.log("Hello 7"), () => Component], + () => console.log("Hello 7") + ) + .use(() => () => "Not ok"); + + router.use("/ok", subrouter); + router.use(() => () => "Not found"); v.routes("body", router); - expect(await v.routes.go('/ok/not/found/url?hello=world')).toEqual('Not ok'); - expect(await v.routes.go('/not/found/url?hello=world')).toEqual('Not found'); - + expect(await v.routes.go("/ok/not/found/url?hello=world")).toEqual( + "Not ok" + ); + expect(await v.routes.go("/not/found/url?hello=world")).toEqual( + "Not found" + ); }); it("Mount and update with POJO component", async () => { @@ -65,7 +94,6 @@ describe('Router', () => { after: '
            Hello John Doe
            ', final: '
            Hello World
            ' }); - }); it("Mount and update with functional stateful component", async () => { @@ -73,8 +101,8 @@ describe('Router', () => { return
            Hello {this.world}
            ; }; - Component.world = 'World'; - Component.id = 'example'; + Component.world = "World"; + Component.id = "example"; let result = {}; let router = v.Router(); @@ -92,11 +120,10 @@ describe('Router', () => { after: '
            Hello John Doe
            ', final: '
            Hello World
            ' }); - }); it("Mount and update with functional stateless subcomponent", async () => { - let SubComponent = props =>
            Hello {props.world}
            ; + let SubComponent = (props) =>
            Hello {props.world}
            ; let state = { world: "World", id: "example" @@ -121,11 +148,10 @@ describe('Router', () => { after: '
            Hello John Doe
            ', final: '
            Hello World
            ' }); - }); it("Antipattern: Mount and update with functional stateless component", async () => { - let Component = props =>
            Hello {props.world}
            ; + let Component = (props) =>
            Hello {props.world}
            ; let props = { world: "World", id: "example" @@ -147,7 +173,6 @@ describe('Router', () => { after: '
            Hello John Doe
            ', final: '
            Hello World
            ' }); - }); it("Test not found url", async () => { @@ -168,7 +193,6 @@ describe('Router', () => { found: "Hello world", notFound: "
            Ups, no route was found.
            " }); - }); it("Test params", async () => { @@ -179,15 +203,19 @@ describe('Router', () => { let Hello = function () { return (
            - Hello {this.world}, what's {this.up} + Hello {this.world}, what's {this.up}
            ); }; let router = v.Router(); - router.get("/hello", () => Object.assign(Hello, Store), () => Hello); + router.get( + "/hello", + () => Object.assign(Hello, Store), + () => Hello + ); router.get("/hello/:world/whats/:up", [ - ({params}) => Object.assign(Hello, params), + ({ params }) => Object.assign(Hello, params), () => Hello ]); @@ -201,7 +229,6 @@ describe('Router', () => { before: "
            Hello world, what's up
            ", after: "
            Hello Mike, what's new
            " }); - }); it("Test mix single and array of middlewares", async () => { @@ -241,26 +268,25 @@ describe('Router', () => { "Middleware 1.2.4", "Middleware 2" ]); - }); it("Test subrouter", async () => { let Component = function () { return (
            - Hello {this.world}, from {this.country} + Hello {this.world}, from {this.country}
            ); }; let subrouter = v.Router(); subrouter - .get("/from/:country", ({params}) => { + .get("/from/:country", ({ params }) => { Component.world = params.world; Component.country = params.country; return Component; }) - .get("/", ({params}) => { + .get("/", ({ params }) => { Component.world = params.world; Component.country = "USA"; return Component; @@ -278,7 +304,6 @@ describe('Router', () => { before: "
            Hello Mike, from USA
            ", after: "
            Hello John, from Mexico
            " }); - }); it("Test with parent component", async () => { @@ -297,7 +322,6 @@ describe('Router', () => { let result = await v.routes.go(ParentComponent, "/"); expect(result).toEqual("
            Hello World
            "); - }); it("Test show error when calling with a non url", async () => { @@ -315,12 +339,13 @@ describe('Router', () => { } expect(err).toEqual("v.router.url.required"); - }); it("Test show error when no component is returned", async () => { let router = v.Router(); - router.get("/", () => {}); + router.get("/", () => { + // Component is not returned + }); v.routes("body", router); let err; @@ -331,7 +356,6 @@ describe('Router', () => { } expect(err).toEqual("The url / requested wasn't found"); - }); it("Test get routes", () => { @@ -344,6 +368,10 @@ describe('Router', () => { v.routes("body", router); - expect(v.routes.get()).toEqual(["/hello/:world/from/:country", "/hello/:world", "/"]); + expect(v.routes.get()).toEqual([ + "/hello/:world/from/:country", + "/hello/:world", + "/" + ]); }); }); diff --git a/test/signals_test.js b/test/signals_test.js index f75425a..db5bc7e 100644 --- a/test/signals_test.js +++ b/test/signals_test.js @@ -1,13 +1,13 @@ -import expect from 'expect'; -import '../lib'; -import nodePlugin from '../plugins/node'; -import signalsPlugin from '../plugins/signals'; +import expect from "expect"; +import "../lib"; +import nodePlugin from "../plugins/node"; +import signalsPlugin from "../plugins/signals"; v.usePlugin(nodePlugin); v.usePlugin(signalsPlugin); -describe('Signals', () => { - it('should create a signal', async () => { +describe("Signals", () => { + it("should create a signal", async () => { // Create signal let counter = v.Signal(0); @@ -27,42 +27,40 @@ describe('Signals', () => { let effect = counter((val) => expect(val).toBeGreaterThanOrEqual(0)); // Named computed / Getter - counter.getter('hello', (val) => 'hello ' + val); + counter.getter("hello", (val) => "hello " + val); // Pure computed - let computed = counter((val) => 'hello ' + val); + let computed = counter((val) => "hello " + val); // Unlinked Pure computed - let unlinked = v.Signal(() => 'hello ' + counter.value); + let unlinked = v.Signal(() => "hello " + counter.value); + let interval = setInterval(() => (counter.value += 1), 1000); + expect(counter.hello).toEqual("hello 0"); + expect(computed()).toEqual("hello 0"); + expect(computed.value).toEqual("hello 0"); + expect(unlinked()).toEqual("hello 0"); + expect(unlinked.value).toEqual("hello 0"); - let interval = setInterval(() => counter.value += 1, 1000); - expect(counter.hello).toEqual('hello 0'); - expect(computed()).toEqual('hello 0'); - expect(computed.value).toEqual('hello 0'); - expect(unlinked()).toEqual('hello 0'); - expect(unlinked.value).toEqual('hello 0'); - - await new Promise(resolve => setTimeout(() => resolve(), 2500)); + await new Promise((resolve) => setTimeout(() => resolve(), 2500)); // effect.unsubscribe(); counter.cleanup(); - expect(counter.hello).toEqual('hello 2'); - expect(computed()).toEqual('hello 2'); - expect(computed.value).toEqual('hello 2'); - expect(unlinked()).toEqual('hello 2'); - expect(unlinked.value).toEqual('hello 2'); + expect(counter.hello).toEqual("hello 2"); + expect(computed()).toEqual("hello 2"); + expect(computed.value).toEqual("hello 2"); + expect(unlinked()).toEqual("hello 2"); + expect(unlinked.value).toEqual("hello 2"); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); clearInterval(interval); - expect(counter.hello).toEqual('hello 4'); - expect(computed()).toEqual('hello 4'); - expect(computed.value).toEqual('hello 4'); - expect(unlinked()).toEqual('hello 4'); - expect(unlinked.value).toEqual('hello 4'); - + expect(counter.hello).toEqual("hello 4"); + expect(computed()).toEqual("hello 4"); + expect(computed.value).toEqual("hello 4"); + expect(unlinked()).toEqual("hello 4"); + expect(unlinked.value).toEqual("hello 4"); }); - it('should test effect cleanup', async () => { + it("should test effect cleanup", async () => { let delay = v.Signal(1000); let count = v.Signal(0); let effectInterval = delay((delay) => { @@ -72,67 +70,68 @@ describe('Signals', () => { return () => clearInterval(interval); }); - await new Promise(resolve => setTimeout(() => resolve(), 1000)); + await new Promise((resolve) => setTimeout(() => resolve(), 1000)); expect(count()).toEqual(1); expect(count.value).toEqual(1); delay(500); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); expect(count()).toEqual(4); expect(count.value).toEqual(4); effectInterval.cleanup(); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); expect(count()).toEqual(4); expect(count.value).toEqual(4); delay.cleanup(); count.cleanup(); }); - it('should test deep state effect cleanup', async () => { + it("should test deep state effect cleanup", async () => { let state = v.Signal({ count: 0, delay: 1000 }); let effectInterval2 = state(() => { let interval = setInterval(() => { - state('count', current => current + 1); + state("count", (current) => current + 1); }, state.value.delay); return () => clearInterval(interval); }); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); - expect(state()).toEqual({count: 1, delay: 1000}); - expect(state.value).toEqual({count: 1, delay: 1000}); - state('delay', 500); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); - expect(state()).toEqual({count: 4, delay: 500}); - expect(state.value).toEqual({count: 4, delay: 500}); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); + expect(state()).toEqual({ count: 1, delay: 1000 }); + expect(state.value).toEqual({ count: 1, delay: 1000 }); + state("delay", 500); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); + expect(state()).toEqual({ count: 4, delay: 500 }); + expect(state.value).toEqual({ count: 4, delay: 500 }); effectInterval2.cleanup(); - await new Promise(resolve => setTimeout(() => resolve(), 2000)); - expect(state()).toEqual({count: 4, delay: 500}); - expect(state.value).toEqual({count: 4, delay: 500}); + await new Promise((resolve) => setTimeout(() => resolve(), 2000)); + expect(state()).toEqual({ count: 4, delay: 500 }); + expect(state.value).toEqual({ count: 4, delay: 500 }); }); }); -describe('Hooks like pattern', () => { - - it('should create a simple counter', async () => { +describe("Hooks like pattern", () => { + it("should create a simple counter", async () => { let Counter = (ms) => { let count = v.Signal(0); let interval = setInterval(() => { count.value = count.value + 1; }, ms); - return () =>
            clearInterval(interval)}>{count.value}
            ; + return () => ( +
            clearInterval(interval)}>{count.value}
            + ); }; - let result = v.mount('div', Counter(1000)); - expect(result).toEqual('
            0
            '); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter(1000)); + expect(result).toEqual("
            0
            "); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
            2
            '); + expect(result).toEqual("
            2
            "); v.unMount(); }); - it('should create a counter with delay change', async () => { + it("should create a counter with delay change", async () => { let Counter = (ms) => { let delay = v.Signal(ms); let count = v.Signal(0); @@ -145,15 +144,15 @@ describe('Hooks like pattern', () => { return () =>
            {count.value}
            ; }; - let result = v.mount('div', Counter(1000)); - expect(result).toEqual('
            0
            '); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter(1000)); + expect(result).toEqual("
            0
            "); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
            2
            '); + expect(result).toEqual("
            2
            "); v.unMount(); }); - it('should create a counter with deep state', async () => { + it("should create a counter with deep state", async () => { let Counter = (ms) => { let state = v.Signal({ count: 0, @@ -161,18 +160,18 @@ describe('Hooks like pattern', () => { }); let interval = state(() => { let interval = setInterval(() => { - state('count', current => current + 1); + state("count", (current) => current + 1); }, state.value.delay); return () => clearInterval(interval); }); return () =>
            {state.value.count}
            ; }; - let result = v.mount('div', Counter(1000)); - expect(result).toEqual('
            0
            '); - await new Promise(resolve => setTimeout(() => resolve(), 2050)); + let result = v.mount("div", Counter(1000)); + expect(result).toEqual("
            0
            "); + await new Promise((resolve) => setTimeout(() => resolve(), 2050)); result = v.update(); - expect(result).toEqual('
            2
            '); + expect(result).toEqual("
            2
            "); v.unMount(); }); }); diff --git a/test/store_test.js b/test/store_test.js index c648d37..8f82a5e 100644 --- a/test/store_test.js +++ b/test/store_test.js @@ -1,6 +1,6 @@ -import expect from 'expect'; -import '../lib'; -import StorePlugin from '../plugins/store'; +import expect from "expect"; +import "../lib"; +import StorePlugin from "../plugins/store"; v.usePlugin(StorePlugin); function getNewStore() { @@ -17,7 +17,7 @@ function getNewStore() { state.a = state.a + payload; }, changeC(state, payload) { - state.c = {...state.c, a: payload }; + state.c = { ...state.c, a: payload }; }, changeCDirectly(state, payload) { state.c.a = payload; @@ -27,7 +27,7 @@ function getNewStore() { pushB(context, payload) { return new Promise((resolve) => { setTimeout(() => { - context.commit('pushB', payload); + context.commit("pushB", payload); resolve(); }, 1000); }); @@ -47,14 +47,13 @@ function getNewStore() { } // eslint-disable-next-line max-lines-per-function -describe('Store slim', () => { - - it('Create empty state if state is not passed', () => { +describe("Store slim", () => { + it("Create empty state if state is not passed", () => { let store = new v.Store(); expect(store.state).toBeDefined(); }); - it('Use deepFrozen to froze the state', () => { + it("Use deepFrozen to froze the state", () => { let store = new v.Store({ state: { a: { @@ -71,71 +70,82 @@ describe('Store slim', () => { expect(Object.isFrozen(store.state.a.b.c.d)).toBeTruthy(); }); - it('Throw error if you try to mutate the state directly', () => { + it("Throw error if you try to mutate the state directly", () => { let store = getNewStore(); - expect(() => (store.state.b = 1)).toThrowError('You need to commit a mutation to change the state'); + expect(() => (store.state.b = 1)).toThrowError( + "You need to commit a mutation to change the state" + ); }); - it('Throw error if you try to mutate a deeper property of the state directly', () => { + it("Throw error if you try to mutate a deeper property of the state directly", () => { let store = getNewStore(); - expect(() => store.state.b.push(1)).toThrowError('Cannot add property 1, object is not extensible'); + expect(() => store.state.b.push(1)).toThrowError( + "Cannot add property 1, object is not extensible" + ); }); - it('Throw error if you try to remove a property directly', () => { + it("Throw error if you try to remove a property directly", () => { let store = getNewStore(); - expect(() => delete store.state.b).toThrowError('You need to commit a mutation to change the state'); + expect(() => delete store.state.b).toThrowError( + "You need to commit a mutation to change the state" + ); }); - it('Throw error if you try to remove a deeper property directly', () => { + it("Throw error if you try to remove a deeper property directly", () => { let store = getNewStore(); - expect(() => delete store.state.c.a).toThrowError("Cannot delete property 'a' of #"); + expect(() => delete store.state.c.a).toThrowError( + "Cannot delete property 'a' of #" + ); }); - it('Mutate the state by commit', () => { + it("Mutate the state by commit", () => { let store = getNewStore(); expect(store.state.a).toEqual(0); - store.commit('increment', 1); + store.commit("increment", 1); expect(store.state.a).toEqual(1); expect(store.state.b).toEqual([1]); - store.commit('deleteB'); + store.commit("deleteB"); expect(store.state.b).toBeUndefined(); }); - it('Throw error if you try to commit an undefined mutation', () => { + it("Throw error if you try to commit an undefined mutation", () => { let store = getNewStore(); - expect(() => store.commit('hello')).toThrowError('The mutation "hello" does not exists.'); + expect(() => store.commit("hello")).toThrowError( + 'The mutation "hello" does not exists.' + ); }); - it('Mutate the state by dispatch', async () => { + it("Mutate the state by dispatch", async () => { let store = getNewStore(); expect(store.state.b).toEqual([1]); - await store.dispatch('pushB', 2); + await store.dispatch("pushB", 2); expect(store.state.b).toEqual([1, 2]); - }); - it('Throw error if you try to dispatch an undefined action', () => { + it("Throw error if you try to dispatch an undefined action", () => { let store = getNewStore(); - expect(() => store.dispatch('hello')).toThrowError('The action "hello" does not exists.'); + expect(() => store.dispatch("hello")).toThrowError( + 'The action "hello" does not exists.' + ); }); - it('Use a getter to obtain a property from the state', () => { + it("Use a getter to obtain a property from the state", () => { let store = getNewStore(); expect(store.getters.items).toEqual([1]); }); - it('Use a getter to obtain data using another getter', () => { + it("Use a getter to obtain data using another getter", () => { let store = getNewStore(); expect(store.getters.length).toEqual(1); }); - it('Fail silently if you try to get an undefined getter, getter must return undefined', () => { + it("Fail silently if you try to get an undefined getter, getter must return undefined", () => { let store = getNewStore(); expect(store.getters.ok).toBeUndefined(); }); - it('Declare state as factory function', () => { + it("Declare state as factory function", () => { const myModule = { state() { return { @@ -152,11 +162,10 @@ describe('Store slim', () => { const store1 = new v.Store(myModule); const store2 = new v.Store(myModule); - store1.commit('increment', 5); - store2.commit('increment', 3); + store1.commit("increment", 5); + store2.commit("increment", 3); expect(store1.state.count).toEqual(6); expect(store2.state.count).toEqual(4); }); - });