diff --git a/.npmignore b/.npmignore
index 7dbef3d..68d4d15 100644
--- a/.npmignore
+++ b/.npmignore
@@ -25,6 +25,5 @@ tags
**.ts
!**.d.ts
**.spec.*
-**.map
**.json
.*
diff --git a/LICENSE.md b/LICENSE.md
index 1f5e1cd..b7f32b6 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2017 Tomek Łaziuk
+Copyright (c) 2019 Tomek Łaziuk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/index.spec.ts b/index.spec.ts
index 3b80145..3b4895f 100644
--- a/index.spec.ts
+++ b/index.spec.ts
@@ -1,268 +1,122 @@
// tslint:disable:no-reference max-line-length max-classes-per-file
-///
-
-import {
- expect,
-} from "chai";
-
-import {
- SinonSpy,
- spy,
-} from "sinon";
-
-import {
- Attributes,
- ClassComponent,
- Component,
- CVnode,
- FactoryComponent,
- Lifecycle,
- Vnode,
-} from "mithril";
-
-import * as m from "mithril/render/hyperscript";
-import * as mTrust from "mithril/render/trust";
-
-import render, {
- Escape as EscapeEnum,
- isClassComponent,
- isComponent,
- isComponentType,
- isFactoryComponent,
-} from "./index";
+
+import { expect } from "chai";
+import { Attributes, ClassComponent, Component, CVnode, FactoryComponent, Vnode } from "mithril";
+// @ts-ignore no type defs
+import m from "mithril/render/hyperscript";
+// @ts-ignore no type defs
+import mTrust from "mithril/render/trust";
+import { SinonSpy, spy } from "sinon";
+import render, { isClassComponent, isComponent, isComponentType, isFactoryComponent } from "./index";
describe(render.name, () => {
describe(`node`, () => {
- it(`should render tag`, async (done) => {
- try {
- expect(await render(m(`span`, `content`))).to.be.equal(`content`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render tag`, async () => {
+ expect(await render(m(`span`, `content`))).to.be.equal(`content`);
});
- it(`should render classname`, async (done) => {
- try {
- expect(await render(m(`.foo`, `content`))).to.be.equal(`
content
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render classname`, async () => {
+ expect(await render(m(`.foo`, `content`))).to.be.equal(`content
`);
});
- it(`should render id`, async (done) => {
- try {
- expect(await render(m(`#bar`, `content`))).to.be.equal(`content
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render id`, async () => {
+ expect(await render(m(`#bar`, `content`))).to.be.equal(`content
`);
});
- it(`should render short nodes when no children`, async (done) => {
- try {
- expect(await render(m(`br`))).to.be.equal(`
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render short nodes when no children`, async () => {
+ expect(await render(m(`br`))).to.be.equal(`
`);
});
- it(`should render short nodes when no children and tag name is uppercase`, async (done) => {
- try {
- expect(await render(m(`HR`))).to.be.equal(`
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render short nodes when no children and tag name is uppercase`, async () => {
+ expect(await render(m(`HR`))).to.be.equal(`
`);
});
- it(`should render short node doctype`, async (done) => {
- try {
- expect(await render(m(`!doctype`))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render short node doctype`, async () => {
+ expect(await render(m(`!doctype`))).to.be.equal(``);
});
- it(`should render short node doctype HTML5`, async (done) => {
- try {
- expect(await render(m(`!doctype`, { html: true }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render short node doctype HTML5`, async () => {
+ expect(await render(m(`!doctype`, { html: true }))).to.be.equal(``);
});
- it(`should render attributes`, async (done) => {
- try {
- expect(await render(m(`span`, { "data-foo": `bar`, "selected": `selected` }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render attributes`, async () => {
+ expect(await render(m(`span`, { "data-foo": `bar`, "selected": `selected` }))).to.be.equal(``);
});
- it(`should render string`, async (done) => {
- try {
- expect(await render(m(`ul`, `huhu`))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render string`, async () => {
+ expect(await render(m(`ul`, `huhu`))).to.be.equal(``);
});
- it(`should render arrays`, async (done) => {
- try {
- expect(await render([m(`span`, `foo`), m(`div`, `bar`)])).to.be.equal(`foobar
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render arrays`, async () => {
+ expect(await render([m(`span`, `foo`), m(`div`, `bar`)])).to.be.equal(`foobar
`);
});
- it(`should render nested arrays`, async (done) => {
- try {
- expect(await render(m(`div`, [[m(`span`, `foo`), m(`div`, `bar`)]]))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render nested arrays`, async () => {
+ expect(await render(m(`div`, [[m(`span`, `foo`), m(`div`, `bar`)]]))).to.be.equal(``);
});
- it(`should render children`, async (done) => {
- try {
- expect(await render(m(`span`, m(`div`)))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render children`, async () => {
+ expect(await render(m(`span`, m(`div`)))).to.be.equal(``);
});
- it(`should not render events`, async (done) => {
- try {
- expect(await render(m(`span`, { onmousemove: () => void 0 }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should not render events`, async () => {
+ expect(await render(m(`span`, { onmousemove: () => void 0 }))).to.be.equal(``);
});
- it(`should render children`, async (done) => {
- try {
- expect(await render(m(`span`, { style: { paddingLeft: `10px`, color: `red` } }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render children`, async () => {
+ expect(await render(m(`span`, { style: { paddingLeft: `10px`, color: `red` } }))).to.be.equal(``);
});
- it(`should render numbers as text nodes`, async (done) => {
- try {
- expect(await render(m(`div`, [1, m(`span`), `2`]))).to.be.equal(`12
`);
- expect(await render(m(`div`, 1))).to.be.equal(`1
`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render numbers as text nodes`, async () => {
+ expect(await render(m(`div`, [1, m(`span`), `2`]))).to.be.equal(`12
`);
+ expect(await render(m(`div`, 1))).to.be.equal(`1
`);
});
- it(`should render booleans as text nodes`, async (done) => {
- try {
- expect(await render(m(`div`, false))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render booleans as text nodes`, async () => {
+ expect(await render(m(`div`, false))).to.be.equal(``);
});
- it(`should render boolean attributes`, async (done) => {
- try {
- expect(await render(m(`div`, { a: true }))).to.be.equal(``);
- expect(await render(m(`div`, { a: false }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render boolean attributes`, async () => {
+ expect(await render(m(`div`, { a: true }))).to.be.equal(``);
+ expect(await render(m(`div`, { a: false }))).to.be.equal(``);
});
- it(`should not render empty attributes`, async (done) => {
- try {
- expect(await render(m(`div`, { a: void 0 }))).to.be.equal(``);
- expect(await render(m(`div`, { style: null }))).to.be.equal(``);
- expect(await render(m(`div`, { style: `` }))).to.be.equal(``);
- expect(await render(m(`div`, { style: { color: `` } }))).to.be.equal(``);
- expect(await render(m(`div`, { style: { height: `20px`, color: `` } }))).to.be.equal(``);
- expect(await render(m(`div`, { style: { height: `20px`, color: ``, width: `10px` } }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should not render empty attributes`, async () => {
+ expect(await render(m(`div`, { a: void 0 }))).to.be.equal(``);
+ expect(await render(m(`div`, { style: null }))).to.be.equal(``);
+ expect(await render(m(`div`, { style: `` }))).to.be.equal(``);
+ expect(await render(m(`div`, { style: { color: `` } }))).to.be.equal(``);
+ expect(await render(m(`div`, { style: { height: `20px`, color: `` } }))).to.be.equal(``);
+ expect(await render(m(`div`, { style: { height: `20px`, color: ``, width: `10px` } }))).to.be.equal(``);
});
- it(`should render custom attributes`, async (done) => {
- try {
- expect(await render(m(`div`, { a: `foo` }))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render custom attributes`, async () => {
+ expect(await render(m(`div`, { a: `foo` }))).to.be.equal(``);
});
- it(`should escape HTML`, async (done) => {
- try {
- expect(await render(m(`div`, mTrust(``)))).to.be.equal(`
`, `trusted html escaped`);
- expect(await render(m(`div`, ``))).to.be.equal(`<foo></foo>
`, `non-trusted html not escaped`);
- expect(await render(m(`div`, { style: `">`, `attribute value not escaped`);
- expect(await render(m(`pre`, `var = ${JSON.stringify({ foo: 1 })}`))).to.be.equal(`var = {"foo":1}
`, `non-html text escaped`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should escape HTML`, async () => {
+ expect(await render(m(`div`, mTrust(``)))).to.be.equal(`
`, `trusted html escaped`);
+ expect(await render(m(`div`, ``))).to.be.equal(`<foo></foo>
`, `non-trusted html not escaped`);
+ expect(await render(m(`div`, { style: `">`, `attribute value not escaped`);
+ expect(await render(m(`pre`, `var = ${JSON.stringify({ foo: 1 })}`))).to.be.equal(`var = {"foo":1}
`, `non-html text escaped`);
});
- it(`should render svg use elements with href attributes`, async (done) => {
- try {
- expect(await render(m(`svg`, m(`use`, { href: `fooga.com` })))).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render svg use elements with href attributes`, async () => {
+ expect(await render(m(`svg`, m(`use`, { href: `fooga.com` })))).to.be.equal(``);
});
- it(`should render closed input-tag`, async (done) => {
- try {
- expect(await render(m(`input`), { strict: true })).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render closed input-tag`, async () => {
+ expect(await render(m(`input`), { strict: true })).to.be.equal(``);
});
- it(`should render closed div-tag`, async (done) => {
- try {
- expect(await render(m(`div`), { strict: true })).to.be.equal(``);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should render closed div-tag`, async () => {
+ expect(await render(m(`div`), { strict: true })).to.be.equal(``);
});
- it(`should throw on non-component`, async (done) => {
- try {
- try {
- await render(Symbol() as any);
- done(new Error(`failed`));
- } catch {
- // pass
- }
- done();
- } catch (err) {
- done(err);
- }
- });
+ it(`should throw on non-component`, () => render(Symbol()).then(
+ () => { throw new Error(`failed`); },
+ () => void 0,
+ ));
});
describe(`lifecycle`, () => {
@@ -276,450 +130,350 @@ describe(render.name, () => {
viewSpy = spy(({ children }: Vnode = {} as any) => children);
});
- it(`node`, async (done) => {
- try {
- await render(m(
- `div`,
- {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- } as Attributes,
- [
- `test`,
- ],
- ));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`'attrs' over 'state'`, async (done) => {
- let oninitAttrsSpy = spy();
- let cmp = {
+ it(`node`, async () => {
+ await render(m(
+ `div`,
+ {
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ } as Attributes,
+ [
+ `test`,
+ ],
+ ));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ });
+
+ it(`'attrs' over 'state'`, async () => {
+ const oninitAttrsSpy = spy();
+ const cmp = {
oninit: oninitSpy,
onremove: onremoveSpy,
view: viewSpy,
} as Component;
- try {
- await (render(m(cmp, { oninit: oninitAttrsSpy })));
- expect(oninitSpy).to.have.property(`callCount`).equal(0, `state lifecycle method called`);
- expect(oninitAttrsSpy).to.have.property(`callCount`).gt(0, `attrs lifecycle method not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`text`, async (done) => {
- try {
- await render(m(
- `#`,
- {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- } as Attributes,
- [
- `test`,
- ],
- ));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`fragment`, async (done) => {
- try {
- await render(m(
- `[`,
- {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- } as Attributes,
- [
- `test`,
- ],
- ));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`trusted html`, async (done) => {
- try {
- await render(m(
- `<`,
- {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- } as Attributes,
- [
- `test
`,
- ],
- ));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`Component`, async (done) => {
- try {
- await render(m(
- {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- view: viewSpy,
- } as Component,
- [
- `test`,
- ],
- ));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`FactoryComponent`, async (done) => {
- try {
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- await render(m(function() {
- return {
- oninit: oninitSpy,
- onremove: onremoveSpy,
- view: viewSpy,
- };
- } as FactoryComponent));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`ClassComponent`, async (done) => {
- try {
- class Cmp implements ClassComponent {
- public oninit = oninitSpy;
- public onremove = onremoveSpy;
- // important note - view method can not be assigned in constructor,
- // view method is used to detect if function is a class,
- // which means it's impossible to do following thing:
- // public view = viewSpy;
- public view() {
- viewSpy();
- };
+ await (render(m(cmp, { oninit: oninitAttrsSpy })));
+ expect(oninitSpy).to.have.property(`callCount`).equal(0, `state lifecycle method called`);
+ expect(oninitAttrsSpy).to.have.property(`callCount`).gt(0, `attrs lifecycle method not called`);
+ });
+
+ it(`text`, async () => {
+ await render(m(
+ `#`,
+ {
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ } as Attributes,
+ [
+ `test`,
+ ],
+ ));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ });
+
+ it(`fragment`, async () => {
+ await render(m(
+ `[`,
+ {
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ } as Attributes,
+ [
+ `test`,
+ ],
+ ));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ });
+
+ it(`trusted html`, async () => {
+ await render(m(
+ `<`,
+ {
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ } as Attributes,
+ [
+ `test
`,
+ ],
+ ));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ });
+
+ it(`Component`, async () => {
+ await render(m(
+ {
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ view: viewSpy,
+ } as Component,
+ [
+ `test`,
+ ],
+ ));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
+ });
+
+ it(`FactoryComponent`, async () => {
+ // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
+ await render(m((() => ({
+ oninit: oninitSpy,
+ onremove: onremoveSpy,
+ view: viewSpy,
+ })) as FactoryComponent));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
+ });
+
+ it(`ClassComponent`, async () => {
+ class Cmp implements ClassComponent {
+ public oninit = oninitSpy;
+ public onremove = onremoveSpy;
+ // important note - view method can not be assigned in constructor,
+ // view method is used to detect if function is a class,
+ // which means it's impossible to do following thing:
+ // public view = viewSpy;
+ public view() {
+ viewSpy();
}
- await render(m(Cmp));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`should have proper call order`, async (done) => {
- try {
- const oninitRootSpy = spy();
- const onremoveRootSpy = spy();
- const oninitFragmentSpy = spy();
- const onremoveFragmentSpy = spy();
- const oninitCmp1Spy = spy();
- const onremoveCmp1Spy = spy();
- const oninitCmp2Spy = spy();
- const onremoveCmp2Spy = spy();
- const cmpRoot = {
- oninit: oninitRootSpy,
- onremove: onremoveRootSpy,
- view: () => [
- `root`,
- m(
- `[`,
- {
- oninit: oninitFragmentSpy,
- onremove: onremoveFragmentSpy,
- },
- [
- m(
- `#`,
- {
- oninit: oninitCmp1Spy,
- onremove: onremoveCmp1Spy,
- },
- `fragment`,
- ),
- ],
- ),
- m(
- `#`,
- {
- oninit: oninitCmp2Spy,
- onremove: onremoveCmp2Spy,
- },
- `cmp`,
- ),
- ],
- } as Component;
- expect(await render(m(cmpRoot))).to.be.equal(`rootcmp
`);
-
- expect(oninitRootSpy.calledOnce).to.be.equal(true, `oninit root not called`);
- expect(onremoveRootSpy.calledOnce).to.be.equal(true, `onremove root not called`);
- expect(oninitFragmentSpy.calledOnce).to.be.equal(true, `oninit fragment not called once`);
- expect(onremoveFragmentSpy.calledOnce).to.be.equal(true, `onremove fragment not called once`);
- expect(oninitCmp1Spy.calledOnce).to.be.equal(true, `oninit cmp1 not called once`);
- expect(onremoveCmp1Spy.calledOnce).to.be.equal(true, `onremove cmp1 not called once`);
- expect(oninitCmp2Spy.calledOnce).to.be.equal(true, `oninit cmp2 not called once`);
- expect(onremoveCmp2Spy.calledOnce).to.be.equal(true, `onremove cmp2 not called once`);
-
- expect(oninitFragmentSpy.calledBefore(oninitCmp2Spy)).to.be.equal(true, `oninit fragment not called before oninit cmp2`);
- expect(oninitRootSpy.calledBefore(oninitFragmentSpy)).to.be.equal(true, `oninit root not called before oninit fragment`);
- expect(onremoveCmp1Spy.calledAfter(oninitCmp1Spy)).to.be.equal(true, `onremove not called after oninit`);
- expect(onremoveCmp2Spy.calledAfter(oninitCmp2Spy)).to.be.equal(true, `onremove not called after oninit`);
- expect(onremoveFragmentSpy.calledAfter(oninitFragmentSpy)).to.be.equal(true, `onremove not called after oninit`);
- expect(onremoveFragmentSpy.calledAfter(onremoveCmp2Spy)).to.be.equal(true, `onremove fragment not called after onremove cmp2`);
- expect(onremoveRootSpy.calledAfter(oninitRootSpy)).to.be.equal(true, `onremove not called after oninit`);
- expect(onremoveRootSpy.calledAfter(onremoveFragmentSpy)).to.be.equal(true, `onremove root not called after onremove fragment`);
- done();
- } catch (err) {
- done(err);
}
+ await render(m(Cmp));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
+ });
+
+ it(`should have proper call order`, async () => {
+ const oninitRootSpy = spy();
+ const onremoveRootSpy = spy();
+ const oninitFragmentSpy = spy();
+ const onremoveFragmentSpy = spy();
+ const oninitCmp1Spy = spy();
+ const onremoveCmp1Spy = spy();
+ const oninitCmp2Spy = spy();
+ const onremoveCmp2Spy = spy();
+ const cmpRoot = {
+ oninit: oninitRootSpy,
+ onremove: onremoveRootSpy,
+ view: () => [
+ `root`,
+ m(
+ `[`,
+ {
+ oninit: oninitFragmentSpy,
+ onremove: onremoveFragmentSpy,
+ },
+ [
+ m(
+ `#`,
+ {
+ oninit: oninitCmp1Spy,
+ onremove: onremoveCmp1Spy,
+ },
+ `fragment`,
+ ),
+ ],
+ ),
+ m(
+ `#`,
+ {
+ oninit: oninitCmp2Spy,
+ onremove: onremoveCmp2Spy,
+ },
+ `cmp`,
+ ),
+ ],
+ } as Component;
+ expect(await render(m(cmpRoot))).to.be.equal(`rootcmp
`);
+
+ expect(oninitRootSpy.calledOnce).to.be.equal(true, `oninit root not called`);
+ expect(onremoveRootSpy.calledOnce).to.be.equal(true, `onremove root not called`);
+ expect(oninitFragmentSpy.calledOnce).to.be.equal(true, `oninit fragment not called once`);
+ expect(onremoveFragmentSpy.calledOnce).to.be.equal(true, `onremove fragment not called once`);
+ expect(oninitCmp1Spy.calledOnce).to.be.equal(true, `oninit cmp1 not called once`);
+ expect(onremoveCmp1Spy.calledOnce).to.be.equal(true, `onremove cmp1 not called once`);
+ expect(oninitCmp2Spy.calledOnce).to.be.equal(true, `oninit cmp2 not called once`);
+ expect(onremoveCmp2Spy.calledOnce).to.be.equal(true, `onremove cmp2 not called once`);
+
+ expect(oninitFragmentSpy.calledBefore(oninitCmp2Spy)).to.be.equal(true, `oninit fragment not called before oninit cmp2`);
+ expect(oninitRootSpy.calledBefore(oninitFragmentSpy)).to.be.equal(true, `oninit root not called before oninit fragment`);
+ expect(onremoveCmp1Spy.calledAfter(oninitCmp1Spy)).to.be.equal(true, `onremove not called after oninit`);
+ expect(onremoveCmp2Spy.calledAfter(oninitCmp2Spy)).to.be.equal(true, `onremove not called after oninit`);
+ expect(onremoveFragmentSpy.calledAfter(oninitFragmentSpy)).to.be.equal(true, `onremove not called after oninit`);
+ expect(onremoveFragmentSpy.calledAfter(onremoveCmp2Spy)).to.be.equal(true, `onremove fragment not called after onremove cmp2`);
+ expect(onremoveRootSpy.calledAfter(oninitRootSpy)).to.be.equal(true, `onremove not called after oninit`);
+ expect(onremoveRootSpy.calledAfter(onremoveFragmentSpy)).to.be.equal(true, `onremove root not called after onremove fragment`);
});
});
describe(`attributes and state`, () => {
- it(`Component`, async (done) => {
- try {
- interface IState {
- text?: string;
- }
- const component = {
- view: ({ attrs, state }) => {
- return attrs.text || state.text || `test`;
- },
- } as Component & IState;
- expect(await render(m(component))).to.be.equal(`test`);
- expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
- component.text = `state`;
- expect(await render(m(component))).to.be.equal(`state`);
- expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`ClassComponent`, async (done) => {
- try {
- class Cmp implements ClassComponent {
- public text?: string;
- public view({ attrs, state }: CVnode) {
- return attrs.text || this.text || `test`;
- }
+ it(`Component`, async () => {
+ interface IState {
+ text?: string;
+ }
+ const component = {
+ view: ({ attrs, state }) => {
+ return attrs.text || state.text || `test`;
+ },
+ } as Component & IState;
+ expect(await render(m(component))).to.be.equal(`test`);
+ expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
+ component.text = `state`;
+ expect(await render(m(component))).to.be.equal(`state`);
+ expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
+ });
+
+ it(`ClassComponent`, async () => {
+ class Cmp implements ClassComponent {
+ public text?: string;
+ public view({ attrs, state }: CVnode) {
+ return attrs.text || this.text || `test`;
}
- expect(await render(m(Cmp))).to.be.equal(`test`);
- expect(await render(m(Cmp, { text: `attr` }))).to.be.equal(`attr`);
- Cmp.prototype.text = `state`;
- expect(await render(m(Cmp))).to.be.equal(`state`);
- expect(await render(m(Cmp, { text: `attr` }))).to.be.equal(`attr`);
- done();
- } catch (err) {
- done(err);
}
+ expect(await render(m(Cmp))).to.be.equal(`test`);
+ expect(await render(m(Cmp, { text: `attr` }))).to.be.equal(`attr`);
+ Cmp.prototype.text = `state`;
+ expect(await render(m(Cmp))).to.be.equal(`state`);
+ expect(await render(m(Cmp, { text: `attr` }))).to.be.equal(`attr`);
});
- it(`FactoryComponent`, async (done) => {
- try {
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- const component = function() {
- return {
- view: ({ attrs }) => {
- return attrs.text || `test`;
- },
- };
- } as FactoryComponent;
- expect(await render(m(component))).to.be.equal(`test`);
- expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`FactoryComponent`, async () => {
+ // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
+ const component = (() => ({
+ view: ({ attrs }) => {
+ return attrs.text || `test`;
+ },
+ })) as FactoryComponent;
+ expect(await render(m(component))).to.be.equal(`test`);
+ expect(await render(m(component, { text: `attr` }))).to.be.equal(`attr`);
});
});
describe(`'this' in text`, () => {
- it(`should 'state' be equal 'this'`, async (done) => {
- try {
- const oninitSpy = spy();
- const onremoveSpy = spy();
- await render(m(`div`, {
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- oninit: function({ state }) {
- oninitSpy();
- expect(this).to.be.equal(state);
- },
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- onremove: function({ state }) {
- onremoveSpy();
- expect(this).to.be.equal(state);
- },
- } as Attributes));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should 'state' be equal 'this'`, async () => {
+ const oninitSpy = spy();
+ const onremoveSpy = spy();
+ await render(m(`div`, {
+ oninit({ state }) {
+ oninitSpy();
+ expect(this).to.be.equal(state);
+ },
+ onremove({ state }) {
+ onremoveSpy();
+ expect(this).to.be.equal(state);
+ },
+ } as Attributes));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
});
});
describe(`'this' in Component`, () => {
- it(`should 'state' be equal 'this'`, async (done) => {
- try {
- const oninitSpy = spy();
- const onremoveSpy = spy();
- const viewSpy = spy();
- await render(m({
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- oninit: function({ state }) {
- oninitSpy();
- expect(this).to.be.equal(state);
- },
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- onremove: function({ state }) {
- onremoveSpy();
- expect(this).to.be.equal(state);
- },
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- view: function({ state }) {
- viewSpy();
- expect(this).to.be.equal(state);
- return ``;
- },
- } as Component));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should 'state' be equal 'this'`, async () => {
+ const oninitSpy = spy();
+ const onremoveSpy = spy();
+ const viewSpy = spy();
+ await render(m({
+ oninit({ state }) {
+ oninitSpy();
+ expect(this).to.be.equal(state);
+ },
+ onremove({ state }) {
+ onremoveSpy();
+ expect(this).to.be.equal(state);
+ },
+ view({ state }) {
+ viewSpy();
+ expect(this).to.be.equal(state);
+ return ``;
+ },
+ } as Component));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
});
});
describe(`'this' in FactoryComponent`, () => {
- it(`should 'state' be equal 'this'`, async (done) => {
- try {
- const oninitSpy = spy();
- const onremoveSpy = spy();
- const viewSpy = spy();
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- await render(m(function() {
- return {
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- oninit: function({ state }) {
- oninitSpy();
- expect(this).to.be.equal(state);
- },
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- onremove: function({ state }) {
- onremoveSpy();
- expect(this).to.be.equal(state);
- },
- // tslint:disable-next-line:only-arrow-functions object-literal-shorthand
- view: function({ state }) {
- viewSpy();
- expect(this).to.be.equal(state);
- return ``;
- },
- };
- } as FactoryComponent));
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should 'state' be equal 'this'`, async () => {
+ const oninitSpy = spy();
+ const onremoveSpy = spy();
+ const viewSpy = spy();
+ await render(m((() => ({
+ oninit({ state }) {
+ oninitSpy();
+ expect(this).to.be.equal(state);
+ },
+ onremove({ state }) {
+ onremoveSpy();
+ expect(this).to.be.equal(state);
+ },
+ view({ state }) {
+ viewSpy();
+ expect(this).to.be.equal(state);
+ return ``;
+ },
+ })) as FactoryComponent));
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
});
});
describe(`'this' in ClassComponent`, () => {
- it(`should 'state' be equal 'this'`, async (done) => {
- try {
- const oninitSpy = spy();
- const onremoveSpy = spy();
- const viewSpy = spy(() => ``);
- class Cmp implements ClassComponent {
- public get oninit() {
- return oninitSpy;
- }
- public get onremove() {
- return onremoveSpy;
- }
- public get view() {
- return viewSpy;
- }
+ it(`should 'state' be equal 'this'`, async () => {
+ const oninitSpy = spy();
+ const onremoveSpy = spy();
+ const viewSpy = spy(() => ``);
+ class Cmp implements ClassComponent {
+ public get oninit() {
+ return oninitSpy;
+ }
+ public get onremove() {
+ return onremoveSpy;
+ }
+ public get view() {
+ return viewSpy;
}
- expect(await render(m(Cmp))).to.be.equal(``);
- expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
- expect(viewSpy.firstCall.thisValue).to.be.equal(viewSpy.firstCall.args[0].state, `view was not with proper 'this'`);
- expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
- expect(onremoveSpy.firstCall.thisValue).to.be.equal(onremoveSpy.firstCall.args[0].state, `onremove was not with proper 'this'`);
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(oninitSpy.firstCall.thisValue).to.be.equal(oninitSpy.firstCall.args[0].state, `oninit was not with proper 'this'`);
- done();
- } catch (err) {
- done(err);
}
+ expect(await render(m(Cmp))).to.be.equal(``);
+ expect(viewSpy.calledOnce).to.be.equal(true, `view was not called`);
+ expect(viewSpy.firstCall.thisValue).to.be.equal(viewSpy.firstCall.args[0].state, `view was not with proper 'this'`);
+ expect(onremoveSpy.calledOnce).to.be.equal(true, `onremove was not called`);
+ expect(onremoveSpy.firstCall.thisValue).to.be.equal(onremoveSpy.firstCall.args[0].state, `onremove was not with proper 'this'`);
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(oninitSpy.firstCall.thisValue).to.be.equal(oninitSpy.firstCall.args[0].state, `oninit was not with proper 'this'`);
});
});
describe(`async`, () => {
- it(`oninit`, async (done) => {
- try {
- interface IState {
- timeout: number;
- }
- const oninitSpy = spy();
- const timeoutSpy = spy();
- const component = {
- oninit: ({ state }: Vnode) => new Promise((resolve, reject) => {
- oninitSpy();
- setTimeout(() => {
- timeoutSpy();
- state.timeout = 50;
- resolve();
- }, 50);
- }),
- timeout: NaN,
- view: ({ state }) => state.timeout,
- } as Component & IState;
- expect(await render(m(component))).to.be.equal(`50`);
- expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(timeoutSpy.calledOnce).to.be.equal(true, `oninit was not called`);
- expect(timeoutSpy.calledAfter(oninitSpy)).to.be.equal(true, `something really weird happend`);
- done();
- } catch (err) {
- done(err);
- }
+ it(`oninit`, async () => {
+ interface IState {
+ timeout: number;
+ }
+ const oninitSpy = spy();
+ const timeoutSpy = spy();
+ const component = {
+ oninit: ({ state }: Vnode) => new Promise((resolve, reject) => {
+ oninitSpy();
+ setTimeout(() => {
+ timeoutSpy();
+ state.timeout = 50;
+ resolve();
+ }, 50);
+ }),
+ timeout: NaN,
+ view: ({ state }) => state.timeout,
+ } as Component & IState;
+ expect(await render(m(component))).to.be.equal(`50`);
+ expect(oninitSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(timeoutSpy.calledOnce).to.be.equal(true, `oninit was not called`);
+ expect(timeoutSpy.calledAfter(oninitSpy)).to.be.equal(true, `something really weird happend`);
});
});
@@ -727,10 +481,7 @@ describe(render.name, () => {
const cmp = {
view: () => m(`#`, `test`),
} as Component;
- // tslint:disable-next-line:only-arrow-functions
- const cmpFactory = function() {
- return cmp;
- } as FactoryComponent;
+ const cmpFactory: FactoryComponent = () => cmp;
// tslint:disable-next-line:class-name
class cmpClass implements ClassComponent {
public view() {
@@ -738,38 +489,28 @@ describe(render.name, () => {
}
}
- it(`should not fail`, async (done) => {
- try {
- expect(await render(cmp)).to.be.a(`string`);
- expect(await render(cmp)).to.be.equal(`test
`);
- expect(await render(cmpFactory)).to.be.a(`string`);
- expect(await render(cmpFactory)).to.be.equal(`test
`);
- expect(await render(cmpClass)).to.be.a(`string`);
- expect(await render(cmpClass)).to.be.equal(`test
`);
- done();
- } catch (err) {
- done(err);
- }
- });
-
- it(`should have access to attributes`, async (done) => {
- try {
- const attrSpy = spy();
- const attributes = {
- oninit: ({ attrs }) => {
- attrSpy();
- expect(attrs.testAttr).to.be.equal(`test`);
- },
- testAttr: `test`,
- } as Attributes;
- expect(await render(cmp, { attrs: attributes })).to.be.a(`string`);
- expect(await render(cmpFactory, { attrs: attributes })).to.be.a(`string`);
- expect(await render(cmpClass, { attrs: attributes })).to.be.a(`string`);
- expect(attrSpy.calledThrice).to.be.equal(true);
- done();
- } catch (err) {
- done(err);
- }
+ it(`should not fail`, async () => {
+ expect(await render(cmp)).to.be.a(`string`);
+ expect(await render(cmp)).to.be.equal(`test
`);
+ expect(await render(cmpFactory)).to.be.a(`string`);
+ expect(await render(cmpFactory)).to.be.equal(`test
`);
+ expect(await render(cmpClass)).to.be.a(`string`);
+ expect(await render(cmpClass)).to.be.equal(`test
`);
+ });
+
+ it(`should have access to attributes`, async () => {
+ const attrSpy = spy();
+ const attributes = {
+ oninit: ({ attrs }) => {
+ attrSpy();
+ expect(attrs.testAttr).to.be.equal(`test`);
+ },
+ testAttr: `test`,
+ } as Attributes;
+ expect(await render(cmp, { attrs: attributes })).to.be.a(`string`);
+ expect(await render(cmpFactory, { attrs: attributes })).to.be.a(`string`);
+ expect(await render(cmpClass, { attrs: attributes })).to.be.a(`string`);
+ expect(attrSpy.calledThrice).to.be.equal(true);
});
});
});
@@ -778,10 +519,7 @@ describe(isComponentType.name, () => {
const cmp = {
view: () => void 0,
} as Component;
- // tslint:disable-next-line:only-arrow-functions
- const cmpFactory = function() {
- return cmp;
- } as FactoryComponent;
+ const cmpFactory: FactoryComponent = () => cmp;
// tslint:disable-next-line:class-name
class cmpClass implements ClassComponent {
public view() {
diff --git a/index.ts b/index.ts
index 46b5941..9d1d906 100644
--- a/index.ts
+++ b/index.ts
@@ -44,7 +44,7 @@ export function isComponent(
export function isClassComponent(
component: any,
-): component is { new(vnode: CVnode): ClassComponent } {
+): component is new (vnode: CVnode) => ClassComponent {
return typeof component === "function" && isComponent(component.prototype);
}
@@ -162,12 +162,12 @@ const parseHooks = async (
}
if (typeof onremove === "function") {
- hooks.push(async () => await onremove.call(vnode.state, vnode));
+ hooks.push(async () => await onremove.call(vnode.state, vnode as any));
}
};
export async function render(
- view: Children | ComponentTypes,
+ view: any,
{
attrs = {},
hooks = [],
diff --git a/package.json b/package.json
index fe64f2f..701dfc4 100644
--- a/package.json
+++ b/package.json
@@ -45,20 +45,21 @@
},
"devDependencies": {
"@types/chai": "^4.0.0",
- "@types/mocha": "^2.2.0",
- "@types/sinon": "^2.3.0",
+ "@types/mocha": "^2.0.0",
+ "@types/sinon": "^7.0.0",
"chai": "^4.0.0",
- "coveralls": "^2.13.0",
+ "coveralls": "^3.0.0",
"mithril": "~1.1.0",
- "mocha": "^2.2.0",
- "nyc": "^11.0.0",
- "sinon": "^2.3.0",
- "ts-node": "^3.2.0",
- "tslint": "^5.5.0",
- "typescript": "~2.5.0"
+ "mocha": "^5.0.0",
+ "nyc": "^13.0.0",
+ "sinon": "^7.0.0",
+ "ts-node": "^8.0.0",
+ "tslint": "^5.0.0",
+ "typescript": "^3.0.0",
+ "typescript-tslint-plugin": "^0.3.0"
},
"dependencies": {
"@types/mithril": "~1.1.0",
- "tslib": "^1.7.0"
+ "tslib": "^1.9.0"
}
}
diff --git a/tsconfig.json b/tsconfig.json
index f28edb4..50455fb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,25 +1,18 @@
{
+ "compileOnSave": false,
"compilerOptions": {
+ "plugins": [
+ { "name": "typescript-tslint-plugin" }
+ ],
"declaration": true,
"emitDecoratorMetadata": true,
+ "esModuleInterop": true,
"experimentalDecorators": true,
"importHelpers": true,
- "inlineSourceMap": false,
- "inlineSources": false,
- "lib": [
- "dom",
- "esnext"
- ],
- "listFiles": false,
+ "lib": ["esnext", "dom"],
"module": "commonjs",
- "noEmitOnError": true,
- "noImplicitAny": true,
- "noImplicitReturns": true,
- "noImplicitThis": true,
- "preserveConstEnums": false,
- "pretty": true,
- "removeComments": true,
+ "sourceMap": true,
"strict": true,
- "target": "es6"
+ "target": "es6",
}
}
diff --git a/types/mithril.d.ts b/types/mithril.d.ts
deleted file mode 100644
index d66a9bd..0000000
--- a/types/mithril.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-declare module "mithril/render/hyperscript";
-declare module "mithril/render/trust";