From 00129c25ab4e1627cc7feae3fb04f3af35fb4e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Wed, 29 Aug 2018 16:36:14 +0200 Subject: [PATCH 1/9] Fix SVG classes example in readme This snippet was added in #287, but it clearly was never tested because it doesn't work (the `underline` class is simply overwritten). --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 47a1692..b8961a9 100644 --- a/README.md +++ b/README.md @@ -525,12 +525,10 @@ You can add dynamic classes to SVG elements for these cases by using the _attrib ```js h('svg', [ - h('text.underline', { // 'underline' is a selector class, remain unchanged between renders. + h('text', { attrs: { - // 'active' and 'red' are dynamic classes, they can change between renders - // so we need to put them in the class attribute. // (Normally we'd use the classModule, but it doesn't work inside SVG) - class: [isActive && "active", isColored && "red"].filter(Boolean).join(" ") + class: ["underline", isActive && "active", isColored && "red"].filter(Boolean).join(" ") } }, 'Hello World' From 102fb5940cb357d1c45faf28a175cf0693c113cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Wed, 29 Aug 2018 17:27:09 +0200 Subject: [PATCH 2/9] Suggesst using classList polyfill This seems like a much better solution --- README.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b8961a9..47be6fc 100644 --- a/README.md +++ b/README.md @@ -517,24 +517,8 @@ See also the [SVG example](./examples/svg) and the [SVG Carousel example](./exam #### Using Classes in SVG Elements Certain browsers (like IE <=11) [do not support `classList` property in SVG elements](http://caniuse.com/#feat=classlist). -Hence, the _class_ module (which uses `classList` property internally) will not work for these browsers. - -The classes in selectors for SVG elements work fine from version 0.6.7. - -You can add dynamic classes to SVG elements for these cases by using the _attributes_ module and an Array as shown below: - -```js -h('svg', [ - h('text', { - attrs: { - // (Normally we'd use the classModule, but it doesn't work inside SVG) - class: ["underline", isActive && "active", isColored && "red"].filter(Boolean).join(" ") - } - }, - 'Hello World' - ) -]) -``` +Because the _class_ module internally uses `classList`, it will not work in this case unless you use a [classList polyfill](https://www.npmjs.com/package/classlist-polyfill). +(If you don't want to use a polyfill, you can use the `class` attribute with the _attributes_ module). ### Thunks From 808944d2f31c4e85e256ac2f9c6356803f1a5dcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2019 08:19:30 +0000 Subject: [PATCH 3/9] Bump handlebars from 4.1.1 to 4.5.1 Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.1 to 4.5.1. - [Release notes](https://github.com/wycats/handlebars.js/releases) - [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md) - [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.1...v4.5.1) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2458e45..eaa52d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3494,9 +3494,9 @@ } }, "handlebars": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", - "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", + "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", "dev": true, "requires": { "neo-async": "^2.6.0", From 4243938d6af9c8232455410daf5b6b8009a6d9d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2019 08:19:31 +0000 Subject: [PATCH 4/9] Bump fstream from 1.0.11 to 1.0.12 Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12. - [Release notes](https://github.com/npm/fstream/releases) - [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12) Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2458e45..d671de6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2881,9 +2881,9 @@ } }, "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -2893,9 +2893,9 @@ }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true } } From 32a0ff3733c7ea16bdce82cef6bdcfc50ad2601e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2019 05:49:57 +0000 Subject: [PATCH 5/9] Bump js-yaml from 3.13.0 to 3.13.1 Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.13.0 to 3.13.1. - [Release notes](https://github.com/nodeca/js-yaml/releases) - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/3.13.0...3.13.1) Signed-off-by: dependabot[bot] --- package-lock.json | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae86ed3..f01c966 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1446,8 +1446,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "import-fresh": { "version": "2.0.0", @@ -1459,16 +1458,6 @@ "resolve-from": "^3.0.0" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -2250,8 +2239,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "glob-parent": { "version": "5.1.0", @@ -2277,16 +2265,6 @@ "is-extglob": "^2.1.1" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", @@ -5224,9 +5202,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", - "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", From 35796cb124f8eeff93ed60f54e01babc0a5c9f31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2019 19:00:21 +0000 Subject: [PATCH 6/9] Bump mixin-deep from 1.3.1 to 1.3.2 Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/jonschlinkert/mixin-deep/releases) - [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 860211e..7f0e9d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6421,9 +6421,9 @@ } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", From dcdde2e8696bb3378a91106f1ef7206d17e65590 Mon Sep 17 00:00:00 2001 From: "Shahar Or (mightyiam)" Date: Fri, 22 Nov 2019 15:02:26 +0700 Subject: [PATCH 7/9] style: @typescript-eslint/array-type --- .eslintrc.js | 1 - src/h.ts | 2 +- src/modules/style.ts | 2 +- src/snabbdom.ts | 26 +++++++++++++------------- src/thunk.ts | 6 +++--- src/tovnode.ts | 2 +- src/vnode.ts | 2 +- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ab441a7..d4b958f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,7 +2,6 @@ module.exports = { extends: 'standard-with-typescript', parserOptions: { project: [ './tsconfig.json', ] }, rules: { - '@typescript-eslint/array-type': 'off', '@typescript-eslint/brace-style': 'off', '@typescript-eslint/consistent-type-assertions': 'off', '@typescript-eslint/consistent-type-definitions': 'off', diff --git a/src/h.ts b/src/h.ts index 9b9886c..ed4593e 100644 --- a/src/h.ts +++ b/src/h.ts @@ -1,5 +1,5 @@ import {vnode, VNode, VNodeData} from './vnode'; -export type VNodes = Array; +export type VNodes = VNode[]; export type VNodeChildElement = VNode | string | number | undefined | null; export type ArrayOrElement = T | T[]; export type VNodeChildren = ArrayOrElement diff --git a/src/modules/style.ts b/src/modules/style.ts index 9514913..33dc57f 100755 --- a/src/modules/style.ts +++ b/src/modules/style.ts @@ -73,7 +73,7 @@ function applyRemoveStyle(vnode: VNode, rm: () => void): void { reflowForced = true; } var name: string, elm = vnode.elm, i = 0, compStyle: CSSStyleDeclaration, - style = s.remove, amount = 0, applied: Array = []; + style = s.remove, amount = 0, applied: string[] = []; for (name in style) { applied.push(name); (elm as any).style[name] = style[name]; diff --git a/src/snabbdom.ts b/src/snabbdom.ts index a6f976b..a61be9f 100644 --- a/src/snabbdom.ts +++ b/src/snabbdom.ts @@ -8,7 +8,7 @@ import htmlDomApi, {DOMAPI} from './htmldomapi'; function isUndef(s: any): boolean { return s === undefined; } function isDef(s: any): boolean { return s !== undefined; } -type VNodeQueue = Array; +type VNodeQueue = VNode[]; const emptyNode = vnode('', {}, [], undefined, undefined); @@ -23,12 +23,12 @@ function isVnode(vnode: any): vnode is VNode { type KeyToIndexMap = {[key: string]: number}; type ArraysOf = { - [K in keyof T]: (T[K])[]; + [K in keyof T]: Array; } type ModuleHooks = ArraysOf; -function createKeyToOldIdx(children: Array, beginIdx: number, endIdx: number): KeyToIndexMap { +function createKeyToOldIdx(children: VNode[], beginIdx: number, endIdx: number): KeyToIndexMap { let i: number, map: KeyToIndexMap = {}, key: Key | undefined, ch; for (i = beginIdx; i <= endIdx; ++i) { ch = children[i]; @@ -40,7 +40,7 @@ function createKeyToOldIdx(children: Array, beginIdx: number, endIdx: num return map; } -const hooks: (keyof Module)[] = ['create', 'update', 'remove', 'destroy', 'pre', 'post']; +const hooks: Array = ['create', 'update', 'remove', 'destroy', 'pre', 'post']; export {h} from './h'; export {thunk} from './thunk'; @@ -55,7 +55,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { for (j = 0; j < modules.length; ++j) { const hook = modules[j][hooks[i]]; if (hook !== undefined) { - (cbs[hooks[i]] as Array).push(hook); + (cbs[hooks[i]] as any[]).push(hook); } } } @@ -126,7 +126,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { function addVnodes( parentElm: Node, before: Node | null, - vnodes: Array, + vnodes: VNode[], startIdx: number, endIdx: number, insertedVnodeQueue: VNodeQueue @@ -156,7 +156,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { } function removeVnodes(parentElm: Node, - vnodes: Array, + vnodes: VNode[], startIdx: number, endIdx: number): void { for (; startIdx <= endIdx; ++startIdx) { @@ -180,8 +180,8 @@ export function init(modules: Array>, domApi?: DOMAPI) { } function updateChildren(parentElm: Node, - oldCh: Array, - newCh: Array, + oldCh: VNode[], + newCh: VNode[], insertedVnodeQueue: VNodeQueue) { let oldStartIdx = 0, newStartIdx = 0; let oldEndIdx = oldCh.length - 1; @@ -269,18 +269,18 @@ export function init(modules: Array>, domApi?: DOMAPI) { } if (isUndef(vnode.text)) { if (isDef(oldCh) && isDef(ch)) { - if (oldCh !== ch) updateChildren(elm, oldCh as Array, ch as Array, insertedVnodeQueue); + if (oldCh !== ch) updateChildren(elm, oldCh as VNode[], ch as VNode[], insertedVnodeQueue); } else if (isDef(ch)) { if (isDef(oldVnode.text)) api.setTextContent(elm, ''); - addVnodes(elm, null, ch as Array, 0, (ch as Array).length - 1, insertedVnodeQueue); + addVnodes(elm, null, ch as VNode[], 0, (ch as VNode[]).length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { - removeVnodes(elm, oldCh as Array, 0, (oldCh as Array).length - 1); + removeVnodes(elm, oldCh as VNode[], 0, (oldCh as VNode[]).length - 1); } else if (isDef(oldVnode.text)) { api.setTextContent(elm, ''); } } else if (oldVnode.text !== vnode.text) { if (isDef(oldCh)) { - removeVnodes(elm, oldCh as Array, 0, (oldCh as Array).length - 1); + removeVnodes(elm, oldCh as VNode[], 0, (oldCh as VNode[]).length - 1); } api.setTextContent(elm, vnode.text as string); } diff --git a/src/thunk.ts b/src/thunk.ts index 3ff05a7..1646fda 100644 --- a/src/thunk.ts +++ b/src/thunk.ts @@ -3,7 +3,7 @@ import {h} from './h'; export interface ThunkData extends VNodeData { fn: () => VNode; - args: Array; + args: any[]; } export interface Thunk extends VNode { @@ -11,8 +11,8 @@ export interface Thunk extends VNode { } export interface ThunkFn { - (sel: string, fn: Function, args: Array): Thunk; - (sel: string, key: any, fn: Function, args: Array): Thunk; + (sel: string, fn: Function, args: any[]): Thunk; + (sel: string, key: any, fn: Function, args: any[]): Thunk; } function copyToThunk(vnode: VNode, thunk: VNode): void { diff --git a/src/tovnode.ts b/src/tovnode.ts index 98e0564..67fef5d 100644 --- a/src/tovnode.ts +++ b/src/tovnode.ts @@ -10,7 +10,7 @@ export function toVNode(node: Node, domApi?: DOMAPI): VNode { const c = cn ? '.' + cn.split(' ').join('.') : ''; const sel = api.tagName(node).toLowerCase() + id + c; const attrs: any = {}; - const children: Array = []; + const children: VNode[] = []; let name: string; let i: number, n: number; const elmAttrs = node.attributes; diff --git a/src/vnode.ts b/src/vnode.ts index 37512d9..1ebe7e7 100644 --- a/src/vnode.ts +++ b/src/vnode.ts @@ -32,7 +32,7 @@ export interface VNodeData { key?: Key; ns?: string; // for SVGs fn?: () => VNode; // for thunks - args?: Array; // for thunks + args?: any[]; // for thunks [key: string]: any; // for any other 3rd party module } From c2e66b5eb1450aa5a175d1ad2bf21e1c1ba8db9d Mon Sep 17 00:00:00 2001 From: Sachin Philip Mathew Date: Sat, 23 Nov 2019 19:06:25 +0530 Subject: [PATCH 8/9] removed broken link of Benchmark from readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4dc1ae1..16673cc 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,7 @@ performance, small size and all the features listed below. * Extendable through modules. * A rich set of hooks available, both per vnode and globally for modules, to hook into any part of the diff and patch process. - * Splendid performance. Snabbdom is among the fastest virtual DOM libraries - in the [Virtual DOM Benchmark](http://vdom-benchmark.github.io/vdom-benchmark/). + * Splendid performance. Snabbdom is among the fastest virtual DOM libraries. * Patch function with a function signature equivalent to a reduce/scan function. Allows for easier integration with a FRP library. * Features in modules From 0881343e01911416c8e39a5dae665089643e1357 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 25 Nov 2019 11:30:19 +0100 Subject: [PATCH 9/9] Update TypeScript, refactor --- .eslintrc.js | 1 + package-lock.json | 6 +-- package.json | 2 +- src/snabbdom.ts | 115 +++++++++++++++++++++++----------------------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d4b958f..45221d4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,6 +2,7 @@ module.exports = { extends: 'standard-with-typescript', parserOptions: { project: [ './tsconfig.json', ] }, rules: { + '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/brace-style': 'off', '@typescript-eslint/consistent-type-assertions': 'off', '@typescript-eslint/consistent-type-definitions': 'off', diff --git a/package-lock.json b/package-lock.json index 860211e..cbe2255 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8888,9 +8888,9 @@ "dev": true }, "typescript": { - "version": "3.3.4000", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.4000.tgz", - "integrity": "sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 69d8b60..a5104f8 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "knuth-shuffle": "^1.0.1", "mocha": "^5.2.0", "npm-run-all": "^4.1.5", - "typescript": "^3.0.3", + "typescript": "^3.7.2", "xyz": "2.1.0" }, "scripts": { diff --git a/src/snabbdom.ts b/src/snabbdom.ts index a61be9f..dae3e7a 100644 --- a/src/snabbdom.ts +++ b/src/snabbdom.ts @@ -1,12 +1,13 @@ /* global module, document, Node */ import {Module} from './modules/module'; -import {Hooks} from './hooks'; -import vnode, {VNode, VNodeData, Key} from './vnode'; +import vnode, {VNode} from './vnode'; import * as is from './is'; import htmlDomApi, {DOMAPI} from './htmldomapi'; +type NonUndefined = T extends undefined ? never : T; + function isUndef(s: any): boolean { return s === undefined; } -function isDef(s: any): boolean { return s !== undefined; } +function isDef(s: A): s is NonUndefined { return s !== undefined; } type VNodeQueue = VNode[]; @@ -29,12 +30,11 @@ type ArraysOf = { type ModuleHooks = ArraysOf; function createKeyToOldIdx(children: VNode[], beginIdx: number, endIdx: number): KeyToIndexMap { - let i: number, map: KeyToIndexMap = {}, key: Key | undefined, ch; - for (i = beginIdx; i <= endIdx; ++i) { - ch = children[i]; - if (ch != null) { - key = ch.key; - if (key !== undefined) map[key] = i; + const map: KeyToIndexMap = {}; + for (let i = beginIdx; i <= endIdx; ++i) { + const key = children[i]?.key; + if (key !== undefined) { + map[key] = i; } } return map; @@ -78,8 +78,9 @@ export function init(modules: Array>, domApi?: DOMAPI) { function createElm(vnode: VNode, insertedVnodeQueue: VNodeQueue): Node { let i: any, data = vnode.data; if (data !== undefined) { - if (isDef(i = data.hook) && isDef(i = i.init)) { - i(vnode); + const init = data.hook?.init; + if (isDef(init)) { + init(vnode); data = vnode.data; } } @@ -88,7 +89,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { if (isUndef(vnode.text)) { vnode.text = ''; } - vnode.elm = api.createComment(vnode.text as string); + vnode.elm = api.createComment(vnode.text!); } else if (sel !== undefined) { // Parse selector const hashIdx = sel.indexOf('#'); @@ -96,7 +97,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { const hash = hashIdx > 0 ? hashIdx : sel.length; const dot = dotIdx > 0 ? dotIdx : sel.length; const tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel; - const elm = vnode.elm = isDef(data) && isDef(i = (data as VNodeData).ns) + const elm = vnode.elm = isDef(data) && isDef(i = data.ns) ? api.createElementNS(i, tag) : api.createElement(tag); if (hash < dot) elm.setAttribute('id', sel.slice(hash + 1, dot)); @@ -112,13 +113,15 @@ export function init(modules: Array>, domApi?: DOMAPI) { } else if (is.primitive(vnode.text)) { api.appendChild(elm, api.createTextNode(vnode.text)); } - i = (vnode.data as VNodeData).hook; // Reuse variable - if (isDef(i)) { - if (i.create) i.create(emptyNode, vnode); - if (i.insert) insertedVnodeQueue.push(vnode); + const hook = vnode.data!.hook; + if (isDef(hook)) { + hook.create?.(emptyNode, vnode); + if (hook.insert) { + insertedVnodeQueue.push(vnode); + } } } else { - vnode.elm = api.createTextNode(vnode.text as string); + vnode.elm = api.createTextNode(vnode.text!); } return vnode.elm; } @@ -140,15 +143,15 @@ export function init(modules: Array>, domApi?: DOMAPI) { } function invokeDestroyHook(vnode: VNode) { - let i: any, j: number, data = vnode.data; + const data = vnode.data; if (data !== undefined) { - if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode); - for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode); + data?.hook?.destroy?.(vnode); + for (let i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode); if (vnode.children !== undefined) { - for (j = 0; j < vnode.children.length; ++j) { - i = vnode.children[j]; - if (i != null && typeof i !== "string") { - invokeDestroyHook(i); + for (let j = 0; j < vnode.children.length; ++j) { + const child = vnode.children[j]; + if (child != null && typeof child !== "string") { + invokeDestroyHook(child); } } } @@ -160,20 +163,21 @@ export function init(modules: Array>, domApi?: DOMAPI) { startIdx: number, endIdx: number): void { for (; startIdx <= endIdx; ++startIdx) { - let i: any, listeners: number, rm: () => void, ch = vnodes[startIdx]; + let listeners: number, rm: () => void, ch = vnodes[startIdx]; if (ch != null) { if (isDef(ch.sel)) { invokeDestroyHook(ch); listeners = cbs.remove.length + 1; - rm = createRmCb(ch.elm as Node, listeners); - for (i = 0; i < cbs.remove.length; ++i) cbs.remove[i](ch, rm); - if (isDef(i = ch.data) && isDef(i = i.hook) && isDef(i = i.remove)) { - i(ch, rm); + rm = createRmCb(ch.elm!, listeners); + for (let i = 0; i < cbs.remove.length; ++i) cbs.remove[i](ch, rm); + const removeHook = ch?.data?.hook?.remove; + if (isDef(removeHook)) { + removeHook(ch, rm); } else { rm(); } } else { // Text node - api.removeChild(parentElm, ch.elm as Node); + api.removeChild(parentElm, ch.elm!); } } } @@ -190,7 +194,7 @@ export function init(modules: Array>, domApi?: DOMAPI) { let newEndIdx = newCh.length - 1; let newStartVnode = newCh[0]; let newEndVnode = newCh[newEndIdx]; - let oldKeyToIdx: any; + let oldKeyToIdx: KeyToIndexMap | undefined; let idxInOld: number; let elmToMove: VNode; let before: any; @@ -214,12 +218,12 @@ export function init(modules: Array>, domApi?: DOMAPI) { newEndVnode = newCh[--newEndIdx]; } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue); - api.insertBefore(parentElm, oldStartVnode.elm as Node, api.nextSibling(oldEndVnode.elm as Node)); + api.insertBefore(parentElm, oldStartVnode.elm!, api.nextSibling(oldEndVnode.elm!)); oldStartVnode = oldCh[++oldStartIdx]; newEndVnode = newCh[--newEndIdx]; } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue); - api.insertBefore(parentElm, oldEndVnode.elm as Node, oldStartVnode.elm as Node); + api.insertBefore(parentElm, oldEndVnode.elm!, oldStartVnode.elm!); oldEndVnode = oldCh[--oldEndIdx]; newStartVnode = newCh[++newStartIdx]; } else { @@ -228,16 +232,16 @@ export function init(modules: Array>, domApi?: DOMAPI) { } idxInOld = oldKeyToIdx[newStartVnode.key as string]; if (isUndef(idxInOld)) { // New element - api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm as Node); + api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm!); newStartVnode = newCh[++newStartIdx]; } else { elmToMove = oldCh[idxInOld]; if (elmToMove.sel !== newStartVnode.sel) { - api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm as Node); + api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm!); } else { patchVnode(elmToMove, newStartVnode, insertedVnodeQueue); oldCh[idxInOld] = undefined as any; - api.insertBefore(parentElm, (elmToMove.elm as Node), oldStartVnode.elm as Node); + api.insertBefore(parentElm, elmToMove.elm!, oldStartVnode.elm!); } newStartVnode = newCh[++newStartIdx]; } @@ -254,39 +258,34 @@ export function init(modules: Array>, domApi?: DOMAPI) { } function patchVnode(oldVnode: VNode, vnode: VNode, insertedVnodeQueue: VNodeQueue) { - let i: any, hook: any; - if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) { - i(oldVnode, vnode); - } - const elm = vnode.elm = (oldVnode.elm as Node); - let oldCh = oldVnode.children; - let ch = vnode.children; + const hook = vnode.data?.hook; + hook?.prepatch?.(oldVnode, vnode); + const elm = vnode.elm = oldVnode.elm!; + let oldCh = oldVnode.children as VNode[]; + let ch = vnode.children as VNode[]; if (oldVnode === vnode) return; if (vnode.data !== undefined) { - for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); - i = vnode.data.hook; - if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode); + for (let i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); + vnode.data.hook?.update?.(oldVnode, vnode); } if (isUndef(vnode.text)) { if (isDef(oldCh) && isDef(ch)) { - if (oldCh !== ch) updateChildren(elm, oldCh as VNode[], ch as VNode[], insertedVnodeQueue); + if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue); } else if (isDef(ch)) { if (isDef(oldVnode.text)) api.setTextContent(elm, ''); - addVnodes(elm, null, ch as VNode[], 0, (ch as VNode[]).length - 1, insertedVnodeQueue); + addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { - removeVnodes(elm, oldCh as VNode[], 0, (oldCh as VNode[]).length - 1); + removeVnodes(elm, oldCh, 0, oldCh.length - 1); } else if (isDef(oldVnode.text)) { api.setTextContent(elm, ''); } } else if (oldVnode.text !== vnode.text) { if (isDef(oldCh)) { - removeVnodes(elm, oldCh as VNode[], 0, (oldCh as VNode[]).length - 1); + removeVnodes(elm, oldCh, 0, oldCh.length - 1); } - api.setTextContent(elm, vnode.text as string); - } - if (isDef(hook) && isDef(i = hook.postpatch)) { - i(oldVnode, vnode); + api.setTextContent(elm, vnode.text!); } + hook?.postpatch?.(oldVnode, vnode); } return function patch(oldVnode: VNode | Element, vnode: VNode): VNode { @@ -301,19 +300,19 @@ export function init(modules: Array>, domApi?: DOMAPI) { if (sameVnode(oldVnode, vnode)) { patchVnode(oldVnode, vnode, insertedVnodeQueue); } else { - elm = oldVnode.elm as Node; + elm = oldVnode.elm!; parent = api.parentNode(elm); createElm(vnode, insertedVnodeQueue); if (parent !== null) { - api.insertBefore(parent, vnode.elm as Node, api.nextSibling(elm)); + api.insertBefore(parent, vnode.elm!, api.nextSibling(elm)); removeVnodes(parent, [oldVnode], 0, 0); } } for (i = 0; i < insertedVnodeQueue.length; ++i) { - (((insertedVnodeQueue[i].data as VNodeData).hook as Hooks).insert as any)(insertedVnodeQueue[i]); + insertedVnodeQueue[i].data!.hook!.insert!(insertedVnodeQueue[i]); } for (i = 0; i < cbs.post.length; ++i) cbs.post[i](); return vnode;