From 277ac9e1718acd66f718c9f68f7fea6f7e9226dd Mon Sep 17 00:00:00 2001 From: Jonah Date: Sat, 15 Apr 2017 16:05:08 -0400 Subject: [PATCH 001/301] Fix issue #1798 --- ospec/ospec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 0c58b347..015f2ac7 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -193,7 +193,7 @@ module.exports = new function init() { function record(message, error) { var result = {pass: message === null} if (result.pass === false) { - if (error == null) { + if (error == null || typeof error === "string") { error = new Error if (error.stack === undefined) new function() {try {throw error} catch (e) {error = e}} } From b004c20f0ca2ea3b51cb3a3c77d3893f67396819 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Gerardy Date: Mon, 6 Feb 2017 00:58:16 +0100 Subject: [PATCH 002/301] Make m.redraw() strictly asynchronous --- api/mount.js | 2 +- api/redraw.js | 17 +++-- api/router.js | 10 ++- api/tests/test-mount.js | 83 +++++++++++------------- api/tests/test-redraw.js | 68 +++++++++++++------- api/tests/test-router.js | 91 +++++++++++++++++++-------- docs/redraw.md | 2 +- docs/route.md | 2 +- test-utils/tests/test-throttleMock.js | 89 ++++++++++++++++++++++++++ test-utils/throttleMock.js | 24 +++++++ tests/test-api.js | 4 +- 11 files changed, 281 insertions(+), 111 deletions(-) create mode 100644 test-utils/tests/test-throttleMock.js create mode 100644 test-utils/throttleMock.js diff --git a/api/mount.js b/api/mount.js index 2178505a..7203bf7c 100644 --- a/api/mount.js +++ b/api/mount.js @@ -16,6 +16,6 @@ module.exports = function(redrawService) { redrawService.render(root, Vnode(component)) } redrawService.subscribe(root, run) - redrawService.redraw() + run() } } diff --git a/api/redraw.js b/api/redraw.js index 1b22271b..07937445 100644 --- a/api/redraw.js +++ b/api/redraw.js @@ -4,26 +4,23 @@ var coreRenderer = require("../render/render") function throttle(callback) { //60fps translates to 16.6ms, round it down since setTimeout requires int - var time = 16 + var delay = 16 var last = 0, pending = null var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout return function() { - var now = Date.now() - if (last === 0 || now - last >= time) { - last = now - callback() - } - else if (pending === null) { + var elapsed = Date.now() - last + if (pending === null) { pending = timeout(function() { pending = null callback() last = Date.now() - }, time - (now - last)) + }, delay - elapsed) } } } -module.exports = function($window) { +module.exports = function($window, throttleMock) { + var _throttle = throttleMock || throttle var renderService = coreRenderer($window) renderService.setEventCallback(function(e) { if (e.redraw !== false) redraw() @@ -32,7 +29,7 @@ module.exports = function($window) { var callbacks = [] function subscribe(key, callback) { unsubscribe(key) - callbacks.push(key, throttle(callback)) + callbacks.push(key, _throttle(callback)) } function unsubscribe(key) { var index = callbacks.indexOf(key) diff --git a/api/router.js b/api/router.js index c182008f..dbdd3c89 100644 --- a/api/router.js +++ b/api/router.js @@ -11,9 +11,14 @@ module.exports = function($window, redrawService) { var render, component, attrs, currentPath, lastUpdate var route = function(root, defaultRoute, routes) { if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined") - var run = function() { + function run() { if (render != null) redrawService.render(root, render(Vnode(component, attrs.key, attrs))) } + var redraw = function() { + run() + redraw = redrawService.redraw + } + redrawService.subscribe(root, run) var bail = function(path) { if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true}) else throw new Error("Could not resolve default route " + defaultRoute) @@ -24,7 +29,7 @@ module.exports = function($window, redrawService) { component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div" attrs = params, currentPath = path, lastUpdate = null render = (routeResolver.render || identity).bind(routeResolver) - run() + redraw() } if (payload.view || typeof payload === "function") update({}, payload) else { @@ -36,7 +41,6 @@ module.exports = function($window, redrawService) { else update(payload, "div") } }, bail) - redrawService.subscribe(root, run) } route.set = function(path, data, options) { if (lastUpdate != null) options = {replace: true} diff --git a/api/tests/test-mount.js b/api/tests/test-mount.js index db2bee04..e115711b 100644 --- a/api/tests/test-mount.js +++ b/api/tests/test-mount.js @@ -3,6 +3,7 @@ var o = require("../../ospec/ospec") var components = require("../../test-utils/components") var domMock = require("../../test-utils/domMock") +var throttleMocker = require("../../test-utils/throttleMock") var m = require("../../render/hyperscript") var coreRenderer = require("../../render/render") @@ -11,18 +12,22 @@ var apiMounter = require("../../api/mount") o.spec("mount", function() { var FRAME_BUDGET = Math.floor(1000 / 60) - var $window, root, redrawService, mount, render + var $window, root, redrawService, mount, render, throttleMock o.beforeEach(function() { $window = domMock() + throttleMock = throttleMocker() root = $window.document.body - - redrawService = apiRedraw($window) + redrawService = apiRedraw($window, throttleMock.throttle) mount = apiMounter(redrawService) render = coreRenderer($window).render }) + o.afterEach(function() { + o(throttleMock.queueLength()).equals(0) + }) + o("throws on invalid component", function() { var threw = false try { @@ -69,7 +74,7 @@ o.spec("mount", function() { o(root.childNodes.length).equals(0) }) - o("redraws on events", function(done) { + o("redraws on events", function() { var onupdate = o.spy() var oninit = o.spy() var onclick = o.spy() @@ -97,17 +102,12 @@ o.spec("mount", function() { o(onclick.args[0].type).equals("click") o(onclick.args[0].target).equals(root.firstChild) - // Wrapped to give time for the rate-limited redraw to fire - setTimeout(function() { - o(onupdate.callCount).equals(1) + throttleMock.fire() - done() - }, FRAME_BUDGET) + o(onupdate.callCount).equals(1) }) - o("redraws several mount points on events", function(done, timeout) { - timeout(60) - + o("redraws several mount points on events", function() { var onupdate0 = o.spy() var oninit0 = o.spy() var onclick0 = o.spy() @@ -154,26 +154,26 @@ o.spec("mount", function() { o(onclick0.callCount).equals(1) o(onclick0.this).equals(root.childNodes[0].firstChild) - setTimeout(function() { - o(onupdate0.callCount).equals(1) - o(onupdate1.callCount).equals(1) + throttleMock.fire() - root.childNodes[1].firstChild.dispatchEvent(e) - o(onclick1.callCount).equals(1) - o(onclick1.this).equals(root.childNodes[1].firstChild) + o(onupdate0.callCount).equals(1) + o(onupdate1.callCount).equals(1) - setTimeout(function() { - o(onupdate0.callCount).equals(2) - o(onupdate1.callCount).equals(2) + root.childNodes[1].firstChild.dispatchEvent(e) - done() - }, FRAME_BUDGET) - }, FRAME_BUDGET) + o(onclick1.callCount).equals(1) + o(onclick1.this).equals(root.childNodes[1].firstChild) + throttleMock.fire() + + o(onupdate0.callCount).equals(2) + o(onupdate1.callCount).equals(2) }) - o("event handlers can skip redraw", function(done) { - var onupdate = o.spy() + o("event handlers can skip redraw", function() { + var onupdate = o.spy(function(){ + throw new Error("This shouldn't have been called") + }) var oninit = o.spy() var e = $window.document.createEvent("MouseEvents") @@ -195,15 +195,12 @@ o.spec("mount", function() { o(oninit.callCount).equals(1) - // Wrapped to ensure no redraw fired - setTimeout(function() { - o(onupdate.callCount).equals(0) + throttleMock.fire() - done() - }, FRAME_BUDGET) + o(onupdate.callCount).equals(0) }) - o("redraws when the render function is run", function(done) { + o("redraws when the render function is run", function() { var onupdate = o.spy() var oninit = o.spy() @@ -221,17 +218,12 @@ o.spec("mount", function() { redrawService.redraw() - // Wrapped to give time for the rate-limited redraw to fire - setTimeout(function() { - o(onupdate.callCount).equals(1) + throttleMock.fire() - done() - }, FRAME_BUDGET) + o(onupdate.callCount).equals(1) }) - o("throttles", function(done, timeout) { - timeout(200) - + o("throttles", function() { var i = 0 mount(root, createComponent({view: function() {i++}})) var before = i @@ -243,12 +235,11 @@ o.spec("mount", function() { var after = i - setTimeout(function(){ - o(before).equals(1) // mounts synchronously - o(after).equals(1) // throttles rest - o(i).equals(2) - done() - },40) + throttleMock.fire() + + o(before).equals(1) // mounts synchronously + o(after).equals(1) // throttles rest + o(i).equals(2) }) }) }) diff --git a/api/tests/test-redraw.js b/api/tests/test-redraw.js index f13c2d3f..80a768dc 100644 --- a/api/tests/test-redraw.js +++ b/api/tests/test-redraw.js @@ -2,6 +2,7 @@ var o = require("../../ospec/ospec") var domMock = require("../../test-utils/domMock") +var throttleMocker = require("../../test-utils/throttleMock") var apiRedraw = require("../../api/redraw") o.spec("redrawService", function() { @@ -17,25 +18,39 @@ o.spec("redrawService", function() { redrawService.redraw() }) + o("honours throttleMock", function() { + var throttleMock = throttleMocker() + redrawService = apiRedraw(domMock(), throttleMock.throttle) + var spy = o.spy() + + redrawService.subscribe(root, spy) + + o(spy.callCount).equals(0) + + redrawService.redraw() + + o(spy.callCount).equals(0) + + throttleMock.fire() + + o(spy.callCount).equals(1) + }) + o("should run a single renderer entry", function(done) { var spy = o.spy() redrawService.subscribe(root, spy) o(spy.callCount).equals(0) - - redrawService.redraw() - - o(spy.callCount).equals(1) redrawService.redraw() redrawService.redraw() redrawService.redraw() - o(spy.callCount).equals(1) + o(spy.callCount).equals(0) setTimeout(function() { - o(spy.callCount).equals(2) - + o(spy.callCount).equals(1) + done() }, 20) }) @@ -54,27 +69,29 @@ o.spec("redrawService", function() { redrawService.redraw() - o(spy1.callCount).equals(1) - o(spy2.callCount).equals(1) - o(spy3.callCount).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + o(spy3.callCount).equals(0) redrawService.redraw() - o(spy1.callCount).equals(1) - o(spy2.callCount).equals(1) - o(spy3.callCount).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + o(spy3.callCount).equals(0) setTimeout(function() { - o(spy1.callCount).equals(2) - o(spy2.callCount).equals(2) - o(spy3.callCount).equals(2) - + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) + o(spy3.callCount).equals(1) + done() }, 20) }) - o("should stop running after unsubscribe", function() { - var spy = o.spy() + o("should stop running after unsubscribe", function(done) { + var spy = o.spy(function() { + throw new Error("This shouldn't have been called") + }) redrawService.subscribe(root, spy) redrawService.unsubscribe(root, spy) @@ -82,9 +99,14 @@ o.spec("redrawService", function() { redrawService.redraw() o(spy.callCount).equals(0) + setTimeout(function() { + o(spy.callCount).equals(0) + + done() + }, 20) }) - o("does nothing on invalid unsubscribe", function() { + o("does nothing on invalid unsubscribe", function(done) { var spy = o.spy() redrawService.subscribe(root, spy) @@ -92,6 +114,10 @@ o.spec("redrawService", function() { redrawService.redraw() - o(spy.callCount).equals(1) + setTimeout(function() { + o(spy.callCount).equals(1) + + done() + }, 20) }) }) diff --git a/api/tests/test-router.js b/api/tests/test-router.js index 9406de70..bc3e7023 100644 --- a/api/tests/test-router.js +++ b/api/tests/test-router.js @@ -3,6 +3,7 @@ var o = require("../../ospec/ospec") var callAsync = require("../../test-utils/callAsync") var browserMock = require("../../test-utils/browserMock") +var throttleMocker = require("../../test-utils/throttleMock") var m = require("../../render/hyperscript") var callAsync = require("../../test-utils/callAsync") @@ -15,18 +16,23 @@ o.spec("route", function() { void ["#", "?", "", "#!", "?!", "/foo"].forEach(function(prefix) { o.spec("using prefix `" + prefix + "` starting on " + env.protocol + "//" + env.hostname, function() { var FRAME_BUDGET = Math.floor(1000 / 60) - var $window, root, redrawService, route + var $window, root, redrawService, route, throttleMock o.beforeEach(function() { $window = browserMock(env) + throttleMock = throttleMocker() root = $window.document.body - redrawService = apiRedraw($window) + redrawService = apiRedraw($window, throttleMock.throttle) route = apiRouter($window, redrawService) route.prefix(prefix) }) + o.afterEach(function() { + o(throttleMock.queueLength()).equals(0) + }) + o("throws on invalid `root` DOM node", function() { var threw = false try { @@ -50,7 +56,7 @@ o.spec("route", function() { o(root.firstChild.nodeName).equals("DIV") }) - o("routed mount points can redraw synchronously (POJO component)", function() { + o("routed mount points only redraw asynchronously (POJO component)", function() { var view = o.spy() $window.location.href = prefix + "/" @@ -60,11 +66,14 @@ o.spec("route", function() { redrawService.redraw() - o(view.callCount).equals(2) + o(view.callCount).equals(1) + throttleMock.fire() + + o(view.callCount).equals(2) }) - o("routed mount points can redraw synchronously (constructible component)", function() { + o("routed mount points only redraw asynchronously (constructible component)", function() { var view = o.spy() var Cmp = function(){} @@ -77,11 +86,14 @@ o.spec("route", function() { redrawService.redraw() - o(view.callCount).equals(2) + o(view.callCount).equals(1) + throttleMock.fire() + + o(view.callCount).equals(2) }) - o("routed mount points can redraw synchronously (closure component)", function() { + o("routed mount points only redraw asynchronously (closure component)", function() { var view = o.spy() function Cmp() {return {view: view}} @@ -93,8 +105,11 @@ o.spec("route", function() { redrawService.redraw() - o(view.callCount).equals(2) + o(view.callCount).equals(1) + throttleMock.fire() + + o(view.callCount).equals(2) }) o("default route doesn't break back button", function(done) { @@ -160,11 +175,12 @@ o.spec("route", function() { o(oninit.callCount).equals(1) redrawService.redraw() + throttleMock.fire() o(onupdate.callCount).equals(1) }) - o("redraws on events", function(done) { + o("redraws on events", function() { var onupdate = o.spy() var oninit = o.spy() var onclick = o.spy() @@ -194,12 +210,9 @@ o.spec("route", function() { o(onclick.args[0].type).equals("click") o(onclick.args[0].target).equals(root.firstChild) - // Wrapped to give time for the rate-limited redraw to fire - callAsync(function() { - o(onupdate.callCount).equals(1) - done() - }) + throttleMock.fire() + o(onupdate.callCount).equals(1) }) o("event handlers can skip redraw", function(done) { @@ -500,7 +513,10 @@ o.spec("route", function() { o(oninit.callCount).equals(1) route.set("/def") callAsync(function() { + throttleMock.fire() + o(oninit.callCount).equals(2) + done() }) }) @@ -536,23 +552,28 @@ o.spec("route", function() { route(root, "/a", { "/a" : { render: function() { - return m("div") + return m("div", m('p')) }, }, "/b" : { render: function() { - return m("div") + return m("div", m('a')) }, }, }) var dom = root.firstChild + var child = dom.firstChild + o(root.firstChild.nodeName).equals("DIV") route.set("/b") callAsync(function() { + throttleMock.fire() + o(root.firstChild).equals(dom) + o(root.firstChild.firstChild).notEquals(child) done() }) @@ -586,6 +607,7 @@ o.spec("route", function() { o(renderCount).equals(1) redrawService.redraw() + throttleMock.fire() o(matchCount).equals(1) o(renderCount).equals(2) @@ -621,6 +643,7 @@ o.spec("route", function() { o(renderCount).equals(1) redrawService.redraw() + throttleMock.fire() o(matchCount).equals(1) o(renderCount).equals(2) @@ -815,10 +838,14 @@ o.spec("route", function() { }) callAsync(function() { - route.set("/b") + throttleMock.fire() + + route.set('/b') callAsync(function() { callAsync(function() { callAsync(function() { + throttleMock.fire() + o(render.callCount).equals(0) o(component.view.callCount).equals(2) @@ -939,6 +966,7 @@ o.spec("route", function() { o(onmatch.callCount).equals(1) redrawService.redraw() + throttleMock.fire() o(view.callCount).equals(2) o(onmatch.callCount).equals(1) @@ -1017,6 +1045,8 @@ o.spec("route", function() { }) callAsync(function() { + throttleMock.fire() + o(onmatch.callCount).equals(1) o(render.callCount).equals(1) @@ -1024,6 +1054,8 @@ o.spec("route", function() { callAsync(function() { callAsync(function() { + throttleMock.fire() + o(onmatch.callCount).equals(2) o(render.callCount).equals(2) @@ -1074,9 +1106,15 @@ o.spec("route", function() { route.set("/b") callAsync(function() { - route.set("/a") + throttleMock.fire() + + o(root.firstChild.nodeName).equals("B") + + route.set('/a') callAsync(function() { + throttleMock.fire() + o(root.firstChild.nodeName).equals("A") done() @@ -1141,7 +1179,9 @@ o.spec("route", function() { route.set("/b") + // setting the route is asynchronous callAsync(function() { + throttleMock.fire() o(spy.callCount).equals(1) done() @@ -1181,9 +1221,7 @@ o.spec("route", function() { }) }) - o("throttles", function(done, timeout) { - timeout(200) - + o("throttles", function() { var i = 0 $window.location.href = prefix + "/" route(root, "/", { @@ -1197,12 +1235,11 @@ o.spec("route", function() { redrawService.redraw() var after = i - setTimeout(function() { - o(before).equals(1) // routes synchronously - o(after).equals(2) // redraws synchronously - o(i).equals(3) // throttles rest - done() - }, FRAME_BUDGET * 2) + throttleMock.fire() + + o(before).equals(1) // routes synchronously + o(after).equals(1) // redraws asynchronously + o(i).equals(2) }) o("m.route.param is available outside of route handlers", function(done) { diff --git a/docs/redraw.md b/docs/redraw.md index 85b397dc..7bb25810 100644 --- a/docs/redraw.md +++ b/docs/redraw.md @@ -14,7 +14,7 @@ You DON'T need to call it if data is modified within the execution context of an You DO need to call it in `setTimeout`/`setInterval`/`requestAnimationFrame` callbacks, or callbacks from 3rd party libraries. -Typically, `m.redraw` triggers an asynchronous redraws, but it may trigger synchronously if Mithril detects it's possible to improve performance by doing so (i.e. if no redraw was requested within the last animation frame). You should write code assuming that it always redraws asynchronously. +`m.redraw` always triggers an asynchronous redraws. --- diff --git a/docs/route.md b/docs/route.md index 6f5c571b..16a08eec 100644 --- a/docs/route.md +++ b/docs/route.md @@ -65,7 +65,7 @@ Argument | Type | Required | D ##### m.route.set -Redirects to a matching route, or to the default route if no matching routes can be found. +Redirects to a matching route, or to the default route if no matching routes can be found. Triggers an asynchronous redraw off all mount points. `m.route.set(path, data, options)` diff --git a/test-utils/tests/test-throttleMock.js b/test-utils/tests/test-throttleMock.js new file mode 100644 index 00000000..8126af05 --- /dev/null +++ b/test-utils/tests/test-throttleMock.js @@ -0,0 +1,89 @@ +var o = require("../../ospec/ospec") +var throttleMocker = require("../../test-utils/throttleMock") + +o.spec("throttleMock", function() { + o("works with one callback", function() { + var throttleMock = throttleMocker() + var spy = o.spy() + + o(throttleMock.queueLength()).equals(0) + + var throttled = throttleMock.throttle(spy) + + o(throttleMock.queueLength()).equals(0) + o(spy.callCount).equals(0) + + throttled() + + o(throttleMock.queueLength()).equals(1) + o(spy.callCount).equals(0) + + throttled() + + o(throttleMock.queueLength()).equals(1) + o(spy.callCount).equals(0) + + throttleMock.fire() + + o(throttleMock.queueLength()).equals(0) + o(spy.callCount).equals(1) + + throttleMock.fire() + + o(spy.callCount).equals(1) + }) + o("works with two callbacks", function() { + var throttleMock = throttleMocker() + var spy1 = o.spy() + var spy2 = o.spy() + + o(throttleMock.queueLength()).equals(0) + + var throttled1 = throttleMock.throttle(spy1) + + o(throttleMock.queueLength()).equals(0) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + throttled1() + + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + throttled1() + + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + var throttled2 = throttleMock.throttle(spy2) + + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + throttled2() + + o(throttleMock.queueLength()).equals(2) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + throttled2() + + o(throttleMock.queueLength()).equals(2) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + + throttleMock.fire() + + o(throttleMock.queueLength()).equals(0) + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) + + throttleMock.fire() + + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) + }) +}) diff --git a/test-utils/throttleMock.js b/test-utils/throttleMock.js new file mode 100644 index 00000000..46076b28 --- /dev/null +++ b/test-utils/throttleMock.js @@ -0,0 +1,24 @@ +module.exports = function() { + var queue = [] + return { + throttle: function(fn) { + var pending = false + return function() { + if (!pending) { + queue.push(function(){ + pending = false + fn() + }) + pending = true + } + } + }, + fire: function() { + queue.forEach(function(fn) {fn()}) + queue.length = 0 + }, + queueLength: function(){ + return queue.length + } + } +} diff --git a/tests/test-api.js b/tests/test-api.js index 3240141c..d0c2cf81 100644 --- a/tests/test-api.js +++ b/tests/test-api.js @@ -163,8 +163,10 @@ o.spec("api", function() { var count = 0 var root = window.document.createElement("div") m.mount(root, createComponent({view: function() {count++}})) + o(count).equals(1) + m.redraw() + o(count).equals(1) setTimeout(function() { - m.redraw() o(count).equals(2) From ccb3d61675da138be61bab83f44bc4c26cdc8ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 13 Jun 2017 15:35:05 +0200 Subject: [PATCH 003/301] Make redraw monolithic, add m.redraw.sync --- api/redraw.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/api/redraw.js b/api/redraw.js index 07937445..33472635 100644 --- a/api/redraw.js +++ b/api/redraw.js @@ -19,26 +19,32 @@ function throttle(callback) { } } + module.exports = function($window, throttleMock) { - var _throttle = throttleMock || throttle var renderService = coreRenderer($window) renderService.setEventCallback(function(e) { if (e.redraw !== false) redraw() }) var callbacks = [] + var rendering = false + function subscribe(key, callback) { unsubscribe(key) - callbacks.push(key, _throttle(callback)) + callbacks.push(key, callback) } function unsubscribe(key) { var index = callbacks.indexOf(key) if (index > -1) callbacks.splice(index, 2) } - function redraw() { - for (var i = 1; i < callbacks.length; i += 2) { - callbacks[i]() - } + function sync() { + if (rendering) throw new Error("Nested m.redraw.sync() call") + rendering = true + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {/*noop*/} + rendering = false } + + var redraw = (throttleMock || throttle)(sync) + redraw.sync = sync return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render} } From 7de012433936ce5a29db5cad4bbb81491eea554b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 13 Jun 2017 16:29:02 +0200 Subject: [PATCH 004/301] Tests for m.redraw.sync() --- api/tests/test-mount.js | 32 ++++++++++++++++++++++++++- api/tests/test-redraw.js | 48 ++++++++++++++++++++++++++++++++++++++++ tests/test-api.js | 8 +++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/api/tests/test-mount.js b/api/tests/test-mount.js index e115711b..80ade907 100644 --- a/api/tests/test-mount.js +++ b/api/tests/test-mount.js @@ -52,7 +52,7 @@ o.spec("mount", function() { o(threw).equals(true) }) - o("renders into `root`", function() { + o("renders into `root` synchronoulsy", function() { mount(root, createComponent({ view : function() { return m("div") @@ -74,6 +74,36 @@ o.spec("mount", function() { o(root.childNodes.length).equals(0) }) + o("Mounting a second root doesn't cause the first one to redraw", function() { + var view = o.spy(function() { + return m("div") + }) + + render(root, [ + m("#child0"), + m("#child1") + ]) + + mount(root.childNodes[0], createComponent({ + view : view + })) + + o(root.firstChild.nodeName).equals("DIV") + o(view.callCount).equals(1) + + mount(root.childNodes[1], createComponent({ + view : function() { + return m("div") + } + })) + + o(view.callCount).equals(1) + + throttleMock.fire() + + o(view.callCount).equals(1) + }) + o("redraws on events", function() { var onupdate = o.spy() var oninit = o.spy() diff --git a/api/tests/test-redraw.js b/api/tests/test-redraw.js index 80a768dc..68b1a911 100644 --- a/api/tests/test-redraw.js +++ b/api/tests/test-redraw.js @@ -106,6 +106,25 @@ o.spec("redrawService", function() { }, 20) }) + o("should stop running after unsubscribe, even if it occurs after redraw is requested", function(done) { + var spy = o.spy(function() { + throw new Error("This shouldn't have been called") + }) + + redrawService.subscribe(root, spy) + + redrawService.redraw() + + redrawService.unsubscribe(root, spy) + + o(spy.callCount).equals(0) + setTimeout(function() { + o(spy.callCount).equals(0) + + done() + }, 20) + }) + o("does nothing on invalid unsubscribe", function(done) { var spy = o.spy() @@ -120,4 +139,33 @@ o.spec("redrawService", function() { done() }, 20) }) + + o("redraw.sync() redraws all roots synchronously", function() { + var el1 = $document.createElement("div") + var el2 = $document.createElement("div") + var el3 = $document.createElement("div") + var spy1 = o.spy() + var spy2 = o.spy() + var spy3 = o.spy() + + redrawService.subscribe(el1, spy1) + redrawService.subscribe(el2, spy2) + redrawService.subscribe(el3, spy3) + + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) + o(spy3.callCount).equals(0) + + redrawService.redraw.sync() + + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) + o(spy3.callCount).equals(1) + + redrawService.redraw.sync() + + o(spy1.callCount).equals(2) + o(spy2.callCount).equals(2) + o(spy3.callCount).equals(2) + }) }) diff --git a/tests/test-api.js b/tests/test-api.js index d0c2cf81..49938d82 100644 --- a/tests/test-api.js +++ b/tests/test-api.js @@ -173,6 +173,14 @@ o.spec("api", function() { done() }, FRAME_BUDGET) }) + o("sync", function() { + var root = window.document.createElement("div") + var view = o.spy() + m.mount(root, createComponent({view: view})) + o(view.callCount).equals(1) + m.redraw.sync() + o(view.callCount).equals(2) + }) }) }) }) From 47d59ea68a266f7eec296e855cedead7542ff122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 13 Jun 2017 23:30:12 +0200 Subject: [PATCH 005/301] [test-utils] Make throttleMock more reliable --- test-utils/throttleMock.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test-utils/throttleMock.js b/test-utils/throttleMock.js index 46076b28..06e74f99 100644 --- a/test-utils/throttleMock.js +++ b/test-utils/throttleMock.js @@ -14,8 +14,9 @@ module.exports = function() { } }, fire: function() { - queue.forEach(function(fn) {fn()}) - queue.length = 0 + var tasks = queue + queue = [] + tasks.forEach(function(fn) {fn()}) }, queueLength: function(){ return queue.length From 0e0ed7c45d658820f8317e8c1041f9e2d87d5ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 14 Jun 2017 00:15:08 +0200 Subject: [PATCH 006/301] Lint --- api/tests/test-mount.js | 1 - api/tests/test-redraw.js | 2 +- api/tests/test-router.js | 9 +- test-utils/tests/test-throttleMock.js | 114 +++++++++++++------------- test-utils/throttleMock.js | 48 +++++------ 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/api/tests/test-mount.js b/api/tests/test-mount.js index 80ade907..6bc69ce9 100644 --- a/api/tests/test-mount.js +++ b/api/tests/test-mount.js @@ -11,7 +11,6 @@ var apiRedraw = require("../../api/redraw") var apiMounter = require("../../api/mount") o.spec("mount", function() { - var FRAME_BUDGET = Math.floor(1000 / 60) var $window, root, redrawService, mount, render, throttleMock o.beforeEach(function() { diff --git a/api/tests/test-redraw.js b/api/tests/test-redraw.js index 68b1a911..65831bb0 100644 --- a/api/tests/test-redraw.js +++ b/api/tests/test-redraw.js @@ -166,6 +166,6 @@ o.spec("redrawService", function() { o(spy1.callCount).equals(2) o(spy2.callCount).equals(2) - o(spy3.callCount).equals(2) + o(spy3.callCount).equals(2) }) }) diff --git a/api/tests/test-router.js b/api/tests/test-router.js index bc3e7023..ad009667 100644 --- a/api/tests/test-router.js +++ b/api/tests/test-router.js @@ -15,7 +15,6 @@ o.spec("route", function() { void [{protocol: "http:", hostname: "localhost"}, {protocol: "file:", hostname: "/"}].forEach(function(env) { void ["#", "?", "", "#!", "?!", "/foo"].forEach(function(prefix) { o.spec("using prefix `" + prefix + "` starting on " + env.protocol + "//" + env.hostname, function() { - var FRAME_BUDGET = Math.floor(1000 / 60) var $window, root, redrawService, route, throttleMock o.beforeEach(function() { @@ -552,12 +551,12 @@ o.spec("route", function() { route(root, "/a", { "/a" : { render: function() { - return m("div", m('p')) + return m("div", m("p")) }, }, "/b" : { render: function() { - return m("div", m('a')) + return m("div", m("a")) }, }, }) @@ -840,7 +839,7 @@ o.spec("route", function() { callAsync(function() { throttleMock.fire() - route.set('/b') + route.set("/b") callAsync(function() { callAsync(function() { callAsync(function() { @@ -1110,7 +1109,7 @@ o.spec("route", function() { o(root.firstChild.nodeName).equals("B") - route.set('/a') + route.set("/a") callAsync(function() { throttleMock.fire() diff --git a/test-utils/tests/test-throttleMock.js b/test-utils/tests/test-throttleMock.js index 8126af05..69920623 100644 --- a/test-utils/tests/test-throttleMock.js +++ b/test-utils/tests/test-throttleMock.js @@ -1,89 +1,91 @@ +"use strict" + var o = require("../../ospec/ospec") var throttleMocker = require("../../test-utils/throttleMock") o.spec("throttleMock", function() { - o("works with one callback", function() { - var throttleMock = throttleMocker() - var spy = o.spy() + o("works with one callback", function() { + var throttleMock = throttleMocker() + var spy = o.spy() - o(throttleMock.queueLength()).equals(0) + o(throttleMock.queueLength()).equals(0) - var throttled = throttleMock.throttle(spy) + var throttled = throttleMock.throttle(spy) - o(throttleMock.queueLength()).equals(0) - o(spy.callCount).equals(0) + o(throttleMock.queueLength()).equals(0) + o(spy.callCount).equals(0) - throttled() + throttled() - o(throttleMock.queueLength()).equals(1) - o(spy.callCount).equals(0) + o(throttleMock.queueLength()).equals(1) + o(spy.callCount).equals(0) - throttled() + throttled() - o(throttleMock.queueLength()).equals(1) - o(spy.callCount).equals(0) + o(throttleMock.queueLength()).equals(1) + o(spy.callCount).equals(0) - throttleMock.fire() + throttleMock.fire() - o(throttleMock.queueLength()).equals(0) - o(spy.callCount).equals(1) + o(throttleMock.queueLength()).equals(0) + o(spy.callCount).equals(1) - throttleMock.fire() + throttleMock.fire() - o(spy.callCount).equals(1) - }) - o("works with two callbacks", function() { - var throttleMock = throttleMocker() - var spy1 = o.spy() - var spy2 = o.spy() + o(spy.callCount).equals(1) + }) + o("works with two callbacks", function() { + var throttleMock = throttleMocker() + var spy1 = o.spy() + var spy2 = o.spy() - o(throttleMock.queueLength()).equals(0) + o(throttleMock.queueLength()).equals(0) - var throttled1 = throttleMock.throttle(spy1) + var throttled1 = throttleMock.throttle(spy1) - o(throttleMock.queueLength()).equals(0) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(0) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - throttled1() + throttled1() - o(throttleMock.queueLength()).equals(1) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - throttled1() + throttled1() - o(throttleMock.queueLength()).equals(1) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - var throttled2 = throttleMock.throttle(spy2) + var throttled2 = throttleMock.throttle(spy2) - o(throttleMock.queueLength()).equals(1) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(1) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - throttled2() + throttled2() - o(throttleMock.queueLength()).equals(2) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(2) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - throttled2() + throttled2() - o(throttleMock.queueLength()).equals(2) - o(spy1.callCount).equals(0) - o(spy2.callCount).equals(0) + o(throttleMock.queueLength()).equals(2) + o(spy1.callCount).equals(0) + o(spy2.callCount).equals(0) - throttleMock.fire() + throttleMock.fire() - o(throttleMock.queueLength()).equals(0) - o(spy1.callCount).equals(1) - o(spy2.callCount).equals(1) + o(throttleMock.queueLength()).equals(0) + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) - throttleMock.fire() + throttleMock.fire() - o(spy1.callCount).equals(1) - o(spy2.callCount).equals(1) - }) + o(spy1.callCount).equals(1) + o(spy2.callCount).equals(1) + }) }) diff --git a/test-utils/throttleMock.js b/test-utils/throttleMock.js index 06e74f99..6cdb5710 100644 --- a/test-utils/throttleMock.js +++ b/test-utils/throttleMock.js @@ -1,25 +1,27 @@ +"use strict" + module.exports = function() { - var queue = [] - return { - throttle: function(fn) { - var pending = false - return function() { - if (!pending) { - queue.push(function(){ - pending = false - fn() - }) - pending = true - } - } - }, - fire: function() { - var tasks = queue - queue = [] - tasks.forEach(function(fn) {fn()}) - }, - queueLength: function(){ - return queue.length - } - } + var queue = [] + return { + throttle: function(fn) { + var pending = false + return function() { + if (!pending) { + queue.push(function(){ + pending = false + fn() + }) + pending = true + } + } + }, + fire: function() { + var tasks = queue + queue = [] + tasks.forEach(function(fn) {fn()}) + }, + queueLength: function(){ + return queue.length + } + } } From 57471ddcff589ee0f032e80b9d2fa3a4542bfec9 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 11 Jul 2017 22:15:27 -0700 Subject: [PATCH 007/301] chore: don't add travis-only deps to package.json `npm@5` changed to save-by-default, which screwed up the plan of keeping travis-only deps out of `package.json`. Fixes #1894 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 494a4fef..ef6f96b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ cache: # Custom install step so the travis-only stuff doesn't need to be in package.json install: - npm install -- npm install @alrra/travis-scripts@^3.0.1 gh-pages@^0.12.0 +- npm install --no-save @alrra/travis-scripts@^3.0.1 gh-pages@^0.12.0 # Bundle before running tests so the bundle is always up-to-date before_script: npm run build --silent From 4dc1f2f5be3ba82a8561704b27e398835fc18d1b Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 11 Jul 2017 22:16:44 -0700 Subject: [PATCH 008/301] chore: remove travis deps from package.json --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 3bab3eed..3ee2a61a 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,8 @@ "postversion": "git push --follow-tags" }, "devDependencies": { - "@alrra/travis-scripts": "^3.0.1", "benchmark": "^2.1.4", "eslint": "^3.19.0", - "gh-pages": "^0.12.0", "istanbul": "^0.4.5", "marked": "^0.3.6" }, From 2182a629b22a18e2873d3aed9fe349b70bbc64a1 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 11 Jul 2017 23:38:27 -0700 Subject: [PATCH 009/301] chore: remove unnecessary branch fields (#1897) --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 494a4fef..be5ee617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,7 +84,6 @@ deploy: on: tags: true repo: MithrilJS/mithril.js - branch: master - provider: npm skip_cleanup: true @@ -94,4 +93,3 @@ deploy: on: tags: true repo: MithrilJS/mithril.js - branch: master From 9b6ec10a9354a0f848609b97c014a1ba4108851d Mon Sep 17 00:00:00 2001 From: theRefugee Date: Wed, 12 Jul 2017 15:20:43 +0200 Subject: [PATCH 010/301] Update request.md --- docs/request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/request.md b/docs/request.md index 3277c378..fe962e50 100644 --- a/docs/request.md +++ b/docs/request.md @@ -329,7 +329,7 @@ function upload(e) { url: "/api/v1/upload", data: data, config: function(xhr) { - xhr.addEventListener("progress", function(e) { + xhr.upload.addEventListener("progress", function(e) { progress = e.loaded / e.total m.redraw() // tell Mithril that data changed and a re-render is needed From 0631a6fd581b808ed3c2220d000d6b882103d2ac Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Wed, 12 Jul 2017 16:11:16 +0000 Subject: [PATCH 011/301] Bundled output for commit 0cd151b08a80229f026655b12818b35d84981b52 [skip ci] --- package-lock.json | 92 ----------------------------------------------- 1 file changed, 92 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fe0b711..088ddc10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3,12 +3,6 @@ "version": "1.1.3", "lockfileVersion": 1, "dependencies": { - "@alrra/travis-scripts": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@alrra/travis-scripts/-/travis-scripts-3.0.1.tgz", - "integrity": "sha1-RdW5NXMXtsxVU9/ZmTGEOuCw5To=", - "dev": true - }, "abbrev": { "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", @@ -182,18 +176,6 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "collections": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz", - "integrity": "sha1-HyMCay7zb5J+7MkB6ZxfDUj6M04=", - "dev": true - }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true - }, "concat-map": { "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", @@ -384,32 +366,6 @@ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true }, - "gh-pages": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.12.0.tgz", - "integrity": "sha1-2VHj7Zi4VpnUsEGOsaFbGgSYjcE=", - "dev": true, - "dependencies": { - "async": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", - "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", - "dev": true - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true - }, - "graceful-fs": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.10.tgz", - "integrity": "sha1-8tcgwiCS90Mih3XHXjYSYyUB8TE=", - "dev": true - } - } - }, "glob": { "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", @@ -430,12 +386,6 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, "handlebars": { "version": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz", "integrity": "sha1-6XMlrrjqC54SucTdc8TDEq0O3lk=", @@ -616,18 +566,6 @@ "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", "dev": true }, - "mime": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", - "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", - "dev": true - }, - "mimeparse": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/mimeparse/-/mimeparse-0.1.4.tgz", - "integrity": "sha1-2vsCdSNw/SJgk64xUsJxrwGsJUo=", - "dev": true - }, "minimatch": { "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", @@ -760,24 +698,6 @@ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true - }, - "q-io": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.2.tgz", - "integrity": "sha1-7qEw1IHdteGqG8WmaFX3OR0G8AM=", - "dev": true - }, - "qs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.2.tgz", - "integrity": "sha1-GbV/8k3CqZzh+L32r82ln472H4g=", - "dev": true - }, "readable-stream": { "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", @@ -952,12 +872,6 @@ "dev": true, "optional": true }, - "url2": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/url2/-/url2-0.0.0.tgz", - "integrity": "sha1-Tqq9HVw6yQ1iq0SFyZhCKGWgSxo=", - "dev": true - }, "user-home": { "version": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", @@ -968,12 +882,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "weak-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.0.tgz", - "integrity": "sha1-tm5Wqd8L0lp2u/G1FNsSkIBhSjc=", - "dev": true - }, "which": { "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", From 482f0e71b9d94f559d8afeb01df349e5c2fe44a6 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 20:34:45 -0700 Subject: [PATCH 012/301] docs: readme rework (#1898) --- .eslintignore | 10 +- .travis.yml | 11 +- README.md | 316 +++++++++-------------------------------------- bundler/cli.js | 20 +-- docs/generate.js | 3 - package.json | 6 +- 6 files changed, 80 insertions(+), 286 deletions(-) diff --git a/.eslintignore b/.eslintignore index 61d2a0b7..62117a94 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,7 @@ -.vscode -/coverage -/docs/lib -/examples +.vscode/ +coverage/ +docs/lib/ +examples/ /mithril.js /mithril.min.js -/node_modules +node_modules/ diff --git a/.travis.yml b/.travis.yml index 654246bb..a0b3b3e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,13 +15,16 @@ install: - npm install - npm install --no-save @alrra/travis-scripts@^3.0.1 gh-pages@^0.12.0 -# Bundle before running tests so the bundle is always up-to-date -before_script: npm run build --silent +# Create bundles before running tests so they're always up-to-date +# Pass -save to build-min so it'll update the readme as well +before_script: +- npm run build-browser +- npm run build-min -- -save # Run tests, lint, and then check for perf regressions script: -- npm test --silent -- npm run perf --silent +- npm test +- npm run perf # After a successful build commit changes back to repo after_success: diff --git a/README.md b/README.md index 08636be2..c5df4082 100644 --- a/README.md +++ b/README.md @@ -1,267 +1,61 @@ -# Introduction +mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://www.npmjs.com/package/mithril) [![NPM License](https://img.shields.io/npm/l/mithril.svg)](https://www.npmjs.com/package/mithril) [![NPM Downloads](https://img.shields.io/npm/dm/mithril.svg)](https://www.npmjs.com/package/mithril) +========== + +

+ + Build Status + + + Gitter + +

- [What is Mithril?](#what-is-mithril) -- [Getting started](#getting-started) -- [Hello world](#hello-world) -- [DOM elements](#dom-elements) -- [Components](#components) -- [Routing](#routing) -- [XHR](#xhr) +- [Installation](#installation) +- [Documentation](#documentation) +- [Getting Help](#getting-help) +- [Contributing](#contributing) + +## What is Mithril? + +A modern client-side Javascript framework for building Single Page Applications. It's small (8.18 KB gzipped), fast and provides routing and XHR utilities out of the box. + +Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. + +Browsers all the way back to IE9 are supported, no polyfills required 👌. + +## Installation + +### CDN + +```html + +``` + +### npm + +```bash +$ npm install mithril +``` + +The ["Getting started" guide](https://mithril.js.org/#getting-started) is a good place to start learning how to use mithril. + +## Documentation + +Documentation lives on [mithril.js.org](https://mithril.js.org). + +You may be interested in the [API Docs](https://mithril.js.org/api.html), a [Simple Application](https://mithril.js.org/simple-application.html), or perhaps some [Examples](https://mithril.js.org/examples.html). + +## Getting Help + +Mithril has an active & welcoming community on [Gitter](https://gitter.im/mithriljs/mithril.js), or feel free to ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/mithril.js) using the `mithril.js` tag. + +## Contributing + +There's a [Contributing FAQ](https://mithril.js.org/contributing.html) on the mithril site that hopefully helps, but if not definitely hop into the [Gitter Room](https://gitter.im/mithriljs/mithril.js) and ask away! --- -### What is Mithril? +Thanks for reading! -Mithril is a modern client-side Javascript framework for building Single Page Applications. -It's small (< 8kb gzip), fast and provides routing and XHR utilities out of the box. - -
-
-
Download size
- Mithril (8kb) -
- Vue + Vue-Router + Vuex + fetch (40kb) -
- React + React-Router + Redux + fetch (64kb) -
- Angular (135kb) -
-
-
-
Performance
- Mithril (6.4ms) -
- Vue (9.8ms) -
- React (12.1ms) -
- Angular (11.5ms) -
-
-
- -Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess. - -If you are an experienced developer and want to know how Mithril compares to other frameworks, see the [framework comparison](http://mithril.js.org/framework-comparison.html) page. - -Mithril supports browsers all the way back to IE9, no polyfills required. - ---- - -### Getting started - -The easiest way to try out Mithril is to include it from a CDN, and follow this tutorial. It'll cover the majority of the API surface (including routing and XHR) but it'll only take 10 minutes. - -Let's create an HTML file to follow along: - -```markup - - - - -``` - ---- - -### Hello world - -Let's start as small as we can: render some text on screen. Copy the code below into your file (and by copy, I mean type it out - you'll learn better) - -```javascript -var root = document.body - -m.render(root, "Hello world") -``` - -Now, let's change the text to something else. Add this line of code under the previous one: - -```javascript -m.render(root, "My first app") -``` - -As you can see, you use the same code to both create and update HTML. Mithril automatically figures out the most efficient way of updating the text, rather than blindly recreating it from scratch. - ---- - -### DOM elements - -Let's wrap our text in an `

` tag. - -```javascript -m.render(root, m("h1", "My first app")) -``` - -The `m()` function can be used to describe any HTML structure you want. So if you need to add a class to the `

`: - -```javascript -m("h1", {class: "title"}, "My first app") -``` - -If you want to have multiple elements: - -```javascript -[ - m("h1", {class: "title"}, "My first app"), - m("button", "A button"), -] -``` - -And so on: - -```javascript -m("main", [ - m("h1", {class: "title"}, "My first app"), - m("button", "A button"), -]) -``` - -Note: If you prefer `` syntax, [it's possible to use it via a Babel plugin](http://mithril.js.org/jsx.html). - -```jsx -// HTML syntax via Babel's JSX plugin -
-

My first app

- -
-``` - ---- - -### Components - -A Mithril component is just an object with a `view` function. Here's the code above as a component: - -```javascript -var Hello = { - view: function() { - return m("main", [ - m("h1", {class: "title"}, "My first app"), - m("button", "A button"), - ]) - } -} -``` - -To activate the component, we use `m.mount`. - -```javascript -m.mount(root, Hello) -``` - -As you would expect, doing so creates this markup: - -```markup -
-

My first app

- -
-``` - -The `m.mount` function is similar to `m.render`, but instead of rendering some HTML only once, it activates Mithril's auto-redrawing system. To understand what that means, let's add some events: - -```javascript -var count = 0 // added a variable - -var Hello = { - view: function() { - return m("main", [ - m("h1", {class: "title"}, "My first app"), - // changed the next line - m("button", {onclick: function() {count++}}, count + " clicks"), - ]) - } -} - -m.mount(root, Hello) -``` - -We defined an `onclick` event on the button, which increments a variable `count` (which was declared at the top). We are now also rendering the value of that variable in the button label. - -You can now update the label of the button by clicking the button. Since we used `m.mount`, you don't need to manually call `m.render` to apply the changes in the `count` variable to the HTML; Mithril does it for you. - -If you're wondering about performance, it turns out Mithril is very fast at rendering updates, because it only touches the parts of the DOM it absolutely needs to. So in our example above, when you click the button, the text in it is the only part of the DOM Mithril actually updates. - ---- - -### Routing - -Routing just means going from one screen to another in an application with several screens. - -Let's add a splash page that appears before our click counter. First we create a component for it: - -```javascript -var Splash = { - view: function() { - return m("a", {href: "#!/hello"}, "Enter!") - } -} -``` - -As you can see, this component simply renders a link to `#!/hello`. The `#!` part is known as a hashbang, and it's a common convention used in Single Page Applications to indicate that the stuff after it (the `/hello` part) is a route path. - -Now that we going to have more than one screen, we use `m.route` instead of `m.mount`. - -```javascript -m.route(root, "/splash", { - "/splash": Splash, - "/hello": Hello, -}) -``` - -The `m.route` function still has the same auto-redrawing functionality that `m.mount` does, and it also enables URL awareness; in other words, it lets Mithril know what to do when it sees a `#!` in the URL. - -The `"/splash"` right after `root` means that's the default route, i.e. if the hashbang in the URL doesn't point to one of the defined routes (`/splash` and `/hello`, in our case), then Mithril redirects to the default route. So if you open the page in a browser and your URL is `http://localhost`, then you get redirected to `http://localhost/#!/splash`. - -Also, as you would expect, clicking on the link on the splash page takes you to the click counter screen we created earlier. Notice that now your URL will point to `http://localhost/#!/hello`. You can navigate back and forth to the splash page using the browser's back and next button. - ---- - -### XHR - -Basically, XHR is just a way to talk to a server. - -Let's change our click counter to make it save data on a server. For the server, we'll use [REM](http://rem-rest-api.herokuapp.com), a mock REST API designed for toy apps like this tutorial. - -First we create a function that calls `m.request`. The `url` specifies an endpoint that represents a resource, the `method` specifies the type of action we're taking (typically the `PUT` method [upserts](https://en.wiktionary.org/wiki/upsert)), `data` is the payload that we're sending to the endpoint and `withCredentials` means to enable cookies (a requirement for the REM API to work) - -```javascript -var count = 0 -var increment = function() { - m.request({ - method: "PUT", - url: "//rem-rest-api.herokuapp.com/api/tutorial/1", - data: {count: count + 1}, - withCredentials: true, - }) - .then(function(data) { - count = parseInt(data.count) - }) -} -``` - -Calling the increment function [upserts](https://en.wiktionary.org/wiki/upsert) an object `{count: 1}` to the `/api/tutorial/1` endpoint. This endpoint returns an object with the same `count` value that was sent to it. Notice that the `count` variable is only updated after the request completes, and it's updated with the response value from the server now. - -Let's replace the event handler in the component to call the `increment` function instead of incrementing the `count` variable directly: - -```javascript -var Hello = { - view: function() { - return m("main", [ - m("h1", {class: "title"}, "My first app"), - m("button", {onclick: increment}, count + " clicks"), - ]) - } -} -``` - -Clicking the button should now update the count. - ---- - -We covered how to create and update HTML, how to create components, routes for a Single Page Application, and interacted with a server via XHR. - -This should be enough to get you started writing the frontend for a real application. Now that you are comfortable with the basics of the Mithril API, [be sure to check out the simple application tutorial](http://mithril.js.org/simple-application.html), which walks you through building a realistic application. +🎁 diff --git a/bundler/cli.js b/bundler/cli.js index f702ce7e..93ad0adf 100644 --- a/bundler/cli.js +++ b/bundler/cli.js @@ -5,7 +5,7 @@ var fs = require("fs"); var bundle = require("./bundle") var minify = require("./minify") -var aliases = {o: "output", m: "minify", w: "watch", a: "aggressive"} +var aliases = {o: "output", m: "minify", w: "watch", a: "aggressive", s: "save"} var params = {} var args = process.argv.slice(2), command = null for (var i = 0; i < args.length; i++) { @@ -27,8 +27,6 @@ function add(value) { bundle(params.input, params.output, {watch: params.watch}) if (params.minify) { minify(params.output, params.output, {watch: params.watch, advanced: params.aggressive}, function(stats) { - var readme, kb; - function format(n) { return n.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") } @@ -36,14 +34,16 @@ if (params.minify) { console.log("Original size: " + format(stats.originalGzipSize) + " bytes gzipped (" + format(stats.originalSize) + " bytes uncompressed)") console.log("Compiled size: " + format(stats.compressedGzipSize) + " bytes gzipped (" + format(stats.compressedSize) + " bytes uncompressed)") - readme = fs.readFileSync("./README.md", "utf8") - kb = stats.compressedGzipSize / 1024 + if (params.save) { + var readme = fs.readFileSync("./README.md", "utf8") + var kb = stats.compressedGzipSize / 1000 - fs.writeFileSync("./README.md", - readme.replace( - /()(.+?)()/, - "$1" + (kb % 1 ? kb.toFixed(2) : kb) + " KB$3" + fs.writeFileSync("./README.md", + readme.replace( + /()(.+?)()/, + "$1" + (kb % 1 ? kb.toFixed(2) : kb) + " KB$3" + ) ) - ) + } }) } diff --git a/docs/generate.js b/docs/generate.js index ef3ce424..5650ae9d 100644 --- a/docs/generate.js +++ b/docs/generate.js @@ -12,9 +12,6 @@ try {fs.mkdirSync("./dist/archive/v" + version)} catch (e) {/* ignore */} var guides = fs.readFileSync("docs/nav-guides.md", "utf-8") var methods = fs.readFileSync("docs/nav-methods.md", "utf-8") -var index = fs.readFileSync("docs/index.md", "utf-8") -fs.writeFileSync("README.md", index.replace(/(\]\()(.+?)\.md(\))/g, "$1http://mithril.js.org/$2.html$3"), "utf-8") - generate("docs") function generate(pathname) { diff --git a/package.json b/package.json index 3ee2a61a..69db5505 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "main": "mithril.js", "repository": "MithrilJS/mithril.js", "scripts": { - "dev": "node bundler/cli browser.js -o mithril.js -w", + "dev": "node bundler/cli browser.js -output mithril.js -watch", "build": "npm run build-browser & npm run build-min", - "build-browser": "node bundler/cli browser.js -o mithril.js", - "build-min": "node bundler/cli browser.js -o mithril.min.js -m", + "build-browser": "node bundler/cli browser.js -output mithril.js", + "build-min": "node bundler/cli browser.js -output mithril.min.js -minify", "lintdocs": "node docs/lint", "gendocs": "node docs/generate", "lint": "eslint . || true", From 353bbe7fffe6e86b16a0c8392f9e9930e98e52bf Mon Sep 17 00:00:00 2001 From: Griffin Date: Wed, 12 Jul 2017 23:38:36 -0400 Subject: [PATCH 013/301] docs: Clarifying babel/webpack docs (#1845) --- docs/jsx.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/jsx.md b/docs/jsx.md index 0b8cd7f9..1c1b92ef 100644 --- a/docs/jsx.md +++ b/docs/jsx.md @@ -98,7 +98,7 @@ npm install babel-core babel-loader babel-preset-es2015 babel-plugin-transform-r Create a `.babelrc` file: -``` +```json { "presets": ["es2015"], "plugins": [ @@ -130,6 +130,8 @@ module.exports = { } ``` +For those familiar with Webpack already, please note that adding the Babel options to the `babel-loader` section of your `webpack.config.js` will throw an error, so you need to include them in the separate `.babelrc` file. + This configuration assumes the source code file for the application entry point is in `src/index.js`, and this will output the bundle to `bin/app.js`. To run the bundler, setup an npm script. Open `package.json` and add this entry under `"scripts"`: From 6502cc366db238f93d139f1cd80ea9dfcbf13f0f Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 20:54:19 -0700 Subject: [PATCH 014/301] docs: update ospec so version/license are automatic --- ospec/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 5a5baf1b..68a39dbe 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -1,12 +1,10 @@ -# ospec +ospec [![NPM Version](https://img.shields.io/npm/v/ospec.svg)](https://www.npmjs.com/package/ospec) [![NPM License](https://img.shields.io/npm/l/ospec.svg)](https://www.npmjs.com/package/ospec) +===== [About](#about) | [Usage](#usage) | [API](#api) | [Goals](#goals) Noiseless testing framework -Version: 1.2.3 -License: MIT - ## About - ~180 LOC From 7abe16cdc950f9bdafade64140061c41ffa4813f Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 20:54:44 -0700 Subject: [PATCH 015/301] chore: add license files to sub-packages --- ospec/LICENSE | 21 +++++++++++++++++++++ stream/LICENSE | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 ospec/LICENSE create mode 100644 stream/LICENSE diff --git a/ospec/LICENSE b/ospec/LICENSE new file mode 100644 index 00000000..2aae0f1e --- /dev/null +++ b/ospec/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Leo Horie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/stream/LICENSE b/stream/LICENSE new file mode 100644 index 00000000..2aae0f1e --- /dev/null +++ b/stream/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Leo Horie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 8bc343459cc52dd2ef2a2e8f8c85329b3723bd0a Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 20:56:11 -0700 Subject: [PATCH 016/301] chore: ospec@1.3.0 --- ospec/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/package.json b/ospec/package.json index 388720f3..7cfa4595 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "1.2.3", + "version": "1.3.0", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From 14726f7dd494dccc66ce5f31d17fe31c5f891c44 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 20:58:38 -0700 Subject: [PATCH 017/301] docs: add basic readme for mithril-stream --- stream/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 stream/README.md diff --git a/stream/README.md b/stream/README.md new file mode 100644 index 00000000..d4cb92c1 --- /dev/null +++ b/stream/README.md @@ -0,0 +1,6 @@ +mithril-stream [![NPM Version](https://img.shields.io/npm/v/mithril-stream.svg)](https://www.npmjs.com/package/mithril-stream) [![NPM License](https://img.shields.io/npm/l/mithril-stream.svg)](https://www.npmjs.com/package/mithril-stream) +============== + +Mithril's `m.stream` as a standalone module. + +See [mithril.js.org/stream.html](https://mithril.js.org/stream.html) for docs/usage. From c7d72ba2de7193ee784f802653cba564867a4b1a Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 12 Jul 2017 21:00:43 -0700 Subject: [PATCH 018/301] chore: mithril-stream@1.1.0 --- stream/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stream/package.json b/stream/package.json index 4eb14a07..f5f4f86c 100644 --- a/stream/package.json +++ b/stream/package.json @@ -1,6 +1,6 @@ { "name": "mithril-stream", - "version": "1.0.0", + "version": "1.1.0", "description": "Streaming data, mithril-style", "main": "stream.js", "directories": { From 1a1ae8e8430b6f4056cdaf7c841d3bb7d6d3aa43 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 17 Jul 2017 21:19:10 +0000 Subject: [PATCH 019/301] Bundled output for commit 8ab31790abdb391a2daba5a721b786302904a172 [skip ci] --- README.md | 2 +- mithril.js | 42 +++++++++++++----------- mithril.min.js | 88 +++++++++++++++++++++++++------------------------- 3 files changed, 68 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index c5df4082..4638fa31 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.18 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.22 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 3b0d05be..9a3c9cba 100644 --- a/mithril.js +++ b/mithril.js @@ -963,7 +963,7 @@ var coreRenderer = function($window) { var hooks = [] var active = $doc.activeElement var namespace = dom.namespaceURI - // First time0 rendering into a node clears it out + // First time rendering0 into a node clears it out if (dom.vnodes == null) dom.textContent = "" if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) @@ -975,44 +975,44 @@ var coreRenderer = function($window) { } function throttle(callback) { //60fps translates to 16.6ms, round it down since setTimeout requires int - var time = 16 + var delay = 16 var last = 0, pending = null var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout return function() { - var now = Date.now() - if (last === 0 || now - last >= time) { - last = now - callback() - } - else if (pending === null) { + var elapsed = Date.now() - last + if (pending === null) { pending = timeout(function() { pending = null callback() last = Date.now() - }, time - (now - last)) + }, delay - elapsed) } } } -var _11 = function($window) { +var _11 = function($window, throttleMock) { var renderService = coreRenderer($window) renderService.setEventCallback(function(e) { if (e.redraw === false) e.redraw = undefined else redraw() }) var callbacks = [] + var rendering = false function subscribe(key1, callback) { unsubscribe(key1) - callbacks.push(key1, throttle(callback)) + callbacks.push(key1, callback) } function unsubscribe(key1) { var index = callbacks.indexOf(key1) if (index > -1) callbacks.splice(index, 2) } - function redraw() { - for (var i = 1; i < callbacks.length; i += 2) { - callbacks[i]() - } + function sync() { + if (rendering) throw new Error("Nested m.redraw.sync() call") + rendering = true + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {/*noop*/} + rendering = false } + var redraw = (throttleMock || throttle)(sync) + redraw.sync = sync return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render} } var redrawService = _11(window) @@ -1031,7 +1031,7 @@ var _16 = function(redrawService0) { redrawService0.render(root, Vnode(component)) } redrawService0.subscribe(root, run0) - redrawService0.redraw() + run0() } } m.mount = _16(redrawService) @@ -1168,9 +1168,14 @@ var _20 = function($window, redrawService0) { var render1, component, attrs3, currentPath, lastUpdate var route = function(root, defaultRoute, routes) { if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined") - var run1 = function() { + function run1() { if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3))) } + var redraw2 = function() { + run1() + redraw2 = redrawService0.redraw + } + redrawService0.subscribe(root, run1) var bail = function(path) { if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true}) else throw new Error("Could not resolve default route " + defaultRoute) @@ -1181,7 +1186,7 @@ var _20 = function($window, redrawService0) { component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div" attrs3 = params, currentPath = path, lastUpdate = null render1 = (routeResolver.render || identity).bind(routeResolver) - run1() + redraw2() } if (payload.view || typeof payload === "function") update({}, payload) else { @@ -1193,7 +1198,6 @@ var _20 = function($window, redrawService0) { else update(payload, "div") } }, bail) - redrawService0.subscribe(root, run1) } route.set = function(path, data, options) { if (lastUpdate != null) { diff --git a/mithril.min.js b/mithril.min.js index d957be37..18a2e091 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,44 +1,44 @@ -(function(){function z(b,d,e,f,g,l){return{tag:b,key:d,attrs:e,children:f,text:g,dom:l,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function A(b){var d,e=arguments[1],f=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&!(d=M[b])){var g="div";for(var l=[],k={};d=P.exec(b);){var r=d[1],p=d[2];""===r&&""!==p?g=p:"#"===r?k.id=p:"."===r?l.push(p): -"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?l.push(r):k[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(x){throw Error(a); -}}function r(a){return a.responseText}function p(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(p(a.type, -b));else{var h=Error(m.responseText),c;for(c in b)h[c]=b[c];e(h)}}catch(q){e(q)}};f&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?x:n(x)},jsonp:function(a,k){var n=e();a=f(a,k);var r=new d(function(d,e){var f=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[f]=function(e){k.parentNode.removeChild(k);d(p(a.type,e));delete b[f]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[f]};null== -a.data&&(a.data={});a.url=g(a.url,a.data);a.data[a.callbackKey||"callback"]=f;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?r:n(r)},setCompletionCallback:function(a){n=a}}}(window,y),O=function(b){function d(h,c,q,a,b,d,g){for(;q=n&&E>=B;){var t=c[n];u=q[B];if(t!==u||b)if(null==t)n++;else if(null==u)B++;else if(t.key===u.key){var w=null!=x&&n>=c.length-x.length||null==x&&b;n++;B++;k(h,t,u,g,p(c,n,f),w,l);b&&t.tag===u.tag&&m(h,r(t),f)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)w=null!=x&&v>=c.length-x.length||null==x&&b, -k(h,t,u,g,p(c,v+1,f),w,l),(b||B=n&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)w=null!=x&&v>=c.length-x.length||null==x&&b,k(h,t,u,g,p(c,v+1,f),w,l),b&&t.tag===u.tag&&m(h,r(t),f),null!=t.dom&&(f=t.dom),v--;else{if(!H){H=c;w=v;t={};var C;for(C=0;Ca.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} +function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText),c; +for(c in b)k[c]=b[c];e(k)}}catch(q){e(q)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:n(y)},jsonp:function(a,h){var r=e();a=l(a,h);var n=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data); +a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?n:r(n)},setCompletionCallback:function(a){n=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=n&&E>=B;){var t=c[n];u=q[B];if(t!==u||b)if(null==t)n++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&n>=c.length-y.length||null==y&&b;n++;B++;h(k,t,u,l,f(c,n,g),x,p);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),(b||B=n&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;C Date: Tue, 18 Jul 2017 22:53:17 -0700 Subject: [PATCH 020/301] refactor: XHR errors have response/code fields So that there's no chance of data loss and it's trivial to get the response code (because it's hella useful) Fixes #1866 Fixes #1876 --- request/request.js | 3 ++- request/tests/test-request.js | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/request/request.js b/request/request.js index 76e218c9..ac5f3391 100644 --- a/request/request.js +++ b/request/request.js @@ -93,7 +93,8 @@ module.exports = function($window, Promise) { } else { var error = new Error(xhr.responseText) - for (var key in response) error[key] = response[key] + error.code = xhr.status + error.response = response reject(error) } } diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 7f965498..94e7e172 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -458,9 +458,10 @@ o.spec("xhr", function() { xhr({method: "GET", url: "/item"}).catch(function(e) { o(e instanceof Error).equals(true) o(e.message).equals(JSON.stringify({error: "error"})) + o(e.code).equals(500) }).then(done) }) - o("extends Error with JSON response", function(done) { + o("adds response to Error", function(done) { mock.$defineRoutes({ "GET /item": function() { return {status: 500, responseText: JSON.stringify({message: "error", stack: "error on line 1"})} @@ -468,8 +469,8 @@ o.spec("xhr", function() { }) xhr({method: "GET", url: "/item"}).catch(function(e) { o(e instanceof Error).equals(true) - o(e.message).equals("error") - o(e.stack).equals("error on line 1") + o(e.response.message).equals("error") + o(e.response.stack).equals("error on line 1") }).then(done) }) o("rejects on non-JSON server error", function(done) { From 5956314e3655a3c85f8425bffc2bd76c1c541a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 19 Jul 2017 09:16:22 +0200 Subject: [PATCH 021/301] Docs for async redraws and assorted changes (see #1592) (#1901) --- docs/change-log.md | 22 ++++++++++++++++++++++ docs/mount.md | 10 ++++++---- docs/redraw.md | 26 ++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 1a1ebbe2..cb2fabf0 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -10,12 +10,31 @@ --- +### v2.0.0 (WIP) + +#### Breaking changes + +- API: `m.redraw()` is always asynchronous ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +- API: `m.mount()` will only render its own root when called, it will not trigger a `redraw()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) + +#### News + +- API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) + +#### Bug fixes + +- API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) + +--- + ### v1.1.3 #### Bug fixes: - move out npm dependencies added by mistake +--- + ### v1.1.2 #### Bug fixes: @@ -42,6 +61,7 @@ Our thanks to [@0joshuaolson1](https://github.com/0joshuaolson1), [@ACXgit](http - Addition of a performance regression test suite ([#1789](https://github.com/MithrilJS/mithril.js/issues/1789)) +--- ### v1.1.1 @@ -51,6 +71,8 @@ Our thanks to [@0joshuaolson1](https://github.com/0joshuaolson1), [@ACXgit](http - hyperscript: restore `attrs.class` handling to what it was in v1.0.1 - [#1764](https://github.com/MithrilJS/mithril.js/issues/1764) / [#1769](https://github.com/MithrilJS/mithril.js/pull/1769) - documentation improvements ([@JAForbes](https://github.com/JAForbes), [@smuemd](https://github.com/smuemd), [@hankeypancake](https://github.com/hankeypancake)) +--- + ### v1.1.0 #### News diff --git a/docs/mount.md b/docs/mount.md index 9e0957a6..19a0110a 100644 --- a/docs/mount.md +++ b/docs/mount.md @@ -35,12 +35,12 @@ m.mount(element, {view: function () {return m(Component, attrs)}}) ### Signature -`m.mount(element, component)` +`m.mount(element, Component)` Argument | Type | Required | Description ----------- | -------------------- | -------- | --- `element` | `Element` | Yes | A DOM element that will be the parent node to the subtree -`component` | `Component|null` | Yes | The [component](components.md) to be rendered. `null` unmounts the tree and cleans up internal state. +`Component` | `Component|null` | Yes | The [component](components.md) to be rendered. `null` unmounts the tree and cleans up internal state. **returns** | | | Returns nothing [How to read signatures](signatures.md) @@ -49,7 +49,9 @@ Argument | Type | Required | Description ### How it works -Similar to [`m.render()`](render.md), the `m.mount()` method takes a component and mounts a corresponding DOM tree into `element`. If `element` already has a DOM tree mounted via a previous `m.mount()` call, the component is diffed against the previous vnode tree and the existing DOM tree is modified only where needed to reflect the changes. Unchanged DOM nodes are not touched at all. +`m.mount(element, Component)`, when called renders the component into the element and subscribe the `(element, Component)` pair to the redraw subsystem. That tree will be re-rendered when [manual](redraw.md) or [automatic](autoredraw.md) redraws are triggered. + +On redraw, the new vDOM tree is compared (or "diffed") with the old one, and the existing DOM tree is modified only where needed to reflect the changes. Unchanged DOM nodes are not touched at all. #### Replace a component @@ -73,7 +75,7 @@ In contrast, traversing a javascript data structure has a much more predictable ### Differences from m.render -A component rendered via `m.mount` automatically auto-redraws in response to view events, `m.redraw()` calls or `m.request()` calls. Vnodes rendered via `m.render()` do not. +A component rendered via `m.mount` [automatically redraws](autoredraw.md) in response to view events, `m.redraw()` calls or `m.request()` calls. Vnodes rendered via `m.render()` do not. `m.mount()` is suitable for application developers integrating Mithril widgets into existing codebases where routing is handled by another library or framework, while still enjoying Mithril's auto-redrawing facilities. diff --git a/docs/redraw.md b/docs/redraw.md index 7bb25810..0d079592 100644 --- a/docs/redraw.md +++ b/docs/redraw.md @@ -2,6 +2,8 @@ - [Description](#description) - [Signature](#signature) + - [Static members](#static-members) + -[m.redraw.sync()](#mredrawsync) - [How it works](#how-it-works) --- @@ -10,12 +12,10 @@ Updates the DOM after a change in the application data layer. -You DON'T need to call it if data is modified within the execution context of an event handler defined in a Mithril view, or after request completion when using `m.request`/`m.jsonp`. +You DON'T need to call it if data is modified within the execution context of an event handler defined in a Mithril view, or after request completion when using `m.request`/`m.jsonp`. The [autoredraw](autoredraw.md) system, which is built on top of `m.redraw()` will take care of it. You DO need to call it in `setTimeout`/`setInterval`/`requestAnimationFrame` callbacks, or callbacks from 3rd party libraries. -`m.redraw` always triggers an asynchronous redraws. - --- ### Signature @@ -26,6 +26,16 @@ Argument | Type | Required | Description ----------- | -------------------- | -------- | --- **returns** | | | Returns nothing +#### Static members + +##### m.redraw.sync + +`m.redraw.sync()` + +Argument | Type | Required | Description +----------- | -------------------- | -------- | --- +**returns** | | | Returns nothing + --- ### How it works @@ -34,4 +44,12 @@ When callbacks outside of Mithril run, you need to notify Mithril's rendering en To trigger a redraw, call `m.redraw()`. Note that `m.redraw` only works if you used `m.mount` or `m.route`. If you rendered via `m.render`, you should use `m.render` to redraw. -You should not call m.redraw from a [lifecycle method](lifecycle-methods.md). Doing so will result in undefined behavior. +`m.redraw()` always triggers an asynchronous redraws, whereas `m.redraw.sync()` triggers a synchronous one. `m.redraw()` is tied to `window.requestAnimationFrame()` (we provide a fallback for IE9). It will thus typically fire at most 60 times per second. It may fire faster if your monitor has a higher refresh rate. + +`m.redraw.sync()` is mostly intended to make videos play work in iOS. That only works in response to user-triggered events. It comes with several caveat: + +- You should not call `m.redraw.sync()` from a [lifecycle method](lifecycle-methods.md) or the `view()` method of a component. Doing so will result in undefined behavior (it throws an error when possible). +- `m.redraw.sync()` called from an event handler can cause the DOM to be modified while an event is bubbling. Depending on the structure of the old and new DOM trees, the event can finish the bubbling phase in the new tree and trigger unwanted handlers. +- It is not throttled. One call to `m.redraw.sync()` causes immediately one `m.render()` call per root registered with [`m.mount()`](mount.md) or [`m.route()`](route.md). + +`m.redraw()` doesn't have any of those issues, you can call it from wherever you like. \ No newline at end of file From 79d7d32139c928b3c89fb60c539dfa948974d811 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Wed, 19 Jul 2017 16:01:00 +0000 Subject: [PATCH 022/301] Bundled output for commit a7820734a7707a7b60bc1299fa1667505e71e686 [skip ci] --- mithril.js | 3 ++- mithril.min.js | 70 +++++++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/mithril.js b/mithril.js index 9a3c9cba..6fbf4ff8 100644 --- a/mithril.js +++ b/mithril.js @@ -296,7 +296,8 @@ var _8 = function($window, Promise) { } else { var error = new Error(xhr.responseText) - for (var key in response) error[key] = response[key] + error.code = xhr.status + error.response = response reject(error) } } diff --git a/mithril.min.js b/mithril.min.js index 18a2e091..c9fd686f 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,44 +1,44 @@ -(function(){function z(b,d,e,l,p,g){return{tag:b,key:d,attrs:e,children:l,text:p,dom:g,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function A(b){var d,e=arguments[1],l=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&!(d=M[b])){var p="div";for(var g=[],h={};d=Q.exec(b);){var r=d[1],f=d[2];""===r&&""!==f?p=f:"#"===r?h.id=f:"."===r?g.push(f): -"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?g.push(r):h[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} -function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText),c; -for(c in b)k[c]=b[c];e(k)}}catch(q){e(q)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:n(y)},jsonp:function(a,h){var r=e();a=l(a,h);var n=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data); -a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?n:r(n)},setCompletionCallback:function(a){n=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=n&&E>=B;){var t=c[n];u=q[B];if(t!==u||b)if(null==t)n++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&n>=c.length-y.length||null==y&&b;n++;B++;h(k,t,u,l,f(c,n,g),x,p);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),(b||B=n&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;Ca.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} +function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText);k.code= +m.status;k.response=b;e(k)}}catch(c){e(c)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:p(y)},jsonp:function(a,h){var r=e();a=l(a,h);var p=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=n(a.url, +a.data);a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&p>=c.length-y.length||null==y&&b;p++;B++;h(k,t,u,l,f(c,p,g),x,n);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;C Date: Wed, 19 Jul 2017 09:04:47 -0700 Subject: [PATCH 023/301] chore: Remove bundle bin (#1902) --- package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 69db5505..9ba626ab 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,6 @@ "marked": "^0.3.6" }, "bin": { - "ospec": "./ospec/bin/ospec", - "bundle": "./bundler/bin/bundle" - }, - "dependencies": {} + "ospec": "./ospec/bin/ospec" + } } From 49e52c6c00871c6d2095d1db6562973de5964a4b Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 19 Jul 2017 11:17:51 -0700 Subject: [PATCH 024/301] chore: Issue/PR templates & CODEOWNERS file (#1906) --- .github/CODEOWNERS | 11 +++++++++++ .github/ISSUE_TEMPLATE.md | 32 ++++++++++++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..30c39524 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,11 @@ +# Leo owns everything, for better or worse +* @lhorie + +.travis.yml @tivac +package.json @tivac +.npmignore @tivac +.eslintrc.js @tivac +.eslintignore @tivac +README.md @tivac +docs/ @tivac +performance/ @tivac diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..be4f8168 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,32 @@ + + +## Expected Behavior + + + +## Current Behavior + + + +## Possible Solution + + + +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + +## Your Environment + +* Version used: +* Browser Name and version: +* Operating System and version (desktop or mobile): +* Link to your project: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9218a937 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ + + +## Description + + +## Motivation and Context + + + +## How Has This Been Tested? + + + + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. From a7849a67cac5a41896d2c862bda74af532086917 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 19 Jul 2017 21:14:13 -0700 Subject: [PATCH 025/301] chore: Implement danger for PRs (#1905) --- .babelrc | 3 + dangerfile.js | 56 + package-lock.json | 2616 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 7 +- 4 files changed, 2615 insertions(+), 67 deletions(-) create mode 100644 .babelrc create mode 100644 dangerfile.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..deef3397 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +// This is solely to avoid https://github.com/danger/danger-js/issues/261 +// and should be fine to remove before much longer +{} diff --git a/dangerfile.js b/dangerfile.js new file mode 100644 index 00000000..0f027250 --- /dev/null +++ b/dangerfile.js @@ -0,0 +1,56 @@ +/* global danger warn fail */ +"use strict"; + +var fs = require("fs"), + path = require("path"), + + locater = require("locater"), + pinpoint = require("pinpoint"), + dedent = require("dedent"); + +// Various views of changed/added files +var jsfiles = danger.git.created_files + .concat(danger.git.modified_files) + .filter((file) => path.extname(file) === ".js"), + + changelog = danger.git.modified_files.find((file) => + file === "docs/change-log.md" + ), + + appfiles = jsfiles.filter((file) => + file.indexOf("tests/") === -1 + ); + +function link(file, anchor, text) { + var repo = danger.github.pr.head.repo.html_url, + ref = danger.github.pr.head.ref; + + return danger.utils.href(`${repo}/blob/${ref}/${file}${anchor || ""}`, file || text); +} + +// All PRs should be targeted against `next` +if(danger.github.pr.base.ref !== "next") { + warn("PRs should be based on `next`, rebase before submitting please"); +} + +// Any non-test JS changes should probably have a change-log entry +if(appfiles.length && !changelog) { + warn(`Please include a ${link("docs/change-log.md", "changelog")} entry.`) +} + +// Call out if `o.only(...)` was left in +jsfiles + .filter((file) => file.indexOf("tests/") > -1) + .forEach((file) => { + var code = fs.readFileSync(file, "utf8"), + locs = locater.find("o.only", code); + + locs.forEach((loc) => + fail(dedent(` + ${link(file, `#L${loc.line}`)} is preventing tests from running. +
+				${pinpoint(code, {line: loc.line, column : loc.cursor})}
+				
+ `)) + ) + }); diff --git a/package-lock.json b/package-lock.json index 088ddc10..de36d7a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,7 +2,14 @@ "name": "mithril", "version": "1.1.3", "lockfileVersion": 1, + "requires": true, "dependencies": { + "abab": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", + "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", + "dev": true + }, "abbrev": { "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", @@ -13,10 +20,22 @@ "integrity": "sha1-xGDfCEkUY/AozLguqzcwvwEIez0=", "dev": true }, + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, + "requires": { + "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz" + } + }, "acorn-jsx": { "version": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, + "requires": { + "acorn": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" + }, "dependencies": { "acorn": { "version": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", @@ -25,10 +44,24 @@ } } }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + } + }, "ajv": { "version": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true + "dev": true, + "requires": { + "co": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz" + } }, "ajv-keywords": { "version": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", @@ -38,7 +71,12 @@ "align-text": { "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true + "dev": true, + "requires": { + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", + "longest": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + } }, "amdefine": { "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -60,34 +98,301 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "anymatch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", + "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", + "dev": true, + "requires": { + "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "micromatch": "2.3.11" + } + }, "argparse": { "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, "array-union": { "version": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true + "dev": true, + "requires": { + "array-uniq": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + } }, "array-uniq": { "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, "arrify": { "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, "async": { "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, "babel-code-frame": { "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz" + } + }, + "babel-core": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", + "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", + "dev": true, + "requires": { + "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "babel-generator": "6.25.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "convert-source-map": "1.5.0", + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "json5": "0.5.1", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + } + }, + "babel-generator": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", + "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "trim-right": "1.0.1" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-jest": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", + "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-plugin-istanbul": "4.1.4", + "babel-preset-jest": "20.0.3" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-istanbul": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", + "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.7.4", + "test-exclude": "4.1.1" + } + }, + "babel-plugin-jest-hoist": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz", + "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=", + "dev": true + }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "babel-preset-jest": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", + "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "20.0.3" + } + }, + "babel-register": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", + "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "home-or-tmp": "2.0.0", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "source-map-support": "0.4.15" + } + }, + "babel-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", + "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "dev": true, + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "babel-template": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", + "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" + } + }, + "babel-traverse": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", + "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "dev": true, + "requires": { + "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "globals": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "invariant": "2.2.2", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" + } + }, + "babel-types": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", + "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.17.4", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", + "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", "dev": true }, "balanced-match": { @@ -95,25 +400,90 @@ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", "dev": true }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, "benchmark": { "version": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", - "dev": true + "dev": true, + "requires": { + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "platform": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } }, "brace-expansion": { "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", - "dev": true + "dev": true, + "requires": { + "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "dev": true, + "requires": { + "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + } + }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "0.4.0" + } }, "buffer-shims": { "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", "dev": true }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, "caller-path": { "version": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true + "dev": true, + "requires": { + "callsites": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz" + } }, "callsites": { "version": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", @@ -123,19 +493,34 @@ "camelcase": { "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, "center-align": { "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "optional": true + "requires": { + "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "lazy-cache": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + } }, "chalk": { "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true + "dev": true, + "requires": { + "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + } }, "circular-json": { "version": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", @@ -145,7 +530,10 @@ "cli-cursor": { "version": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true + "dev": true, + "requires": { + "restore-cursor": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz" + } }, "cli-width": { "version": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", @@ -156,13 +544,16 @@ "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, - "optional": true, + "requires": { + "center-align": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "right-align": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + }, "dependencies": { "wordwrap": { "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "optional": true + "dev": true } } }, @@ -176,6 +567,21 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, "concat-map": { "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", @@ -184,6 +590,29 @@ "concat-stream": { "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", + "typedarray": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + } + }, + "content-type-parser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", + "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", "dev": true }, "core-util-is": { @@ -191,21 +620,100 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, "d": { "version": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true + "dev": true, + "requires": { + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + } + }, + "danger": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/danger/-/danger-1.0.0.tgz", + "integrity": "sha512-q3tpcDOS93gETx9bLZmPRqw4kke/eX7chJvX7KwDymFHM1DvQWPLye91yVb8q15IoQg9uGHb1rP+UjXWJ3RBfg==", + "dev": true, + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "commander": "2.11.0", + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "dtslint": "0.1.2", + "github": "9.2.0", + "jest-config": "20.0.4", + "jest-environment-node": "20.0.3", + "jest-runtime": "20.0.4", + "jsome": "2.3.26", + "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "lodash.find": "4.6.0", + "lodash.includes": "4.3.0", + "lodash.isobject": "2.4.1", + "lodash.keys": "4.2.0", + "node-fetch": "1.7.1", + "parse-diff": "0.4.0", + "rfc6902": "1.3.0", + "voca": "1.3.0" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } }, "debug": { "version": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", "integrity": "sha1-qfpvvpykPPHnn3O3XAGJy7fW21o=", - "dev": true + "dev": true, + "requires": { + "ms": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz" + } }, "decamelize": { "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "optional": true + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true }, "deep-is": { "version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -215,42 +723,160 @@ "del": { "version": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "is-path-cwd": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "is-path-in-cwd": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "diff": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", + "integrity": "sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg==", "dev": true }, "doctrine": { "version": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true + "dev": true, + "requires": { + "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + } + }, + "dtslint": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-0.1.2.tgz", + "integrity": "sha1-V0vrcmM/RSaJYF3hgG2mKBRSrC4=", + "dev": true, + "optional": true, + "requires": { + "fs-promise": "2.0.3", + "parsimmon": "1.6.2", + "strip-json-comments": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "tsutils": "1.9.1" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + } + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "requires": { + "prr": "0.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } }, "es5-ext": { "version": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", "integrity": "sha1-wzClk0we4hKEp8CBqG5f2TfJHqY=", - "dev": true + "dev": true, + "requires": { + "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + } }, "es6-iterator": { "version": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", + "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + } }, "es6-map": { "version": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", + "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "es6-set": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "event-emitter": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + } }, "es6-set": { "version": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", + "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "event-emitter": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + } }, "es6-symbol": { "version": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + } }, "es6-weak-map": { "version": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", + "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + } }, "escape-string-regexp": { "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -261,6 +887,13 @@ "version": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, + "requires": { + "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "optionator": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + }, "dependencies": { "esprima": { "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -277,17 +910,64 @@ "escope": { "version": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true + "dev": true, + "requires": { + "es6-map": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "es6-weak-map": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "esrecurse": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", + "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" + } }, "eslint": { "version": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", - "dev": true + "dev": true, + "requires": { + "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "doctrine": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "escope": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "espree": "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz", + "esquery": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "file-entry-cache": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "globals": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "ignore": "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz", + "imurmurhash": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "inquirer": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "is-my-json-valid": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "is-resolvable": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", + "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "levn": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "natural-compare": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "optionator": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "path-is-inside": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "pluralize": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "progress": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "require-uncached": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "shelljs": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", + "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "strip-json-comments": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "table": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "text-table": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "user-home": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz" + } }, "espree": { "version": "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz", "integrity": "sha1-ONve2+3JW4lhofvwRzSo9qnIxZI=", - "dev": true + "dev": true, + "requires": { + "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", + "acorn-jsx": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz" + } }, "esprima": { "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", @@ -297,12 +977,19 @@ "esquery": { "version": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true + "dev": true, + "requires": { + "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" + } }, "esrecurse": { "version": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", "integrity": "sha1-RxO2U2rffyrE8yfVWed1a/9kgiA=", "dev": true, + "requires": { + "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + }, "dependencies": { "estraverse": { "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", @@ -324,33 +1011,202 @@ "event-emitter": { "version": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true + "dev": true, + "requires": { + "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + } + }, + "exec-sh": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", + "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", + "dev": true, + "requires": { + "merge": "1.2.0" + } }, "exit-hook": { "version": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "dev": true + }, "fast-levenshtein": { "version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "2.0.0" + } + }, "figures": { "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true + "dev": true, + "requires": { + "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + } }, "file-entry-cache": { "version": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, "flat-cache": { "version": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true, + "requires": { + "circular-json": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", + "del": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "write": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" + } + }, + "follow-redirects": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", + "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", + "dev": true, + "requires": { + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "stream-consume": "0.1.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs-extra": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "jsonfile": "2.4.0" + } + }, + "fs-promise": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fs-promise/-/fs-promise-2.0.3.tgz", + "integrity": "sha1-9k5PhUvPaJqovdy6JokW2z20aFQ=", + "dev": true, + "optional": true, + "requires": { + "any-promise": "1.3.0", + "fs-extra": "2.1.2", + "mz": "2.6.0", + "thenify-all": "1.6.0" + } + }, "fs.realpath": { "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", @@ -364,12 +1220,71 @@ "generate-object-property": { "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true + "dev": true, + "requires": { + "is-property": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "github": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/github/-/github-9.2.0.tgz", + "integrity": "sha1-iohtxA3WNjZwfcr5nfPfJsWfFvw=", + "dev": true, + "requires": { + "follow-redirects": "0.0.7", + "https-proxy-agent": "1.0.0", + "mime": "1.3.6", + "netrc": "0.1.4" + } }, "glob": { "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true + "dev": true, + "requires": { + "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } }, "globals": { "version": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", @@ -379,7 +1294,15 @@ "globby": { "version": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true + "dev": true, + "requires": { + "array-union": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + } }, "graceful-fs": { "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -390,17 +1313,116 @@ "version": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz", "integrity": "sha1-6XMlrrjqC54SucTdc8TDEq0O3lk=", "dev": true, + "requires": { + "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "optimist": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz" + }, "dependencies": { "source-map": { "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true + "dev": true, + "requires": { + "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" + } } } }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "har-schema": "1.0.5" + } + }, "has-ansi": { "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", + "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.1" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "extend": "3.0.1" + } + }, + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", "dev": true }, "ignore": { @@ -416,7 +1438,11 @@ "inflight": { "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true + "dev": true, + "requires": { + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } }, "inherits": { "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -426,27 +1452,129 @@ "inquirer": { "version": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true + "dev": true, + "requires": { + "ansi-escapes": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "cli-cursor": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "cli-width": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "figures": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "readline2": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "run-async": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "rx-lite": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "string-width": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } }, "interpret": { "version": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", "dev": true }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-buffer": { "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", "dev": true }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + } + }, "is-fullwidth-code-point": { "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true + "dev": true, + "requires": { + "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } }, "is-my-json-valid": { "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", - "dev": true + "dev": true, + "requires": { + "generate-function": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "generate-object-property": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + } }, "is-path-cwd": { "version": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -456,11 +1584,29 @@ "is-path-in-cwd": { "version": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true + "dev": true, + "requires": { + "is-path-inside": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz" + } }, "is-path-inside": { "version": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, "is-property": { @@ -471,6 +1617,21 @@ "is-resolvable": { "version": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "isarray": { @@ -483,10 +1644,41 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, "istanbul": { "version": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, + "requires": { + "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "escodegen": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "glob": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "handlebars": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz", + "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", + "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "nopt": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + }, "dependencies": { "esprima": { "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -496,7 +1688,14 @@ "glob": { "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true + "dev": true, + "requires": { + "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + } }, "resolve": { "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -506,10 +1705,258 @@ "supports-color": { "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + } + } + } + } + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.4.tgz", + "integrity": "sha1-6f2SDkdn89Ge3HZeLWs/XMvQ7qg=", + "dev": true, + "requires": { + "babel-generator": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true } } }, + "jest-config": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", + "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "jest-environment-jsdom": "20.0.3", + "jest-environment-node": "20.0.3", + "jest-jasmine2": "20.0.4", + "jest-matcher-utils": "20.0.3", + "jest-regex-util": "20.0.3", + "jest-resolve": "20.0.4", + "jest-validate": "20.0.3", + "pretty-format": "20.0.3" + } + }, + "jest-diff": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", + "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "diff": "3.3.0", + "jest-matcher-utils": "20.0.3", + "pretty-format": "20.0.3" + } + }, + "jest-docblock": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz", + "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI=", + "dev": true + }, + "jest-environment-jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", + "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", + "dev": true, + "requires": { + "jest-mock": "20.0.3", + "jest-util": "20.0.3", + "jsdom": "9.12.0" + } + }, + "jest-environment-node": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", + "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", + "dev": true, + "requires": { + "jest-mock": "20.0.3", + "jest-util": "20.0.3" + } + }, + "jest-haste-map": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.4.tgz", + "integrity": "sha1-ZT61XIic48Ah97lGk/IKQVm63wM=", + "dev": true, + "requires": { + "fb-watchman": "2.0.0", + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "jest-docblock": "20.0.3", + "micromatch": "2.3.11", + "sane": "1.6.0", + "worker-farm": "1.4.1" + } + }, + "jest-jasmine2": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", + "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-matchers": "20.0.3", + "jest-message-util": "20.0.3", + "jest-snapshot": "20.0.3", + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "p-map": "1.1.1" + } + }, + "jest-matcher-utils": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", + "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "pretty-format": "20.0.3" + } + }, + "jest-matchers": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", + "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", + "dev": true, + "requires": { + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-message-util": "20.0.3", + "jest-regex-util": "20.0.3" + } + }, + "jest-message-util": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", + "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "micromatch": "2.3.11", + "slash": "1.0.0" + } + }, + "jest-mock": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz", + "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk=", + "dev": true + }, + "jest-regex-util": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz", + "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I=", + "dev": true + }, + "jest-resolve": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", + "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "is-builtin-module": "1.0.0", + "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + } + }, + "jest-runtime": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", + "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-jest": "20.0.3", + "babel-plugin-istanbul": "4.1.4", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "convert-source-map": "1.5.0", + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "jest-config": "20.0.4", + "jest-haste-map": "20.0.4", + "jest-regex-util": "20.0.3", + "jest-resolve": "20.0.4", + "jest-util": "20.0.3", + "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "micromatch": "2.3.11", + "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + } + }, + "jest-snapshot": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", + "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-util": "20.0.3", + "natural-compare": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "pretty-format": "20.0.3" + } + }, + "jest-util": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", + "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "jest-message-util": "20.0.3", + "jest-mock": "20.0.3", + "jest-validate": "20.0.3", + "leven": "2.1.0", + "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + } + }, + "jest-validate": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", + "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "jest-matcher-utils": "20.0.3", + "leven": "2.1.0", + "pretty-format": "20.0.3" + } + }, "js-tokens": { "version": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", @@ -518,13 +1965,99 @@ "js-yaml": { "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", "integrity": "sha1-M6BexIHIUMiHWSkWb+G+thxyh2Y=", + "dev": true, + "requires": { + "argparse": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "esprima": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsdom": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", + "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", + "dev": true, + "requires": { + "abab": "1.0.3", + "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", + "acorn-globals": "3.1.0", + "array-equal": "1.0.0", + "content-type-parser": "1.0.1", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "html-encoding-sniffer": "1.0.1", + "nwmatcher": "1.4.1", + "parse5": "1.5.1", + "request": "2.81.0", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.2", + "webidl-conversions": "4.0.1", + "whatwg-encoding": "1.0.1", + "whatwg-url": "4.8.0", + "xml-name-validator": "2.0.1" + } + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "jsome": { + "version": "2.3.26", + "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.3.26.tgz", + "integrity": "sha1-jLRDiSTSyd1SlMkK3wPzVBT7PKk=", + "dev": true, + "requires": { + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "json-stringify-safe": "5.0.1", + "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-stable-stringify": { "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz" + } + }, "jsonify": { "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", @@ -535,20 +2068,81 @@ "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", "dev": true }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, "kind-of": { "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", "integrity": "sha1-tYq+TVwEStM3JqjBUltIz4kb/wc=", - "dev": true + "dev": true, + "requires": { + "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz" + } }, "lazy-cache": { "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true, - "optional": true + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true }, "levn": { "version": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "parse-json": "2.2.0", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "locater": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/locater/-/locater-1.3.0.tgz", + "integrity": "sha1-3HPcjgytwGQOP0IXIHtCZ7BEFOs=", "dev": true }, "lodash": { @@ -556,20 +2150,122 @@ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, + "lodash._objecttypes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", + "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", + "dev": true + }, + "lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", + "dev": true + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", + "dev": true + }, + "lodash.isobject": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", + "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", + "dev": true, + "requires": { + "lodash._objecttypes": "2.4.1" + } + }, + "lodash.keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz", + "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=", + "dev": true + }, "longest": { "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.4" + } + }, "marked": { "version": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", "dev": true }, + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } + }, + "mime": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", + "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", + "dev": true + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, "minimatch": { "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", - "dev": true + "dev": true, + "requires": { + "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz" + } }, "minimist": { "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", @@ -579,7 +2275,10 @@ "mkdirp": { "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true + "dev": true, + "requires": { + "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + } }, "ms": { "version": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", @@ -591,30 +2290,113 @@ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, + "mz": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.6.0.tgz", + "integrity": "sha1-yLhSHZWN8KTydoAl22nHGe5O8c4=", + "dev": true, + "optional": true, + "requires": { + "any-promise": "1.3.0", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "thenify-all": "1.6.0" + } + }, "natural-compare": { "version": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "netrc": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz", + "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=", + "dev": true + }, + "node-fetch": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", + "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, "nopt": { "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true + "dev": true, + "requires": { + "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.0.3", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.0.2" + } }, "number-is-nan": { "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nwmatcher": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", + "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, "object-assign": { "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, "once": { "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true + "dev": true, + "requires": { + "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } }, "onetime": { "version": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", @@ -625,6 +2407,10 @@ "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, + "requires": { + "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + }, "dependencies": { "wordwrap": { "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -636,13 +2422,94 @@ "optionator": { "version": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true + "dev": true, + "requires": { + "deep-is": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "fast-levenshtein": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "levn": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + } }, "os-homedir": { "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "p-map": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", + "integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=", + "dev": true + }, + "parse-diff": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.4.0.tgz", + "integrity": "sha1-nONbzOj8C3xY9G1xETOU/AtJgt0=", + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "parse5": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "dev": true + }, + "parsimmon": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.6.2.tgz", + "integrity": "sha512-bJNB0ZQhHyM5KqO2Z5ttQAVn/PZ2pccxaOnMcZ0Su7HA1Iv4GQTfUmzSZ6N3jcsCn9F68PZcypAvF3nDRRL+3g==", + "dev": true, + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", @@ -658,6 +2525,23 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, "pify": { "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", @@ -671,6 +2555,15 @@ "pinkie-promise": { "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + } + }, + "pinpoint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pinpoint/-/pinpoint-1.1.0.tgz", + "integrity": "sha1-DPd1eml38b9/ajIge3CeN3OI6HQ=", "dev": true }, "platform": { @@ -688,6 +2581,28 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-format": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", + "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + } + }, + "private": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", + "dev": true + }, "process-nextick-args": { "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", @@ -698,19 +2613,145 @@ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + } + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + } + } + } + }, "readable-stream": { "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", - "dev": true + "dev": true, + "requires": { + "buffer-shims": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", + "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + } }, "readline2": { "version": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true + "dev": true, + "requires": { + "code-point-at": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "mute-stream": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" + } }, "rechoir": { "version": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + }, + "regex-cache": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } + }, + "remove-trailing-separator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "dev": true }, "repeat-string": { @@ -718,15 +2759,67 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, "require-uncached": { "version": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true + "dev": true, + "requires": { + "caller-path": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "resolve-from": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz" + } }, "resolve": { "version": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", - "dev": true + "dev": true, + "requires": { + "path-parse": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz" + } }, "resolve-from": { "version": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", @@ -736,32 +2829,114 @@ "restore-cursor": { "version": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "onetime": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" + } + }, + "rfc6902": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-1.3.0.tgz", + "integrity": "sha1-hbLGnELc8RYIJDe5gpqWJEa0xKU=", "dev": true }, "right-align": { "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "optional": true + "requires": { + "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" + } }, "rimraf": { "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true + "dev": true, + "requires": { + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz" + } }, "run-async": { "version": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true + "dev": true, + "requires": { + "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + } }, "rx-lite": { "version": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", "dev": true }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sane": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", + "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", + "dev": true, + "requires": { + "anymatch": "1.3.0", + "exec-sh": "0.2.0", + "fb-watchman": "1.9.2", + "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "walker": "1.0.7", + "watch": "0.10.0" + }, + "dependencies": { + "bser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", + "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", + "dev": true, + "requires": { + "node-int64": "0.4.0" + } + }, + "fb-watchman": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", + "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", + "dev": true, + "requires": { + "bser": "1.0.2" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + }, "shelljs": { "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", "integrity": "sha1-svXHfvlxSPS09uImguELuoZnz/E=", + "dev": true, + "requires": { + "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "interpret": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", + "rechoir": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, "slice-ansi": { @@ -769,31 +2944,119 @@ "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, "source-map": { "version": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, - "optional": true + "requires": { + "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" + } + }, + "source-map-support": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", + "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", + "dev": true, + "requires": { + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true }, "sprintf-js": { "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "stream-consume": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", + "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", + "dev": true + }, "string_decoder": { "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", "integrity": "sha1-8G9BFXtmTYYGn4S9vcmw2KsoFmc=", - "dev": true + "dev": true, + "requires": { + "buffer-shims": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz" + } }, "string-width": { "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true }, "strip-ansi": { "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + } }, "strip-bom": { "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -810,10 +3073,24 @@ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, "table": { "version": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, + "requires": { + "ajv": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "ajv-keywords": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "slice-ansi": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "string-width": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz" + }, "dependencies": { "is-fullwidth-code-point": { "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -823,29 +3100,123 @@ "string-width": { "version": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", - "dev": true + "dev": true, + "requires": { + "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + } } } }, + "test-exclude": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", + "dev": true, + "requires": { + "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "micromatch": "2.3.11", + "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + } + }, "text-table": { "version": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "dev": true, + "requires": { + "any-promise": "1.3.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": "3.3.0" + } + }, "through": { "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, "tryit": { "version": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", "dev": true }, + "tsutils": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-1.9.1.tgz", + "integrity": "sha1-ufmrROVa+WgYMdXyjQrur1x1DLA=", + "dev": true, + "optional": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, "type-check": { "version": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true + "dev": true, + "requires": { + "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + } }, "typedarray": { "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -857,6 +3228,11 @@ "integrity": "sha1-1Uk0d4qNoUkD+imjJvskwKtRoaA=", "dev": true, "optional": true, + "requires": { + "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + }, "dependencies": { "source-map": { "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", @@ -875,29 +3251,123 @@ "user-home": { "version": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true + "dev": true, + "requires": { + "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + } }, "util-deprecate": { "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "voca": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/voca/-/voca-1.3.0.tgz", + "integrity": "sha1-AnUayDm/DJLiz+iOScOTyU3VCsM=", + "dev": true + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.11" + } + }, + "watch": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", + "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", + "dev": true + }, + "webidl-conversions": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz", + "integrity": "sha1-gBWherg+fhsxFjhIas6B2mziBqA=", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", + "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + } + }, + "whatwg-url": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", + "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", + "dev": true, + "requires": { + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" + }, + "dependencies": { + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + } + } + }, "which": { "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true + "dev": true, + "requires": { + "isexe": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + } }, "window-size": { "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "optional": true + "dev": true }, "wordwrap": { "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "worker-farm": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", + "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", + "dev": true, + "requires": { + "errno": "0.1.4", + "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + } + }, "wrappy": { "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", @@ -906,6 +3376,15 @@ "write": { "version": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + } + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", "dev": true }, "xtend": { @@ -917,7 +3396,12 @@ "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "optional": true + "requires": { + "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "cliui": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + } } } } diff --git a/package.json b/package.json index 9ba626ab..39fe184b 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build": "npm run build-browser & npm run build-min", "build-browser": "node bundler/cli browser.js -output mithril.js", "build-min": "node bundler/cli browser.js -output mithril.min.js -minify", + "danger": "danger", "lintdocs": "node docs/lint", "gendocs": "node docs/generate", "lint": "eslint . || true", @@ -26,9 +27,13 @@ }, "devDependencies": { "benchmark": "^2.1.4", + "danger": "^1.0.0", + "dedent": "^0.7.0", "eslint": "^3.19.0", "istanbul": "^0.4.5", - "marked": "^0.3.6" + "locater": "^1.3.0", + "marked": "^0.3.6", + "pinpoint": "^1.1.0" }, "bin": { "ospec": "./ospec/bin/ospec" From bee11087af88336f5a7650b8c35fd37ef97be25c Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Fri, 21 Jul 2017 23:19:08 -0700 Subject: [PATCH 026/301] test: enable danger & tweak messaging --- .travis.yml | 5 +++-- dangerfile.js | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a0b3b3e2..d825fa73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,11 @@ install: - npm install - npm install --no-save @alrra/travis-scripts@^3.0.1 gh-pages@^0.12.0 -# Create bundles before running tests so they're always up-to-date -# Pass -save to build-min so it'll update the readme as well +# Run danger, build bundles (so they're always up to date) before_script: +- npx danger run - npm run build-browser +# Pass -save so it'll update the readme as well - npm run build-min -- -save # Run tests, lint, and then check for perf regressions diff --git a/dangerfile.js b/dangerfile.js index 0f027250..89ea4277 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -35,7 +35,9 @@ if(danger.github.pr.base.ref !== "next") { // Any non-test JS changes should probably have a change-log entry if(appfiles.length && !changelog) { - warn(`Please include a ${link("docs/change-log.md", "changelog")} entry.`) + warn(dedent(` + Please add an entry to ${link("docs/change-log.md")}. + `)) } // Call out if `o.only(...)` was left in @@ -47,7 +49,7 @@ jsfiles locs.forEach((loc) => fail(dedent(` - ${link(file, `#L${loc.line}`)} is preventing tests from running. + Please remove the \`o.only\` from ${link(file, `#L${loc.line}`)}.
 				${pinpoint(code, {line: loc.line, column : loc.cursor})}
 				
From 4ff0f2170eef32a30c373b1d4c8126bff1b07d60 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Sat, 22 Jul 2017 03:09:54 -0400 Subject: [PATCH 027/301] Don't show diffs for package lock files [skip ci] --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index 6de5c647..41c00ba2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ * text=auto /mithril.js binary /mithril.min.js binary +/package-lock.json binary +/yarn.lock From 584117a00dcdac13b4ecc9887cf0ef2b02f23bd6 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Sat, 22 Jul 2017 03:16:27 -0400 Subject: [PATCH 028/301] Missed a word [skip ci] --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 41c00ba2..7296866f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,4 +2,4 @@ /mithril.js binary /mithril.min.js binary /package-lock.json binary -/yarn.lock +/yarn.lock binary From 45b69d4acaf9300e2313c2de85d9f12b971cdb7d Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Sat, 22 Jul 2017 13:12:01 -0700 Subject: [PATCH 029/301] chore: run eslint --fix against commits (#1912) --- .travis.yml | 3 +- package-lock.json | 2147 +++++++++++++++++++++++++++++++++------------ package.json | 12 +- 3 files changed, 1582 insertions(+), 580 deletions(-) diff --git a/.travis.yml b/.travis.yml index d825fa73..d4470ebd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,8 @@ cache: # Custom install step so the travis-only stuff doesn't need to be in package.json install: - npm install -- npm install --no-save @alrra/travis-scripts@^3.0.1 gh-pages@^0.12.0 +# This is to prevent lint-staged/prettier from running on the bundles +- npm rm husky # Run danger, build bundles (so they're always up to date) before_script: diff --git a/package-lock.json b/package-lock.json index de36d7a9..9e4e54dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,12 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@alrra/travis-scripts": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@alrra/travis-scripts/-/travis-scripts-3.0.1.tgz", + "integrity": "sha1-RdW5NXMXtsxVU9/ZmTGEOuCw5To=", + "dev": true + }, "abab": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", @@ -11,13 +17,15 @@ "dev": true }, "abbrev": { - "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, "acorn": { - "version": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", - "integrity": "sha1-xGDfCEkUY/AozLguqzcwvwEIez0=", + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", "dev": true }, "acorn-globals": { @@ -26,19 +34,21 @@ "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", "dev": true, "requires": { - "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz" + "acorn": "4.0.13" } }, "acorn-jsx": { - "version": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" + "acorn": "3.3.0" }, "dependencies": { "acorn": { - "version": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", "dev": true } @@ -55,46 +65,53 @@ } }, "ajv": { - "version": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "co": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz" + "co": "4.6.0", + "json-stable-stringify": "1.0.1" } }, "ajv-keywords": { - "version": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", "dev": true }, "align-text": { - "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", - "longest": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" } }, "amdefine": { - "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-escapes": { - "version": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "dev": true }, "ansi-regex": { - "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { - "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, @@ -110,16 +127,23 @@ "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", "dev": true, "requires": { - "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "arrify": "1.0.1", "micromatch": "2.3.11" } }, + "app-root-path": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", + "integrity": "sha1-zWLc+OT9WkF+/GZNLlsQZTxlG0Y=", + "dev": true + }, "argparse": { - "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, "requires": { - "sprintf-js": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "sprintf-js": "1.0.3" } }, "arr-diff": { @@ -144,15 +168,17 @@ "dev": true }, "array-union": { - "version": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + "array-uniq": "1.0.3" } }, "array-uniq": { - "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, @@ -163,7 +189,8 @@ "dev": true }, "arrify": { - "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, @@ -180,9 +207,13 @@ "dev": true }, "async": { - "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", + "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } }, "asynckit": { "version": "0.4.0", @@ -203,13 +234,14 @@ "dev": true }, "babel-code-frame": { - "version": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "babel-core": { @@ -218,7 +250,7 @@ "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", "dev": true, "requires": { - "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "babel-code-frame": "6.22.0", "babel-generator": "6.25.0", "babel-helpers": "6.24.1", "babel-messages": "6.23.0", @@ -229,14 +261,22 @@ "babel-types": "6.25.0", "babylon": "6.17.4", "convert-source-map": "1.5.0", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "debug": "2.6.8", "json5": "0.5.1", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", "private": "0.1.7", "slash": "1.0.0", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + "source-map": "0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } } }, "babel-generator": { @@ -250,9 +290,17 @@ "babel-types": "6.25.0", "detect-indent": "4.0.0", "jsesc": "1.3.0", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "lodash": "4.17.4", + "source-map": "0.5.6", "trim-right": "1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } } }, "babel-helpers": { @@ -332,8 +380,8 @@ "babel-runtime": "6.23.0", "core-js": "2.4.1", "home-or-tmp": "2.0.0", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "lodash": "4.17.4", + "mkdirp": "0.5.1", "source-map-support": "0.4.15" } }, @@ -357,7 +405,7 @@ "babel-traverse": "6.25.0", "babel-types": "6.25.0", "babylon": "6.17.4", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" + "lodash": "4.17.4" } }, "babel-traverse": { @@ -366,15 +414,15 @@ "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", "dev": true, "requires": { - "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "babel-code-frame": "6.22.0", "babel-messages": "6.23.0", "babel-runtime": "6.23.0", "babel-types": "6.25.0", "babylon": "6.17.4", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", - "globals": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "debug": "2.6.8", + "globals": "9.18.0", "invariant": "2.2.2", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" + "lodash": "4.17.4" } }, "babel-types": { @@ -384,8 +432,8 @@ "dev": true, "requires": { "babel-runtime": "6.23.0", - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "esutils": "2.0.2", + "lodash": "4.17.4", "to-fast-properties": "1.0.3" } }, @@ -396,8 +444,9 @@ "dev": true }, "balanced-match": { - "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "bcrypt-pbkdf": { @@ -411,12 +460,13 @@ } }, "benchmark": { - "version": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", "dev": true, "requires": { - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "platform": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz" + "lodash": "4.17.4", + "platform": "1.3.4" } }, "boom": { @@ -429,12 +479,13 @@ } }, "brace-expansion": { - "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", - "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "balanced-match": "1.0.0", + "concat-map": "0.0.1" } }, "braces": { @@ -454,7 +505,15 @@ "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", "dev": true, "requires": { - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } } }, "bser": { @@ -466,11 +525,6 @@ "node-int64": "0.4.0" } }, - "buffer-shims": { - "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", - "dev": true - }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -478,21 +532,24 @@ "dev": true }, "caller-path": { - "version": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz" + "callsites": "0.2.0" } }, "callsites": { - "version": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, "camelcase": { - "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", "dev": true }, "caseless": { @@ -502,71 +559,119 @@ "dev": true }, "center-align": { - "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, + "optional": true, "requires": { - "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "lazy-cache": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + "align-text": "0.1.4", + "lazy-cache": "1.0.4" } }, "chalk": { - "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, + "ci-info": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz", + "integrity": "sha1-3FKF8rTiUYIWg2gcOBwziPRuxTQ=", + "dev": true + }, "circular-json": { - "version": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", "dev": true }, "cli-cursor": { - "version": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { - "restore-cursor": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz" + "restore-cursor": "1.0.1" + } + }, + "cli-spinners": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", + "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", + "dev": true + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "1.0.2" } }, "cli-width": { - "version": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", "dev": true }, "cliui": { - "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "center-align": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "right-align": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" - }, - "dependencies": { - "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - } + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" } }, "co": { - "version": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, "code-point-at": { - "version": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collections": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz", + "integrity": "sha1-HyMCay7zb5J+7MkB6ZxfDUj6M04=", + "dev": true, + "requires": { + "weak-map": "1.0.0" + } + }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", @@ -583,18 +688,20 @@ "dev": true }, "concat-map": { - "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "concat-stream": { - "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, "requires": { - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", - "typedarray": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" } }, "content-type-parser": { @@ -616,10 +723,46 @@ "dev": true }, "core-util-is": { - "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cosmiconfig": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-1.1.0.tgz", + "integrity": "sha1-DeoPmATv37kp+7GxiOJVU+oFPTc=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "js-yaml": "3.9.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "pinkie-promise": "2.0.1", + "require-from-string": "1.2.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } + }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", @@ -645,11 +788,12 @@ } }, "d": { - "version": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + "es5-ext": "0.10.24" } }, "danger": { @@ -659,16 +803,16 @@ "dev": true, "requires": { "babel-polyfill": "6.23.0", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "commander": "2.11.0", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "debug": "2.6.8", "dtslint": "0.1.2", "github": "9.2.0", "jest-config": "20.0.4", "jest-environment-node": "20.0.3", "jest-runtime": "20.0.4", "jsome": "2.3.26", - "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "jsonpointer": "4.0.1", "lodash.find": "4.6.0", "lodash.includes": "4.3.0", "lodash.isobject": "2.4.1", @@ -696,16 +840,24 @@ } } }, + "date-fns": { + "version": "1.28.5", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.28.5.tgz", + "integrity": "sha1-JXz8RdMi30XvVlhmWWfuhBzXP68=", + "dev": true + }, "debug": { - "version": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", - "integrity": "sha1-qfpvvpykPPHnn3O3XAGJy7fW21o=", + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "dev": true, "requires": { - "ms": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz" + "ms": "2.0.0" } }, "decamelize": { - "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, @@ -716,22 +868,24 @@ "dev": true }, "deep-is": { - "version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, "del": { - "version": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "is-path-cwd": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "is-path-in-cwd": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz" + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" } }, "delayed-stream": { @@ -756,12 +910,13 @@ "dev": true }, "doctrine": { - "version": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "esutils": "2.0.2", + "isarray": "1.0.0" } }, "dtslint": { @@ -773,7 +928,7 @@ "requires": { "fs-promise": "2.0.3", "parsimmon": "1.6.2", - "strip-json-comments": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "strip-json-comments": "2.0.1", "tsutils": "1.9.1" } }, @@ -787,6 +942,12 @@ "jsbn": "0.1.1" } }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", @@ -815,206 +976,244 @@ } }, "es5-ext": { - "version": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", - "integrity": "sha1-wzClk0we4hKEp8CBqG5f2TfJHqY=", + "version": "0.10.24", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", + "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", "dev": true, "requires": { - "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" } }, "es6-iterator": { - "version": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", - "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-symbol": "3.1.1" } }, "es6-map": { - "version": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", - "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "es6-set": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "event-emitter": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" } }, "es6-set": { - "version": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", - "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "event-emitter": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" } }, "es6-symbol": { - "version": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24" } }, "es6-weak-map": { - "version": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz", - "es6-iterator": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "es6-symbol": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" } }, "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "escodegen": { - "version": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "optionator": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" }, "dependencies": { - "esprima": { - "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, "estraverse": { - "version": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true } } }, - "escope": { - "version": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true, - "requires": { - "es6-map": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "es6-weak-map": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "esrecurse": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" - } - }, "eslint": { - "version": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, "requires": { - "babel-code-frame": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "concat-stream": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", - "doctrine": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", - "escope": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "espree": "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz", - "esquery": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "file-entry-cache": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "globals": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", - "ignore": "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz", - "imurmurhash": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "inquirer": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "is-my-json-valid": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", - "is-resolvable": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", - "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", - "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "levn": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "natural-compare": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "optionator": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "path-is-inside": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "pluralize": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "progress": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "require-uncached": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "shelljs": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "strip-json-comments": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "table": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "text-table": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "user-home": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz" - } - }, - "espree": { - "version": "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz", - "integrity": "sha1-ONve2+3JW4lhofvwRzSo9qnIxZI=", - "dev": true, - "requires": { - "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", - "acorn-jsx": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz" - } - }, - "esprima": { - "version": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "esquery": { - "version": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", - "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true, - "requires": { - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" - } - }, - "esrecurse": { - "version": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", - "integrity": "sha1-RxO2U2rffyrE8yfVWed1a/9kgiA=", - "dev": true, - "requires": { - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.4.3", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.16.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.9.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" }, "dependencies": { "estraverse": { - "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", - "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } + } + }, + "espree": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", + "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "dev": true, + "requires": { + "acorn": "5.1.1", + "acorn-jsx": "3.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "dev": true + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true } } }, "estraverse": { - "version": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", "dev": true }, "esutils": { - "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "event-emitter": { - "version": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "es5-ext": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz" + "d": "1.0.0", + "es5-ext": "0.10.24" } }, "exec-sh": { @@ -1026,8 +1225,24 @@ "merge": "1.2.0" } }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, "exit-hook": { - "version": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, @@ -1071,7 +1286,8 @@ "dev": true }, "fast-levenshtein": { - "version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, @@ -1085,21 +1301,23 @@ } }, "figures": { - "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" } }, "file-entry-cache": { - "version": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "flat-cache": "1.2.2", + "object-assign": "4.1.1" } }, "filename-regex": { @@ -1118,7 +1336,7 @@ "isobject": "2.1.0", "randomatic": "1.1.7", "repeat-element": "1.1.2", - "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + "repeat-string": "1.6.1" } }, "find-up": { @@ -1131,14 +1349,15 @@ } }, "flat-cache": { - "version": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", "dev": true, "requires": { - "circular-json": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", - "del": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "write": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" + "circular-json": "0.3.1", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" } }, "follow-redirects": { @@ -1147,7 +1366,7 @@ "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", "dev": true, "requires": { - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "debug": "2.6.8", "stream-consume": "0.1.0" } }, @@ -1190,7 +1409,7 @@ "dev": true, "optional": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "graceful-fs": "4.1.11", "jsonfile": "2.4.0" } }, @@ -1208,23 +1427,38 @@ } }, "fs.realpath": { - "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "generate-function": { - "version": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", "dev": true }, "generate-object-property": { - "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { - "is-property": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + "is-property": "1.0.2" } }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -1242,6 +1476,51 @@ } } }, + "gh-pages": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.12.0.tgz", + "integrity": "sha1-2VHj7Zi4VpnUsEGOsaFbGgSYjcE=", + "dev": true, + "requires": { + "async": "2.1.2", + "commander": "2.9.0", + "globby": "6.1.0", + "graceful-fs": "4.1.10", + "q": "1.4.1", + "q-io": "1.13.2", + "rimraf": "2.6.1" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.10.tgz", + "integrity": "sha1-8tcgwiCS90Mih3XHXjYSYyUB8TE=", + "dev": true + } + } + }, "github": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/github/-/github-9.2.0.tgz", @@ -1255,16 +1534,17 @@ } }, "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-base": { @@ -1287,45 +1567,62 @@ } }, "globals": { - "version": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", - "integrity": "sha1-DAymltm5u2lNLlRwvTd3fKrVAoY=", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "globby": { - "version": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, "handlebars": { - "version": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz", - "integrity": "sha1-6XMlrrjqC54SucTdc8TDEq0O3lk=", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, "requires": { - "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "optimist": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz" + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" }, "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" + "amdefine": "1.0.1" } } } @@ -1342,16 +1639,17 @@ "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "dev": true, "requires": { - "ajv": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "ajv": "4.11.8", "har-schema": "1.0.5" } }, "has-ansi": { - "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + "ansi-regex": "2.1.1" } }, "hawk": { @@ -1378,7 +1676,7 @@ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "dev": true, "requires": { - "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "os-homedir": "1.0.2", "os-tmpdir": "1.0.2" } }, @@ -1415,10 +1713,29 @@ "dev": true, "requires": { "agent-base": "2.1.1", - "debug": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz", + "debug": "2.6.8", "extend": "3.0.1" } }, + "husky": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz", + "integrity": "sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA==", + "dev": true, + "requires": { + "is-ci": "1.0.10", + "normalize-path": "1.0.0", + "strip-indent": "2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", + "dev": true + } + } + }, "iconv-lite": { "version": "0.4.13", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", @@ -1426,51 +1743,66 @@ "dev": true }, "ignore": { - "version": "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz", - "integrity": "sha1-SBDKXx2OylWVITo0uU8utO2Sa70=", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", + "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", "dev": true }, "imurmurhash": { - "version": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, "inflight": { - "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { - "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "inquirer": { - "version": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { - "ansi-escapes": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "cli-cursor": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "cli-width": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", - "figures": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "readline2": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "run-async": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "rx-lite": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "string-width": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" } }, "interpret": { - "version": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", "dev": true }, @@ -1483,6 +1815,12 @@ "loose-envify": "1.3.1" } }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1490,7 +1828,8 @@ "dev": true }, "is-buffer": { - "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", "dev": true }, @@ -1503,6 +1842,15 @@ "builtin-modules": "1.1.1" } }, + "is-ci": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", + "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", + "dev": true, + "requires": { + "ci-info": "1.0.0" + } + }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -1536,15 +1884,16 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + "number-is-nan": "1.0.1" } }, "is-fullwidth-code-point": { - "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + "number-is-nan": "1.0.1" } }, "is-glob": { @@ -1557,14 +1906,15 @@ } }, "is-my-json-valid": { - "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", "dev": true, "requires": { - "generate-function": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "generate-object-property": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" } }, "is-number": { @@ -1573,28 +1923,31 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + "kind-of": "3.2.2" } }, "is-path-cwd": { - "version": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", "dev": true }, "is-path-in-cwd": { - "version": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz" + "is-path-inside": "1.0.0" } }, "is-path-inside": { - "version": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "dev": true, "requires": { - "path-is-inside": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + "path-is-inside": "1.0.2" } }, "is-posix-bracket": { @@ -1609,17 +1962,25 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-property": { - "version": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, "is-resolvable": { - "version": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "dev": true, "requires": { - "tryit": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz" + "tryit": "1.0.3" } }, "is-stream": { @@ -1634,13 +1995,21 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { - "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, @@ -1650,7 +2019,7 @@ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "isarray": "1.0.0" } }, "isstream": { @@ -1660,50 +2029,61 @@ "dev": true }, "istanbul": { - "version": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "escodegen": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "handlebars": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz", - "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "nopt": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.10", + "js-yaml": "3.9.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.2.14", + "wordwrap": "1.0.0" }, "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "esprima": { - "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "resolve": { - "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { @@ -1755,8 +2135,8 @@ "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "chalk": "1.1.3", + "glob": "7.1.2", "jest-environment-jsdom": "20.0.3", "jest-environment-node": "20.0.3", "jest-jasmine2": "20.0.4", @@ -1773,7 +2153,7 @@ "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "diff": "3.3.0", "jest-matcher-utils": "20.0.3", "pretty-format": "20.0.3" @@ -1813,7 +2193,7 @@ "dev": true, "requires": { "fb-watchman": "2.0.0", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "graceful-fs": "4.1.11", "jest-docblock": "20.0.3", "micromatch": "2.3.11", "sane": "1.6.0", @@ -1826,14 +2206,14 @@ "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "chalk": "1.1.3", + "graceful-fs": "4.1.11", "jest-diff": "20.0.3", "jest-matcher-utils": "20.0.3", "jest-matchers": "20.0.3", "jest-message-util": "20.0.3", "jest-snapshot": "20.0.3", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "once": "1.4.0", "p-map": "1.1.1" } }, @@ -1843,7 +2223,7 @@ "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "pretty-format": "20.0.3" } }, @@ -1865,7 +2245,7 @@ "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "micromatch": "2.3.11", "slash": "1.0.0" } @@ -1890,7 +2270,7 @@ "requires": { "browser-resolve": "1.11.2", "is-builtin-module": "1.0.0", - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + "resolve": "1.3.3" } }, "jest-runtime": { @@ -1902,18 +2282,18 @@ "babel-core": "6.25.0", "babel-jest": "20.0.3", "babel-plugin-istanbul": "4.1.4", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "convert-source-map": "1.5.0", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "graceful-fs": "4.1.11", "jest-config": "20.0.4", "jest-haste-map": "20.0.4", "jest-regex-util": "20.0.3", "jest-resolve": "20.0.4", "jest-util": "20.0.3", - "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "json-stable-stringify": "1.0.1", "micromatch": "2.3.11", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + "strip-bom": "3.0.0", + "yargs": "7.1.0" } }, "jest-snapshot": { @@ -1922,11 +2302,11 @@ "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "jest-diff": "20.0.3", "jest-matcher-utils": "20.0.3", "jest-util": "20.0.3", - "natural-compare": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "natural-compare": "1.4.0", "pretty-format": "20.0.3" } }, @@ -1936,13 +2316,13 @@ "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "chalk": "1.1.3", + "graceful-fs": "4.1.11", "jest-message-util": "20.0.3", "jest-mock": "20.0.3", "jest-validate": "20.0.3", "leven": "2.1.0", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + "mkdirp": "0.5.1" } }, "jest-validate": { @@ -1951,24 +2331,34 @@ "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "jest-matcher-utils": "20.0.3", "leven": "2.1.0", "pretty-format": "20.0.3" } }, "js-tokens": { - "version": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", - "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, "js-yaml": { - "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz", - "integrity": "sha1-M6BexIHIUMiHWSkWb+G+thxyh2Y=", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz", + "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", "dev": true, "requires": { - "argparse": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "esprima": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz" + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } } }, "jsbn": { @@ -1985,13 +2375,13 @@ "dev": true, "requires": { "abab": "1.0.3", - "acorn": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz", + "acorn": "4.0.13", "acorn-globals": "3.1.0", "array-equal": "1.0.0", "content-type-parser": "1.0.1", "cssom": "0.3.2", "cssstyle": "0.2.37", - "escodegen": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "escodegen": "1.8.1", "html-encoding-sniffer": "1.0.1", "nwmatcher": "1.4.1", "parse5": "1.5.1", @@ -2017,9 +2407,43 @@ "integrity": "sha1-jLRDiSTSyd1SlMkK3wPzVBT7PKk=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "chalk": "1.1.3", "json-stringify-safe": "5.0.1", - "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + "yargs": "4.8.1" + }, + "dependencies": { + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "requires": { + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + } + } } }, "json-schema": { @@ -2029,11 +2453,12 @@ "dev": true }, "json-stable-stringify": { - "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" + "jsonify": "0.0.0" } }, "json-stringify-safe": { @@ -2055,16 +2480,18 @@ "dev": true, "optional": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz" + "graceful-fs": "4.1.11" } }, "jsonify": { - "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, "jsonpointer": { - "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", "dev": true }, @@ -2089,17 +2516,29 @@ } }, "kind-of": { - "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", - "integrity": "sha1-tYq+TVwEStM3JqjBUltIz4kb/wc=", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz" + "is-buffer": "1.1.5" } }, "lazy-cache": { - "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } }, "leven": { "version": "2.1.0", @@ -2108,12 +2547,96 @@ "dev": true }, "levn": { - "version": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lint-staged": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.0.2.tgz", + "integrity": "sha1-joPhHp4WVsCbYRf22w1V/UlgocA=", + "dev": true, + "requires": { + "app-root-path": "2.0.1", + "cosmiconfig": "1.1.0", + "execa": "0.7.0", + "listr": "0.12.0", + "lodash.chunk": "4.2.0", + "minimatch": "3.0.4", + "npm-which": "3.0.1", + "p-map": "1.1.1", + "staged-git-files": "0.0.4" + } + }, + "listr": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", + "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "figures": "1.7.0", + "indent-string": "2.1.0", + "is-promise": "2.1.0", + "is-stream": "1.1.0", + "listr-silent-renderer": "1.1.1", + "listr-update-renderer": "0.2.0", + "listr-verbose-renderer": "0.4.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "ora": "0.2.3", + "p-map": "1.1.1", + "rxjs": "5.4.2", + "stream-to-observable": "0.1.0", + "strip-ansi": "3.0.1" + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", + "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "elegant-spinner": "1.0.1", + "figures": "1.7.0", + "indent-string": "3.1.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "indent-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.1.0.tgz", + "integrity": "sha1-CP9DNGAziDmbMp5rlTjcejz13n0=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz", + "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "date-fns": "1.28.5", + "figures": "1.7.0" } }, "load-json-file": { @@ -2122,11 +2645,22 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "graceful-fs": "4.1.11", "parse-json": "2.2.0", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + } } }, "locate-path": { @@ -2146,7 +2680,8 @@ "dev": true }, "lodash": { - "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, @@ -2156,6 +2691,18 @@ "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", "dev": true }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=", + "dev": true + }, "lodash.find": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", @@ -2183,8 +2730,28 @@ "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=", "dev": true }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "1.1.3" + } + }, + "log-update": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", + "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "cli-cursor": "1.0.2" + } + }, "longest": { - "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, @@ -2194,7 +2761,17 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz" + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "makeerror": { @@ -2231,7 +2808,7 @@ "filename-regex": "2.0.1", "is-extglob": "1.0.0", "is-glob": "2.0.1", - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", + "kind-of": "3.2.2", "normalize-path": "2.1.1", "object.omit": "2.0.1", "parse-glob": "3.0.4", @@ -2259,34 +2836,45 @@ "mime-db": "1.27.0" } }, + "mimeparse": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/mimeparse/-/mimeparse-0.1.4.tgz", + "integrity": "sha1-2vsCdSNw/SJgk64xUsJxrwGsJUo=", + "dev": true + }, "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz" + "brace-expansion": "1.1.8" } }, "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { - "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "minimist": "0.0.8" } }, "ms": { - "version": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", - "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "mute-stream": { - "version": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, @@ -2298,12 +2886,13 @@ "optional": true, "requires": { "any-promise": "1.3.0", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "object-assign": "4.1.1", "thenify-all": "1.6.0" } }, "natural-compare": { - "version": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, @@ -2330,11 +2919,12 @@ "dev": true }, "nopt": { - "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + "abbrev": "1.0.9" } }, "normalize-package-data": { @@ -2358,8 +2948,38 @@ "remove-trailing-separator": "1.0.2" } }, + "npm-path": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.3.tgz", + "integrity": "sha1-Fc/04ciaONp39W9gVbJPl137K74=", + "dev": true, + "requires": { + "which": "1.2.14" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "2.11.0", + "npm-path": "2.0.3", + "which": "1.2.14" + } + }, "number-is-nan": { - "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, @@ -2376,7 +2996,8 @@ "dev": true }, "object-assign": { - "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, @@ -2391,58 +3012,91 @@ } }, "once": { - "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "wrappy": "1.0.2" } }, "onetime": { - "version": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, "optimist": { - "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + "minimist": "0.0.8", + "wordwrap": "0.0.3" }, "dependencies": { "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true } } }, "optionator": { - "version": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "fast-levenshtein": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "levn": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "ora": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", + "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-spinners": "0.1.2", + "object-assign": "4.1.1" } }, "os-homedir": { - "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, "p-limit": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", @@ -2511,17 +3165,26 @@ "dev": true }, "path-is-absolute": { - "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-is-inside": { - "version": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-parse": { - "version": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, @@ -2531,9 +3194,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "performance-now": { @@ -2543,21 +3206,24 @@ "dev": true }, "pify": { - "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { - "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { - "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + "pinkie": "2.0.4" } }, "pinpoint": { @@ -2567,17 +3233,20 @@ "dev": true }, "platform": { - "version": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz", "integrity": "sha1-bw+xftqqSPIUQrOpdcBjEw8cPr0=", "dev": true }, "pluralize": { - "version": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", "dev": true }, "prelude-ls": { - "version": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, @@ -2593,8 +3262,19 @@ "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + "ansi-regex": "2.1.1", + "ansi-styles": "3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", + "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + } } }, "private": { @@ -2604,12 +3284,14 @@ "dev": true }, "process-nextick-args": { - "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, "progress": { - "version": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, @@ -2619,12 +3301,46 @@ "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", "dev": true }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "q-io": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.2.tgz", + "integrity": "sha1-7qEw1IHdteGqG8WmaFX3OR0G8AM=", + "dev": true, + "requires": { + "collections": "0.2.2", + "mime": "1.3.6", + "mimeparse": "0.1.4", + "q": "1.4.1", + "qs": "1.2.2", + "url2": "0.0.0" + }, + "dependencies": { + "qs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.2.tgz", + "integrity": "sha1-GbV/8k3CqZzh+L32r82ln472H4g=", + "dev": true + } + } + }, "qs": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", @@ -2638,7 +3354,7 @@ "dev": true, "requires": { "is-number": "3.0.0", - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + "kind-of": "4.0.0" }, "dependencies": { "is-number": { @@ -2647,7 +3363,27 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz" + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" } } } @@ -2680,7 +3416,7 @@ "dev": true, "requires": { "path-exists": "2.1.0", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "pinkie-promise": "2.0.1" } }, "path-exists": { @@ -2689,41 +3425,44 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "pinkie-promise": "2.0.1" } } } }, "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", - "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "buffer-shims": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", - "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "readline2": { - "version": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { - "code-point-at": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "mute-stream": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" } }, "rechoir": { - "version": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz" + "resolve": "1.3.3" } }, "regenerator-runtime": { @@ -2755,7 +3494,8 @@ "dev": true }, "repeat-string": { - "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, @@ -2798,6 +3538,18 @@ "uuid": "3.1.0" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", @@ -2805,34 +3557,38 @@ "dev": true }, "require-uncached": { - "version": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "resolve-from": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz" + "caller-path": "0.1.0", + "resolve-from": "1.0.1" } }, "resolve": { - "version": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", "dev": true, "requires": { - "path-parse": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz" + "path-parse": "1.0.5" } }, "resolve-from": { - "version": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", "dev": true }, "restore-cursor": { - "version": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { - "exit-hook": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "onetime": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" + "exit-hook": "1.1.1", + "onetime": "1.1.0" } }, "rfc6902": { @@ -2842,34 +3598,48 @@ "dev": true }, "right-align": { - "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, + "optional": true, "requires": { - "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" + "align-text": "0.1.4" } }, "rimraf": { - "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", "dev": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz" + "glob": "7.1.2" } }, "run-async": { - "version": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "once": "1.4.0" } }, "rx-lite": { - "version": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", "dev": true }, + "rxjs": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.2.tgz", + "integrity": "sha1-KjI2/L8D31e64G/Wly/ZnlwI/Pc=", + "dev": true, + "requires": { + "symbol-observable": "1.0.4" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -2885,8 +3655,8 @@ "anymatch": "1.3.0", "exec-sh": "0.2.0", "fb-watchman": "1.9.2", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "minimatch": "3.0.4", + "minimist": "1.2.0", "walker": "1.0.7", "watch": "0.10.0" }, @@ -2908,6 +3678,12 @@ "requires": { "bser": "1.0.2" } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true } } }, @@ -2923,16 +3699,44 @@ "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", "dev": true }, - "shelljs": { - "version": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", - "integrity": "sha1-svXHfvlxSPS09uImguELuoZnz/E=", + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "interpret": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", - "rechoir": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" + "shebang-regex": "1.0.0" } }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", @@ -2940,7 +3744,8 @@ "dev": true }, "slice-ansi": { - "version": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, @@ -2954,11 +3759,13 @@ } }, "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, + "optional": true, "requires": { - "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" + "amdefine": "1.0.1" } }, "source-map-support": { @@ -2967,7 +3774,15 @@ "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", "dev": true, "requires": { - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" + "source-map": "0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } } }, "spdx-correct": { @@ -2992,7 +3807,8 @@ "dev": true }, "sprintf-js": { - "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, @@ -3020,28 +3836,42 @@ } } }, + "staged-git-files": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-0.0.4.tgz", + "integrity": "sha1-15fhtVHKemOd7AI33G60u5vhfTU=", + "dev": true + }, "stream-consume": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", "dev": true }, + "stream-to-observable": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", + "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=", + "dev": true + }, "string_decoder": { - "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", - "integrity": "sha1-8G9BFXtmTYYGn4S9vcmw2KsoFmc=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "buffer-shims": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz" + "safe-buffer": "5.1.1" } }, "string-width": { - "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "stringstream": { @@ -3051,28 +3881,50 @@ "dev": true }, "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + "ansi-regex": "2.1.1" } }, "strip-bom": { - "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, "strip-json-comments": { - "version": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "symbol-observable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", + "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=", + "dev": true + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", @@ -3080,30 +3932,48 @@ "dev": true }, "table": { - "version": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { - "ajv": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "ajv-keywords": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "slice-ansi": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "string-width": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz" + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "is-fullwidth-code-point": { - "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "string-width": { - "version": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", - "integrity": "sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" } } } @@ -3114,15 +3984,16 @@ "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", "dev": true, "requires": { - "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "arrify": "1.0.1", "micromatch": "2.3.11", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "object-assign": "4.1.1", "read-pkg-up": "1.0.1", "require-main-filename": "1.0.1" } }, "text-table": { - "version": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, @@ -3145,7 +4016,8 @@ } }, "through": { - "version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -3183,7 +4055,8 @@ "dev": true }, "tryit": { - "version": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", "dev": true }, @@ -3211,53 +4084,112 @@ "optional": true }, "type-check": { - "version": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + "prelude-ls": "1.1.2" } }, "typedarray": { - "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "uglify-js": { - "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz", - "integrity": "sha1-1Uk0d4qNoUkD+imjJvskwKtRoaA=", + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, "requires": { - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" }, "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", "dev": true, "optional": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } } } }, "uglify-to-browserify": { - "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, + "url2": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/url2/-/url2-0.0.0.tgz", + "integrity": "sha1-Tqq9HVw6yQ1iq0SFyZhCKGWgSxo=", + "dev": true + }, "user-home": { - "version": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { - "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + "os-homedir": "1.0.2" } }, "util-deprecate": { - "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, @@ -3307,6 +4239,12 @@ "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", "dev": true }, + "weak-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.0.tgz", + "integrity": "sha1-tm5Wqd8L0lp2u/G1FNsSkIBhSjc=", + "dev": true + }, "webidl-conversions": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz", @@ -3341,20 +4279,29 @@ } }, "which": { - "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "dev": true, "requires": { - "isexe": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "isexe": "2.0.0" } }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, "window-size": { - "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", "dev": true }, "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, @@ -3365,20 +4312,32 @@ "dev": true, "requires": { "errno": "0.1.4", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "xtend": "4.0.1" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" } }, "wrappy": { - "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write": { - "version": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz" + "mkdirp": "0.5.1" } }, "xml-name-validator": { @@ -3388,19 +4347,51 @@ "dev": true }, "xtend": { - "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, "yargs": { - "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "dev": true, "requires": { - "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "cliui": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "3.0.0" } } } diff --git a/package.json b/package.json index 39fe184b..cd1171eb 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "build": "npm run build-browser & npm run build-min", "build-browser": "node bundler/cli browser.js -output mithril.js", "build-min": "node bundler/cli browser.js -output mithril.min.js -minify", - "danger": "danger", + "precommit": "lint-staged", "lintdocs": "node docs/lint", "gendocs": "node docs/generate", "lint": "eslint . || true", @@ -26,16 +26,26 @@ "postversion": "git push --follow-tags" }, "devDependencies": { + "@alrra/travis-scripts": "^3.0.1", "benchmark": "^2.1.4", "danger": "^1.0.0", "dedent": "^0.7.0", "eslint": "^3.19.0", + "gh-pages": "^0.12.0", + "husky": "^0.14.3", "istanbul": "^0.4.5", "locater": "^1.3.0", "marked": "^0.3.6", + "lint-staged": "^4.0.2", "pinpoint": "^1.1.0" }, "bin": { "ospec": "./ospec/bin/ospec" + }, + "lint-staged": { + "*.js": [ + "eslint . --fix", + "git add" + ] } } From 5e62c13558545b099cfb7b1c207b562627f5bef1 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Sat, 22 Jul 2017 13:13:13 -0700 Subject: [PATCH 030/301] docs: add changelog entry to PR template (#1911) --- .github/PULL_REQUEST_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9218a937..b60b2e54 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,3 +27,4 @@ - [ ] I have read the **CONTRIBUTING** document. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. +- [ ] I have updated `docs/change-log.md` From fd86c95d24b2aae72cc999f73c3c1fad8a01e9eb Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sat, 22 Jul 2017 20:15:05 +0000 Subject: [PATCH 031/301] Bundled output for commit 5e62c13558545b099cfb7b1c207b562627f5bef1 [skip ci] --- package-lock.json | 40 ---------------------------------------- package.json | 3 +-- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e4e54dc..4dbd54bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -582,12 +582,6 @@ "supports-color": "2.0.0" } }, - "ci-info": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz", - "integrity": "sha1-3FKF8rTiUYIWg2gcOBwziPRuxTQ=", - "dev": true - }, "circular-json": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", @@ -1717,25 +1711,6 @@ "extend": "3.0.1" } }, - "husky": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz", - "integrity": "sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA==", - "dev": true, - "requires": { - "is-ci": "1.0.10", - "normalize-path": "1.0.0", - "strip-indent": "2.0.0" - }, - "dependencies": { - "normalize-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", - "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", - "dev": true - } - } - }, "iconv-lite": { "version": "0.4.13", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", @@ -1842,15 +1817,6 @@ "builtin-modules": "1.1.1" } }, - "is-ci": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", - "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", - "dev": true, - "requires": { - "ci-info": "1.0.0" - } - }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -3901,12 +3867,6 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", diff --git a/package.json b/package.json index cd1171eb..2462892a 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,10 @@ "dedent": "^0.7.0", "eslint": "^3.19.0", "gh-pages": "^0.12.0", - "husky": "^0.14.3", "istanbul": "^0.4.5", + "lint-staged": "^4.0.2", "locater": "^1.3.0", "marked": "^0.3.6", - "lint-staged": "^4.0.2", "pinpoint": "^1.1.0" }, "bin": { From 8d013142535ee7f08d686d40b3ecc379d3cdb8f2 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sat, 22 Jul 2017 20:41:22 +0000 Subject: [PATCH 032/301] Bundled output for commit 60481685058e101119f7d0c6dde8b0674f3336ca [skip ci] --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2462892a..e49599bf 100644 --- a/package.json +++ b/package.json @@ -46,5 +46,6 @@ "eslint . --fix", "git add" ] - } + }, + "dependencies": {} } From 1da69da4dd86707475c241eac1285dbdf76ad993 Mon Sep 17 00:00:00 2001 From: Jared Morrow Date: Thu, 27 Jul 2017 13:54:04 -0600 Subject: [PATCH 033/301] docs: Fix mismatched brace in Authentication example (#1917) --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index 16a08eec..a8f7a2fe 100644 --- a/docs/route.md +++ b/docs/route.md @@ -568,7 +568,7 @@ var Login = { return m("form", [ m("input[type=text]", {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}), m("input[type=password]", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}), - m("button[type=button]", {onclick: Auth.login, "Login") + m("button[type=button]", {onclick: Auth.login}, "Login") ]) } } From da6122753c93d1b8fece23f3d402a6b95ee2778c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 31 Jul 2017 11:39:36 +0200 Subject: [PATCH 034/301] Add tests for issue 1921 (onremove fires on childrent that don't end up in the instance) --- render/tests/test-onremove.js | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/render/tests/test-onremove.js b/render/tests/test-onremove.js index a7f88a6b..f509e704 100644 --- a/render/tests/test-onremove.js +++ b/render/tests/test-onremove.js @@ -89,6 +89,7 @@ o.spec("onremove", function() { o(vnode.dom.onremove).equals(undefined) o(vnode.dom.attributes["onremove"]).equals(undefined) + o(vnode.events).equals(undefined) }) o("calls onremove on recycle", function() { var remove = o.spy() @@ -150,6 +151,46 @@ o.spec("onremove", function() { o(spy.callCount).equals(1) }) + o("doesn't call onremove on children when the corresponding view returns null (after removing the parent)", function() { + var threw = false + var spy = o.spy() + var parent = createComponent({ + view: function() {} + }) + var child = createComponent({ + view: function() {}, + onremove: spy + }) + render(root, {tag: parent, children: [child]}) + try { + render(root, null) + } catch (e) { + threw = e + } + + o(spy.callCount).equals(0) + o(threw).equals(false) + }) + o("doesn't call onremove on children when the corresponding view returns null (after removing the children)", function() { + var threw = false + var spy = o.spy() + var parent = createComponent({ + view: function() {} + }) + var child = createComponent({ + view: function() {}, + onremove: spy + }) + render(root, {tag: parent, children: [child]}) + try { + render(root, {tag: parent}) + } catch (e) { + threw = true + } + + o(spy.callCount).equals(0) + o(threw).equals(false) + }) }) }) }) \ No newline at end of file From c96e08579973fcbee1800163fafd2c25944992a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 31 Jul 2017 11:48:15 +0200 Subject: [PATCH 035/301] core: don't call onremove on the children passed to components that return from their view, fix #1921 --- docs/change-log.md | 1 + render/render.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index cb2fabf0..9df82039 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -24,6 +24,7 @@ #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +- core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) --- diff --git a/render/render.js b/render/render.js index e24a76eb..6bebd212 100644 --- a/render/render.js +++ b/render/render.js @@ -451,9 +451,10 @@ module.exports = function($window) { } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") vnode.attrs.onremove.call(vnode.state, vnode) - if (typeof vnode.tag !== "string" && typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) - if (vnode.instance != null) onremove(vnode.instance) - else { + if (typeof vnode.tag !== "string") { + if (typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) + if (vnode.instance != null) onremove(vnode.instance) + } else { var children = vnode.children if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { From 6f77450d03d997da80e9a344648e4d06fab40f14 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 31 Jul 2017 10:15:31 +0000 Subject: [PATCH 036/301] Bundled output for commit 157fb7d446ff097f98b1582ada3526d12de6600d [skip ci] --- mithril.js | 7 ++++--- mithril.min.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mithril.js b/mithril.js index 6fbf4ff8..77e3c6d9 100644 --- a/mithril.js +++ b/mithril.js @@ -806,9 +806,10 @@ var coreRenderer = function($window) { } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") vnode.attrs.onremove.call(vnode.state, vnode) - if (typeof vnode.tag !== "string" && typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) - if (vnode.instance != null) onremove(vnode.instance) - else { + if (typeof vnode.tag !== "string") { + if (typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) + if (vnode.instance != null) onremove(vnode.instance) + } else { var children = vnode.children if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { diff --git a/mithril.min.js b/mithril.min.js index c9fd686f..c68ee276 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -27,7 +27,7 @@ a.text):(null!=c.text&&(c.children=[z("#",void 0,void 0,c.text,void 0,c.dom.firs a.dom=a.instance.dom,a.domSize=a.instance.domSize):null!=c.instance?(y(c.instance,null),a.dom=void 0,a.domSize=0):(a.dom=c.dom,a.domSize=c.domSize)}}else y(c,null),e(k,a,b,m,d)}function r(a){var c=a.domSize;if(null!=c||null==a.dom){var b=x.createDocumentFragment();if(0 Date: Mon, 31 Jul 2017 12:28:40 +0200 Subject: [PATCH 037/301] Move the #1921/#1922 line into the v1.1.4 change set --- docs/change-log.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 9df82039..64c727c8 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,5 +1,7 @@ # Change log +- [v2.0.0](#v113) +- [v1.1.4](#v113) - [v1.1.3](#v113) - [v1.1.2](#v112) - [v1.1.1](#v111) @@ -24,6 +26,13 @@ #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) + +--- + +### v1.1.4 + +#### Bug fixes: + - core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) --- From fecee45a829efe225f74b300fa1e312dba2601ca Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Mon, 31 Jul 2017 06:38:36 -0400 Subject: [PATCH 038/301] Add me as a `render/` owner [skip ci] --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 30c39524..ab8484ef 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,3 +9,4 @@ package.json @tivac README.md @tivac docs/ @tivac performance/ @tivac +render/ @isiahmeadows From b4856a9ecd946356e882f1b6b7d7c368aa537e40 Mon Sep 17 00:00:00 2001 From: tkilliansc Date: Thu, 3 Aug 2017 13:48:19 -0700 Subject: [PATCH 039/301] fix issue 1919 --- docs/change-log.md | 1 + request/request.js | 4 ++-- test-utils/tests/test-xhrMock.js | 8 ++++++++ test-utils/xhrMock.js | 12 +++++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index cb2fabf0..de0b3769 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -24,6 +24,7 @@ #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +- API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) --- diff --git a/request/request.js b/request/request.js index ac5f3391..7e4ec744 100644 --- a/request/request.js +++ b/request/request.js @@ -67,10 +67,10 @@ module.exports = function($window, Promise) { xhr.open(args.method, args.url, typeof args.async === "boolean" ? args.async : true, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined) - if (args.serialize === JSON.stringify && useBody) { + if (args.serialize === JSON.stringify && useBody && !(args.headers && args.headers.hasOwnProperty("Content-Type"))) { xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8") } - if (args.deserialize === deserialize) { + if (args.deserialize === deserialize && !(args.headers && args.headers.hasOwnProperty("Accept"))) { xhr.setRequestHeader("Accept", "application/json, text/*") } if (args.withCredentials) xhr.withCredentials = args.withCredentials diff --git a/test-utils/tests/test-xhrMock.js b/test-utils/tests/test-xhrMock.js index 8bdfcf21..8c64a308 100644 --- a/test-utils/tests/test-xhrMock.js +++ b/test-utils/tests/test-xhrMock.js @@ -72,6 +72,14 @@ o.spec("xhrMock", function() { } xhr.send("a=b") }) + o("Setting a header twice merges the header", function() { + // Source: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader + var xhr = new $window.XMLHttpRequest() + xhr.open("POST", "/test") + xhr.setRequestHeader("Content-Type", "foo") + xhr.setRequestHeader("Content-Type", "bar") + o(xhr.getRequestHeader("Content-Type")).equals("foo, bar") + }) }) o.spec("jsonp", function() { o("works", function(done) { diff --git a/test-utils/xhrMock.js b/test-utils/xhrMock.js index d3bbf5b8..379bce28 100644 --- a/test-utils/xhrMock.js +++ b/test-utils/xhrMock.js @@ -17,7 +17,17 @@ module.exports = function() { var headers = {} var aborted = false this.setRequestHeader = function(header, value) { - headers[header] = value + /* + the behavior of setHeader is not your expected setX API. + If the header is already set, it'll merge with whatever you add + rather than overwrite + Source: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader + */ + if (headers[header]) { + headers[header] += ", " + value; + } else { + headers[header] = value + } } this.getRequestHeader = function(header) { return headers[header] From 771dcd4738ff21468489cff015ae293b63b31777 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Thu, 3 Aug 2017 23:07:49 +0000 Subject: [PATCH 040/301] Bundled output for commit 2032131340e51aa12ada12b89099c00de5b9d6e8 [skip ci] --- README.md | 2 +- mithril.js | 4 +-- mithril.min.js | 66 +++++++++++++++++++++++++------------------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 4638fa31..0e5959d8 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.22 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.25 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 77e3c6d9..f6bd38af 100644 --- a/mithril.js +++ b/mithril.js @@ -274,10 +274,10 @@ var _8 = function($window, Promise) { _abort.call(xhr) } xhr.open(args.method, args.url, typeof args.async === "boolean" ? args.async : true, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined) - if (args.serialize === JSON.stringify && useBody) { + if (args.serialize === JSON.stringify && useBody && !(args.headers && args.headers.hasOwnProperty("Content-Type"))) { xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8") } - if (args.deserialize === deserialize) { + if (args.deserialize === deserialize && !(args.headers && args.headers.hasOwnProperty("Accept"))) { xhr.setRequestHeader("Accept", "application/json, text/*") } if (args.withCredentials) xhr.withCredentials = args.withCredentials diff --git a/mithril.min.js b/mithril.min.js index c68ee276..edc24225 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -9,36 +9,36 @@ g[h]=b;n===l&&d(g)}null==b[h]||"object"!==typeof b[h]&&"function"!==typeof b[h]| 0;ha.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText);k.code= -m.status;k.response=b;e(k)}}catch(c){e(c)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:p(y)},jsonp:function(a,h){var r=e();a=l(a,h);var p=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=n(a.url, -a.data);a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&p>=c.length-y.length||null==y&&b;p++;B++;h(k,t,u,l,f(c,p,g),x,n);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;Cm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText);k.code=m.status;k.response=b;e(k)}}catch(c){e(c)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:p(y)},jsonp:function(a,h){var r=e();a=l(a,h);var p=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l); +e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=n(a.url,a.data);a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&p>=c.length-y.length||null==y&&b;p++;B++;h(k,t,u,l,f(c,p,g),x,n);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length- +y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;C Date: Sun, 6 Aug 2017 22:18:57 -0700 Subject: [PATCH 041/301] chore: ignore test-ospec when checking PRs --- dangerfile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dangerfile.js b/dangerfile.js index 89ea4277..bd9cd30b 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -43,6 +43,8 @@ if(appfiles.length && !changelog) { // Call out if `o.only(...)` was left in jsfiles .filter((file) => file.indexOf("tests/") > -1) + // Have to exclude test-ospec.js because it specifically has a purposeful "o.only" in it + .filter((file) => file.indexOf("test-ospec") === -1) .forEach((file) => { var code = fs.readFileSync(file, "utf8"), locs = locater.find("o.only", code); From 1e56f7763e85ff6f0178fc12a0f9a01c56b41503 Mon Sep 17 00:00:00 2001 From: spacejack Date: Sun, 13 Aug 2017 18:32:32 -0400 Subject: [PATCH 042/301] More accurate style object diffs --- render/render.js | 12 ++++++++++++ render/tests/test-updateElement.js | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/render/render.js b/render/render.js index 6bebd212..40eca443 100644 --- a/render/render.js +++ b/render/render.js @@ -552,6 +552,18 @@ module.exports = function($window) { //style function updateStyle(element, old, style) { + if (old != null && style != null && typeof old === "object" && typeof style === "object" && style !== old) { + // Both old & new are (different) objects. + // Update style properties that have changed + for (var key in style) { + if (style[key] !== old[key]) element.style[key] = style[key] + } + // Remove style properties that no longer exist + for (var key in old) { + if (!(key in style)) element.style[key] = "" + } + return + } if (old === style) element.style.cssText = "", old = null if (style == null) element.style.cssText = "" else if (typeof style === "string") element.style.cssText = style diff --git a/render/tests/test-updateElement.js b/render/tests/test-updateElement.js index 313fe1a9..a2ae0fcb 100644 --- a/render/tests/test-updateElement.js +++ b/render/tests/test-updateElement.js @@ -192,6 +192,19 @@ o.spec("updateElement", function() { o(updated.dom.style.backgroundColor).equals("") o(updated.dom.style.color).equals("gold") }) + o("does not re-render element styles for equivalent style objects", function() { + var style = {color: "gold"} + var vnode = {tag: "a", attrs: {style: style}} + + render(root, [vnode]) + + root.firstChild.style.color = "red" + style = {color: "gold"} + var updated = {tag: "a", attrs: {style: style}} + render(root, [updated]) + + o(updated.dom.style.color).equals("red") + }) o("replaces el", function() { var vnode = {tag: "a"} var updated = {tag: "b"} From ae0b7915300881d8c5a685d8df36176416a70879 Mon Sep 17 00:00:00 2001 From: spacejack Date: Tue, 15 Aug 2017 15:53:23 -0400 Subject: [PATCH 043/301] Eleminate now-redundant if block. Add change-log notes. --- docs/change-log.md | 1 + render/render.js | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 6ea8b86a..82686f0e 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -27,6 +27,7 @@ - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) +- API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. --- diff --git a/render/render.js b/render/render.js index 40eca443..f6782297 100644 --- a/render/render.js +++ b/render/render.js @@ -572,11 +572,6 @@ module.exports = function($window) { for (var key in style) { element.style[key] = style[key] } - if (old != null && typeof old !== "string") { - for (var key in old) { - if (!(key in style)) element.style[key] = "" - } - } } } From 96aa1853020998c584a22883fe8b417bc82b0c89 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Wed, 16 Aug 2017 07:14:17 +0000 Subject: [PATCH 044/301] Bundled output for commit 457dd92d467045b04fbbc1d1bb13e50b4c8f0a8c [skip ci] --- README.md | 2 +- mithril.js | 17 +++++++--- mithril.min.js | 88 +++++++++++++++++++++++++------------------------- 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 0e5959d8..6ddbbb0a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.25 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.29 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index f6bd38af..e2c8944e 100644 --- a/mithril.js +++ b/mithril.js @@ -905,6 +905,18 @@ var coreRenderer = function($window) { } //style function updateStyle(element, old, style) { + if (old != null && style != null && typeof old === "object" && typeof style === "object" && style !== old) { + // Both old & new are (different) objects. + // Update style properties that have changed + for (var key2 in style) { + if (style[key2] !== old[key2]) element.style[key2] = style[key2] + } + // Remove style properties that no longer exist + for (var key2 in old) { + if (!(key2 in style)) element.style[key2] = "" + } + return + } if (old === style) element.style.cssText = "", old = null if (style == null) element.style.cssText = "" else if (typeof style === "string") element.style.cssText = style @@ -913,11 +925,6 @@ var coreRenderer = function($window) { for (var key2 in style) { element.style[key2] = style[key2] } - if (old != null && typeof old !== "string") { - for (var key2 in old) { - if (!(key2 in style)) element.style[key2] = "" - } - } } } //event diff --git a/mithril.min.js b/mithril.min.js index edc24225..05686d0c 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,44 +1,44 @@ -(function(){function z(b,d,e,l,n,g){return{tag:b,key:d,attrs:e,children:l,text:n,dom:g,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function A(b){var d,e=arguments[1],l=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&!(d=M[b])){var n="div";for(var g=[],h={};d=Q.exec(b);){var r=d[1],f=d[2];""===r&&""!==f?n=f:"#"===r?h.id=f:"."===r?g.push(f): -"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?g.push(r):h[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} -function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText);k.code=m.status;k.response=b;e(k)}}catch(c){e(c)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:p(y)},jsonp:function(a,h){var r=e();a=l(a,h);var p=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l); -e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=n(a.url,a.data);a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&p>=c.length-y.length||null==y&&b;p++;B++;h(k,t,u,l,f(c,p,g),x,n);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length- -y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,n),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;Ca.indexOf("?")?"?":"&";a+=f+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText} +function g(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dn.status||304===n.status||S.test(a.url))d(g(a.type,b));else{var l=Error(n.responseText);l.code=n.status;l.response=b;f(l)}}catch(c){f(c)}};m&&null!=a.data?n.send(a.data):n.send()});return!0===a.background?z:p(z)},jsonp:function(a,k){var r=f();a=m(a,k);var p=new d(function(d,f){var k=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+n++,m=b.document.createElement("script");b[k]=function(f){m.parentNode.removeChild(m);d(g(a.type,f));delete b[k]};m.onerror=function(){m.parentNode.removeChild(m); +f(Error("JSONP request failed"));delete b[k]};null==a.data&&(a.data={});a.url=q(a.url,a.data);a.data[a.callbackKey||"callback"]=k;m.src=h(a.url,a.data);b.document.documentElement.appendChild(m)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(l,c,e,a,b,d,g){for(;e=p&&E>=B;){var u=c[p];t=e[B];if(u!==t||b)if(null==u)p++;else if(null==t)B++;else if(u.key===t.key){var x=null!=z&&p>=c.length-z.length||null==z&&b;p++;B++;k(l,u,t,m,g(c,p,h),x,q);b&&u.tag===t.tag&&n(l,r(u),h)}else if(u=c[v],u!==t||b)if(null==u)v--;else if(null==t)B++;else if(u.key===t.key)x=null!=z&&v>=c.length- +z.length||null==z&&b,k(l,u,t,m,g(c,v+1,h),x,q),(b||B=p&&E>=B;){u=c[v];t=e[E];if(u!==t||b)if(null==u)v--;else{if(null!=t)if(u.key===t.key)x=null!=z&&v>=c.length-z.length||null==z&&b,k(l,u,t,m,g(c,v+1,h),x,q),b&&u.tag===t.tag&&n(l,r(u),h),null!=u.dom&&(h=u.dom),v--;else{if(!F){F=c;x=v;u={};var w;for(w=0;w Date: Fri, 18 Aug 2017 23:02:38 -0700 Subject: [PATCH 045/301] docs: Fix typo (#1940) --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index a8f7a2fe..8706119e 100644 --- a/docs/route.md +++ b/docs/route.md @@ -107,7 +107,7 @@ This function can be used as the `oncreate` (and `onupdate`) hook in a `m("a")` m("a[href=/]", {oncreate: m.route.link})`. ``` -Using `m.route.link` as a `oncreate` hook causes the link to behave as a router link (i.e. it navigates to the route specified in `href`, instead of nagivating away from the current page to the URL specified in `href`. +Using `m.route.link` as a `oncreate` hook causes the link to behave as a router link (i.e. it navigates to the route specified in `href`, instead of navigating away from the current page to the URL specified in `href`. If the `href` attribute is not static, the `onupdate` hook must also be set: From 9e6b175519dbcc78303d7315ffb08c6a53488156 Mon Sep 17 00:00:00 2001 From: Ilya Sarantsev Date: Mon, 21 Aug 2017 18:55:42 +0300 Subject: [PATCH 046/301] Handle shared attributes object in hyperscript (#1941) --- docs/change-log.md | 1 + render/hyperscript.js | 12 ++++++++++++ render/tests/test-hyperscript.js | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 82686f0e..e73ff1b6 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -36,6 +36,7 @@ #### Bug fixes: - core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) +- hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) --- diff --git a/render/hyperscript.js b/render/hyperscript.js index 5b5fda29..ea56c893 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -28,6 +28,18 @@ function execSelector(state, attrs, children) { var hasAttrs = false, childList, text var className = attrs.className || attrs.class + if (Object.keys(state.attrs).length && Object.keys(attrs).length) { + var newAttrs = {} + + for(var key in attrs) { + if (hasOwn.call(attrs, key)) { + newAttrs[key] = attrs[key] + } + } + + attrs = newAttrs + } + for (var key in state.attrs) { if (hasOwn.call(state.attrs, key)) { attrs[key] = state.attrs[key] diff --git a/render/tests/test-hyperscript.js b/render/tests/test-hyperscript.js index 498a9dbf..f7c5f889 100644 --- a/render/tests/test-hyperscript.js +++ b/render/tests/test-hyperscript.js @@ -507,6 +507,23 @@ o.spec("hyperscript", function() { o(vnode.children[0].tag).equals("i") o(vnode.children[1].tag).equals("s") }) + o("handles shared attrs", function() { + var attrs = {a: "b"} + + var nodeA = m(".a", attrs) + var nodeB = m(".b", attrs) + + o(nodeA.attrs.className).equals("a") + o(nodeA.attrs.a).equals("b") + + o(nodeB.attrs.className).equals("b") + o(nodeB.attrs.a).equals("b") + }) + o("doesnt modify passed attributes object", function() { + var attrs = {a: "b"} + m(".a", attrs) + o(attrs).deepEquals({a: "b"}) + }) o("handles fragment children without attr unwrapped", function() { var vnode = m("div", [m("i")], [m("s")]) From 44c89f32571291bd052fd0b2cd1e47507d78bbbf Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Tue, 1 Aug 2017 20:06:48 -0400 Subject: [PATCH 047/301] Update package lockfile and danger/lint-staged --- .npmignore | 1 + package-lock.json | 1804 +++++++-------------------------------------- package.json | 4 +- 3 files changed, 249 insertions(+), 1560 deletions(-) diff --git a/.npmignore b/.npmignore index bf023d92..d81ad888 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ .gitignore .travis.yml CONTRIBUTING.md +yarn.lock diff --git a/package-lock.json b/package-lock.json index 4dbd54bd..7b4aff41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,7 +2,6 @@ "name": "mithril", "version": "1.1.3", "lockfileVersion": 1, - "requires": true, "dependencies": { "@alrra/travis-scripts": { "version": "3.0.1", @@ -32,19 +31,13 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "dev": true, - "requires": { - "acorn": "4.0.13" - } + "dev": true }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, - "requires": { - "acorn": "3.3.0" - }, "dependencies": { "acorn": { "version": "3.3.0", @@ -58,21 +51,13 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "dev": true, - "requires": { - "extend": "3.0.1", - "semver": "5.0.3" - } + "dev": true }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } + "dev": true }, "ajv-keywords": { "version": "1.5.1", @@ -84,12 +69,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" - } + "dev": true }, "amdefine": { "version": "1.0.1", @@ -115,21 +95,11 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, "anymatch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", - "dev": true, - "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11" - } + "dev": true }, "app-root-path": { "version": "2.0.1", @@ -141,19 +111,13 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true, - "requires": { - "sprintf-js": "1.0.3" - } + "dev": true }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "1.1.0" - } + "dev": true }, "arr-flatten": { "version": "1.1.0", @@ -171,10 +135,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "1.0.3" - } + "dev": true }, "array-uniq": { "version": "1.0.3", @@ -210,10 +171,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", - "dev": true, - "requires": { - "lodash": "4.17.4" - } + "dev": true }, "asynckit": { "version": "0.4.0", @@ -237,39 +195,13 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } + "dev": true }, "babel-core": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", "dev": true, - "requires": { - "babel-code-frame": "6.22.0", - "babel-generator": "6.25.0", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.24.1", - "babel-runtime": "6.23.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "convert-source-map": "1.5.0", - "debug": "2.6.8", - "json5": "0.5.1", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.7", - "slash": "1.0.0", - "source-map": "0.5.6" - }, "dependencies": { "source-map": { "version": "0.5.6", @@ -284,16 +216,6 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", "dev": true, - "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.23.0", - "babel-types": "6.25.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.6", - "trim-right": "1.0.1" - }, "dependencies": { "source-map": { "version": "0.5.6", @@ -307,42 +229,25 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "babel-template": "6.25.0" - } + "dev": true }, "babel-jest": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-plugin-istanbul": "4.1.4", - "babel-preset-jest": "20.0.3" - } + "dev": true }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0" - } + "dev": true }, "babel-plugin-istanbul": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", - "dev": true, - "requires": { - "find-up": "2.1.0", - "istanbul-lib-instrument": "1.7.4", - "test-exclude": "4.1.1" - } + "dev": true }, "babel-plugin-jest-hoist": { "version": "20.0.3", @@ -354,88 +259,43 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "core-js": "2.4.1", - "regenerator-runtime": "0.10.5" - } + "dev": true }, "babel-preset-jest": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "20.0.3" - } + "dev": true }, "babel-register": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-runtime": "6.23.0", - "core-js": "2.4.1", - "home-or-tmp": "2.0.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "source-map-support": "0.4.15" - } + "dev": true }, "babel-runtime": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", - "dev": true, - "requires": { - "core-js": "2.4.1", - "regenerator-runtime": "0.10.5" - } + "dev": true }, "babel-template": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "lodash": "4.17.4" - } + "dev": true }, "babel-traverse": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", - "dev": true, - "requires": { - "babel-code-frame": "6.22.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.23.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "debug": "2.6.8", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" - } + "dev": true }, "babel-types": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" - } + "dev": true }, "babylon": { "version": "6.17.4", @@ -454,59 +314,37 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } + "optional": true }, "benchmark": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", - "dev": true, - "requires": { - "lodash": "4.17.4", - "platform": "1.3.4" - } + "dev": true }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } + "dev": true }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } + "dev": true }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" - } + "dev": true }, "browser-resolve": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", "dev": true, - "requires": { - "resolve": "1.1.7" - }, "dependencies": { "resolve": { "version": "1.1.7", @@ -520,10 +358,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", - "dev": true, - "requires": { - "node-int64": "0.4.0" - } + "dev": true }, "builtin-modules": { "version": "1.1.1", @@ -535,10 +370,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "0.2.0" - } + "dev": true }, "callsites": { "version": "0.2.0", @@ -563,24 +395,13 @@ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "optional": true, - "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" - } + "optional": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } + "dev": true }, "circular-json": { "version": "0.3.1", @@ -592,10 +413,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "1.0.1" - } + "dev": true }, "cli-spinners": { "version": "0.1.2", @@ -607,11 +425,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "1.0.2" - } + "dev": true }, "cli-width": { "version": "2.1.0", @@ -623,12 +437,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - } + "dev": true }, "co": { "version": "4.6.0", @@ -646,19 +455,13 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz", "integrity": "sha1-HyMCay7zb5J+7MkB6ZxfDUj6M04=", - "dev": true, - "requires": { - "weak-map": "1.0.0" - } + "dev": true }, "color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } + "dev": true }, "color-name": { "version": "1.1.3", @@ -670,10 +473,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } + "dev": true }, "commander": { "version": "2.11.0", @@ -691,12 +491,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" - } + "dev": true }, "content-type-parser": { "version": "1.0.1", @@ -727,16 +522,6 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-1.1.0.tgz", "integrity": "sha1-DeoPmATv37kp+7GxiOJVU+oFPTc=", "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "js-yaml": "3.9.0", - "minimist": "1.2.0", - "object-assign": "4.1.1", - "os-homedir": "1.0.2", - "parse-json": "2.2.0", - "pinkie-promise": "2.0.1", - "require-from-string": "1.2.1" - }, "dependencies": { "minimist": { "version": "1.2.0", @@ -750,21 +535,13 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.2.14" - } + "dev": true }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } + "dev": true }, "cssom": { "version": "0.3.2", @@ -776,45 +553,38 @@ "version": "0.2.37", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", - "dev": true, - "requires": { - "cssom": "0.3.2" - } + "dev": true }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true, - "requires": { - "es5-ext": "0.10.24" - } + "dev": true }, "danger": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/danger/-/danger-1.0.0.tgz", - "integrity": "sha512-q3tpcDOS93gETx9bLZmPRqw4kke/eX7chJvX7KwDymFHM1DvQWPLye91yVb8q15IoQg9uGHb1rP+UjXWJ3RBfg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/danger/-/danger-1.2.0.tgz", + "integrity": "sha512-uFZb/QIGMnuHgireqI1Nu0pLoYGOtCj7E5DD8wUkNyRq0LjDiz3P2M5SMjbgparl8BG+suqmWc+fo3VksSJJnw==", "dev": true, - "requires": { - "babel-polyfill": "6.23.0", - "chalk": "1.1.3", - "commander": "2.11.0", - "debug": "2.6.8", - "dtslint": "0.1.2", - "github": "9.2.0", - "jest-config": "20.0.4", - "jest-environment-node": "20.0.3", - "jest-runtime": "20.0.4", - "jsome": "2.3.26", - "jsonpointer": "4.0.1", - "lodash.find": "4.6.0", - "lodash.includes": "4.3.0", - "lodash.isobject": "2.4.1", - "lodash.keys": "4.2.0", - "node-fetch": "1.7.1", - "parse-diff": "0.4.0", - "rfc6902": "1.3.0", - "voca": "1.3.0" + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "dev": true + } } }, "dashdash": { @@ -822,9 +592,6 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -844,10 +611,7 @@ "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } + "dev": true }, "decamelize": { "version": "1.2.0", @@ -871,16 +635,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.1" - } + "dev": true }, "delayed-stream": { "version": "1.0.0", @@ -892,10 +647,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } + "dev": true }, "diff": { "version": "3.3.0", @@ -907,34 +659,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - }, - "dtslint": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-0.1.2.tgz", - "integrity": "sha1-V0vrcmM/RSaJYF3hgG2mKBRSrC4=", - "dev": true, - "optional": true, - "requires": { - "fs-promise": "2.0.3", - "parsimmon": "1.6.2", - "strip-json-comments": "2.0.1", - "tsutils": "1.9.1" - } + "dev": true }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } + "optional": true }, "elegant-spinner": { "version": "1.0.1", @@ -946,98 +678,55 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "0.4.13" - } + "dev": true }, "errno": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "dev": true, - "requires": { - "prr": "0.0.0" - } + "dev": true }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } + "dev": true }, "es5-ext": { "version": "0.10.24", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", - "dev": true, - "requires": { - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } + "dev": true }, "es6-iterator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-symbol": "3.1.1" - } + "dev": true }, "es6-map": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } + "dev": true }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } + "dev": true }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" - } + "dev": true }, "es6-weak-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -1049,26 +738,13 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "2.7.3", - "estraverse": "1.9.3", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.2.0" - } + "dev": true }, "escope": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, - "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -1083,43 +759,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, - "requires": { - "babel-code-frame": "6.22.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.6.8", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.4.3", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.3", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.0", - "is-resolvable": "1.0.0", - "js-yaml": "3.9.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" - }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -1134,10 +773,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", "dev": true, - "requires": { - "acorn": "5.1.1", - "acorn-jsx": "3.0.1" - }, "dependencies": { "acorn": { "version": "5.1.1", @@ -1158,9 +793,6 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, - "requires": { - "estraverse": "4.2.0" - }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -1175,10 +807,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, - "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" - }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -1204,35 +832,13 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" - } + "dev": true }, "exec-sh": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", - "dev": true, - "requires": { - "merge": "1.2.0" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - } + "dev": true }, "exit-hook": { "version": "1.1.1", @@ -1244,19 +850,13 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "0.1.1" - } + "dev": true }, "expand-range": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "2.2.3" - } + "dev": true }, "extend": { "version": "3.0.1", @@ -1268,10 +868,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } + "dev": true }, "extsprintf": { "version": "1.0.2", @@ -1289,30 +886,19 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "2.0.0" - } + "dev": true }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" - } + "dev": true }, "file-entry-cache": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "1.2.2", - "object-assign": "4.1.1" - } + "dev": true }, "filename-regex": { "version": "2.0.1", @@ -1324,45 +910,25 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - } + "dev": true }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - } + "dev": true }, "flat-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true, - "requires": { - "circular-json": "0.3.1", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } + "dev": true }, "follow-redirects": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", - "dev": true, - "requires": { - "debug": "2.6.8", - "stream-consume": "0.1.0" - } + "dev": true }, "for-in": { "version": "1.0.2", @@ -1374,10 +940,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } + "dev": true }, "forever-agent": { "version": "0.6.1", @@ -1389,36 +952,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs-extra": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", - "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "2.4.0" - } - }, - "fs-promise": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fs-promise/-/fs-promise-2.0.3.tgz", - "integrity": "sha1-9k5PhUvPaJqovdy6JokW2z20aFQ=", - "dev": true, - "optional": true, - "requires": { - "any-promise": "1.3.0", - "fs-extra": "2.1.2", - "mz": "2.6.0", - "thenify-all": "1.6.0" - } + "dev": true }, "fs.realpath": { "version": "1.0.0", @@ -1436,10 +970,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "1.0.2" - } + "dev": true }, "get-caller-file": { "version": "1.0.2", @@ -1458,9 +989,6 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -1475,37 +1003,18 @@ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.12.0.tgz", "integrity": "sha1-2VHj7Zi4VpnUsEGOsaFbGgSYjcE=", "dev": true, - "requires": { - "async": "2.1.2", - "commander": "2.9.0", - "globby": "6.1.0", - "graceful-fs": "4.1.10", - "q": "1.4.1", - "q-io": "1.13.2", - "rimraf": "2.6.1" - }, "dependencies": { "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } + "dev": true }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "1.0.2", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } + "dev": true }, "graceful-fs": { "version": "4.1.10", @@ -1519,46 +1028,25 @@ "version": "9.2.0", "resolved": "https://registry.npmjs.org/github/-/github-9.2.0.tgz", "integrity": "sha1-iohtxA3WNjZwfcr5nfPfJsWfFvw=", - "dev": true, - "requires": { - "follow-redirects": "0.0.7", - "https-proxy-agent": "1.0.0", - "mime": "1.3.6", - "netrc": "0.1.4" - } + "dev": true }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } + "dev": true }, "glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" - } + "dev": true }, "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "2.0.1" - } + "dev": true }, "globals": { "version": "9.18.0", @@ -1570,15 +1058,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } + "dev": true }, "graceful-fs": { "version": "4.1.11", @@ -1597,12 +1077,6 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, - "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" - }, "dependencies": { "async": { "version": "1.5.2", @@ -1614,10 +1088,7 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } + "dev": true } } }, @@ -1631,32 +1102,25 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } + "dev": true }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } + "dev": true }, "hoek": { "version": "2.16.3", @@ -1668,11 +1132,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } + "dev": true }, "hosted-git-info": { "version": "2.5.0", @@ -1684,32 +1144,19 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", - "dev": true, - "requires": { - "whatwg-encoding": "1.0.1" - } + "dev": true }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.1" - } + "dev": true }, "https-proxy-agent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dev": true, - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.8", - "extend": "3.0.1" - } + "dev": true }, "iconv-lite": { "version": "0.4.13", @@ -1733,20 +1180,13 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } + "dev": true }, "inherits": { "version": "2.0.3", @@ -1758,22 +1198,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.1.0", - "figures": "1.7.0", - "lodash": "4.17.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" - } + "dev": true }, "interpret": { "version": "1.0.3", @@ -1785,10 +1210,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "requires": { - "loose-envify": "1.3.1" - } + "dev": true }, "invert-kv": { "version": "1.0.0", @@ -1812,10 +1234,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - } + "dev": true }, "is-dotfile": { "version": "1.0.3", @@ -1827,10 +1246,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "2.0.0" - } + "dev": true }, "is-extendable": { "version": "0.1.1", @@ -1848,49 +1264,31 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } + "dev": true }, "is-my-json-valid": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", - "dev": true, - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" - } + "dev": true }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } + "dev": true }, "is-path-cwd": { "version": "1.0.0", @@ -1902,19 +1300,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true, - "requires": { - "is-path-inside": "1.0.0" - } + "dev": true }, "is-path-inside": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "dev": true, - "requires": { - "path-is-inside": "1.0.2" - } + "dev": true }, "is-posix-bracket": { "version": "0.1.1", @@ -1944,10 +1336,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true, - "requires": { - "tryit": "1.0.3" - } + "dev": true }, "is-stream": { "version": "1.1.0", @@ -1983,10 +1372,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } + "dev": true }, "isstream": { "version": "0.1.2", @@ -1999,22 +1385,6 @@ "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, - "requires": { - "abbrev": "1.0.9", - "async": "1.5.2", - "escodegen": "1.8.1", - "esprima": "2.7.3", - "glob": "5.0.15", - "handlebars": "4.0.10", - "js-yaml": "3.9.0", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "once": "1.4.0", - "resolve": "1.1.7", - "supports-color": "3.2.3", - "which": "1.2.14", - "wordwrap": "1.0.0" - }, "dependencies": { "async": { "version": "1.5.2", @@ -2032,14 +1402,7 @@ "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } + "dev": true }, "resolve": { "version": "1.1.7", @@ -2052,9 +1415,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, - "requires": { - "has-flag": "1.0.0" - }, "dependencies": { "has-flag": { "version": "1.0.0", @@ -2077,15 +1437,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.4.tgz", "integrity": "sha1-6f2SDkdn89Ge3HZeLWs/XMvQ7qg=", "dev": true, - "requires": { - "babel-generator": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "istanbul-lib-coverage": "1.1.1", - "semver": "5.3.0" - }, "dependencies": { "semver": { "version": "5.3.0", @@ -2099,31 +1450,13 @@ "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "glob": "7.1.2", - "jest-environment-jsdom": "20.0.3", - "jest-environment-node": "20.0.3", - "jest-jasmine2": "20.0.4", - "jest-matcher-utils": "20.0.3", - "jest-regex-util": "20.0.3", - "jest-resolve": "20.0.4", - "jest-validate": "20.0.3", - "pretty-format": "20.0.3" - } + "dev": true }, "jest-diff": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "diff": "3.3.0", - "jest-matcher-utils": "20.0.3", - "pretty-format": "20.0.3" - } + "dev": true }, "jest-docblock": { "version": "20.0.3", @@ -2135,86 +1468,43 @@ "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", - "dev": true, - "requires": { - "jest-mock": "20.0.3", - "jest-util": "20.0.3", - "jsdom": "9.12.0" - } + "dev": true }, "jest-environment-node": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", - "dev": true, - "requires": { - "jest-mock": "20.0.3", - "jest-util": "20.0.3" - } + "dev": true }, "jest-haste-map": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.4.tgz", "integrity": "sha1-ZT61XIic48Ah97lGk/IKQVm63wM=", - "dev": true, - "requires": { - "fb-watchman": "2.0.0", - "graceful-fs": "4.1.11", - "jest-docblock": "20.0.3", - "micromatch": "2.3.11", - "sane": "1.6.0", - "worker-farm": "1.4.1" - } + "dev": true }, "jest-jasmine2": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "graceful-fs": "4.1.11", - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-matchers": "20.0.3", - "jest-message-util": "20.0.3", - "jest-snapshot": "20.0.3", - "once": "1.4.0", - "p-map": "1.1.1" - } + "dev": true }, "jest-matcher-utils": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "pretty-format": "20.0.3" - } + "dev": true }, "jest-matchers": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", - "dev": true, - "requires": { - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-message-util": "20.0.3", - "jest-regex-util": "20.0.3" - } + "dev": true }, "jest-message-util": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "micromatch": "2.3.11", - "slash": "1.0.0" - } + "dev": true }, "jest-mock": { "version": "20.0.3", @@ -2232,76 +1522,31 @@ "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", - "dev": true, - "requires": { - "browser-resolve": "1.11.2", - "is-builtin-module": "1.0.0", - "resolve": "1.3.3" - } + "dev": true }, "jest-runtime": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-jest": "20.0.3", - "babel-plugin-istanbul": "4.1.4", - "chalk": "1.1.3", - "convert-source-map": "1.5.0", - "graceful-fs": "4.1.11", - "jest-config": "20.0.4", - "jest-haste-map": "20.0.4", - "jest-regex-util": "20.0.3", - "jest-resolve": "20.0.4", - "jest-util": "20.0.3", - "json-stable-stringify": "1.0.1", - "micromatch": "2.3.11", - "strip-bom": "3.0.0", - "yargs": "7.1.0" - } + "dev": true }, "jest-snapshot": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-util": "20.0.3", - "natural-compare": "1.4.0", - "pretty-format": "20.0.3" - } + "dev": true }, "jest-util": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "graceful-fs": "4.1.11", - "jest-message-util": "20.0.3", - "jest-mock": "20.0.3", - "jest-validate": "20.0.3", - "leven": "2.1.0", - "mkdirp": "0.5.1" - } + "dev": true }, "jest-validate": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "jest-matcher-utils": "20.0.3", - "leven": "2.1.0", - "pretty-format": "20.0.3" - } + "dev": true }, "js-tokens": { "version": "3.0.2", @@ -2314,10 +1559,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz", "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", "dev": true, - "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" - }, "dependencies": { "esprima": { "version": "4.0.0", @@ -2338,28 +1579,7 @@ "version": "9.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", - "dev": true, - "requires": { - "abab": "1.0.3", - "acorn": "4.0.13", - "acorn-globals": "3.1.0", - "array-equal": "1.0.0", - "content-type-parser": "1.0.1", - "cssom": "0.3.2", - "cssstyle": "0.2.37", - "escodegen": "1.8.1", - "html-encoding-sniffer": "1.0.1", - "nwmatcher": "1.4.1", - "parse5": "1.5.1", - "request": "2.81.0", - "sax": "1.2.4", - "symbol-tree": "3.2.2", - "tough-cookie": "2.3.2", - "webidl-conversions": "4.0.1", - "whatwg-encoding": "1.0.1", - "whatwg-url": "4.8.0", - "xml-name-validator": "2.0.1" - } + "dev": true }, "jsesc": { "version": "1.3.0", @@ -2372,43 +1592,18 @@ "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.3.26.tgz", "integrity": "sha1-jLRDiSTSyd1SlMkK3wPzVBT7PKk=", "dev": true, - "requires": { - "chalk": "1.1.3", - "json-stringify-safe": "5.0.1", - "yargs": "4.8.1" - }, "dependencies": { "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "dev": true, - "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "lodash.assign": "4.2.0", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "window-size": "0.2.0", - "y18n": "3.2.1", - "yargs-parser": "2.4.1" - } + "dev": true }, "yargs-parser": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "dev": true, - "requires": { - "camelcase": "3.0.0", - "lodash.assign": "4.2.0" - } + "dev": true } } }, @@ -2422,10 +1617,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } + "dev": true }, "json-stringify-safe": { "version": "5.0.1", @@ -2439,16 +1631,6 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "4.1.11" - } - }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -2466,12 +1648,6 @@ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -2485,10 +1661,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.5" - } + "dev": true }, "lazy-cache": { "version": "1.0.4", @@ -2501,10 +1674,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "1.0.0" - } + "dev": true }, "leven": { "version": "2.1.0", @@ -2516,52 +1686,27 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } + "dev": true }, "lint-staged": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.0.2.tgz", - "integrity": "sha1-joPhHp4WVsCbYRf22w1V/UlgocA=", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.0.4.tgz", + "integrity": "sha1-nKaWizDfv+gTZbenY81PSZKJZVM=", "dev": true, - "requires": { - "app-root-path": "2.0.1", - "cosmiconfig": "1.1.0", - "execa": "0.7.0", - "listr": "0.12.0", - "lodash.chunk": "4.2.0", - "minimatch": "3.0.4", - "npm-which": "3.0.1", - "p-map": "1.1.1", - "staged-git-files": "0.0.4" + "dependencies": { + "execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", + "dev": true + } } }, "listr": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "cli-truncate": "0.2.1", - "figures": "1.7.0", - "indent-string": "2.1.0", - "is-promise": "2.1.0", - "is-stream": "1.1.0", - "listr-silent-renderer": "1.1.1", - "listr-update-renderer": "0.2.0", - "listr-verbose-renderer": "0.4.0", - "log-symbols": "1.0.2", - "log-update": "1.0.2", - "ora": "0.2.3", - "p-map": "1.1.1", - "rxjs": "5.4.2", - "stream-to-observable": "0.1.0", - "strip-ansi": "3.0.1" - } + "dev": true }, "listr-silent-renderer": { "version": "1.1.1", @@ -2574,16 +1719,6 @@ "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", "dev": true, - "requires": { - "chalk": "1.1.3", - "cli-truncate": "0.2.1", - "elegant-spinner": "1.0.1", - "figures": "1.7.0", - "indent-string": "3.1.0", - "log-symbols": "1.0.2", - "log-update": "1.0.2", - "strip-ansi": "3.0.1" - }, "dependencies": { "indent-string": { "version": "3.1.0", @@ -2597,35 +1732,19 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz", "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "date-fns": "1.28.5", - "figures": "1.7.0" - } + "dev": true }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - }, "dependencies": { "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "0.2.1" - } + "dev": true } } }, @@ -2633,11 +1752,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - } + "dev": true }, "locater": { "version": "1.3.0", @@ -2685,10 +1800,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "2.4.1" - } + "dev": true }, "lodash.keys": { "version": "4.2.0", @@ -2700,20 +1812,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "1.1.3" - } + "dev": true }, "log-update": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "dev": true, - "requires": { - "ansi-escapes": "1.4.0", - "cli-cursor": "1.0.2" - } + "dev": true }, "longest": { "version": "1.0.1", @@ -2725,29 +1830,19 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "3.0.2" - } + "dev": true }, "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } + "dev": true }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.4" - } + "dev": true }, "marked": { "version": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", @@ -2764,22 +1859,7 @@ "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.3" - } + "dev": true }, "mime": { "version": "1.3.6", @@ -2797,10 +1877,7 @@ "version": "2.1.15", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "dev": true, - "requires": { - "mime-db": "1.27.0" - } + "dev": true }, "mimeparse": { "version": "0.1.4", @@ -2812,10 +1889,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } + "dev": true }, "minimist": { "version": "0.0.8", @@ -2827,10 +1901,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } + "dev": true }, "ms": { "version": "2.0.0", @@ -2844,18 +1915,6 @@ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, - "mz": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.6.0.tgz", - "integrity": "sha1-yLhSHZWN8KTydoAl22nHGe5O8c4=", - "dev": true, - "optional": true, - "requires": { - "any-promise": "1.3.0", - "object-assign": "4.1.1", - "thenify-all": "1.6.0" - } - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2872,11 +1931,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", - "dev": true, - "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" - } + "dev": true }, "node-int64": { "version": "0.4.0", @@ -2888,60 +1943,37 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1.0.9" - } + "dev": true }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.0.3", - "validate-npm-package-license": "3.0.1" - } + "dev": true }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.0.2" - } + "dev": true }, "npm-path": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.3.tgz", "integrity": "sha1-Fc/04ciaONp39W9gVbJPl137K74=", - "dev": true, - "requires": { - "which": "1.2.14" - } + "dev": true }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "2.0.1" - } + "dev": true }, "npm-which": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", - "dev": true, - "requires": { - "commander": "2.11.0", - "npm-path": "2.0.3", - "which": "1.2.14" - } + "dev": true }, "number-is-nan": { "version": "1.0.1", @@ -2971,20 +2003,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" - } + "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } + "dev": true }, "onetime": { "version": "1.1.0", @@ -2997,10 +2022,6 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, - "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" - }, "dependencies": { "wordwrap": { "version": "0.0.3", @@ -3014,27 +2035,13 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } + "dev": true }, "ora": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-spinners": "0.1.2", - "object-assign": "4.1.1" - } + "dev": true }, "os-homedir": { "version": "1.0.2", @@ -3046,10 +2053,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "1.0.0" - } + "dev": true }, "os-tmpdir": { "version": "1.0.2", @@ -3073,10 +2077,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "1.1.0" - } + "dev": true }, "p-map": { "version": "1.1.1", @@ -3094,22 +2095,19 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" - } + "dev": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.1" - } + "dev": true + }, + "parse-link-header": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", + "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", + "dev": true }, "parse5": { "version": "1.5.1", @@ -3117,13 +2115,6 @@ "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", "dev": true }, - "parsimmon": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.6.2.tgz", - "integrity": "sha512-bJNB0ZQhHyM5KqO2Z5ttQAVn/PZ2pccxaOnMcZ0Su7HA1Iv4GQTfUmzSZ6N3jcsCn9F68PZcypAvF3nDRRL+3g==", - "dev": true, - "optional": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -3158,12 +2149,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } + "dev": true }, "performance-now": { "version": "0.2.0", @@ -3187,10 +2173,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } + "dev": true }, "pinpoint": { "version": "1.1.0", @@ -3227,19 +2210,12 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", "dev": true, - "requires": { - "ansi-regex": "2.1.1", - "ansi-styles": "3.1.0" - }, "dependencies": { "ansi-styles": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } + "dev": true } } }, @@ -3290,14 +2266,6 @@ "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.2.tgz", "integrity": "sha1-7qEw1IHdteGqG8WmaFX3OR0G8AM=", "dev": true, - "requires": { - "collections": "0.2.2", - "mime": "1.3.6", - "mimeparse": "0.1.4", - "q": "1.4.1", - "qs": "1.2.2", - "url2": "0.0.0" - }, "dependencies": { "qs": { "version": "1.2.2", @@ -3318,28 +2286,18 @@ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, "dependencies": { "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, - "requires": { - "kind-of": "3.2.2" - }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.5" - } + "dev": true } } }, @@ -3347,10 +2305,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "1.1.5" - } + "dev": true } } }, @@ -3358,41 +2313,25 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } + "dev": true }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - }, "dependencies": { "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } + "dev": true }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } + "dev": true } } }, @@ -3400,36 +2339,19 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } + "dev": true }, "readline2": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "mute-stream": "0.0.5" - } + "dev": true }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "1.3.3" - } + "dev": true }, "regenerator-runtime": { "version": "0.10.5", @@ -3441,11 +2363,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", - "dev": true, - "requires": { - "is-equal-shallow": "0.1.3", - "is-primitive": "2.0.0" - } + "dev": true }, "remove-trailing-separator": { "version": "1.0.2", @@ -3469,40 +2387,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "1.0.2" - } + "dev": true }, "request": { "version": "2.81.0", "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } + "dev": true }, "require-directory": { "version": "2.1.1", @@ -3526,20 +2417,13 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } + "dev": true }, "resolve": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } + "dev": true }, "resolve-from": { "version": "1.0.1", @@ -3551,11 +2435,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" - } + "dev": true }, "rfc6902": { "version": "1.3.0", @@ -3568,28 +2448,19 @@ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "optional": true, - "requires": { - "align-text": "0.1.4" - } + "optional": true }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true, - "requires": { - "glob": "7.1.2" - } + "dev": true }, "run-async": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true, - "requires": { - "once": "1.4.0" - } + "dev": true }, "rx-lite": { "version": "3.1.2", @@ -3601,10 +2472,7 @@ "version": "5.4.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.2.tgz", "integrity": "sha1-KjI2/L8D31e64G/Wly/ZnlwI/Pc=", - "dev": true, - "requires": { - "symbol-observable": "1.0.4" - } + "dev": true }, "safe-buffer": { "version": "5.1.1", @@ -3617,33 +2485,18 @@ "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", "dev": true, - "requires": { - "anymatch": "1.3.0", - "exec-sh": "0.2.0", - "fb-watchman": "1.9.2", - "minimatch": "3.0.4", - "minimist": "1.2.0", - "walker": "1.0.7", - "watch": "0.10.0" - }, "dependencies": { "bser": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", - "dev": true, - "requires": { - "node-int64": "0.4.0" - } + "dev": true }, "fb-watchman": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", - "dev": true, - "requires": { - "bser": "1.0.2" - } + "dev": true }, "minimist": { "version": "1.2.0", @@ -3675,10 +2528,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "1.0.0" - } + "dev": true }, "shebang-regex": { "version": "1.0.0", @@ -3690,12 +2540,7 @@ "version": "0.7.8", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true, - "requires": { - "glob": "7.1.2", - "interpret": "1.0.3", - "rechoir": "0.6.2" - } + "dev": true }, "signal-exit": { "version": "3.0.2", @@ -3719,29 +2564,20 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } + "dev": true }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, - "optional": true, - "requires": { - "amdefine": "1.0.1" - } + "optional": true }, "source-map-support": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", "dev": true, - "requires": { - "source-map": "0.5.6" - }, "dependencies": { "source-map": { "version": "0.5.6", @@ -3755,10 +2591,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "1.2.2" - } + "dev": true }, "spdx-expression-parse": { "version": "1.0.4", @@ -3783,16 +2616,6 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", "dev": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -3824,21 +2647,13 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } + "dev": true }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } + "dev": true }, "stringstream": { "version": "0.0.5", @@ -3850,10 +2665,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } + "dev": true }, "strip-bom": { "version": "3.0.0", @@ -3896,14 +2708,6 @@ "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, - "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", - "slice-ansi": "0.0.4", - "string-width": "2.1.1" - }, "dependencies": { "ansi-regex": { "version": "3.0.0", @@ -3921,20 +2725,13 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } + "dev": true }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } + "dev": true } } }, @@ -3942,14 +2739,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", - "dev": true, - "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1" - } + "dev": true }, "text-table": { "version": "0.2.0", @@ -3957,24 +2747,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "thenify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", - "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", - "dev": true, - "requires": { - "any-promise": "1.3.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "requires": { - "thenify": "3.3.0" - } - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -3997,10 +2769,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "dev": true, - "requires": { - "punycode": "1.4.1" - } + "dev": true }, "tr46": { "version": "0.0.3", @@ -4020,21 +2789,11 @@ "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", "dev": true }, - "tsutils": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-1.9.1.tgz", - "integrity": "sha1-ufmrROVa+WgYMdXyjQrur1x1DLA=", - "dev": true, - "optional": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } + "dev": true }, "tweetnacl": { "version": "0.14.5", @@ -4047,10 +2806,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2" - } + "dev": true }, "typedarray": { "version": "0.0.6", @@ -4064,11 +2820,6 @@ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, - "requires": { - "source-map": "0.5.6", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - }, "dependencies": { "camelcase": { "version": "1.2.1", @@ -4082,12 +2833,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, - "optional": true, - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - } + "optional": true }, "source-map": { "version": "0.5.6", @@ -4115,13 +2861,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "optional": true, - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } + "optional": true } } }, @@ -4142,10 +2882,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true, - "requires": { - "os-homedir": "1.0.2" - } + "dev": true }, "util-deprecate": { "version": "1.0.2", @@ -4163,20 +2900,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } + "dev": true }, "verror": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", - "dev": true, - "requires": { - "extsprintf": "1.0.2" - } + "dev": true }, "voca": { "version": "1.3.0", @@ -4188,10 +2918,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.11" - } + "dev": true }, "watch": { "version": "0.10.0", @@ -4215,20 +2942,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", - "dev": true, - "requires": { - "iconv-lite": "0.4.13" - } + "dev": true }, "whatwg-url": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", "dev": true, - "requires": { - "tr46": "0.0.3", - "webidl-conversions": "3.0.1" - }, "dependencies": { "webidl-conversions": { "version": "3.0.1", @@ -4242,10 +2962,7 @@ "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "2.0.0" - } + "dev": true }, "which-module": { "version": "1.0.0", @@ -4269,21 +2986,13 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", - "dev": true, - "requires": { - "errno": "0.1.4", - "xtend": "4.0.1" - } + "dev": true }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - } + "dev": true }, "wrappy": { "version": "1.0.2", @@ -4295,10 +3004,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "0.5.1" - } + "dev": true }, "xml-name-validator": { "version": "2.0.1", @@ -4328,31 +3034,13 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true, - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "5.0.0" - } + "dev": true }, "yargs-parser": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true, - "requires": { - "camelcase": "3.0.0" - } + "dev": true } } } diff --git a/package.json b/package.json index e49599bf..6597d49e 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "devDependencies": { "@alrra/travis-scripts": "^3.0.1", "benchmark": "^2.1.4", - "danger": "^1.0.0", + "danger": "^1.2.0", "dedent": "^0.7.0", "eslint": "^3.19.0", "gh-pages": "^0.12.0", "istanbul": "^0.4.5", - "lint-staged": "^4.0.2", + "lint-staged": "^4.0.4", "locater": "^1.3.0", "marked": "^0.3.6", "pinpoint": "^1.1.0" From dbbdb0664a5f8b99a057c4ffdeaeaed0b9925107 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Fri, 25 Aug 2017 05:19:30 -0400 Subject: [PATCH 048/301] Reduce memory allocation/usage across multiple event handlers - `handleEvent` is a very useful tool. - Always use `addEventListener`/`removeEventListener`, since it's required for this optimization. - Change log updated. - Drive-by: make DOM mock work with both event listener types. - Drive-by: eliminate possibility of `Object.prototype` interference. --- docs/change-log.md | 3 +++ render/render.js | 40 ++++++++++++++++++++++++---------------- test-utils/domMock.js | 4 +++- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 82686f0e..01b4810c 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -28,6 +28,9 @@ - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) - API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. +- core: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. +- core: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. +- core: `Object.prototype` properties can no longer interfere with event listener calls. --- diff --git a/render/render.js b/render/render.js index f6782297..bcecf29a 100644 --- a/render/render.js +++ b/render/render.js @@ -575,24 +575,32 @@ module.exports = function($window) { } } + // Here's an explanation of how this works: + // 1. The event names are always (by design) prefixed by `on`. + // 2. The EventListener interface accepts either a function or an object + // with a `handleEvent` method. + // 3. The object does not inherit from `Object.prototype`, to avoid + // any potential interference with that (e.g. setters). + // 4. The event name is remapped to the handler before calling it. + // 5. In function-based event handlers, `ev.target === this`. We replicate + // that below. + function EventDict() {} + EventDict.prototype = Object.create(null) + EventDict.prototype.handleEvent = function (ev) { + this["on" + ev.type].call(ev.target, ev) + if (typeof onevent === "function") onevent.call(ev.target, ev) + } + //event function updateEvent(vnode, key, value) { - var element = vnode.dom - var callback = typeof onevent !== "function" ? value : function(e) { - var result = value.call(element, e) - onevent.call(element, e) - return result - } - if (key in element) element[key] = typeof value === "function" ? callback : null - else { - var eventName = key.slice(2) - if (vnode.events === undefined) vnode.events = {} - if (vnode.events[key] === callback) return - if (vnode.events[key] != null) element.removeEventListener(eventName, vnode.events[key], false) - if (typeof value === "function") { - vnode.events[key] = callback - element.addEventListener(eventName, vnode.events[key], false) - } + if (typeof value === "function") { + if (vnode.events == null) vnode.events = new EventDict() + if (vnode.events[key] === value) return + if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false) + vnode.events[key] = value + } else if (vnode.events != null) { + if (vnode.events[key] != null) vnode.dom.removeEventListener(key.slice(2), vnode.events, false) + delete vnode.events[key] } } diff --git a/test-utils/domMock.js b/test-utils/domMock.js index 060ba4f7..d99dce47 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -278,7 +278,9 @@ module.exports = function(options) { e.target = this if (events[e.type] != null) { for (var i = 0; i < events[e.type].length; i++) { - events[e.type][i].call(this, e) + var handler = events[e.type][i] + if (typeof handler === "function") handler.call(this, e) + else handler.handleEvent(e) } } e.preventDefault = function() { From 2c92d8405840ef59e50c3298a645f24f636a7119 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Fri, 25 Aug 2017 06:06:46 -0400 Subject: [PATCH 049/301] Add support for object event handlers (using `handleEvent`) - `handleEvent` is checked on dispatch, like in the DOM. - Had to reorder attribute key checking so `undefined` events still got removed. - Drive-by: Optimize the initial attribute key checking a little. - Drive-by: Fix changelog v2.0.0 link in TOC. --- docs/change-log.md | 4 +- render/render.js | 16 ++-- render/tests/test-event.js | 191 ++++++++++++++++++++++++++++++++++++- 3 files changed, 200 insertions(+), 11 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 01b4810c..8e263532 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,6 +1,6 @@ # Change log -- [v2.0.0](#v113) +- [v2.0.0](#v200-wip) - [v1.1.4](#v113) - [v1.1.3](#v113) - [v1.1.2](#v112) @@ -22,6 +22,7 @@ #### News - API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +- API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). #### Bug fixes @@ -31,6 +32,7 @@ - core: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. - core: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. - core: `Object.prototype` properties can no longer interfere with event listener calls. +- API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. --- diff --git a/render/render.js b/render/render.js index bcecf29a..1ed2f473 100644 --- a/render/render.js +++ b/render/render.js @@ -472,13 +472,11 @@ module.exports = function($window) { } } function setAttr(vnode, key, old, value, ns) { + if (key === "key" || key === "is" || isLifecycleMethod(key)) return + if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) + if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value === undefined) return var element = vnode.dom - if (key === "key" || key === "is" || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key)) return - var nsLastIndex = key.indexOf(":") - if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") { - element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value) - } - else if (key[0] === "o" && key[1] === "n" && typeof value === "function") updateEvent(vnode, key, value) + if (key.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) else if (key === "style") updateStyle(element, old, value) else if (key in element && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { if (key === "value") { @@ -587,13 +585,15 @@ module.exports = function($window) { function EventDict() {} EventDict.prototype = Object.create(null) EventDict.prototype.handleEvent = function (ev) { - this["on" + ev.type].call(ev.target, ev) + var handler = this["on" + ev.type] + if (typeof handler === "function") handler.call(ev.target, ev) + else if (typeof handler.handleEvent === "function") handler.handleEvent(ev) if (typeof onevent === "function") onevent.call(ev.target, ev) } //event function updateEvent(vnode, key, value) { - if (typeof value === "function") { + if (typeof value === "function" || value != null && typeof value === "object") { if (vnode.events == null) vnode.events = new EventDict() if (vnode.events[key] === value) return if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false) diff --git a/render/tests/test-event.js b/render/tests/test-event.js index 1f7eec2a..b6cb1540 100644 --- a/render/tests/test-event.js +++ b/render/tests/test-event.js @@ -33,7 +33,27 @@ o.spec("event", function() { o(onevent.args[0].type).equals("click") o(onevent.args[0].target).equals(div.dom) }) - + + o("handles click EventListener object", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var div = {tag: "div", attrs: {onclick: listener}} + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + + render(root, [div]) + div.dom.dispatchEvent(e) + + o(spy.callCount).equals(1) + o(spy.this).equals(listener) + o(spy.args[0].type).equals("click") + o(spy.args[0].target).equals(div.dom) + o(onevent.callCount).equals(1) + o(onevent.this).equals(div.dom) + o(onevent.args[0].type).equals("click") + o(onevent.args[0].target).equals(div.dom) + }) + o("removes event", function() { var spy = o.spy() var vnode = {tag: "a", attrs: {onclick: spy}} @@ -45,7 +65,130 @@ o.spec("event", function() { var e = $window.document.createEvent("MouseEvents") e.initEvent("click", true, true) vnode.dom.dispatchEvent(e) - + + o(spy.callCount).equals(0) + }) + + o("removes event when null", function() { + var spy = o.spy() + var vnode = {tag: "a", attrs: {onclick: spy}} + var updated = {tag: "a", attrs: {onclick: null}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes event when undefined", function() { + var spy = o.spy() + var vnode = {tag: "a", attrs: {onclick: spy}} + var updated = {tag: "a", attrs: {onclick: undefined}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes event added via addEventListener when null", function() { + var spy = o.spy() + var vnode = {tag: "a", attrs: {ontouchstart: spy}} + var updated = {tag: "a", attrs: {ontouchstart: null}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("TouchEvents") + e.initEvent("touchstart", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes event added via addEventListener", function() { + var spy = o.spy() + var vnode = {tag: "a", attrs: {ontouchstart: spy}} + var updated = {tag: "a", attrs: {}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("TouchEvents") + e.initEvent("touchstart", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes event added via addEventListener when undefined", function() { + var spy = o.spy() + var vnode = {tag: "a", attrs: {ontouchstart: spy}} + var updated = {tag: "a", attrs: {ontouchstart: undefined}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("TouchEvents") + e.initEvent("touchstart", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes EventListener object", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var vnode = {tag: "a", attrs: {onclick: listener}} + var updated = {tag: "a", attrs: {}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes EventListener object when null", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var vnode = {tag: "a", attrs: {onclick: listener}} + var updated = {tag: "a", attrs: {onclick: null}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + vnode.dom.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + + o("removes EventListener object when undefined", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var vnode = {tag: "a", attrs: {onclick: listener}} + var updated = {tag: "a", attrs: {onclick: undefined}} + + render(root, [vnode]) + render(root, [updated]) + + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + vnode.dom.dispatchEvent(e) + o(spy.callCount).equals(0) }) @@ -72,6 +215,30 @@ o.spec("event", function() { o(div.dom.attributes["id"].value).equals("b") }) + o("fires click EventListener object only once after redraw", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var div = {tag: "div", attrs: {id: "a", onclick: listener}} + var updated = {tag: "div", attrs: {id: "b", onclick: listener}} + var e = $window.document.createEvent("MouseEvents") + e.initEvent("click", true, true) + + render(root, [div]) + render(root, [updated]) + div.dom.dispatchEvent(e) + + o(spy.callCount).equals(1) + o(spy.this).equals(listener) + o(spy.args[0].type).equals("click") + o(spy.args[0].target).equals(div.dom) + o(onevent.callCount).equals(1) + o(onevent.this).equals(div.dom) + o(onevent.args[0].type).equals("click") + o(onevent.args[0].target).equals(div.dom) + o(div.dom).equals(updated.dom) + o(div.dom.attributes["id"].value).equals("b") + }) + o("handles ontransitionend", function() { var spy = o.spy() var div = {tag: "div", attrs: {ontransitionend: spy}} @@ -90,4 +257,24 @@ o.spec("event", function() { o(onevent.args[0].type).equals("transitionend") o(onevent.args[0].target).equals(div.dom) }) + + o("handles transitionend EventListener object", function() { + var spy = o.spy() + var listener = {handleEvent: spy} + var div = {tag: "div", attrs: {ontransitionend: listener}} + var e = $window.document.createEvent("HTMLEvents") + e.initEvent("transitionend", true, true) + + render(root, [div]) + div.dom.dispatchEvent(e) + + o(spy.callCount).equals(1) + o(spy.this).equals(listener) + o(spy.args[0].type).equals("transitionend") + o(spy.args[0].target).equals(div.dom) + o(onevent.callCount).equals(1) + o(onevent.this).equals(div.dom) + o(onevent.args[0].type).equals("transitionend") + o(onevent.args[0].target).equals(div.dom) + }) }) From b14347ce035374ebe98cb68809b68769e3fa1a73 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Fri, 25 Aug 2017 11:20:01 +0000 Subject: [PATCH 050/301] Bundled output for commit 3a4a01508be363bf93f6fd6374c2abb996c22a11 [skip ci] --- package-lock.json | 1680 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 1472 insertions(+), 208 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b4aff41..779147ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,7 @@ "name": "mithril", "version": "1.1.3", "lockfileVersion": 1, + "requires": true, "dependencies": { "@alrra/travis-scripts": { "version": "3.0.1", @@ -31,13 +32,19 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "dev": true + "dev": true, + "requires": { + "acorn": "4.0.13" + } }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, + "requires": { + "acorn": "3.3.0" + }, "dependencies": { "acorn": { "version": "3.3.0", @@ -51,13 +58,21 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "dev": true + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + } }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } }, "ajv-keywords": { "version": "1.5.1", @@ -69,7 +84,12 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } }, "amdefine": { "version": "1.0.1", @@ -99,7 +119,11 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", - "dev": true + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11" + } }, "app-root-path": { "version": "2.0.1", @@ -111,13 +135,19 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } }, "arr-flatten": { "version": "1.1.0", @@ -135,7 +165,10 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } }, "array-uniq": { "version": "1.0.3", @@ -171,7 +204,10 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", - "dev": true + "dev": true, + "requires": { + "lodash": "4.17.4" + } }, "asynckit": { "version": "0.4.0", @@ -195,13 +231,39 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } }, "babel-core": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-generator": "6.25.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.6" + }, "dependencies": { "source-map": { "version": "0.5.6", @@ -216,6 +278,16 @@ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.6", + "trim-right": "1.0.1" + }, "dependencies": { "source-map": { "version": "0.5.6", @@ -229,25 +301,42 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } }, "babel-jest": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", - "dev": true + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-plugin-istanbul": "4.1.4", + "babel-preset-jest": "20.0.3" + } }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true + "dev": true, + "requires": { + "babel-runtime": "6.23.0" + } }, "babel-plugin-istanbul": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", - "dev": true + "dev": true, + "requires": { + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.7.4", + "test-exclude": "4.1.1" + } }, "babel-plugin-jest-hoist": { "version": "20.0.3", @@ -259,43 +348,88 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", - "dev": true + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } }, "babel-preset-jest": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", - "dev": true + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "20.0.3" + } }, "babel-register": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", - "dev": true + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.15" + } }, "babel-runtime": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", - "dev": true + "dev": true, + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } }, "babel-template": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", - "dev": true + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "4.17.4" + } }, "babel-traverse": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", - "dev": true + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } }, "babel-types": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", - "dev": true + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } }, "babylon": { "version": "6.17.4", @@ -314,37 +448,59 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, - "optional": true + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } }, "benchmark": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", - "dev": true + "dev": true, + "requires": { + "lodash": "4.17.4", + "platform": "1.3.4" + } }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true + "dev": true, + "requires": { + "hoek": "2.16.3" + } }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } }, "browser-resolve": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", "dev": true, + "requires": { + "resolve": "1.1.7" + }, "dependencies": { "resolve": { "version": "1.1.7", @@ -358,7 +514,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", - "dev": true + "dev": true, + "requires": { + "node-int64": "0.4.0" + } }, "builtin-modules": { "version": "1.1.1", @@ -370,7 +529,10 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true + "dev": true, + "requires": { + "callsites": "0.2.0" + } }, "callsites": { "version": "0.2.0", @@ -395,13 +557,24 @@ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "optional": true + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } }, "circular-json": { "version": "0.3.1", @@ -413,7 +586,10 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } }, "cli-spinners": { "version": "0.1.2", @@ -425,7 +601,11 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "1.0.2" + } }, "cli-width": { "version": "2.1.0", @@ -437,7 +617,12 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } }, "co": { "version": "4.6.0", @@ -455,13 +640,19 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz", "integrity": "sha1-HyMCay7zb5J+7MkB6ZxfDUj6M04=", - "dev": true + "dev": true, + "requires": { + "weak-map": "1.0.0" + } }, "color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "dev": true + "dev": true, + "requires": { + "color-name": "1.1.3" + } }, "color-name": { "version": "1.1.3", @@ -473,7 +664,10 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } }, "commander": { "version": "2.11.0", @@ -491,7 +685,12 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } }, "content-type-parser": { "version": "1.0.1", @@ -522,6 +721,16 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-1.1.0.tgz", "integrity": "sha1-DeoPmATv37kp+7GxiOJVU+oFPTc=", "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "js-yaml": "3.9.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "pinkie-promise": "2.0.1", + "require-from-string": "1.2.1" + }, "dependencies": { "minimist": { "version": "1.2.0", @@ -535,13 +744,21 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true + "dev": true, + "requires": { + "boom": "2.10.1" + } }, "cssom": { "version": "0.3.2", @@ -553,37 +770,75 @@ "version": "0.2.37", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", - "dev": true + "dev": true, + "requires": { + "cssom": "0.3.2" + } }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true + "dev": true, + "requires": { + "es5-ext": "0.10.24" + } }, "danger": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/danger/-/danger-1.2.0.tgz", "integrity": "sha512-uFZb/QIGMnuHgireqI1Nu0pLoYGOtCj7E5DD8wUkNyRq0LjDiz3P2M5SMjbgparl8BG+suqmWc+fo3VksSJJnw==", "dev": true, + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "2.1.0", + "commander": "2.11.0", + "debug": "2.6.8", + "github": "9.2.0", + "jest-config": "20.0.4", + "jest-environment-node": "20.0.3", + "jest-runtime": "20.0.4", + "jsome": "2.3.26", + "jsonpointer": "4.0.1", + "lodash.find": "4.6.0", + "lodash.includes": "4.3.0", + "lodash.isobject": "2.4.1", + "lodash.keys": "4.2.0", + "node-fetch": "1.7.1", + "parse-diff": "0.4.0", + "parse-link-header": "1.0.1", + "rfc6902": "1.3.0", + "voca": "1.3.0" + }, "dependencies": { "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true + "dev": true, + "requires": { + "color-convert": "1.9.0" + } }, "chalk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", - "dev": true + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } }, "supports-color": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", - "dev": true + "dev": true, + "requires": { + "has-flag": "2.0.0" + } } } }, @@ -592,6 +847,9 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -611,7 +869,10 @@ "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true + "dev": true, + "requires": { + "ms": "2.0.0" + } }, "decamelize": { "version": "1.2.0", @@ -635,7 +896,16 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" + } }, "delayed-stream": { "version": "1.0.0", @@ -647,7 +917,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true + "dev": true, + "requires": { + "repeating": "2.0.1" + } }, "diff": { "version": "3.3.0", @@ -659,14 +932,21 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, - "optional": true + "optional": true, + "requires": { + "jsbn": "0.1.1" + } }, "elegant-spinner": { "version": "1.0.1", @@ -678,55 +958,98 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + } }, "errno": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "dev": true + "dev": true, + "requires": { + "prr": "0.0.0" + } }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } }, "es5-ext": { "version": "0.10.24", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", - "dev": true + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } }, "es6-iterator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-symbol": "3.1.1" + } }, "es6-map": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24" + } }, "es6-weak-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } }, "escape-string-regexp": { "version": "1.0.5", @@ -738,13 +1061,26 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true + "dev": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + } }, "escope": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -759,6 +1095,43 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.4.3", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.16.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.9.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -773,6 +1146,10 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", "dev": true, + "requires": { + "acorn": "5.1.1", + "acorn-jsx": "3.0.1" + }, "dependencies": { "acorn": { "version": "5.1.1", @@ -793,6 +1170,9 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, + "requires": { + "estraverse": "4.2.0" + }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -807,6 +1187,10 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + }, "dependencies": { "estraverse": { "version": "4.2.0", @@ -832,13 +1216,20 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24" + } }, "exec-sh": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", - "dev": true + "dev": true, + "requires": { + "merge": "1.2.0" + } }, "exit-hook": { "version": "1.1.1", @@ -850,13 +1241,19 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } }, "expand-range": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true + "dev": true, + "requires": { + "fill-range": "2.2.3" + } }, "extend": { "version": "3.0.1", @@ -868,7 +1265,10 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } }, "extsprintf": { "version": "1.0.2", @@ -886,19 +1286,30 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true + "dev": true, + "requires": { + "bser": "2.0.0" + } }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } }, "file-entry-cache": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true + "dev": true, + "requires": { + "flat-cache": "1.2.2", + "object-assign": "4.1.1" + } }, "filename-regex": { "version": "2.0.1", @@ -910,25 +1321,45 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true + "dev": true, + "requires": { + "locate-path": "2.0.0" + } }, "flat-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true + "dev": true, + "requires": { + "circular-json": "0.3.1", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } }, "follow-redirects": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", - "dev": true + "dev": true, + "requires": { + "debug": "2.6.8", + "stream-consume": "0.1.0" + } }, "for-in": { "version": "1.0.2", @@ -940,7 +1371,10 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true + "dev": true, + "requires": { + "for-in": "1.0.2" + } }, "forever-agent": { "version": "0.6.1", @@ -952,7 +1386,12 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } }, "fs.realpath": { "version": "1.0.0", @@ -970,7 +1409,10 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true + "dev": true, + "requires": { + "is-property": "1.0.2" + } }, "get-caller-file": { "version": "1.0.2", @@ -989,6 +1431,9 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -1003,18 +1448,37 @@ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.12.0.tgz", "integrity": "sha1-2VHj7Zi4VpnUsEGOsaFbGgSYjcE=", "dev": true, + "requires": { + "async": "2.1.2", + "commander": "2.9.0", + "globby": "6.1.0", + "graceful-fs": "4.1.10", + "q": "1.4.1", + "q-io": "1.13.2", + "rimraf": "2.6.1" + }, "dependencies": { "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "graceful-fs": { "version": "4.1.10", @@ -1028,25 +1492,46 @@ "version": "9.2.0", "resolved": "https://registry.npmjs.org/github/-/github-9.2.0.tgz", "integrity": "sha1-iohtxA3WNjZwfcr5nfPfJsWfFvw=", - "dev": true + "dev": true, + "requires": { + "follow-redirects": "0.0.7", + "https-proxy-agent": "1.0.0", + "mime": "1.3.6", + "netrc": "0.1.4" + } }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } }, "glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } }, "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true + "dev": true, + "requires": { + "is-glob": "2.0.1" + } }, "globals": { "version": "9.18.0", @@ -1058,7 +1543,15 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "graceful-fs": { "version": "4.1.11", @@ -1077,6 +1570,12 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, "dependencies": { "async": { "version": "1.5.2", @@ -1088,7 +1587,10 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true + "dev": true, + "requires": { + "amdefine": "1.0.1" + } } } }, @@ -1102,13 +1604,20 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true + "dev": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } }, "has-flag": { "version": "2.0.0", @@ -1120,7 +1629,13 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } }, "hoek": { "version": "2.16.3", @@ -1132,7 +1647,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } }, "hosted-git-info": { "version": "2.5.0", @@ -1144,19 +1663,32 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", - "dev": true + "dev": true, + "requires": { + "whatwg-encoding": "1.0.1" + } }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } }, "https-proxy-agent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dev": true + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.8", + "extend": "3.0.1" + } }, "iconv-lite": { "version": "0.4.13", @@ -1180,13 +1712,20 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true + "dev": true, + "requires": { + "repeating": "2.0.1" + } }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } }, "inherits": { "version": "2.0.3", @@ -1198,7 +1737,22 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } }, "interpret": { "version": "1.0.3", @@ -1210,7 +1764,10 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } }, "invert-kv": { "version": "1.0.0", @@ -1234,7 +1791,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } }, "is-dotfile": { "version": "1.0.3", @@ -1246,7 +1806,10 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } }, "is-extendable": { "version": "0.1.1", @@ -1264,31 +1827,49 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } }, "is-my-json-valid": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", - "dev": true + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true + "dev": true, + "requires": { + "kind-of": "3.2.2" + } }, "is-path-cwd": { "version": "1.0.0", @@ -1300,13 +1881,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } }, "is-path-inside": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "dev": true + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } }, "is-posix-bracket": { "version": "0.1.1", @@ -1336,7 +1923,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true + "dev": true, + "requires": { + "tryit": "1.0.3" + } }, "is-stream": { "version": "1.1.0", @@ -1372,7 +1962,10 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true + "dev": true, + "requires": { + "isarray": "1.0.0" + } }, "isstream": { "version": "0.1.2", @@ -1385,6 +1978,22 @@ "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.10", + "js-yaml": "3.9.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.2.14", + "wordwrap": "1.0.0" + }, "dependencies": { "async": { "version": "1.5.2", @@ -1402,7 +2011,14 @@ "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } }, "resolve": { "version": "1.1.7", @@ -1415,6 +2031,9 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, + "requires": { + "has-flag": "1.0.0" + }, "dependencies": { "has-flag": { "version": "1.0.0", @@ -1437,6 +2056,15 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.4.tgz", "integrity": "sha1-6f2SDkdn89Ge3HZeLWs/XMvQ7qg=", "dev": true, + "requires": { + "babel-generator": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.3.0" + }, "dependencies": { "semver": { "version": "5.3.0", @@ -1450,13 +2078,31 @@ "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "glob": "7.1.2", + "jest-environment-jsdom": "20.0.3", + "jest-environment-node": "20.0.3", + "jest-jasmine2": "20.0.4", + "jest-matcher-utils": "20.0.3", + "jest-regex-util": "20.0.3", + "jest-resolve": "20.0.4", + "jest-validate": "20.0.3", + "pretty-format": "20.0.3" + } }, "jest-diff": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "diff": "3.3.0", + "jest-matcher-utils": "20.0.3", + "pretty-format": "20.0.3" + } }, "jest-docblock": { "version": "20.0.3", @@ -1468,43 +2114,86 @@ "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", - "dev": true + "dev": true, + "requires": { + "jest-mock": "20.0.3", + "jest-util": "20.0.3", + "jsdom": "9.12.0" + } }, "jest-environment-node": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", - "dev": true + "dev": true, + "requires": { + "jest-mock": "20.0.3", + "jest-util": "20.0.3" + } }, "jest-haste-map": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.4.tgz", "integrity": "sha1-ZT61XIic48Ah97lGk/IKQVm63wM=", - "dev": true + "dev": true, + "requires": { + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.11", + "jest-docblock": "20.0.3", + "micromatch": "2.3.11", + "sane": "1.6.0", + "worker-farm": "1.4.1" + } }, "jest-jasmine2": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "graceful-fs": "4.1.11", + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-matchers": "20.0.3", + "jest-message-util": "20.0.3", + "jest-snapshot": "20.0.3", + "once": "1.4.0", + "p-map": "1.1.1" + } }, "jest-matcher-utils": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "pretty-format": "20.0.3" + } }, "jest-matchers": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", - "dev": true + "dev": true, + "requires": { + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-message-util": "20.0.3", + "jest-regex-util": "20.0.3" + } }, "jest-message-util": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "micromatch": "2.3.11", + "slash": "1.0.0" + } }, "jest-mock": { "version": "20.0.3", @@ -1522,31 +2211,76 @@ "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", - "dev": true + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "is-builtin-module": "1.0.0", + "resolve": "1.3.3" + } }, "jest-runtime": { "version": "20.0.4", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", - "dev": true + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-jest": "20.0.3", + "babel-plugin-istanbul": "4.1.4", + "chalk": "1.1.3", + "convert-source-map": "1.5.0", + "graceful-fs": "4.1.11", + "jest-config": "20.0.4", + "jest-haste-map": "20.0.4", + "jest-regex-util": "20.0.3", + "jest-resolve": "20.0.4", + "jest-util": "20.0.3", + "json-stable-stringify": "1.0.1", + "micromatch": "2.3.11", + "strip-bom": "3.0.0", + "yargs": "7.1.0" + } }, "jest-snapshot": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "jest-diff": "20.0.3", + "jest-matcher-utils": "20.0.3", + "jest-util": "20.0.3", + "natural-compare": "1.4.0", + "pretty-format": "20.0.3" + } }, "jest-util": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "graceful-fs": "4.1.11", + "jest-message-util": "20.0.3", + "jest-mock": "20.0.3", + "jest-validate": "20.0.3", + "leven": "2.1.0", + "mkdirp": "0.5.1" + } }, "jest-validate": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "jest-matcher-utils": "20.0.3", + "leven": "2.1.0", + "pretty-format": "20.0.3" + } }, "js-tokens": { "version": "3.0.2", @@ -1559,6 +2293,10 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz", "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, "dependencies": { "esprima": { "version": "4.0.0", @@ -1579,7 +2317,28 @@ "version": "9.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", - "dev": true + "dev": true, + "requires": { + "abab": "1.0.3", + "acorn": "4.0.13", + "acorn-globals": "3.1.0", + "array-equal": "1.0.0", + "content-type-parser": "1.0.1", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "1.8.1", + "html-encoding-sniffer": "1.0.1", + "nwmatcher": "1.4.1", + "parse5": "1.5.1", + "request": "2.81.0", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.2", + "webidl-conversions": "4.0.1", + "whatwg-encoding": "1.0.1", + "whatwg-url": "4.8.0", + "xml-name-validator": "2.0.1" + } }, "jsesc": { "version": "1.3.0", @@ -1592,18 +2351,43 @@ "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.3.26.tgz", "integrity": "sha1-jLRDiSTSyd1SlMkK3wPzVBT7PKk=", "dev": true, + "requires": { + "chalk": "1.1.3", + "json-stringify-safe": "5.0.1", + "yargs": "4.8.1" + }, "dependencies": { "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "dev": true + "dev": true, + "requires": { + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "2.4.1" + } }, "yargs-parser": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "dev": true + "dev": true, + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + } } } }, @@ -1617,7 +2401,10 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true + "dev": true, + "requires": { + "jsonify": "0.0.0" + } }, "json-stringify-safe": { "version": "5.0.1", @@ -1648,6 +2435,12 @@ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -1661,7 +2454,10 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } }, "lazy-cache": { "version": "1.0.4", @@ -1674,7 +2470,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } }, "leven": { "version": "2.1.0", @@ -1686,19 +2485,43 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } }, "lint-staged": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.0.4.tgz", "integrity": "sha1-nKaWizDfv+gTZbenY81PSZKJZVM=", "dev": true, + "requires": { + "app-root-path": "2.0.1", + "cosmiconfig": "1.1.0", + "execa": "0.8.0", + "listr": "0.12.0", + "lodash.chunk": "4.2.0", + "minimatch": "3.0.4", + "npm-which": "3.0.1", + "p-map": "1.1.1", + "staged-git-files": "0.0.4" + }, "dependencies": { "execa": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } } } }, @@ -1706,7 +2529,25 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "figures": "1.7.0", + "indent-string": "2.1.0", + "is-promise": "2.1.0", + "is-stream": "1.1.0", + "listr-silent-renderer": "1.1.1", + "listr-update-renderer": "0.2.0", + "listr-verbose-renderer": "0.4.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "ora": "0.2.3", + "p-map": "1.1.1", + "rxjs": "5.4.2", + "stream-to-observable": "0.1.0", + "strip-ansi": "3.0.1" + } }, "listr-silent-renderer": { "version": "1.1.1", @@ -1719,6 +2560,16 @@ "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "elegant-spinner": "1.0.1", + "figures": "1.7.0", + "indent-string": "3.1.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "strip-ansi": "3.0.1" + }, "dependencies": { "indent-string": { "version": "3.1.0", @@ -1732,19 +2583,35 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz", "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "date-fns": "1.28.5", + "figures": "1.7.0" + } }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, "dependencies": { "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } } } }, @@ -1752,7 +2619,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } }, "locater": { "version": "1.3.0", @@ -1800,7 +2671,10 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true + "dev": true, + "requires": { + "lodash._objecttypes": "2.4.1" + } }, "lodash.keys": { "version": "4.2.0", @@ -1812,13 +2686,20 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3" + } }, "log-update": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "dev": true + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "cli-cursor": "1.0.2" + } }, "longest": { "version": "1.0.1", @@ -1830,22 +2711,33 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } }, "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true + "dev": true, + "requires": { + "tmpl": "1.0.4" + } }, "marked": { - "version": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", "dev": true }, @@ -1859,7 +2751,22 @@ "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } }, "mime": { "version": "1.3.6", @@ -1877,7 +2784,10 @@ "version": "2.1.15", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "dev": true + "dev": true, + "requires": { + "mime-db": "1.27.0" + } }, "mimeparse": { "version": "0.1.4", @@ -1889,7 +2799,10 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } }, "minimist": { "version": "0.0.8", @@ -1901,7 +2814,10 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true + "dev": true, + "requires": { + "minimist": "0.0.8" + } }, "ms": { "version": "2.0.0", @@ -1931,7 +2847,11 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", - "dev": true + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } }, "node-int64": { "version": "0.4.0", @@ -1943,37 +2863,60 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true + "dev": true, + "requires": { + "abbrev": "1.0.9" + } }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.0.3", + "validate-npm-package-license": "3.0.1" + } }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true + "dev": true, + "requires": { + "remove-trailing-separator": "1.0.2" + } }, "npm-path": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.3.tgz", "integrity": "sha1-Fc/04ciaONp39W9gVbJPl137K74=", - "dev": true + "dev": true, + "requires": { + "which": "1.2.14" + } }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true + "dev": true, + "requires": { + "path-key": "2.0.1" + } }, "npm-which": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", - "dev": true + "dev": true, + "requires": { + "commander": "2.11.0", + "npm-path": "2.0.3", + "which": "1.2.14" + } }, "number-is-nan": { "version": "1.0.1", @@ -2003,13 +2946,20 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true + "dev": true, + "requires": { + "wrappy": "1.0.2" + } }, "onetime": { "version": "1.1.0", @@ -2022,6 +2972,10 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + }, "dependencies": { "wordwrap": { "version": "0.0.3", @@ -2035,13 +2989,27 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } }, "ora": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-spinners": "0.1.2", + "object-assign": "4.1.1" + } }, "os-homedir": { "version": "1.0.2", @@ -2053,7 +3021,10 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true + "dev": true, + "requires": { + "lcid": "1.0.0" + } }, "os-tmpdir": { "version": "1.0.2", @@ -2077,7 +3048,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true + "dev": true, + "requires": { + "p-limit": "1.1.0" + } }, "p-map": { "version": "1.1.1", @@ -2095,19 +3069,31 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true + "dev": true, + "requires": { + "error-ex": "1.3.1" + } }, "parse-link-header": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", - "dev": true + "dev": true, + "requires": { + "xtend": "4.0.1" + } }, "parse5": { "version": "1.5.1", @@ -2149,7 +3135,12 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "performance-now": { "version": "0.2.0", @@ -2173,7 +3164,10 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true + "dev": true, + "requires": { + "pinkie": "2.0.4" + } }, "pinpoint": { "version": "1.1.0", @@ -2210,12 +3204,19 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", "dev": true, + "requires": { + "ansi-regex": "2.1.1", + "ansi-styles": "3.1.0" + }, "dependencies": { "ansi-styles": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", - "dev": true + "dev": true, + "requires": { + "color-convert": "1.9.0" + } } } }, @@ -2266,6 +3267,14 @@ "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.2.tgz", "integrity": "sha1-7qEw1IHdteGqG8WmaFX3OR0G8AM=", "dev": true, + "requires": { + "collections": "0.2.2", + "mime": "1.3.6", + "mimeparse": "0.1.4", + "q": "1.4.1", + "qs": "1.2.2", + "url2": "0.0.0" + }, "dependencies": { "qs": { "version": "1.2.2", @@ -2286,18 +3295,28 @@ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, "dependencies": { "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, + "requires": { + "kind-of": "3.2.2" + }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } } } }, @@ -2305,7 +3324,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } } } }, @@ -2313,25 +3335,41 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, "dependencies": { "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } } } }, @@ -2339,19 +3377,36 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } }, "readline2": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + } }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true + "dev": true, + "requires": { + "resolve": "1.3.3" + } }, "regenerator-runtime": { "version": "0.10.5", @@ -2363,7 +3418,11 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", - "dev": true + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } }, "remove-trailing-separator": { "version": "1.0.2", @@ -2387,13 +3446,40 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true + "dev": true, + "requires": { + "is-finite": "1.0.2" + } }, "request": { "version": "2.81.0", "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } }, "require-directory": { "version": "2.1.1", @@ -2417,13 +3503,20 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } }, "resolve": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", - "dev": true + "dev": true, + "requires": { + "path-parse": "1.0.5" + } }, "resolve-from": { "version": "1.0.1", @@ -2435,7 +3528,11 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } }, "rfc6902": { "version": "1.3.0", @@ -2448,19 +3545,28 @@ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "optional": true + "optional": true, + "requires": { + "align-text": "0.1.4" + } }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true + "dev": true, + "requires": { + "glob": "7.1.2" + } }, "run-async": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true + "dev": true, + "requires": { + "once": "1.4.0" + } }, "rx-lite": { "version": "3.1.2", @@ -2472,7 +3578,10 @@ "version": "5.4.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.2.tgz", "integrity": "sha1-KjI2/L8D31e64G/Wly/ZnlwI/Pc=", - "dev": true + "dev": true, + "requires": { + "symbol-observable": "1.0.4" + } }, "safe-buffer": { "version": "5.1.1", @@ -2485,18 +3594,33 @@ "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", "dev": true, + "requires": { + "anymatch": "1.3.0", + "exec-sh": "0.2.0", + "fb-watchman": "1.9.2", + "minimatch": "3.0.4", + "minimist": "1.2.0", + "walker": "1.0.7", + "watch": "0.10.0" + }, "dependencies": { "bser": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", - "dev": true + "dev": true, + "requires": { + "node-int64": "0.4.0" + } }, "fb-watchman": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", - "dev": true + "dev": true, + "requires": { + "bser": "1.0.2" + } }, "minimist": { "version": "1.2.0", @@ -2528,7 +3652,10 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } }, "shebang-regex": { "version": "1.0.0", @@ -2540,7 +3667,12 @@ "version": "0.7.8", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + } }, "signal-exit": { "version": "3.0.2", @@ -2564,20 +3696,29 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true + "dev": true, + "requires": { + "hoek": "2.16.3" + } }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, - "optional": true + "optional": true, + "requires": { + "amdefine": "1.0.1" + } }, "source-map-support": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", "dev": true, + "requires": { + "source-map": "0.5.6" + }, "dependencies": { "source-map": { "version": "0.5.6", @@ -2591,7 +3732,10 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } }, "spdx-expression-parse": { "version": "1.0.4", @@ -2616,6 +3760,16 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, "dependencies": { "assert-plus": { "version": "1.0.0", @@ -2647,13 +3801,21 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } }, "stringstream": { "version": "0.0.5", @@ -2665,7 +3827,10 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } }, "strip-bom": { "version": "3.0.0", @@ -2708,6 +3873,14 @@ "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, "dependencies": { "ansi-regex": { "version": "3.0.0", @@ -2725,13 +3898,20 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } } } }, @@ -2739,7 +3919,14 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", - "dev": true + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + } }, "text-table": { "version": "0.2.0", @@ -2769,7 +3956,10 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "dev": true + "dev": true, + "requires": { + "punycode": "1.4.1" + } }, "tr46": { "version": "0.0.3", @@ -2793,7 +3983,10 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } }, "tweetnacl": { "version": "0.14.5", @@ -2806,7 +3999,10 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } }, "typedarray": { "version": "0.0.6", @@ -2820,6 +4016,11 @@ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, "dependencies": { "camelcase": { "version": "1.2.1", @@ -2833,7 +4034,12 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, - "optional": true + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } }, "source-map": { "version": "0.5.6", @@ -2861,7 +4067,13 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "optional": true + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } } } }, @@ -2882,7 +4094,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } }, "util-deprecate": { "version": "1.0.2", @@ -2900,13 +4115,20 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } }, "verror": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", - "dev": true + "dev": true, + "requires": { + "extsprintf": "1.0.2" + } }, "voca": { "version": "1.3.0", @@ -2918,7 +4140,10 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true + "dev": true, + "requires": { + "makeerror": "1.0.11" + } }, "watch": { "version": "0.10.0", @@ -2942,13 +4167,20 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", - "dev": true + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + } }, "whatwg-url": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", "dev": true, + "requires": { + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" + }, "dependencies": { "webidl-conversions": { "version": "3.0.1", @@ -2962,7 +4194,10 @@ "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true + "dev": true, + "requires": { + "isexe": "2.0.0" + } }, "which-module": { "version": "1.0.0", @@ -2986,13 +4221,21 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", - "dev": true + "dev": true, + "requires": { + "errno": "0.1.4", + "xtend": "4.0.1" + } }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } }, "wrappy": { "version": "1.0.2", @@ -3004,7 +4247,10 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } }, "xml-name-validator": { "version": "2.0.1", @@ -3034,13 +4280,31 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + } }, "yargs-parser": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true + "dev": true, + "requires": { + "camelcase": "3.0.0" + } } } } From 106fd7514572d7ea600dd6493290414bbec6e4a5 Mon Sep 17 00:00:00 2001 From: Ilya Sarantsev Date: Sat, 26 Aug 2017 22:42:29 +0300 Subject: [PATCH 051/301] Performance optimization for #1941 per @isiahmeadows suggestion --- render/hyperscript.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/render/hyperscript.js b/render/hyperscript.js index ea56c893..00c438c9 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -6,6 +6,11 @@ var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\[" var selectorCache = {} var hasOwn = {}.hasOwnProperty +function isEmpty(object) { + for (var key in object) if (hasOwn.call(object, key)) return false + return true +} + function compileSelector(selector) { var match, tag = "div", classes = [], attrs = {} while (match = selectorParser.exec(selector)) { @@ -28,7 +33,7 @@ function execSelector(state, attrs, children) { var hasAttrs = false, childList, text var className = attrs.className || attrs.class - if (Object.keys(state.attrs).length && Object.keys(attrs).length) { + if (!isEmpty(state.attrs) && !isEmpty(attrs)) { var newAttrs = {} for(var key in attrs) { From 19969e25558ac7d68d86dcad614d918f9fc132b1 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sun, 27 Aug 2017 13:57:53 +0000 Subject: [PATCH 052/301] Bundled output for commit c9629ffcbca3ac535c675ee1b4d29c0b6bb07bb4 [skip ci] --- README.md | 2 +- mithril.js | 13 ++++++++ mithril.min.js | 89 +++++++++++++++++++++++++------------------------- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 6ddbbb0a..d96eb04b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.29 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.33 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index e2c8944e..03d2224e 100644 --- a/mithril.js +++ b/mithril.js @@ -17,6 +17,10 @@ Vnode.normalizeChildren = function normalizeChildren(children) { var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g var selectorCache = {} var hasOwn = {}.hasOwnProperty +function isEmpty(object) { + for (var key in object) if (hasOwn.call(object, key)) return false + return true +} function compileSelector(selector) { var match, tag = "div", classes = [], attrs = {} while (match = selectorParser.exec(selector)) { @@ -37,6 +41,15 @@ function compileSelector(selector) { function execSelector(state, attrs, children) { var hasAttrs = false, childList, text var className = attrs.className || attrs.class + if (!isEmpty(state.attrs) && !isEmpty(attrs)) { + var newAttrs = {} + for(var key in attrs) { + if (hasOwn.call(attrs, key)) { + newAttrs[key] = attrs[key] + } + } + attrs = newAttrs + } for (var key in state.attrs) { if (hasOwn.call(state.attrs, key)) { attrs[key] = state.attrs[key] diff --git a/mithril.min.js b/mithril.min.js index 05686d0c..9b3d144a 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,44 +1,45 @@ -(function(){function y(b,d,f,m,q,h){return{tag:b,key:d,attrs:f,children:m,text:q,dom:h,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function A(b){var d,f=arguments[1],m=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&!(d=M[b])){var q="div";for(var h=[],k={};d=Q.exec(b);){var r=d[1],g=d[2];""===r&&""!==g?q=g:"#"===r?k.id=g:"."===r?h.push(g): -"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?h.push(r):k[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=f+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText} -function g(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dn.status||304===n.status||S.test(a.url))d(g(a.type,b));else{var l=Error(n.responseText);l.code=n.status;l.response=b;f(l)}}catch(c){f(c)}};m&&null!=a.data?n.send(a.data):n.send()});return!0===a.background?z:p(z)},jsonp:function(a,k){var r=f();a=m(a,k);var p=new d(function(d,f){var k=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+n++,m=b.document.createElement("script");b[k]=function(f){m.parentNode.removeChild(m);d(g(a.type,f));delete b[k]};m.onerror=function(){m.parentNode.removeChild(m); -f(Error("JSONP request failed"));delete b[k]};null==a.data&&(a.data={});a.url=q(a.url,a.data);a.data[a.callbackKey||"callback"]=k;m.src=h(a.url,a.data);b.document.documentElement.appendChild(m)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),P=function(b){function d(l,c,e,a,b,d,g){for(;e=p&&E>=B;){var u=c[p];t=e[B];if(u!==t||b)if(null==u)p++;else if(null==t)B++;else if(u.key===t.key){var x=null!=z&&p>=c.length-z.length||null==z&&b;p++;B++;k(l,u,t,m,g(c,p,h),x,q);b&&u.tag===t.tag&&n(l,r(u),h)}else if(u=c[v],u!==t||b)if(null==u)v--;else if(null==t)B++;else if(u.key===t.key)x=null!=z&&v>=c.length- -z.length||null==z&&b,k(l,u,t,m,g(c,v+1,h),x,q),(b||B=p&&E>=B;){u=c[v];t=e[E];if(u!==t||b)if(null==u)v--;else{if(null!=t)if(u.key===t.key)x=null!=z&&v>=c.length-z.length||null==z&&b,k(l,u,t,m,g(c,v+1,h),x,q),b&&u.tag===t.tag&&n(l,r(u),h),null!=u.dom&&(h=u.dom),v--;else{if(!F){F=c;x=v;u={};var w;for(w=0;wa.indexOf("?")?"?":"&";a+=e+d}return a}function g(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText}function l(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||T.test(a.url))d(l(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(c){e(c)}};k&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?z:p(z)},jsonp:function(a,g){var r=e();a=k(a,g);var p=new d(function(d,e){var g=a.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[g]=function(e){k.parentNode.removeChild(k);d(l(a.type,e));delete b[g]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[g]};null==a.data&&(a.data={});a.url=n(a.url,a.data);a.data[a.callbackKey||"callback"]=g;k.src=f(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),Q=function(b){function d(h, +c,q,a,b,d,l){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x= +null!=z&&p>=c.length-z.length||null==z&&b;p++;B++;g(h,t,u,k,l(c,p,f),x,n);b&&t.tag===u.tag&&m(h,r(t),f)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=z&&v>=c.length-z.length||null==z&&b,g(h,t,u,k,l(c,v+1,f),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=z&&v>=c.length-z.length||null==z&&b,g(h,t,u,k,l(c,v+1,f),x,n),b&&t.tag=== +u.tag&&m(h,r(t),f),null!=t.dom&&(f=t.dom),v--;else{if(!F){F=c;x=v;t={};var w;for(w=0;w Date: Tue, 22 Aug 2017 14:04:24 -0500 Subject: [PATCH 053/301] Fixing IE bug causing active element to be null causing render function to throw error --- docs/change-log.md | 1 + render/render.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index e73ff1b6..05c1e601 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -28,6 +28,7 @@ - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) - API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. +- Fix IE11 active element is null causing render function to throw error. --- diff --git a/render/render.js b/render/render.js index f6782297..0a5938d6 100644 --- a/render/render.js +++ b/render/render.js @@ -630,7 +630,7 @@ module.exports = function($window) { updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() - if ($doc.activeElement !== active) active.focus() + if (active !== null && $doc.activeElement !== active) active.focus() } return {render: render, setEventCallback: setEventCallback} From aaa448ac4e84afcfc791a733f48f68d8e288571e Mon Sep 17 00:00:00 2001 From: Jackson Nowotny Date: Tue, 22 Aug 2017 15:51:47 -0500 Subject: [PATCH 054/301] adding comment specifying bug --- render/render.js | 1 + 1 file changed, 1 insertion(+) diff --git a/render/render.js b/render/render.js index 0a5938d6..c733f9fc 100644 --- a/render/render.js +++ b/render/render.js @@ -630,6 +630,7 @@ module.exports = function($window) { updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() + // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active !== null && $doc.activeElement !== active) active.focus() } From 5303e70fde7aa115af4727b52dc8cb728373d001 Mon Sep 17 00:00:00 2001 From: Jackson Nowotny Date: Tue, 29 Aug 2017 10:30:45 -0500 Subject: [PATCH 055/301] fixing merge conflicts --- docs/change-log.md | 2 +- render/render.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 05c1e601..5b30bb0a 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -28,7 +28,6 @@ - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) - API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. -- Fix IE11 active element is null causing render function to throw error. --- @@ -38,6 +37,7 @@ - core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) - hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) +- Fix IE bug where active element is null causing render function to throw error. ([1943](https://github.com/MithrilJS/mithril.js/pull/1943)) --- diff --git a/render/render.js b/render/render.js index c733f9fc..cc6afd51 100644 --- a/render/render.js +++ b/render/render.js @@ -631,7 +631,7 @@ module.exports = function($window) { dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement - if (active !== null && $doc.activeElement !== active) active.focus() + if (active != null && $doc.activeElement !== active) active.focus() } return {render: render, setEventCallback: setEventCallback} From 67e1aad944efa4ba82f1a9d9b404b0bb7ec0fc19 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Wed, 30 Aug 2017 11:59:27 +0000 Subject: [PATCH 056/301] Bundled output for commit 11183f339d9430da22ab14b9f3bfb5f37df722f8 [skip ci] --- README.md | 2 +- mithril.js | 3 ++- mithril.min.js | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d96eb04b..30e9ab21 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.33 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.32 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 03d2224e..42d5cbb4 100644 --- a/mithril.js +++ b/mithril.js @@ -991,7 +991,8 @@ var coreRenderer = function($window) { updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() - if ($doc.activeElement !== active) active.focus() + // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement + if (active != null && $doc.activeElement !== active) active.focus() } return {render: render, setEventCallback: setEventCallback} } diff --git a/mithril.min.js b/mithril.min.js index 9b3d144a..0f005532 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -33,13 +33,13 @@ c,d);else if("style"===c)if(a=b,null!=a&&null!=d&&"object"===typeof a&&"object"= c){f=""+d;if(("input"===a.tag||"textarea"===a.tag)&&a.dom.value===f&&a.dom===x.activeElement)return;if("select"===a.tag)if(null===d){if(-1===a.dom.selectedIndex&&a.dom===x.activeElement)return}else if(null!==b&&a.dom.value===f&&a.dom===x.activeElement)return;if("option"===a.tag&&null!=b&&a.dom.value===f)return}"input"===a.tag&&"type"===c?h.setAttribute(c,d):h[c]=d}else"boolean"===typeof d?d?h.setAttribute(c,""):h.removeAttribute(c):h.setAttribute("className"===c?"class":c,d)}}function w(a){return"oninit"=== a||"oncreate"===a||"onupdate"===a||"onremove"===a||"onbeforeremove"===a||"onbeforeupdate"===a}function G(a,b,d){var c=a.dom,e="function"!==typeof C?d:function(a){var b=d.call(c,a);C.call(c,a);return b};if(b in c)c[b]="function"===typeof d?e:null;else{var h=b.slice(2);void 0===a.events&&(a.events={});a.events[b]!==e&&(null!=a.events[b]&&c.removeEventListener(h,a.events[b],!1),"function"===typeof d&&(a.events[b]=e,c.addEventListener(h,a.events[b],!1)))}}function A(a,b,d){"function"===typeof a.oninit&& a.oninit.call(b.state,b);"function"===typeof a.oncreate&&d.push(a.oncreate.bind(b.state,b))}function J(a,b,d){"function"===typeof a.onupdate&&d.push(a.onupdate.bind(b.state,b))}var x=b.document,K=x.createDocumentFragment(),P={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},C;return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=x.activeElement,e=a.namespaceURI;null==a.vnodes&&(a.textContent= -"");Array.isArray(b)||(b=[b]);f(a,a.vnodes,y.normalizeChildren(b),!1,c,null,"http://www.w3.org/1999/xhtml"===e?void 0:e);a.vnodes=b;for(e=0;e Date: Thu, 31 Aug 2017 05:31:07 -0400 Subject: [PATCH 057/301] Make the benchmark a little more precise We special-case identical vnode trees, so it's better that we test both identical and rebuilt trees when benchmarking rendering. --- performance/test-perf.js | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/performance/test-perf.js b/performance/test-perf.js index 2ba9b622..89160a05 100644 --- a/performance/test-perf.js +++ b/performance/test-perf.js @@ -70,7 +70,7 @@ suite.on("complete", function() { suite.on("error", console.error.bind(console)) suite.add({ - name : "rerender without changes", + name : "rerender identical vnode", onStart : function() { this.vdom = m("div", {class: "foo bar", "data-foo": "bar", p: 2}, m("header", @@ -119,6 +119,53 @@ suite.add({ } }) +suite.add({ + name : "rerender same tree", + fn : function() { + m.render(scratch, m("div", {class: "foo bar", "data-foo": "bar", p: 2}, + m("header", + m("h1", {class: "asdf"}, "a ", "b", " c ", 0, " d"), + m("nav", + m("a", {href: "/foo"}, "Foo"), + m("a", {href: "/bar"}, "Bar") + ) + ), + m("main", + m("form", {onSubmit: function onSubmit() {}}, + m("input", {type: "checkbox", checked: true}), + m("input", {type: "checkbox", checked: false}), + m("fieldset", + m("label", + m("input", {type: "radio", checked: true}) + ), + m("label", + m("input", {type: "radio"}) + ) + ), + m("button-bar", + m("button", + {style: "width:10px; height:10px; border:1px solid #FFF;"}, + "Normal CSS" + ), + m("button", + {style: "top:0 ; right: 20"}, + "Poor CSS" + ), + m("button", + {style: "invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;", icon: true}, + "Poorer CSS" + ), + m("button", + {style: {margin: 0, padding: "10px", overflow: "visible"}}, + "Object CSS" + ) + ) + ) + ) + )) + } +}) + suite.add({ name : "construct large VDOM tree", From b345e4f023f236b4ff65d946e1b530e81511bf0d Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Fri, 4 Aug 2017 09:23:20 +0200 Subject: [PATCH 058/301] Support promise return in ospec --- ospec/README.md | 33 +++++++++++++++++++++++- ospec/ospec.js | 54 +++++++++++++++++++++++++-------------- ospec/tests/test-ospec.js | 45 +++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 21 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 68a39dbe..dc3d923e 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -148,6 +148,22 @@ o("setTimeout calls callback", function(done) { }) ``` +Alternativly you can return a promise or even use an async function in tests: + +```javascript +o("promise test", function() { + return new Promise(function(resolve) { + setTimeout(resolve, 10) + }) +}) +``` + +```javascript +o("promise test", async function() { + await someOtherAsyncFunction() +}) +``` + By default, asynchronous tests time out after 20ms. This can be changed on a per-test basis using the `timeout` argument: ```javascript @@ -158,7 +174,22 @@ o("setTimeout calls callback", function(done, timeout) { }) ``` -Note that the `timeout` function call must be the first statement in its test. +Note that the `timeout` function call must be the first statement in its test. This currently does not work for promise tests. You can combine both methods to do this: + +```javascript +o("promise test", function(done, timeout) { + timeout(1000) + someOtherAsyncFunctionThatTakes900ms().then(done) +}) +``` + +```javascript +o("promise test", async function(done, timeout) { + timeout(1000) + await someOtherAsyncFunctionThatTakes900ms() + done() +}) +``` Asynchronous tests generate an assertion that succeeds upon calling `done` or fails on timeout with the error message `async test timed out`. diff --git a/ospec/ospec.js b/ospec/ospec.js index 26d5c195..cac962a6 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -84,23 +84,34 @@ module.exports = new function init(name) { if (cursor === fns.length) return var fn = fns[cursor++] + var timeout = 0, delay = 200, s = new Date + var isDone = false + + function done() { + if (timeout !== undefined) { + timeout = clearTimeout(timeout) + if (delay !== Infinity) record(null) + if (!isDone) next() + else throw new Error("`" + arg + "()` should only be called once") + isDone = true + } + else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms") + } + + function startTimer() { + timeout = setTimeout(function() { + timeout = undefined + record("async test timed out") + next() + }, Math.min(delay, 2147483647)) + } + if (fn.length > 0) { - var timeout = 0, delay = 200, s = new Date - var isDone = false var body = fn.toString() var arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once") try { - fn(function done() { - if (timeout !== undefined) { - timeout = clearTimeout(timeout) - if (delay !== Infinity) record(null) - if (!isDone) next() - else throw new Error("`" + arg + "()` should only be called once") - isDone = true - } - else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms") - }, function(t) {delay = t}) + fn(done, function(t) {delay = t}) } catch (e) { record(e.message, e) @@ -108,16 +119,21 @@ module.exports = new function init(name) { next() } if (timeout === 0) { - timeout = setTimeout(function() { - timeout = undefined - record("async test timed out") - next() - }, Math.min(delay, 2147483647)) + startTimer() } } else { - fn() - nextTickish(next) + var p = fn() + if (p && p.then) { + startTimer() + p.then(done, e => { + record(e.message, e) + subjects.pop() + next() + }) + } else { + nextTickish(next) + } } } } diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 0367e6ec..dfc3f7b0 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -107,7 +107,7 @@ o.spec("ospec", function() { o(output).deepEquals({tag: "div", children: children}) }) }) - o.spec("async", function() { + o.spec("async callback", function() { var a = 0, b = 0 o.before(function(done) { @@ -148,4 +148,47 @@ o.spec("ospec", function() { }) }) }) + + o.spec("async promise", function() { + var a = 0, b = 0 + + function wrapPromise(fn) { + return new Promise(resolve => { + callAsync(() => { + fn() + resolve() + }) + }) + } + + o.before(function() { + return wrapPromise(() => { + a = 1 + }) + }) + + o.after(function() { + return wrapPromise(function() { + a = 0 + }) + }) + + o.beforeEach(function() { + return wrapPromise(function() { + b = 1 + }) + }) + o.afterEach(function() { + return wrapPromise(function() { + b = 0 + }) + }) + + o("promise functions", async function() { + await wrapPromise(function() { + o(a).equals(b) + o(a).equals(1)("a and b should be initialized") + }) + }) + }) }) From 39be9134f94f78da635a6ad86d1722f047326c01 Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Tue, 8 Aug 2017 09:07:39 +0200 Subject: [PATCH 059/301] Support err as first argument for done callbacks in async tests --- ospec/ospec.js | 18 +++++++++--------- ospec/tests/test-ospec.js | 10 +++++++--- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index cac962a6..a757543f 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -87,7 +87,13 @@ module.exports = new function init(name) { var timeout = 0, delay = 200, s = new Date var isDone = false - function done() { + function done(err) { + if (err) { + if (err.message) record(err.message, err) + else record(err) + subjects.pop() + next() + } if (timeout !== undefined) { timeout = clearTimeout(timeout) if (delay !== Infinity) record(null) @@ -114,9 +120,7 @@ module.exports = new function init(name) { fn(done, function(t) {delay = t}) } catch (e) { - record(e.message, e) - subjects.pop() - next() + done(e) } if (timeout === 0) { startTimer() @@ -126,11 +130,7 @@ module.exports = new function init(name) { var p = fn() if (p && p.then) { startTimer() - p.then(done, e => { - record(e.message, e) - subjects.pop() - next() - }) + p.then(function() { done() }, done) } else { nextTickish(next) } diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index dfc3f7b0..69f2e1f1 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -153,10 +153,14 @@ o.spec("ospec", function() { var a = 0, b = 0 function wrapPromise(fn) { - return new Promise(resolve => { + return new Promise((resolve, reject) => { callAsync(() => { - fn() - resolve() + try { + fn() + resolve() + } catch(e) { + reject(e) + } }) }) } From d8113a44706a3f9ebb8cad0162b20ca44ae53a7a Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Tue, 8 Aug 2017 09:12:25 +0200 Subject: [PATCH 060/301] Adapt change-log --- docs/change-log.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 5b30bb0a..fa0fcd9d 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -23,6 +23,11 @@ - API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +#### Ospec improvements: + +- Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) +- Error handling for async tests with `done` callbacks supports error as first argument + #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) From 6fd8a52da0f4cc21815e5a20957cca8631afbdf8 Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Tue, 8 Aug 2017 20:57:34 +0200 Subject: [PATCH 061/301] Adapt test to new async callback behaviour --- promise/tests/test-promise.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index 48a9fac3..e368165c 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -131,7 +131,7 @@ o.spec("promise", function() { callAsync(function() {resolve(promise)}) }) - promise.then(null, done) + promise.then(null, () => done()) }) o("non-function onFulfilled is ignored", function(done) { var promise = Promise.resolve(1) From 406a08d8363163b46d4087db5138b2f33e56a594 Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Fri, 1 Sep 2017 14:02:58 +0200 Subject: [PATCH 062/301] Use util.inspect to log in node - fixes #1661 --- ospec/ospec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ospec/ospec.js b/ospec/ospec.js index a757543f..147e2dc4 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -222,6 +222,7 @@ module.exports = new function init(name) { results.push(result) } function serialize(value) { + if (hasProcess) return require("util").inspect(value) if (value === null || (typeof value === "object" && !(value instanceof Array)) || typeof value === "number") return String(value) else if (typeof value === "function") return value.name || "" try {return JSON.stringify(value)} catch (e) {return String(value)} From 6083c67f0733c999e23164a2fd32bd6755438c7f Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Fri, 1 Sep 2017 17:58:12 +0200 Subject: [PATCH 063/301] Update change-log.md --- docs/change-log.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index fa0fcd9d..f8f29e03 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -44,6 +44,9 @@ - hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) - Fix IE bug where active element is null causing render function to throw error. ([1943](https://github.com/MithrilJS/mithril.js/pull/1943)) +#### Ospec improvements: + +- Log using util.inspect to show object content instead of "[object Object]" ([#1661](https://github.com/MithrilJS/mithril.js/issues/1661), [@porsager](https://github.com/porsager)) --- ### v1.1.3 From a1a7038e55b0f058f5f86d06479d6a7c1f46c8e1 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Fri, 1 Sep 2017 17:06:19 -0400 Subject: [PATCH 064/301] Rework event diffing for better optimizability Re-ordered the type checks so that I can avoid polymorphic property lookups in event updates. (It improved the common case of no change by a little over ~40%.) --- render/render.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/render/render.js b/render/render.js index 8cc2efb4..d8de6e0d 100644 --- a/render/render.js +++ b/render/render.js @@ -593,14 +593,19 @@ module.exports = function($window) { //event function updateEvent(vnode, key, value) { - if (typeof value === "function" || value != null && typeof value === "object") { - if (vnode.events == null) vnode.events = new EventDict() + if (vnode.events != null) { if (vnode.events[key] === value) return - if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false) + if (value != null && (typeof value === "function" || typeof value === "object")) { + if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false) + vnode.events[key] = value + } else { + if (vnode.events[key] != null) vnode.dom.removeEventListener(key.slice(2), vnode.events, false) + vnode.events[key] = undefined + } + } else if (value != null && (typeof value === "function" || typeof value === "object")) { + vnode.events = new EventDict() + vnode.dom.addEventListener(key.slice(2), vnode.events, false) vnode.events[key] = value - } else if (vnode.events != null) { - if (vnode.events[key] != null) vnode.dom.removeEventListener(key.slice(2), vnode.events, false) - delete vnode.events[key] } } From b26e67d1e91816fabe0fb503f408d629e1670e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Glas=C3=B8=20Skifjeld?= Date: Tue, 5 Sep 2017 18:50:11 +0200 Subject: [PATCH 065/301] docs: Fix typo in jsx docs (#1959) --- docs/jsx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/jsx.md b/docs/jsx.md index 1c1b92ef..826d8ce0 100644 --- a/docs/jsx.md +++ b/docs/jsx.md @@ -191,7 +191,7 @@ JSX is useful for teams where HTML is primarily written by someone without Javas Hyperscript is the compiled representation of JSX. It's designed to be readable and can also be used as-is, instead of JSX (as is done in most of the documentation). Hyperscript tends to be terser than JSX for a couple of reasons: - it does not require repeating the tag name in closing tags (e.g. `m("div")` vs `
`) -- static attributes can be written using CSS selector syntax (i.e. `m("a.button")` vs `
` +- static attributes can be written using CSS selector syntax (i.e. `m("a.button")` vs ``) In addition, since hyperscript is plain Javascript, it's often more natural to indent than JSX: From 12d9085fe7d75961c225763cb4248163efc76af1 Mon Sep 17 00:00:00 2001 From: Matilda Smeds Date: Tue, 12 Sep 2017 08:09:44 +0200 Subject: [PATCH 066/301] docs: Consistent filepath comments to tutorial (#1965) --- docs/simple-application.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/simple-application.md b/docs/simple-application.md index d1763fba..cd943cc8 100644 --- a/docs/simple-application.md +++ b/docs/simple-application.md @@ -136,6 +136,7 @@ By default, Mithril views are described using [hyperscript](hyperscript.md). Hyp Let's use Mithril hyperscript to create a list of items. Hyperscript is the most idiomatic way of writing Mithril views, but [JSX is another popular alternative that you could explore](jsx.md) once you're more comfortable with the basics: ```javascript +// src/views/UserList.js var m = require("mithril") var User = require("../models/User") @@ -539,6 +540,7 @@ Currently, we're only able to navigate back to the user list via the browser bac Let's create a file `src/views/Layout.js`: ```javascript +// src/views/Layout.js var m = require("mithril") module.exports = { From 685cdedc624b4a975d42cda56352243212db5547 Mon Sep 17 00:00:00 2001 From: Matilda Smeds Date: Fri, 15 Sep 2017 08:10:11 +0200 Subject: [PATCH 067/301] docs: Fix typo (#1968) --- docs/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/components.md b/docs/components.md index 4df9dfe4..f597d88d 100644 --- a/docs/components.md +++ b/docs/components.md @@ -177,7 +177,7 @@ They can be consumed in the same way regular components can. m.render(document.body, m(closureComponent)) // EXAMPLE: via m.mount -m.mount(document.body, closuresComponent) +m.mount(document.body, closureComponent) // EXAMPLE: via m.route m.route(document.body, "/", { From 5eb6c1696526e1b1cadbfae2ada21557fac15209 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Fri, 15 Sep 2017 06:11:37 +0000 Subject: [PATCH 068/301] Bundled output for commit 685cdedc624b4a975d42cda56352243212db5547 [skip ci] --- README.md | 2 +- mithril.min.js | 90 +++++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 30e9ab21..5b67f110 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.32 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.34 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.min.js b/mithril.min.js index 0f005532..1d996296 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function y(b,d,e,k,n,f){return{tag:b,key:d,attrs:e,children:k,text:n,dom:f,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function N(b){for(var d in b)if(C.call(b,d))return!1;return!0}function A(b){var d,e=arguments[1],k=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&!(d=O[b])){var n="div";for(var f=[],g={};d=R.exec(b);){var r= -d[1],l=d[2];""===r&&""!==l?n=l:"#"===r?g.id=l:"."===r?f.push(l):"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?f.push(r):g[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function g(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText}function l(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||T.test(a.url))d(l(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(c){e(c)}};k&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?z:p(z)},jsonp:function(a,g){var r=e();a=k(a,g);var p=new d(function(d,e){var g=a.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[g]=function(e){k.parentNode.removeChild(k);d(l(a.type,e));delete b[g]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[g]};null==a.data&&(a.data={});a.url=n(a.url,a.data);a.data[a.callbackKey||"callback"]=g;k.src=f(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),Q=function(b){function d(h, -c,q,a,b,d,l){for(;q=p&&E>=B;){var t=c[p];u=q[B];if(t!==u||b)if(null==t)p++;else if(null==u)B++;else if(t.key===u.key){var x= -null!=z&&p>=c.length-z.length||null==z&&b;p++;B++;g(h,t,u,k,l(c,p,f),x,n);b&&t.tag===u.tag&&m(h,r(t),f)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=z&&v>=c.length-z.length||null==z&&b,g(h,t,u,k,l(c,v+1,f),x,n),(b||B=p&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=z&&v>=c.length-z.length||null==z&&b,g(h,t,u,k,l(c,v+1,f),x,n),b&&t.tag=== -u.tag&&m(h,r(t),f),null!=t.dom&&(f=t.dom),v--;else{if(!F){F=c;x=v;t={};var w;for(w=0;wa.indexOf("?")?"?":"&";a+=e+d}return a}function f(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText}function e(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||T.test(a.url))d(e(a.type,b));else{var k=Error(m.responseText);k.code=m.status;k.response=b;g(k)}}catch(c){g(c)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?z:n(z)},jsonp:function(a,f){var r=g();a=h(a,f);var n=new d(function(d,g){var h=a.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+m++,f=b.document.createElement("script");b[h]=function(g){f.parentNode.removeChild(f);d(e(a.type,g));delete b[h]};f.onerror=function(){f.parentNode.removeChild(f);g(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;f.src=l(a.url,a.data);b.document.documentElement.appendChild(f)});return!0===a.background?n:r(n)},setCompletionCallback:function(a){n=a}}}(window,v),P=function(b){function d(k, +c,q,a,b,d,e){for(;q=x&&D>=n;){var u=c[x],t=q[n];if(u!==t||b)if(null==u)x++;else if(null==t)n++;else if(u.key===t.key){var v=null!= +z&&x>=c.length-z.length||null==z&&b;x++;n++;f(k,u,t,h,e(c,x,l),v,p);b&&u.tag===t.tag&&m(k,r(u),l)}else if(u=c[w],u!==t||b)if(null==u)w--;else if(null==t)n++;else if(u.key===t.key)v=null!=z&&w>=c.length-z.length||null==z&&b,f(k,u,t,h,e(c,w+1,l),v,p),(b||n=x&&D>=n;){u=c[w];t=q[D];if(u!==t||b)if(null==u)w--;else{if(null!=t)if(u.key===t.key)v=null!=z&&w>=c.length-z.length||null==z&&b,f(k,u,t,h,e(c,w+1,l),v,p),b&&u.tag===t.tag&& +m(k,r(u),l),null!=u.dom&&(l=u.dom),w--;else{if(!E){E=c;u=w;v={};var y;for(y=0;y Date: Fri, 15 Sep 2017 06:11:46 +0000 Subject: [PATCH 069/301] docs: clarify PR process --- docs/contributing.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index 189d0b99..4e672470 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -22,9 +22,11 @@ To send a pull request: - fork the repo (button at the top right in GitHub) - clone the forked repo to your computer (green button in GitHub) +- Switch to the `next` branch (run `git checkout next`) - create a feature branch (run `git checkout -b the-feature-branch-name`) - make your changes -- run the tests (run `npm t`) +- run the tests (run `npm test`) +- push your changes to your fork - submit a pull request (go to the pull requests tab in GitHub, click the green button and select your feature branch) From 40229a1ab9872f9e868af1d34e4799760cbec669 Mon Sep 17 00:00:00 2001 From: matildasmeds Date: Fri, 15 Sep 2017 16:39:30 +0200 Subject: [PATCH 070/301] docs: reorder lifecycle methods to match actual event order --- docs/components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/components.md b/docs/components.md index f597d88d..cbb97cc0 100644 --- a/docs/components.md +++ b/docs/components.md @@ -61,6 +61,9 @@ var ComponentWithHooks = { oncreate: function(vnode) { console.log("DOM created") }, + onbeforeupdate: function(vnode, old) { + return true + }, onupdate: function(vnode) { console.log("DOM updated") }, @@ -74,9 +77,6 @@ var ComponentWithHooks = { onremove: function(vnode) { console.log("removing DOM element") }, - onbeforeupdate: function(vnode, old) { - return true - }, view: function(vnode) { return "hello" } From e7d0e5a5060d2d641457859fc09ed6e5b8d1f590 Mon Sep 17 00:00:00 2001 From: matildasmeds Date: Sat, 16 Sep 2017 14:12:42 +0200 Subject: [PATCH 071/301] docs: Fix typo in css.md --- docs/css.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/css.md b/docs/css.md index 7664d1ca..ab4f3e2f 100644 --- a/docs/css.md +++ b/docs/css.md @@ -87,7 +87,7 @@ Nowadays there are [a lot of CSS-in-JS libraries with various degrees of robustn The main problem with many of these libraries is that even though they require a non-trivial amount of transpiler tooling and configuration, they also require sacrificing code readability in order to work, e.g. `` vs `` (or `m("a.button.danger")` if we're using hyperscript). -Often sacrifices also need to be made at time of debugging, when mapping rendered CSS class names back to their source. Often all you get in browser developer tools is a class like `button_fvp6zc2gdj35evhsl73ffzq_0 danger_fgdl0s2a5fmle5g56rbuax71_0` with useless source maps (or worse, entirely criptic class names). +Often sacrifices also need to be made at time of debugging, when mapping rendered CSS class names back to their source. Often all you get in browser developer tools is a class like `button_fvp6zc2gdj35evhsl73ffzq_0 danger_fgdl0s2a5fmle5g56rbuax71_0` with useless source maps (or worse, entirely cryptic class names). Another common issue is lack of support for less basic CSS features such as `@keyframes` and `@font-face`. From bdb04e1772467ee8f7de53c5f3721861c46c425c Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 18 Sep 2017 00:39:56 +0000 Subject: [PATCH 072/301] Bundled output for commit 98933b8bc1869bcf166244de7dc08a4360b5a354 [skip ci] --- README.md | 2 +- mithril.js | 62 ++++++++++++++++++++-------------- mithril.min.js | 90 +++++++++++++++++++++++++------------------------- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 5b67f110..58a263eb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.34 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.41 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 42d5cbb4..ba541f5e 100644 --- a/mithril.js +++ b/mithril.js @@ -839,13 +839,11 @@ var coreRenderer = function($window) { } } function setAttr(vnode, key2, old, value, ns) { + if (key2 === "key" || key2 === "is" || isLifecycleMethod(key2)) return + if (key2[0] === "o" && key2[1] === "n") return updateEvent(vnode, key2, value) + if ((old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || value === undefined) return var element = vnode.dom - if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return - var nsLastIndex = key2.indexOf(":") - if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") { - element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value) - } - else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value) + if (key2.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(6), value) else if (key2 === "style") updateStyle(element, old, value) else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) { if (key2 === "value") { @@ -940,24 +938,38 @@ var coreRenderer = function($window) { } } } + // Here's an explanation of how this works: + // 1. The event names are always (by design) prefixed by `on`. + // 2. The EventListener interface accepts either a function or an object + // with a `handleEvent` method. + // 3. The object does not inherit from `Object.prototype`, to avoid + // any potential interference with that (e.g. setters). + // 4. The event name is remapped to the handler0 before calling it. + // 5. In function-based event handlers, `ev.target === this`. We replicate + // that below. + function EventDict() {} + EventDict.prototype = Object.create(null) + EventDict.prototype.handleEvent = function (ev) { + var handler0 = this["on" + ev.type] + if (typeof handler0 === "function") handler0.call(ev.target, ev) + else if (typeof handler0.handleEvent === "function") handler0.handleEvent(ev) + if (typeof onevent === "function") onevent.call(ev.target, ev) + } //event function updateEvent(vnode, key2, value) { - var element = vnode.dom - var callback = typeof onevent !== "function" ? value : function(e) { - var result = value.call(element, e) - onevent.call(element, e) - return result - } - if (key2 in element) element[key2] = typeof value === "function" ? callback : null - else { - var eventName = key2.slice(2) - if (vnode.events === undefined) vnode.events = {} - if (vnode.events[key2] === callback) return - if (vnode.events[key2] != null) element.removeEventListener(eventName, vnode.events[key2], false) - if (typeof value === "function") { - vnode.events[key2] = callback - element.addEventListener(eventName, vnode.events[key2], false) + if (vnode.events != null) { + if (vnode.events[key2] === value) return + if (value != null && (typeof value === "function" || typeof value === "object")) { + if (vnode.events[key2] == null) vnode.dom.addEventListener(key2.slice(2), vnode.events, false) + vnode.events[key2] = value + } else { + if (vnode.events[key2] != null) vnode.dom.removeEventListener(key2.slice(2), vnode.events, false) + vnode.events[key2] = undefined } + } else if (value != null && (typeof value === "function" || typeof value === "object")) { + vnode.events = new EventDict() + vnode.dom.addEventListener(key2.slice(2), vnode.events, false) + vnode.events[key2] = value } } //lifecycle @@ -1098,12 +1110,12 @@ var coreRouter = function($window) { return data } var asyncId - function debounceAsync(callback0) { + function debounceAsync(callback) { return function() { if (asyncId != null) return asyncId = callAsync0(function() { asyncId = null - callback0() + callback() }) } } @@ -1250,9 +1262,9 @@ var _20 = function($window, redrawService0) { return route } m.route = _20(window, redrawService) -m.withAttr = function(attrName, callback1, context) { +m.withAttr = function(attrName, callback, context) { return function(e) { - callback1.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) + callback.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) } } var _28 = coreRenderer(window) diff --git a/mithril.min.js b/mithril.min.js index 1d996296..bfb4f117 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function y(b,d,g,h,p,l){return{tag:b,key:d,attrs:g,children:h,text:p,dom:l,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function M(b){for(var d in b)if(C.call(b,d))return!1;return!0}function A(b){var d=arguments[1],g=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b){var h;if(!(h=N[b])){var p="div";for(var l=[],f={};h=Q.exec(b);){var r= -h[1],e=h[2];""===r&&""!==e?p=e:"#"===r?f.id=e:"."===r?l.push(e):"["===h[3][0]&&((r=h[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(r):f[h[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function f(a){try{return""!==a?JSON.parse(a):null}catch(z){throw Error(a);}}function r(a){return a.responseText}function e(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||T.test(a.url))d(e(a.type,b));else{var k=Error(m.responseText);k.code=m.status;k.response=b;g(k)}}catch(c){g(c)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?z:n(z)},jsonp:function(a,f){var r=g();a=h(a,f);var n=new d(function(d,g){var h=a.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+m++,f=b.document.createElement("script");b[h]=function(g){f.parentNode.removeChild(f);d(e(a.type,g));delete b[h]};f.onerror=function(){f.parentNode.removeChild(f);g(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;f.src=l(a.url,a.data);b.document.documentElement.appendChild(f)});return!0===a.background?n:r(n)},setCompletionCallback:function(a){n=a}}}(window,v),P=function(b){function d(k, -c,q,a,b,d,e){for(;q=x&&D>=n;){var u=c[x],t=q[n];if(u!==t||b)if(null==u)x++;else if(null==t)n++;else if(u.key===t.key){var v=null!= -z&&x>=c.length-z.length||null==z&&b;x++;n++;f(k,u,t,h,e(c,x,l),v,p);b&&u.tag===t.tag&&m(k,r(u),l)}else if(u=c[w],u!==t||b)if(null==u)w--;else if(null==t)n++;else if(u.key===t.key)v=null!=z&&w>=c.length-z.length||null==z&&b,f(k,u,t,h,e(c,w+1,l),v,p),(b||n=x&&D>=n;){u=c[w];t=q[D];if(u!==t||b)if(null==u)w--;else{if(null!=t)if(u.key===t.key)v=null!=z&&w>=c.length-z.length||null==z&&b,f(k,u,t,h,e(c,w+1,l),v,p),b&&u.tag===t.tag&& -m(k,r(u),l),null!=u.dom&&(l=u.dom),w--;else{if(!E){E=c;u=w;v={};var y;for(y=0;ya.indexOf("?")?"?":"&";a+=f+d}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(v){throw Error(a);}}function r(a){return a.responseText}function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dn.status||304===n.status||U.test(a.url))d(f(a.type,b));else{var k=Error(n.responseText);k.code=n.status;k.response=b;h(k)}}catch(g){h(g)}};k&&null!=a.data?n.send(a.data):n.send()});return!0===a.background?v:p(v)},jsonp:function(a,l){var r=h();a=k(a,l);var p=new d(function(d,h){var k=a.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+n++,l=b.document.createElement("script");b[k]=function(h){l.parentNode.removeChild(l);d(f(a.type,h));delete b[k]};l.onerror=function(){l.parentNode.removeChild(l);h(Error("JSONP request failed"));delete b[k]};null==a.data&&(a.data={});a.url=q(a.url,a.data);a.data[a.callbackKey||"callback"]=k;l.src=m(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),Q=function(b){function d(g, +c,e,a,b,d,k){for(;e=x&&F>=p;){var z=c[x],t=e[p];if(z!==t||b)if(null==z)x++;else if(null==t)p++;else if(z.key===t.key){var B=null!= +C&&x>=c.length-C.length||null==C&&b;x++;p++;l(g,z,t,k,f(c,x,m),B,q);b&&z.tag===t.tag&&n(g,r(z),m)}else if(z=c[v],z!==t||b)if(null==z)v--;else if(null==t)p++;else if(z.key===t.key)B=null!=C&&v>=c.length-C.length||null==C&&b,l(g,z,t,k,f(c,v+1,m),B,q),(b||p=x&&F>=p;){z=c[v];t=e[F];if(z!==t||b)if(null==z)v--;else{if(null!=t)if(z.key===t.key)B=null!=C&&v>=c.length-C.length||null==C&&b,l(g,z,t,k,f(c,v+1,m),B,q),b&&z.tag===t.tag&& +n(g,r(z),m),null!=z.dom&&(m=z.dom),v--;else{if(!u){u=c;z=v;B={};var w;for(w=0;w Date: Sun, 24 Sep 2017 21:09:36 +0200 Subject: [PATCH 073/301] api/redraw: Log `render()` errors. --- api/redraw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/redraw.js b/api/redraw.js index 45a86588..9259e55f 100644 --- a/api/redraw.js +++ b/api/redraw.js @@ -41,7 +41,7 @@ module.exports = function($window, throttleMock) { function sync() { if (rendering) throw new Error("Nested m.redraw.sync() call") rendering = true - for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {/*noop*/} + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {console.error(e)} rendering = false } From 6c6caa1b5743bd7c88d15b962d5754922a5fdb98 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sun, 24 Sep 2017 19:11:27 +0000 Subject: [PATCH 074/301] Bundled output for commit cf9a31b7b0df29cffa50e159dba2b53e718bb325 [skip ci] --- README.md | 2 +- mithril.js | 4 ++-- mithril.min.js | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 58a263eb..21055536 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.41 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.42 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index ba541f5e..3de1950e 100644 --- a/mithril.js +++ b/mithril.js @@ -861,7 +861,7 @@ var coreRenderer = function($window) { //setting option[value] to same value while having select open blinks select dropdown in Chrome if (vnode.tag === "option" && old != null && vnode.dom.value === normalized0) return } - // If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error0 will occur. + // If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error1 will occur. if (vnode.tag === "input" && key2 === "type") { element.setAttribute(key2, value) return @@ -1043,7 +1043,7 @@ var _11 = function($window, throttleMock) { function sync() { if (rendering) throw new Error("Nested m.redraw.sync() call") rendering = true - for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {/*noop*/} + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {console.error(e)} rendering = false } var redraw = (throttleMock || throttle)(sync) diff --git a/mithril.min.js b/mithril.min.js index bfb4f117..142c3037 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -34,12 +34,12 @@ a.dom.value===g&&a.dom===t.activeElement)return;if("select"===a.tag)if(null===d) a||"onbeforeremove"===a||"onbeforeupdate"===a}function H(){}function A(a,c,b){null!=a.events?a.events[c]!==b&&(null==b||"function"!==typeof b&&"object"!==typeof b?(null!=a.events[c]&&a.dom.removeEventListener(c.slice(2),a.events,!1),a.events[c]=void 0):(null==a.events[c]&&a.dom.addEventListener(c.slice(2),a.events,!1),a.events[c]=b)):null==b||"function"!==typeof b&&"object"!==typeof b||(a.events=new H,a.dom.addEventListener(c.slice(2),a.events,!1),a.events[c]=b)}function I(a,c,b){"function"===typeof a.oninit&& a.oninit.call(c.state,c);"function"===typeof a.oncreate&&b.push(a.oncreate.bind(c.state,c))}function K(a,c,b){"function"===typeof a.onupdate&&b.push(a.onupdate.bind(c.state,c))}var t=b.document,L=t.createDocumentFragment(),G={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},E;H.prototype=Object.create(null);H.prototype.handleEvent=function(a){var c=this["on"+a.type];"function"===typeof c?c.call(a.target,a):"function"===typeof c.handleEvent&&c.handleEvent(a);"function"=== typeof E&&E.call(a.target,a)};return{render:function(a,c){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var b=[],d=t.activeElement,f=a.namespaceURI;null==a.vnodes&&(a.textContent="");Array.isArray(c)||(c=[c]);m(a,a.vnodes,y.normalizeChildren(c),!1,b,null,"http://www.w3.org/1999/xhtml"===f?void 0:f);a.vnodes=c;for(f=0;f Date: Mon, 25 Sep 2017 17:03:48 +0200 Subject: [PATCH 075/301] api/redraw, console check for IE9 compat. --- api/redraw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/redraw.js b/api/redraw.js index 9259e55f..a6549975 100644 --- a/api/redraw.js +++ b/api/redraw.js @@ -41,7 +41,7 @@ module.exports = function($window, throttleMock) { function sync() { if (rendering) throw new Error("Nested m.redraw.sync() call") rendering = true - for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {console.error(e)} + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {if (typeof console !== "undefined") console.error(e)} rendering = false } From c64822f5764ad5308cdd844549cf93124f21bc38 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 25 Sep 2017 15:06:03 +0000 Subject: [PATCH 076/301] Bundled output for commit 8a4280eb427ba86a3c57f67ea57423355b08aadf [skip ci] --- mithril.js | 2 +- mithril.min.js | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mithril.js b/mithril.js index 3de1950e..7bab017d 100644 --- a/mithril.js +++ b/mithril.js @@ -1043,7 +1043,7 @@ var _11 = function($window, throttleMock) { function sync() { if (rendering) throw new Error("Nested m.redraw.sync() call") rendering = true - for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {console.error(e)} + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {if (typeof console !== "undefined") console.error(e)} rendering = false } var redraw = (throttleMock || throttle)(sync) diff --git a/mithril.min.js b/mithril.min.js index 142c3037..0885ab90 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -34,12 +34,12 @@ a.dom.value===g&&a.dom===t.activeElement)return;if("select"===a.tag)if(null===d) a||"onbeforeremove"===a||"onbeforeupdate"===a}function H(){}function A(a,c,b){null!=a.events?a.events[c]!==b&&(null==b||"function"!==typeof b&&"object"!==typeof b?(null!=a.events[c]&&a.dom.removeEventListener(c.slice(2),a.events,!1),a.events[c]=void 0):(null==a.events[c]&&a.dom.addEventListener(c.slice(2),a.events,!1),a.events[c]=b)):null==b||"function"!==typeof b&&"object"!==typeof b||(a.events=new H,a.dom.addEventListener(c.slice(2),a.events,!1),a.events[c]=b)}function I(a,c,b){"function"===typeof a.oninit&& a.oninit.call(c.state,c);"function"===typeof a.oncreate&&b.push(a.oncreate.bind(c.state,c))}function K(a,c,b){"function"===typeof a.onupdate&&b.push(a.onupdate.bind(c.state,c))}var t=b.document,L=t.createDocumentFragment(),G={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},E;H.prototype=Object.create(null);H.prototype.handleEvent=function(a){var c=this["on"+a.type];"function"===typeof c?c.call(a.target,a):"function"===typeof c.handleEvent&&c.handleEvent(a);"function"=== typeof E&&E.call(a.target,a)};return{render:function(a,c){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var b=[],d=t.activeElement,f=a.namespaceURI;null==a.vnodes&&(a.textContent="");Array.isArray(c)||(c=[c]);m(a,a.vnodes,y.normalizeChildren(c),!1,b,null,"http://www.w3.org/1999/xhtml"===f?void 0:f);a.vnodes=c;for(f=0;f Date: Wed, 27 Sep 2017 03:11:02 +0300 Subject: [PATCH 077/301] Fix menu css z-index --- docs/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/style.css b/docs/style.css index cb2f1e10..bf0e6874 100644 --- a/docs/style.css +++ b/docs/style.css @@ -37,7 +37,7 @@ h2 a:visited,h3 a:visited,h4 a:visited,h5 a:visited {color:#000;text-decoration: h2::before,h3::before,h4::before,h5::before {content:"#";position:absolute;left:-20px;visibility:hidden;} h2:hover::before,h3:hover::before,h4:hover::before,h5:hover::before {visibility:visible;} #signature + p code {padding:3px 10px;} -h1 + ul {margin:40px 0 0 -270px;padding:0;position:absolute;width:250px;} +h1 + ul {margin:40px 0 0 -270px;padding:0;position:absolute;width:250px;z-index:1;} h1 + ul + hr {display:none;} h1 + ul li {list-style:none;margin:0;padding:0;} h1 + ul li:last-child {border-bottom:0;} From 348bed0a7e1ba0376281792f2081bd1c057aa607 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Sun, 1 Oct 2017 19:26:43 -0400 Subject: [PATCH 078/301] Allow `xlink:href` to get removed, fix `option.value` in mock --- docs/change-log.md | 1 + render/render.js | 2 +- render/tests/test-attributes.js | 10 +++++----- render/tests/test-createElement.js | 22 ++++++++++++++++++++-- test-utils/domMock.js | 2 +- test-utils/tests/test-domMock.js | 4 ++-- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 722d5975..3873c6b8 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -38,6 +38,7 @@ - core: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. - core: `Object.prototype` properties can no longer interfere with event listener calls. - API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. +- core: `xlink:href` attributes are now correctly removed --- diff --git a/render/render.js b/render/render.js index d8de6e0d..121083ca 100644 --- a/render/render.js +++ b/render/render.js @@ -476,7 +476,7 @@ module.exports = function($window) { if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value === undefined) return var element = vnode.dom - if (key.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) + if (key.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key, value) else if (key === "style") updateStyle(element, old, value) else if (key in element && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { if (key === "value") { diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index fcc7f150..d54ed9d4 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -376,15 +376,15 @@ o.spec("attributes", function() { o(a.dom.value).equals("1") }) - o("null becomes the empty string", function() { + o("null becomes 'null'", function() { var a = {tag: "option", attrs: {value: null}} var b = {tag: "option", attrs: {value: "test"}} var c = {tag: "option", attrs: {value: null}} render(root, [a]); - o(a.dom.value).equals("") - o(a.dom.getAttribute("value")).equals("") + o(a.dom.value).equals("null") + o(a.dom.getAttribute("value")).equals("null") render(root, [b]); @@ -393,8 +393,8 @@ o.spec("attributes", function() { render(root, [c]); - o(c.dom.value).equals("") - o(c.dom.getAttribute("value")).equals("") + o(c.dom.value).equals("null") + o(c.dom.getAttribute("value")).equals("null") }) o("'' and 0 are different values", function() { var a = {tag: "option", attrs: {value: 0}, children:[{tag:"#", children:""}]} diff --git a/render/tests/test-createElement.js b/render/tests/test-createElement.js index 6e3dcdd7..c2dc1d90 100644 --- a/render/tests/test-createElement.js +++ b/render/tests/test-createElement.js @@ -65,8 +65,8 @@ o.spec("createElement", function() { o(vnode.dom.namespaceURI).equals("http://www.w3.org/2000/svg") o(vnode.dom.firstChild.nodeName).equals("a") o(vnode.dom.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg") - o(vnode.dom.firstChild.attributes["href"].value).equals("javascript:;") - o(vnode.dom.firstChild.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") + o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") o(vnode.dom.childNodes[1].nodeName).equals("foreignObject") o(vnode.dom.childNodes[1].firstChild.nodeName).equals("body") o(vnode.dom.childNodes[1].firstChild.namespaceURI).equals("http://www.w3.org/1999/xhtml") @@ -77,6 +77,24 @@ o.spec("createElement", function() { o(vnode.dom.attributes["viewBox"].value).equals("0 0 100 100") }) + o("removes xlink:href", function() { + var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ + {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {"xlink:href": "javascript:;"}} + ]} + render(root, [vnode]) + + o(vnode.dom.nodeName).equals("svg") + o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") + o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + + vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ + {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {}} + ]} + render(root, [vnode]) + + o(vnode.dom.nodeName).equals("svg") + o(vnode.dom.firstChild.attributes["xlink:href"]).equals(undefined) + }) o("creates mathml", function() { var vnode = {tag: "math", ns: "http://www.w3.org/1998/Math/MathML", children: [{tag: "mrow", ns: "http://www.w3.org/1998/Math/MathML"}]} render(root, [vnode]) diff --git a/test-utils/domMock.js b/test-utils/domMock.js index d99dce47..b8f5d1a3 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -445,7 +445,7 @@ module.exports = function(options) { if (element.nodeName === "OPTION") { var valueSetter = spy(function(value) { /*eslint-disable no-implicit-coercion*/ - this.setAttribute("value", value === null ? "" : "" + value) + this.setAttribute("value", "" + value) /*eslint-enable no-implicit-coercion*/ }) Object.defineProperty(element, "value", { diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index a5829458..3e4a9567 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -954,11 +954,11 @@ o.spec("domMock", function() { o(select.selectedIndex).equals(1) } }) - o("option.value = null is converted to the empty string", function() { + o("option.value = null is converted to 'null'", function() { var option = $document.createElement("option") option.value = null - o(option.value).equals("") + o(option.value).equals("null") }) o("setting valid value works with optgroup", function() { var select = $document.createElement("select") From ed941a8f181f943dfbc8d8abf0959ae1b843b733 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sun, 1 Oct 2017 23:44:44 +0000 Subject: [PATCH 079/301] Bundled output for commit d00c34a72186e61a5f446d882a7145a81098e5f1 [skip ci] --- README.md | 2 +- mithril.js | 2 +- mithril.min.js | 28 ++++++++++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 21055536..105894ed 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.42 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.43 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 7bab017d..a953152b 100644 --- a/mithril.js +++ b/mithril.js @@ -843,7 +843,7 @@ var coreRenderer = function($window) { if (key2[0] === "o" && key2[1] === "n") return updateEvent(vnode, key2, value) if ((old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || value === undefined) return var element = vnode.dom - if (key2.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(6), value) + if (key2.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key2, value) else if (key2 === "style") updateStyle(element, old, value) else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) { if (key2 === "value") { diff --git a/mithril.min.js b/mithril.min.js index 0885ab90..5a8f5c34 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -28,18 +28,18 @@ y.normalize(e._state.view.call(e.state,e));if(e.instance===e)throw Error("A view t.createDocumentFragment();if(0 Date: Sun, 1 Oct 2017 16:48:08 -0400 Subject: [PATCH 080/301] Remove support for `vnode.state = ...` - Remove docs for it - Remove tests for it - Add runtime check for unexpected reassignment, since we can't freeze the property (we internally have to be able to modify it) --- docs/change-log.md | 1 + docs/vnodes.md | 3 +- render/render.js | 54 ++++++++++++----- render/tests/test-component.js | 91 ----------------------------- render/tests/test-onbeforeremove.js | 6 +- render/vnode.js | 2 +- 6 files changed, 43 insertions(+), 114 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 722d5975..cc30ad1f 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -18,6 +18,7 @@ - API: `m.redraw()` is always asynchronous ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: `m.mount()` will only render its own root when called, it will not trigger a `redraw()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) +- API: Assigning to `vnode.state` (as in `vnode.state = ...`) is no longer supported. Instead, an error is thrown if `vnode.state` changes upon the invocation of a lifecycle hook. #### News diff --git a/docs/vnodes.md b/docs/vnodes.md index cff0ebe4..783f432f 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -74,7 +74,6 @@ Property | Type | Description `dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragments and trusted HTML vnodes, `dom` points to the first element in the range. `domSize` | `Number?` | This is only set in fragment and trusted HTML vnodes, and it's `undefined` in all other vnode types. It defines the number of DOM elements that the vnode represents (starting from the element referenced by the `dom` property). `state` | `Object?` | An object that is persisted between redraws. It is provided by the core engine when needed. In POJO component vnodes, the `state` inherits prototypically from the component object/class. In class component vnodes it is an instance of the class. In closure components it is the object returned by the closure. -`_state` | `Object?` | For components, a reference to the original `vnode.state` object, used to lookup the `view` and hooks. This property is only used internally by Mithril, do not use or modify it. `events` | `Object?` | An object that is persisted between redraws and that stores event handlers so that they can be removed using the DOM API. The `events` property is `undefined` if there are no event handlers defined. This property is only used internally by Mithril, do not use or modify it. `instance` | `Object?` | For components, a storage location for the value returned by the `view`. This property is only used internally by Mithril, do not use or modify it. `skip` | `Boolean` | This property is only used internally by Mithril when diffing keyed lists, do not use or modify it. @@ -89,7 +88,7 @@ The `tag` property of a vnode determines its type. There are five vnode types: Vnode type | Example | Description ------------ | ------------------------------ | --- Element | `{tag: "div"}` | Represents a DOM element. -Fragment | `{tag: "[", children: []}` | Represents a list of DOM elements whose parent DOM element may also contain other elements that are not in the fragment. When using the [`m()`](hyperscript.md) helper function, fragment vnodes can only be created by nesting arrays into the `children` parameter of `m()`. `m("[")` does not create a valid vnode. +Fragment | `{tag: "[", children: []}` | Represents a list of DOM elements whose parent DOM element may also contain other elements that are not in the fragment. When using the [`m()`](hyperscript.md) helper function, fragment vnodes can only be created by nesting arrays into the `children` parameter of `m()`. `m("[")` does not create a valid vnode. Text | `{tag: "#", children: ""}` | Represents a DOM text node. Trusted HTML | `{tag: "<", children: "
"}` | Represents a list of DOM elements from an HTML string. Component | `{tag: ExampleComponent}` | If `tag` is a Javascript object with a `view` method, the vnode represents the DOM generated by rendering the component. diff --git a/render/render.js b/render/render.js index d8de6e0d..51532255 100644 --- a/render/render.js +++ b/render/render.js @@ -18,6 +18,24 @@ module.exports = function($window) { return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag] } + //sanity check to discourage people from doing `vnode.state = ...` + function checkState(vnode, original) { + if (vnode.state !== original) throw new Error("`vnode.state` must not be modified") + } + + //Note: the hook is passed as the `this` argument to allow proxying the + //arguments without requiring a full array allocation to do so. It also + //takes advantage of the fact the current `vnode` is the first argument in + //all lifecycle methods. + function callHook(vnode) { + var original = vnode.state + try { + return this.apply(original, arguments) + } finally { + checkState(vnode, original) + } + } + //create function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) { for (var i = start; i < end; i++) { @@ -121,10 +139,9 @@ module.exports = function($window) { sentinel.$$reentrantLock$$ = true vnode.state = (vnode.tag.prototype != null && typeof vnode.tag.prototype.view === "function") ? new vnode.tag(vnode) : vnode.tag(vnode) } - vnode._state = vnode.state if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) - initLifecycle(vnode._state, vnode, hooks) - vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode)) + initLifecycle(vnode.state, vnode, hooks) + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") sentinel.$$reentrantLock$$ = null } @@ -240,7 +257,6 @@ module.exports = function($window) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { vnode.state = old.state - vnode._state = old._state vnode.events = old.events if (!recycling && shouldNotUpdate(vnode, old)) return if (typeof oldTag === "string") { @@ -321,10 +337,10 @@ module.exports = function($window) { if (recycling) { initComponent(vnode, hooks) } else { - vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode)) + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) - updateLifecycle(vnode._state, vnode, hooks) + updateLifecycle(vnode.state, vnode, hooks) } if (vnode.instance != null) { if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling) @@ -410,15 +426,16 @@ module.exports = function($window) { } function removeNode(vnode, context) { var expected = 1, called = 0 + var original = vnode.state if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode) + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) if (result != null && typeof result.then === "function") { expected++ result.then(continuation, continuation) } } - if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeremove === "function") { - var result = vnode._state.onbeforeremove.call(vnode.state, vnode) + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) if (result != null && typeof result.then === "function") { expected++ result.then(continuation, continuation) @@ -427,6 +444,7 @@ module.exports = function($window) { continuation() function continuation() { if (++called === expected) { + checkState(vnode, original) onremove(vnode) if (vnode.dom) { var count = vnode.domSize || 1 @@ -450,9 +468,9 @@ module.exports = function($window) { if (parent != null) parent.removeChild(node) } function onremove(vnode) { - if (vnode.attrs && typeof vnode.attrs.onremove === "function") vnode.attrs.onremove.call(vnode.state, vnode) + if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { - if (typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) + if (typeof vnode.state.onremove === "function") callHook.call(vnode.state.onremove, vnode) if (vnode.instance != null) onremove(vnode.instance) } else { var children = vnode.children @@ -611,16 +629,20 @@ module.exports = function($window) { //lifecycle function initLifecycle(source, vnode, hooks) { - if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode) - if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode)) + if (typeof source.oninit === "function") callHook.call(source.oninit, vnode) + if (typeof source.oncreate === "function") hooks.push(callHook.bind(source.oncreate, vnode)) } function updateLifecycle(source, vnode, hooks) { - if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode)) + if (typeof source.onupdate === "function") hooks.push(callHook.bind(source.onupdate, vnode)) } function shouldNotUpdate(vnode, old) { var forceVnodeUpdate, forceComponentUpdate - if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old) - if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeupdate === "function") forceComponentUpdate = vnode._state.onbeforeupdate.call(vnode.state, vnode, old) + if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") { + forceVnodeUpdate = callHook.call(vnode.attrs.onbeforeupdate, vnode, old) + } + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") { + forceComponentUpdate = callHook.call(vnode.state.onbeforeupdate, vnode, old) + } if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) { vnode.dom = old.dom vnode.domSize = old.domSize diff --git a/render/tests/test-component.js b/render/tests/test-component.js index c391ddd2..ea3d1624 100644 --- a/render/tests/test-component.js +++ b/render/tests/test-component.js @@ -764,97 +764,6 @@ o.spec("component", function() { o(attrs[hook].callCount).equals(methods[hook].callCount)(hook) }) }) - o("lifecycle timing megatest (for a single component with the state overwritten)", function() { - var methods = { - view: o.spy(function(vnode) { - o(vnode.state).equals(1) - return "" - }) - } - var attrs = {} - var hooks = [ - "oninit", "oncreate", "onbeforeupdate", - "onupdate", "onbeforeremove", "onremove" - ] - hooks.forEach(function(hook) { - // the `attrs` hooks are called before the component ones - attrs[hook] = o.spy(function(vnode) { - o(vnode.state).equals(1) - o(attrs[hook].callCount).equals(methods[hook].callCount + 1) - }) - methods[hook] = o.spy(function(vnode) { - o(vnode.state).equals(1) - o(attrs[hook].callCount).equals(methods[hook].callCount) - }) - }) - - var attrsOninit = attrs.oninit - var methodsOninit = methods.oninit - attrs.oninit = o.spy(function(vnode){ - vnode.state = 1 - return attrsOninit.call(this, vnode) - }) - methods.oninit = o.spy(function(vnode){ - vnode.state = 1 - return methodsOninit.call(this, vnode) - }) - - var component = createComponent(methods) - - o(methods.view.callCount).equals(0) - o(methods.oninit.callCount).equals(0) - o(methods.oncreate.callCount).equals(0) - o(methods.onbeforeupdate.callCount).equals(0) - o(methods.onupdate.callCount).equals(0) - o(methods.onbeforeremove.callCount).equals(0) - o(methods.onremove.callCount).equals(0) - - hooks.forEach(function(hook) { - o(attrs[hook].callCount).equals(methods[hook].callCount)(hook) - }) - - render(root, [{tag: component, attrs: attrs}]) - - o(methods.view.callCount).equals(1) - o(methods.oninit.callCount).equals(1) - o(methods.oncreate.callCount).equals(1) - o(methods.onbeforeupdate.callCount).equals(0) - o(methods.onupdate.callCount).equals(0) - o(methods.onbeforeremove.callCount).equals(0) - o(methods.onremove.callCount).equals(0) - - hooks.forEach(function(hook) { - o(attrs[hook].callCount).equals(methods[hook].callCount)(hook) - }) - - render(root, [{tag: component, attrs: attrs}]) - - o(methods.view.callCount).equals(2) - o(methods.oninit.callCount).equals(1) - o(methods.oncreate.callCount).equals(1) - o(methods.onbeforeupdate.callCount).equals(1) - o(methods.onupdate.callCount).equals(1) - o(methods.onbeforeremove.callCount).equals(0) - o(methods.onremove.callCount).equals(0) - - hooks.forEach(function(hook) { - o(attrs[hook].callCount).equals(methods[hook].callCount)(hook) - }) - - render(root, []) - - o(methods.view.callCount).equals(2) - o(methods.oninit.callCount).equals(1) - o(methods.oncreate.callCount).equals(1) - o(methods.onbeforeupdate.callCount).equals(1) - o(methods.onupdate.callCount).equals(1) - o(methods.onbeforeremove.callCount).equals(1) - o(methods.onremove.callCount).equals(1) - - hooks.forEach(function(hook) { - o(attrs[hook].callCount).equals(methods[hook].callCount)(hook) - }) - }) o("hook state and arguments validation", function(){ var methods = { view: o.spy(function(vnode) { diff --git a/render/tests/test-onbeforeremove.js b/render/tests/test-onbeforeremove.js index 0e83d4a0..834f7510 100644 --- a/render/tests/test-onbeforeremove.js +++ b/render/tests/test-onbeforeremove.js @@ -36,10 +36,7 @@ o.spec("onbeforeremove", function() { o(update.callCount).equals(0) }) o("calls onbeforeremove when removing element", function(done) { - var vnode = {tag: "div", attrs: { - oninit: function() {vnode.state = {}}, - onbeforeremove: remove - }} + var vnode = {tag: "div", attrs: {onbeforeremove: remove}} render(root, [vnode]) render(root, []) @@ -47,6 +44,7 @@ o.spec("onbeforeremove", function() { function remove(node) { o(node).equals(vnode) o(this).equals(vnode.state) + o(this != null && typeof this === "object").equals(true) o(root.childNodes.length).equals(1) o(root.firstChild).equals(vnode.dom) diff --git a/render/vnode.js b/render/vnode.js index ce137703..13ed393f 100644 --- a/render/vnode.js +++ b/render/vnode.js @@ -1,7 +1,7 @@ "use strict" function Vnode(tag, key, attrs, children, text, dom) { - return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: undefined, _state: undefined, events: undefined, instance: undefined, skip: false} + return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined, skip: false} } Vnode.normalize = function(node) { if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) From 000cc8382a278b4aad7c9b8bd5e66c2d9758a491 Mon Sep 17 00:00:00 2001 From: Vasil Rimar Date: Tue, 3 Oct 2017 16:05:36 -0400 Subject: [PATCH 081/301] docs: Fix typos (#1981) --- docs/animation.md | 2 +- docs/keys.md | 2 +- docs/promise.md | 2 +- docs/render.md | 2 +- docs/route.md | 4 ++-- docs/testing.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/animation.md b/docs/animation.md index de9d2bea..7e251580 100644 --- a/docs/animation.md +++ b/docs/animation.md @@ -102,4 +102,4 @@ Note that the `onbeforeremove` hook only fires on the element that loses its `pa When creating animations, it's recommended that you only use the `opacity` and `transform` CSS rules, since these can be hardware-accelerated by modern browsers and yield better performance than animating `top`, `left`, `width`, and `height`. -It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. If you want to animate a `box-shadow`, consider [putting the `box-shadow` rule on a pseudo element, and animate that element's opacity instead](http://tobiasahlin.com/blog/how-to-animate-box-shadow/). Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute postioned element over a fixed element). +It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. If you want to animate a `box-shadow`, consider [putting the `box-shadow` rule on a pseudo element, and animate that element's opacity instead](http://tobiasahlin.com/blog/how-to-animate-box-shadow/). Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute positioned element over a fixed element). diff --git a/docs/keys.md b/docs/keys.md index 0ad0b0c5..377e65ba 100644 --- a/docs/keys.md +++ b/docs/keys.md @@ -180,7 +180,7 @@ m("div", [ #### Avoid passing model data directly to components if the model uses `key` as a data property -The `key` property may appear in your data model in a way that conflicts with Mithril's key logic. For example, a component may represent an entity whose `key` property is expected to change over time. This can lead to components receiving the wrong data, re-initialise, or change positions unexpectedly. If your data model uses the `key` property, make sure to wrap the data such that Mithril doesn't misinterpret it as a rendering instruction: +The `key` property may appear in your data model in a way that conflicts with Mithril's key logic. For example, a component may represent an entity whose `key` property is expected to change over time. This can lead to components receiving the wrong data, re-initialize, or change positions unexpectedly. If your data model uses the `key` property, make sure to wrap the data such that Mithril doesn't misinterpret it as a rendering instruction: ```javascript // Data model diff --git a/docs/promise.md b/docs/promise.md index 119d3a51..8091c2e2 100644 --- a/docs/promise.md +++ b/docs/promise.md @@ -302,7 +302,7 @@ This example also illustrates another benefit of smaller functions: we reused th ### Why not callbacks -Callbacks are another mechanism for working with asynchrounous computations, and are indeed more adequate to use if an asynchronous computation may occur more than one time (for example, an `onscroll` event handler). +Callbacks are another mechanism for working with asynchronous computations, and are indeed more adequate to use if an asynchronous computation may occur more than one time (for example, an `onscroll` event handler). However, for asynchronous computations that only occur once in response to an action, promises can be refactored more effectively, reducing code smells known as pyramids of doom (deeply nested series of callbacks with unmanaged state being used across several closure levels). diff --git a/docs/render.md b/docs/render.md index 1a0f81d9..aefbb172 100644 --- a/docs/render.md +++ b/docs/render.md @@ -68,4 +68,4 @@ Another difference is that `m.render` method expects a [vnode](vnodes.md) (or a The `m.render` module is similar in scope to view libraries like Knockout, React and Vue. It is approximately 500 lines of code (3kb min+gzip) and implements a virtual DOM diffing engine with a modern search space reduction algorithm and DOM recycling, which translate to top-of-class performance, both in terms of initial page load and re-rendering. It has no dependencies on other parts of Mithril and can be used as a standalone library. -Despite being incredibly small, the render module is fully functional and self-suficient. It supports everything you might expect: SVG, custom elements, and all valid attributes and events - without any weird case-sensitive edge cases or exceptions. Of course, it also fully supports [components](components.md) and [lifecycle methods](lifecycle-methods.md). +Despite being incredibly small, the render module is fully functional and self-sufficient. It supports everything you might expect: SVG, custom elements, and all valid attributes and events - without any weird case-sensitive edge cases or exceptions. Of course, it also fully supports [components](components.md) and [lifecycle methods](lifecycle-methods.md). diff --git a/docs/route.md b/docs/route.md index 8706119e..73b0e395 100644 --- a/docs/route.md +++ b/docs/route.md @@ -323,7 +323,7 @@ m.route(document.body, "/edit/pictures/image.jpg", { #### Handling 404s -For isomorphic / universal javascript app, an url param and a variadic route combined is very usefull to display custom 404 error page. +For isomorphic / universal javascript app, an url param and a variadic route combined is very useful to display custom 404 error page. In a case of 404 Not Found error, the server send back the custom page to client. When Mithril is loaded, it will redirect client to the default route because it can't know that route. @@ -508,7 +508,7 @@ In example 2, since `Layout` is the top-level component in both routes, the DOM #### Authentication -The RouteResolver's `onmatch` hook can be used to run logic before the top level component in a route is initializated. The example below shows how to implement a login wall that prevents users from seeing the `/secret` page unless they login. +The RouteResolver's `onmatch` hook can be used to run logic before the top level component in a route is initialized. The example below shows how to implement a login wall that prevents users from seeing the `/secret` page unless they login. ```javascript var isLoggedIn = false diff --git a/docs/testing.md b/docs/testing.md index 03bce6b0..ba850a5b 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -58,7 +58,7 @@ Generally speaking, there are two ways to write tests: upfront and after the fac Writing tests upfront requires specifications to be frozen. Upfront tests are a great way of codifying the rules that a yet-to-be-implemented API must obey. However, writing tests upfront may not be a suitable strategy if you don't have a reasonable idea of what your project will look like, if the scope of the API is not well known or if it's likely to change (e.g. based on previous history at the company). -Writing tests after the fact is a way to document the behavior of a system and avoid regressions. They are useful to ensure that obscure corner cases are not inadvertedly broken and that previously fixed bugs do not get re-introduced by unrelated changes. +Writing tests after the fact is a way to document the behavior of a system and avoid regressions. They are useful to ensure that obscure corner cases are not inadvertently broken and that previously fixed bugs do not get re-introduced by unrelated changes. --- From 77378af23237076d7303742703e68800eb21ec9f Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Wed, 4 Oct 2017 22:02:02 +0000 Subject: [PATCH 082/301] Bundled output for commit ae27c0ff183da5c36c9bf0052567d9c2b8ae464c [skip ci] --- README.md | 2 +- mithril.js | 54 ++++++++++++++++++++---------- mithril.min.js | 90 +++++++++++++++++++++++++------------------------- 3 files changed, 83 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 105894ed..21055536 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.43 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.42 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index a953152b..3360f865 100644 --- a/mithril.js +++ b/mithril.js @@ -1,7 +1,7 @@ ;(function() { "use strict" function Vnode(tag, key, attrs0, children, text, dom) { - return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: undefined, _state: undefined, events: undefined, instance: undefined, skip: false} + return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined, skip: false} } Vnode.normalize = function(node) { if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) @@ -398,6 +398,22 @@ var coreRenderer = function($window) { function getNameSpace(vnode) { return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag] } + //sanity check to discourage people from doing `vnode.state = ...` + function checkState(vnode, original) { + if (vnode.state !== original) throw new Error("`vnode.state` must not be modified") + } + //Note: the hook is passed as the `this` argument to allow proxying the + //arguments without requiring a full array allocation to do so. It also + //takes advantage of the fact the current `vnode` is the first argument in + //all lifecycle methods. + function callHook(vnode) { + var original = vnode.state + try { + return this.apply(original, arguments) + } finally { + checkState(vnode, original) + } + } //create function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) { for (var i = start; i < end; i++) { @@ -495,10 +511,9 @@ var coreRenderer = function($window) { sentinel.$$reentrantLock$$ = true vnode.state = (vnode.tag.prototype != null && typeof vnode.tag.prototype.view === "function") ? new vnode.tag(vnode) : vnode.tag(vnode) } - vnode._state = vnode.state if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) - initLifecycle(vnode._state, vnode, hooks) - vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode)) + initLifecycle(vnode.state, vnode, hooks) + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") sentinel.$$reentrantLock$$ = null } @@ -612,7 +627,6 @@ var coreRenderer = function($window) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { vnode.state = old.state - vnode._state = old._state vnode.events = old.events if (!recycling && shouldNotUpdate(vnode, old)) return if (typeof oldTag === "string") { @@ -692,10 +706,10 @@ var coreRenderer = function($window) { if (recycling) { initComponent(vnode, hooks) } else { - vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode)) + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) - updateLifecycle(vnode._state, vnode, hooks) + updateLifecycle(vnode.state, vnode, hooks) } if (vnode.instance != null) { if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling) @@ -778,15 +792,16 @@ var coreRenderer = function($window) { } function removeNode(vnode, context) { var expected = 1, called = 0 + var original = vnode.state if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode) + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) if (result != null && typeof result.then === "function") { expected++ result.then(continuation, continuation) } } - if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeremove === "function") { - var result = vnode._state.onbeforeremove.call(vnode.state, vnode) + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) if (result != null && typeof result.then === "function") { expected++ result.then(continuation, continuation) @@ -795,6 +810,7 @@ var coreRenderer = function($window) { continuation() function continuation() { if (++called === expected) { + checkState(vnode, original) onremove(vnode) if (vnode.dom) { var count0 = vnode.domSize || 1 @@ -818,9 +834,9 @@ var coreRenderer = function($window) { if (parent != null) parent.removeChild(node) } function onremove(vnode) { - if (vnode.attrs && typeof vnode.attrs.onremove === "function") vnode.attrs.onremove.call(vnode.state, vnode) + if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { - if (typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode) + if (typeof vnode.state.onremove === "function") callHook.call(vnode.state.onremove, vnode) if (vnode.instance != null) onremove(vnode.instance) } else { var children = vnode.children @@ -974,16 +990,20 @@ var coreRenderer = function($window) { } //lifecycle function initLifecycle(source, vnode, hooks) { - if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode) - if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode)) + if (typeof source.oninit === "function") callHook.call(source.oninit, vnode) + if (typeof source.oncreate === "function") hooks.push(callHook.bind(source.oncreate, vnode)) } function updateLifecycle(source, vnode, hooks) { - if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode)) + if (typeof source.onupdate === "function") hooks.push(callHook.bind(source.onupdate, vnode)) } function shouldNotUpdate(vnode, old) { var forceVnodeUpdate, forceComponentUpdate - if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old) - if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeupdate === "function") forceComponentUpdate = vnode._state.onbeforeupdate.call(vnode.state, vnode, old) + if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") { + forceVnodeUpdate = callHook.call(vnode.attrs.onbeforeupdate, vnode, old) + } + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") { + forceComponentUpdate = callHook.call(vnode.state.onbeforeupdate, vnode, old) + } if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) { vnode.dom = old.dom vnode.domSize = old.domSize diff --git a/mithril.min.js b/mithril.min.js index 5a8f5c34..cd027993 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function y(b,d,h,k,q,m){return{tag:b,key:d,attrs:h,children:k,text:q,dom:m,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function O(b){for(var d in b)if(G.call(b,d))return!1;return!0}function A(b){var d=arguments[1],h=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b){var k;if(!(k=P[b])){var q="div";for(var m=[],l={};k=R.exec(b);){var r= -k[1],f=k[2];""===r&&""!==f?q=f:"#"===r?l.id=f:"."===r?m.push(f):"["===k[3][0]&&((r=k[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===k[4]?m.push(r):l[k[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=f+d}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(v){throw Error(a);}}function r(a){return a.responseText}function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dn.status||304===n.status||U.test(a.url))d(f(a.type,b));else{var k=Error(n.responseText);k.code=n.status;k.response=b;h(k)}}catch(g){h(g)}};k&&null!=a.data?n.send(a.data):n.send()});return!0===a.background?v:p(v)},jsonp:function(a,l){var r=h();a=k(a,l);var p=new d(function(d,h){var k=a.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+n++,l=b.document.createElement("script");b[k]=function(h){l.parentNode.removeChild(l);d(f(a.type,h));delete b[k]};l.onerror=function(){l.parentNode.removeChild(l);h(Error("JSONP request failed"));delete b[k]};null==a.data&&(a.data={});a.url=q(a.url,a.data);a.data[a.callbackKey||"callback"]=k;l.src=m(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?p:r(p)},setCompletionCallback:function(a){p=a}}}(window,w),Q=function(b){function d(g, -c,e,a,b,d,k){for(;e=x&&F>=p;){var z=c[x],t=e[p];if(z!==t||b)if(null==z)x++;else if(null==t)p++;else if(z.key===t.key){var B=null!= -C&&x>=c.length-C.length||null==C&&b;x++;p++;l(g,z,t,k,f(c,x,m),B,q);b&&z.tag===t.tag&&n(g,r(z),m)}else if(z=c[v],z!==t||b)if(null==z)v--;else if(null==t)p++;else if(z.key===t.key)B=null!=C&&v>=c.length-C.length||null==C&&b,l(g,z,t,k,f(c,v+1,m),B,q),(b||p=x&&F>=p;){z=c[v];t=e[F];if(z!==t||b)if(null==z)v--;else{if(null!=t)if(z.key===t.key)B=null!=C&&v>=c.length-C.length||null==C&&b,l(g,z,t,k,f(c,v+1,m),B,q),b&&z.tag===t.tag&& -n(g,r(z),m),null!=z.dom&&(m=z.dom),v--;else{if(!u){u=c;z=v;B={};var w;for(w=0;wb.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function q(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||V.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(W){e(W)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:t(v)},jsonp:function(b,g){var t=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:t(q)},setCompletionCallback:function(b){t=b}}}(window,r),R=function(a){function c(h, +d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&x>=p;){var y= +d[u],z=a[p];if(y!==z||c)if(null==y)u++;else if(null==z)p++;else if(y.key===z.key){var r=null!=q&&u>=d.length-q.length||null==q&&c;u++;p++;m(h,y,z,e,t(d,u,g),r,k);c&&y.tag===z.tag&&b(h,l(y),g)}else if(y=d[v],y!==z||c)if(null==y)v--;else if(null==z)p++;else if(y.key===z.key)r=null!=q&&v>=d.length-q.length||null==q&&c,m(h,y,z,e,t(d,v+1,g),r,k),(c||p=u&&x>=p;){y=d[v];z=a[x];if(y!==z||c)if(null==y)v--;else{if(null!=z)if(y.key=== +z.key)r=null!=q&&v>=d.length-q.length||null==q&&c,m(h,y,z,e,t(d,v+1,g),r,k),c&&y.tag===z.tag&&b(h,l(y),g),null!=y.dom&&(g=y.dom),v--;else{if(!I){I=d;y=v;r={};var w;for(w=0;w Date: Tue, 10 Oct 2017 22:53:19 -0400 Subject: [PATCH 083/301] Handle newlines in error messages, fixes #1495 --- docs/change-log.md | 1 + ospec/ospec.js | 5 ++++- ospec/tests/test-ospec.js | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index c365276d..9dc3e7b4 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -29,6 +29,7 @@ - Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) - Error handling for async tests with `done` callbacks supports error as first argument +- Error messages which include newline characters do not swallow the stack trace ([#1495](https://github.com/MithrilJS/mithril.js/issues/1495)) #### Bug fixes diff --git a/ospec/ospec.js b/ospec/ospec.js index 147e2dc4..5c9b223a 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -49,6 +49,9 @@ module.exports = new function init(name) { spy.callCount = 0 return spy } + o.cleanStackTrace = function(stack) { + return stack.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/gm).pop() + } o.run = function() { results = [] start = new Date @@ -235,7 +238,7 @@ module.exports = new function init(name) { var status = 0 for (var i = 0, r; r = results[i]; i++) { if (!r.pass) { - var stackTrace = r.error.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/m) + var stackTrace = o.cleanStackTrace(r.error) console.error(r.context + ":\n" + highlight(r.message) + (stackTrace ? "\n\n" + stackTrace + "\n\n" : ""), hasProcess ? "" : "color:red", hasProcess ? "" : "color:black") status = 1 } diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 69f2e1f1..9b9f24d5 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -149,6 +149,18 @@ o.spec("ospec", function() { }) }) + o.spec('stack trace cleaner', function() { + o('handles line breaks', function() { + try { + throw new Error('line\nbreak') + } catch(error) { + var trace = o.cleanStackTrace(error.stack) + o(trace).notEquals('break') + o(trace.includes("test-ospec.js")).equals(true) + } + }) + }) + o.spec("async promise", function() { var a = 0, b = 0 From 8b56c7091169c0fb057d7afac041a23a4700bcdb Mon Sep 17 00:00:00 2001 From: Mateusz Jaworski Date: Sat, 14 Oct 2017 07:31:03 +0200 Subject: [PATCH 084/301] fix: Allow for changing focus in lifecycle hooks (#1988) --- docs/change-log.md | 1 + render/render.js | 2 +- render/tests/test-input.js | 10 ++++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index c365276d..99997ba7 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -40,6 +40,7 @@ - core: `Object.prototype` properties can no longer interfere with event listener calls. - API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. - core: `xlink:href` attributes are now correctly removed +- core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks --- diff --git a/render/render.js b/render/render.js index 0b881b2b..8674925b 100644 --- a/render/render.js +++ b/render/render.js @@ -664,9 +664,9 @@ module.exports = function($window) { if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes - for (var i = 0; i < hooks.length; i++) hooks[i]() // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active != null && $doc.activeElement !== active) active.focus() + for (var i = 0; i < hooks.length; i++) hooks[i]() } return {render: render, setEventCallback: setEventCallback} diff --git a/render/tests/test-input.js b/render/tests/test-input.js index d61bad54..1f9a24d7 100644 --- a/render/tests/test-input.js +++ b/render/tests/test-input.js @@ -30,6 +30,16 @@ o.spec("form inputs", function() { o($window.document.activeElement).equals(input.dom) }) + o("maintains focus when changed manually in hook", function() { + var input = {tag: "input", attrs: {oncreate: function() { + input.dom.focus(); + }}}; + + render(root, [input]) + + o($window.document.activeElement).equals(input.dom) + }) + o("syncs input value if DOM value differs from vdom value", function() { var input = {tag: "input", attrs: {value: "aaa", oninput: function() {}}} var updated = {tag: "input", attrs: {value: "aaa", oninput: function() {}}} From 1e41f0c9a33e73c46628a8fbbc400eda3cd7cf1c Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sat, 14 Oct 2017 05:32:56 +0000 Subject: [PATCH 085/301] Bundled output for commit 8b56c7091169c0fb057d7afac041a23a4700bcdb [skip ci] --- mithril.js | 2 +- mithril.min.js | 54 +++++++++++++++++++++++------------------------ package-lock.json | 18 ++++++++-------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/mithril.js b/mithril.js index 3360f865..4aa0ae29 100644 --- a/mithril.js +++ b/mithril.js @@ -1022,9 +1022,9 @@ var coreRenderer = function($window) { if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes - for (var i = 0; i < hooks.length; i++) hooks[i]() // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active != null && $doc.activeElement !== active) active.focus() + for (var i = 0; i < hooks.length; i++) hooks[i]() } return {render: render, setEventCallback: setEventCallback} } diff --git a/mithril.min.js b/mithril.min.js index cd027993..18f6fe49 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function w(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function O(a){for(var c in a)if(D.call(a,c))return!1;return!0}function A(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=P[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var q=f[1], +(function(){function w(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function O(a){for(var c in a)if(E.call(a,c))return!1;return!0}function z(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=P[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var q=f[1], m=f[2];""===q&&""!==m?n=m:"#"===q?g.id=m:"."===q?k.push(m):"["===f[3][0]&&((q=f[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(q):g[f[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function q(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||V.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(W){e(W)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:t(v)},jsonp:function(b,g){var t=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:t(q)},setCompletionCallback:function(b){t=b}}}(window,r),R=function(a){function c(h, -d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&x>=p;){var y= -d[u],z=a[p];if(y!==z||c)if(null==y)u++;else if(null==z)p++;else if(y.key===z.key){var r=null!=q&&u>=d.length-q.length||null==q&&c;u++;p++;m(h,y,z,e,t(d,u,g),r,k);c&&y.tag===z.tag&&b(h,l(y),g)}else if(y=d[v],y!==z||c)if(null==y)v--;else if(null==z)p++;else if(y.key===z.key)r=null!=q&&v>=d.length-q.length||null==q&&c,m(h,y,z,e,t(d,v+1,g),r,k),(c||p=u&&x>=p;){y=d[v];z=a[x];if(y!==z||c)if(null==y)v--;else{if(null!=z)if(y.key=== -z.key)r=null!=q&&v>=d.length-q.length||null==q&&c,m(h,y,z,e,t(d,v+1,g),r,k),c&&y.tag===z.tag&&b(h,l(y),g),null!=y.dom&&(g=y.dom),v--;else{if(!I){I=d;y=v;r={};var w;for(w=0;w=u&&D>=p;){var x= +d[u],r=a[p];if(x!==r||c)if(null==x)u++;else if(null==r)p++;else if(x.key===r.key){var C=null!=q&&u>=d.length-q.length||null==q&&c;u++;p++;m(h,x,r,e,t(d,u,g),C,k);c&&x.tag===r.tag&&b(h,l(x),g)}else if(x=d[v],x!==r||c)if(null==x)v--;else if(null==r)p++;else if(x.key===r.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,x,r,e,t(d,v+1,g),C,k),(c||p=u&&D>=p;){x=d[v];r=a[D];if(x!==r||c)if(null==x)v--;else{if(null!=r)if(x.key=== +r.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,x,r,e,t(d,v+1,g),C,k),c&&x.tag===r.tag&&b(h,l(x),g),null!=x.dom&&(g=x.dom),v--;else{if(!I){I=d;x=v;C={};var w;for(w=0;w Date: Sat, 14 Oct 2017 06:09:46 +0000 Subject: [PATCH 086/301] docs: fix v1.1.4 link --- docs/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 99997ba7..214a98a6 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,7 +1,7 @@ # Change log - [v2.0.0](#v200-wip) -- [v1.1.4](#v113) +- [v1.1.4](#v114) - [v1.1.3](#v113) - [v1.1.2](#v112) - [v1.1.1](#v111) From 0691662fd4ffd77dd3cd8ee0280286dd26edb47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 14 Oct 2017 08:50:15 +0200 Subject: [PATCH 087/301] change log: add v1.1.5 in next --- docs/change-log.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 214a98a6..6c5adc35 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -33,7 +33,6 @@ #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) -- API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) - API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. - core: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. - core: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. @@ -44,6 +43,12 @@ --- +### v1.1.5 + +- API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) + +--- + ### v1.1.4 #### Bug fixes: From 622e00981138601d8e9a309013e0f251a0e3d44b Mon Sep 17 00:00:00 2001 From: valtron Date: Mon, 16 Oct 2017 00:38:44 -0600 Subject: [PATCH 088/301] recycling => shouldRecycle, Fix #1992 (#1993) * Fix #1992 * doc in changelog * add test for #1992 --- docs/change-log.md | 1 + render/render.js | 2 +- render/tests/test-oninit.js | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 6c5adc35..a2f8259d 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -40,6 +40,7 @@ - API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. - core: `xlink:href` attributes are now correctly removed - core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks +- render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) --- diff --git a/render/render.js b/render/render.js index 8674925b..37855447 100644 --- a/render/render.js +++ b/render/render.js @@ -235,7 +235,7 @@ module.exports = function($window) { if (oldIndex != null) { var movable = old[oldIndex] var shouldRecycle = (pool != null && oldIndex >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) + updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) insertNode(parent, toFragment(movable), nextSibling) old[oldIndex].skip = true if (movable.dom != null) nextSibling = movable.dom diff --git a/render/tests/test-oninit.js b/render/tests/test-oninit.js index 4d94cae4..f6ffb873 100644 --- a/render/tests/test-oninit.js +++ b/render/tests/test-oninit.js @@ -199,4 +199,27 @@ o.spec("oninit", function() { o(vnode.dom.oninit).equals(undefined) o(vnode.dom.attributes["oninit"]).equals(undefined) }) + + o("No spurious oninit calls in mapped keyed diff when the pool is involved (#1992)", function () { + var oninit1 = o.spy() + var oninit2 = o.spy() + var oninit3 = o.spy() + + render(root, [ + {tag: "p", key: 1, attrs: {oninit: oninit1}}, + {tag: "p", key: 2, attrs: {oninit: oninit2}}, + {tag: "p", key: 3, attrs: {oninit: oninit3}}, + ]) + render(root, [ + {tag: "p", key: 1, attrs: {oninit: oninit1}}, + {tag: "p", key: 3, attrs: {oninit: oninit3}}, + ]) + render(root, [ + {tag: "p", key: 3, attrs: {oninit: oninit3}}, + ]) + + o(oninit1.callCount).equals(1) + o(oninit2.callCount).equals(1) + o(oninit3.callCount).equals(1) + }) }) From f03427db8565bd93c8a491ad6aafbbc6788983e2 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 16 Oct 2017 06:40:15 +0000 Subject: [PATCH 089/301] Bundled output for commit 622e00981138601d8e9a309013e0f251a0e3d44b [skip ci] --- mithril.js | 2 +- mithril.min.js | 78 +++++++++++++++++++++++++------------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/mithril.js b/mithril.js index 4aa0ae29..91e870e5 100644 --- a/mithril.js +++ b/mithril.js @@ -605,7 +605,7 @@ var coreRenderer = function($window) { if (oldIndex != null) { var movable = old[oldIndex] var shouldRecycle = (pool != null && oldIndex >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns) + updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) insertNode(parent, toFragment(movable), nextSibling) old[oldIndex].skip = true if (movable.dom != null) nextSibling = movable.dom diff --git a/mithril.min.js b/mithril.min.js index 18f6fe49..fbaa5741 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function w(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function O(a){for(var c in a)if(E.call(a,c))return!1;return!0}function z(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=P[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var q=f[1], -m=f[2];""===q&&""!==m?n=m:"#"===q?g.id=m:"."===q?k.push(m):"["===f[3][0]&&((q=f[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(q):g[f[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function q(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cb.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(w){throw Error(b);}}function p(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||V.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(W){e(W)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:t(v)},jsonp:function(b,g){var t=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:t(q)},setCompletionCallback:function(b){t=b}}}(window,r),R=function(a){function c(h, +"function"===typeof b.config&&(l=b.config(l,b)||l);l.onreadystatechange=function(){if(!t&&4===l.readyState)try{var a=b.extract!==p?b.extract(l,b):b.deserialize(b.extract(l,b));if(200<=l.status&&300>l.status||304===l.status||V.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(W){e(W)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?w:t(w)},jsonp:function(b,g){var t=e();b=f(b,g);var p=new c(function(c,e){var f=b.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?p:t(p)},setCompletionCallback:function(b){t=b}}}(window,r),R=function(a){function c(h, d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&D>=p;){var x= -d[u],r=a[p];if(x!==r||c)if(null==x)u++;else if(null==r)p++;else if(x.key===r.key){var C=null!=q&&u>=d.length-q.length||null==q&&c;u++;p++;m(h,x,r,e,t(d,u,g),C,k);c&&x.tag===r.tag&&b(h,l(x),g)}else if(x=d[v],x!==r||c)if(null==x)v--;else if(null==r)p++;else if(x.key===r.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,x,r,e,t(d,v+1,g),C,k),(c||p=u&&D>=p;){x=d[v];r=a[D];if(x!==r||c)if(null==x)v--;else{if(null!=r)if(x.key=== -r.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,x,r,e,t(d,v+1,g),C,k),c&&x.tag===r.tag&&b(h,l(x),g),null!=x.dom&&(g=x.dom),v--;else{if(!I){I=d;x=v;C={};var w;for(w=0;w=u&&C>=q;){var x= +d[u],r=a[q];if(x!==r||c)if(null==x)u++;else if(null==r)q++;else if(x.key===r.key){var D=null!=p&&u>=d.length-p.length||null==p&&c;u++;q++;m(h,x,r,e,t(d,u,g),D,k);c&&x.tag===r.tag&&b(h,l(x),g)}else if(x=d[w],x!==r||c)if(null==x)w--;else if(null==r)q++;else if(x.key===r.key)D=null!=p&&w>=d.length-p.length||null==p&&c,m(h,x,r,e,t(d,w+1,g),D,k),(c||q=u&&C>=q;){x=d[w];r=a[C];if(x!==r||c)if(null==x)w--;else{if(null!=r)if(x.key=== +r.key)D=null!=p&&w>=d.length-p.length||null==p&&c,m(h,x,r,e,t(d,w+1,g),D,k),c&&x.tag===r.tag&&b(h,l(x),g),null!=x.dom&&(g=x.dom),w--;else{if(!I){I=d;D=w;x={};var v;for(v=0;v=d.length-p.length||null==p&&c,m(h,v,r,e,t(d,w+1,g),D,k),b(h,l(v),g),d[x].skip=!0,null!=v.dom&&(g=v.dom)):g=n(h,r,e,k,g))}C--}else w--,C--;if(C Date: Mon, 16 Oct 2017 08:56:24 -0700 Subject: [PATCH 090/301] docs: add v1.1.5 TOC entry --- docs/change-log.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/change-log.md b/docs/change-log.md index a2f8259d..8fb0ddf2 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,6 +1,7 @@ # Change log - [v2.0.0](#v200-wip) +- [v1.1.5](#v115) - [v1.1.4](#v114) - [v1.1.3](#v113) - [v1.1.2](#v112) From 5400501aa7d650d39c0e06fa219c4a1e0f296cb9 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 17 Oct 2017 05:36:31 +0000 Subject: [PATCH 091/301] docs: reformat & flesh out webpack quickstart Fixes #1995 --- docs/installation.md | 58 +++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index c4604ad5..57efabe6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -17,28 +17,48 @@ If you're new to Javascript or just want a very simple setup to get your feet we #### Quick start with Webpack + +1. Initialize the directory as an npm package ```bash -# 1) install -npm install mithril --save - -npm install webpack --save - -# 2) add this line into the scripts section in package.json -# "scripts": { -# "start": "webpack src/index.js bin/app.js --watch" -# } - -# 3) create an `src/index.js` file - -# 4) create an `index.html` file containing `` - -# 5) run bundler -npm start - -# 6) open `index.html` in the (default) browser -open index.html +$> npm init --yes ``` +2. install required tools +```bash +$> npm install mithril --save +$> npm install webpack --save +``` + +3. Add a "start" entry to the scripts section in `package.json` +```js +{ + // ... + "scripts": { + "start": "webpack src/index.js bin/app.js --watch" + } +} +``` + +3. Create `src/index.js` +```js +import m from "mithril"; + +m.render(document.body, "hello world"); +``` + +4. create `index.html` +```html + + + +``` + +5. run bundler +```bash +$> npm start +``` +6. open `index.html` in your (default) browser + #### Step by step For production-level projects, the recommended way of installing Mithril is to use NPM. From 1a6b6a591c76ec6d4918840331188eb5ee0f0785 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 17 Oct 2017 15:25:15 -0700 Subject: [PATCH 092/301] chore(ospec): merge package.json @ 1.4.0 back --- ospec/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/package.json b/ospec/package.json index 7cfa4595..acc0ae47 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "1.3.0", + "version": "1.4.0", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From bd83b32709453ea78b01585078f04e886100d8e4 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 17 Oct 2017 15:37:43 -0700 Subject: [PATCH 093/301] docs: Add ospec releasing process & TOC --- docs/releasing.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/releasing.md b/docs/releasing.md index 37bec28d..ce4a871d 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -2,6 +2,10 @@ **Note** These steps all assume that `MithrilJS/mithril.js` is a git remote named `mithriljs`, adjust accordingly if that doesn't match your setup. +- [Releasing a new Mithril version](#releasing-a-new-mithril-version) +- [Updating mithril.js.org](#updating-mithriljsorg) +- [Releasing a new ospec version](#releasing-a-new-ospec-version) + ## Releasing a new Mithril version ### Prepare the release @@ -112,3 +116,61 @@ $ git push mithriljs ``` After the Travis build completes the updated docs should appear on https://mithril.js.org in a few minutes. + +## Releasing a new ospec version + +1. Ensure your local branch is up to date + +```bash +$ git co next +$ git pull --rebase mithriljs next +``` + +2. Determine patch level of the change +3. Update `version` field in `ospec/package.json` to match new version being prepared for release +4. Commit changes to `next` + +``` +$ git add . +$ git commit -m "chore(ospec): ospec@" + +# Push to your branch +$ git push + +# Push to MithrilJS/mithril.js +$ git push mithriljs next +``` + +### Merge from `next` to `master` + +5. Switch to `master` and make sure it's up to date + +```bash +$ git co master +$ git pull --rebase mithriljs master +``` + +6. merge `next` on top of it + +```bash +$ git checkout next -- ./ospec +$ git add . +$ git commit -m "chore(ospec): ospec@" +``` + +7. Ensure the tests are passing! + +### Publish the release + +8. Push the changes to `MithrilJS/mithril.js` + +```bash +$ git push mithriljs master +``` + +9. Publish the changes to npm **from the `/ospec` folder**. That bit is important to ensure you don't accidentally ship a new Mithril release! + +```bash +$ cd ./ospec +$ npm publish +``` From f88da1c6da88f1cb221165b4156ceeae295d688c Mon Sep 17 00:00:00 2001 From: Sage Gerard Date: Fri, 27 Oct 2017 15:25:34 -0400 Subject: [PATCH 094/301] Clarify source of 2nd render pass re: preloading data While the docs do say that a second render pass for preloaded data comes from request completion, the example code for preloading data suggests that a promise chain returned from `oninit` has a role to play in controlling the second render pass. The docs should make explicit where the redraw is initiated so the reader does not mistakingly believe that `oninit()` retuning a promise changes anything. --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index 73b0e395..faa5623b 100644 --- a/docs/route.md +++ b/docs/route.md @@ -588,7 +588,7 @@ m.route(document.body, "/secret", { #### Preloading data -Typically, a component can load data upon initialization. Loading data this way renders the component twice (once upon routing, and once after the request completes). +Typically, a component can load data upon initialization. Loading data this way renders the component twice. The first render pass occurs upon routing, and the second fires after the request completes. Take care to note that `loadUsers()` returns a Promise, but any Promise returned by `oninit` is currently ignored. The second render pass comes from the [`background` option for `m.request`](request.md). ```javascript var state = { From 0736f848cb19778b980fe93ef428c4cc2957efde Mon Sep 17 00:00:00 2001 From: spacejack Date: Sat, 28 Oct 2017 17:39:32 -0400 Subject: [PATCH 095/301] Silence global-require rule in ospec, add ecma 2017 parser to eslintrc for async/await in test-ospec --- .eslintrc.js | 5 ++++- ospec/ospec.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c14d0119..4eeef493 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,7 +4,10 @@ module.exports = { "commonjs": true, "es6": true, "node": true - }, + }, + "parserOptions": { + "ecmaVersion": 2017, + }, "extends": "eslint:recommended", "rules": { "accessor-pairs": "error", diff --git a/ospec/ospec.js b/ospec/ospec.js index 147e2dc4..fabf4de8 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -1,4 +1,4 @@ -/* eslint-disable no-bitwise, no-process-exit */ +/* eslint-disable global-require, no-bitwise, no-process-exit */ "use strict" module.exports = new function init(name) { From 3fe56bb503edbac9eb8dbb6e7e5a80f4491a068f Mon Sep 17 00:00:00 2001 From: spacejack Date: Sat, 28 Oct 2017 18:32:58 -0400 Subject: [PATCH 096/301] Revert eslintrc change, return Promise instead of using async/await --- .eslintrc.js | 3 --- ospec/tests/test-ospec.js | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4eeef493..a38c5e1b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,9 +5,6 @@ module.exports = { "es6": true, "node": true }, - "parserOptions": { - "ecmaVersion": 2017, - }, "extends": "eslint:recommended", "rules": { "accessor-pairs": "error", diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 69f2e1f1..d1ddf496 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -188,8 +188,8 @@ o.spec("ospec", function() { }) }) - o("promise functions", async function() { - await wrapPromise(function() { + o("promise functions", function() { + return wrapPromise(function() { o(a).equals(b) o(a).equals(1)("a and b should be initialized") }) From efb0e94d99b78533475859bad3c1c84238fa17d5 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Sat, 28 Oct 2017 22:57:52 -0700 Subject: [PATCH 097/301] fix: closure compiler requires HTTPS now (#2007) Also barfing out the response from the server when JSON parsing errors happen --- bundler/minify.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bundler/minify.js b/bundler/minify.js index 51b2b775..3b1d3cae 100644 --- a/bundler/minify.js +++ b/bundler/minify.js @@ -1,6 +1,6 @@ "use strict" -var http = require("http") +var http = require("https") var querystring = require("querystring") var fs = require("fs") @@ -22,7 +22,6 @@ module.exports = function(input, output, options, done) { var response = "" var req = http.request({ method: "POST", - protocol: "http:", hostname: "closure-compiler.appspot.com", path: "/compile", headers: { @@ -33,8 +32,16 @@ module.exports = function(input, output, options, done) { res.on("data", function(chunk) { response += chunk.toString() }) + res.on("end", function() { - var results = JSON.parse(response) + try { + var results = JSON.parse(response) + } catch(e) { + console.error(response); + + throw e; + } + if (results.errors) { for (var i = 0; i < results.errors.length; i++) console.log(results.errors[i]) } From 217b9c194cea23c0dc2ed83ebf2c33aaba67d2a7 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Sat, 28 Oct 2017 22:58:21 -0700 Subject: [PATCH 098/301] chore: update CODEOWNERS to match reality --- .github/CODEOWNERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ab8484ef..6485e4d6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,3 @@ -# Leo owns everything, for better or worse -* @lhorie - .travis.yml @tivac package.json @tivac .npmignore @tivac @@ -9,4 +6,4 @@ package.json @tivac README.md @tivac docs/ @tivac performance/ @tivac -render/ @isiahmeadows +render/ @isiahmeadows @pygy From 131e61002eef422ebe20a61a98de376e22b5817c Mon Sep 17 00:00:00 2001 From: Patrik Johnson Date: Tue, 8 Aug 2017 15:06:30 +0300 Subject: [PATCH 099/301] Enable setting navigation options with m.route.link API --- api/router.js | 8 ++++++-- api/tests/test-router.js | 30 ++++++++++++++++++++++++++++++ docs/change-log.md | 1 + docs/route.md | 20 +++++++++++++------- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/api/router.js b/api/router.js index 40ccb7cd..4d893acc 100644 --- a/api/router.js +++ b/api/router.js @@ -52,7 +52,7 @@ module.exports = function($window, redrawService) { } route.get = function() {return currentPath} route.prefix = function(prefix) {routeService.prefix = prefix} - route.link = function(vnode) { + var link = function(options, vnode) { vnode.dom.setAttribute("href", routeService.prefix + vnode.attrs.href) vnode.dom.onclick = function(e) { if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return @@ -60,9 +60,13 @@ module.exports = function($window, redrawService) { e.redraw = false var href = this.getAttribute("href") if (href.indexOf(routeService.prefix) === 0) href = href.slice(routeService.prefix.length) - route.set(href, undefined, undefined) + route.set(href, undefined, options) } } + route.link = function(args) { + if (args.tag == null) return link.bind(link, args) + return link({}, args) + } route.param = function(key) { if(typeof attrs !== "undefined" && typeof key !== "undefined") return attrs[key] return attrs diff --git a/api/tests/test-router.js b/api/tests/test-router.js index 69aff4ca..f5336625 100644 --- a/api/tests/test-router.js +++ b/api/tests/test-router.js @@ -281,6 +281,36 @@ o.spec("route", function() { o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test") }) + o("passes options on route.link", function() { + var opts = {} + var e = $window.document.createEvent("MouseEvents") + + e.initEvent("click", true, true) + $window.location.href = prefix + "/" + + route(root, "/", { + "/" : { + view: function() { + return m("a", { + href: "/test", + oncreate: route.link(opts) + }) + } + }, + "/test" : { + view : function() { + return m("div") + } + } + }) + route.set = o.spy(route.set) + + root.firstChild.dispatchEvent(e) + + o(route.set.callCount).equals(1) + o(route.set.args[2]).equals(opts) + }) + o("accepts RouteResolver with onmatch that returns Component", function(done) { var matchCount = 0 var renderCount = 0 diff --git a/docs/change-log.md b/docs/change-log.md index be3b48be..09b28302 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -25,6 +25,7 @@ - API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). +- API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) #### Ospec improvements: diff --git a/docs/route.md b/docs/route.md index faa5623b..712c6845 100644 --- a/docs/route.md +++ b/docs/route.md @@ -104,7 +104,7 @@ Argument | Type | Required | Description This function can be used as the `oncreate` (and `onupdate`) hook in a `m("a")` vnode: ```JS -m("a[href=/]", {oncreate: m.route.link})`. +m("a[href=/]", {oncreate: m.route.link}) ``` Using `m.route.link` as a `oncreate` hook causes the link to behave as a router link (i.e. it navigates to the route specified in `href`, instead of navigating away from the current page to the URL specified in `href`. @@ -112,15 +112,21 @@ Using `m.route.link` as a `oncreate` hook causes the link to behave as a router If the `href` attribute is not static, the `onupdate` hook must also be set: ```JS -m("a", {href: someVariable, oncreate: m.route.link, onupdate: m.route.link})` +m("a", {href: someVariable, oncreate: m.route.link, onupdate: m.route.link}) ``` -`m.route.link(vnode)` +`m.route.link` can also set the `options` passed to `m.route.set` when the link is clicked by calling the function in the lifecycle methods: -Argument | Type | Required | Description ------------------ | ----------- | -------- | --- -`vnode` | `Vnode` | Yes | This method is meant to be used as or in conjunction with an `` [vnode](vnodes.md)'s [`oncreate` and `onupdate` hooks](lifecycle-methods.md) -**returns** | | | Returns `undefined` +```JS +m("a[href=/]", {oncreate: m.route.link({replace: true})}) +``` + +`m.route.link(args)` + +Argument | Type | Required | Description +----------------- | ---------------| -------- | --- +`args` | `Vnode|Object` | Yes | This method is meant to be used as or in conjunction with an `` [vnode](vnodes.md)'s [`oncreate` and `onupdate` hooks](lifecycle-methods.md) +**returns** | `function` | | Returns the onclick handler function for the component ##### m.route.param From f22d7d4ca9e8d882d097e911d8e7921f9c128914 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sun, 29 Oct 2017 10:35:41 +0000 Subject: [PATCH 100/301] Bundled output for commit 1a81c1cfebed69193d7c5a4f7951bfc6a39a5533 [skip ci] --- README.md | 2 +- mithril.js | 8 +++-- mithril.min.js | 91 +++++++++++++++++++++++++------------------------- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 21055536..d931eeb5 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.42 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.44 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 91e870e5..3d5c1d1b 100644 --- a/mithril.js +++ b/mithril.js @@ -1264,7 +1264,7 @@ var _20 = function($window, redrawService0) { } route.get = function() {return currentPath} route.prefix = function(prefix0) {routeService.prefix = prefix0} - route.link = function(vnode1) { + var link = function(options, vnode1) { vnode1.dom.setAttribute("href", routeService.prefix + vnode1.attrs.href) vnode1.dom.onclick = function(e) { if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return @@ -1272,9 +1272,13 @@ var _20 = function($window, redrawService0) { e.redraw = false var href = this.getAttribute("href") if (href.indexOf(routeService.prefix) === 0) href = href.slice(routeService.prefix.length) - route.set(href, undefined, undefined) + route.set(href, undefined, options) } } + route.link = function(args0) { + if (args0.tag == null) return link.bind(link, args0) + return link({}, args0) + } route.param = function(key3) { if(typeof attrs3 !== "undefined" && typeof key3 !== "undefined") return attrs3[key3] return attrs3 diff --git a/mithril.min.js b/mithril.min.js index fbaa5741..f9b5258f 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,46 @@ -(function(){function v(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function O(a){for(var c in a)if(E.call(a,c))return!1;return!0}function z(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=P[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var p=f[1], -m=f[2];""===p&&""!==m?n=m:"#"===p?g.id=m:"."===p?k.push(m):"["===f[3][0]&&((p=f[6])&&(p=p.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(p):g[f[4]]=""===p?p:p||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(w){throw Error(b);}}function p(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||V.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(W){e(W)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?w:t(w)},jsonp:function(b,g){var t=e();b=f(b,g);var p=new c(function(c,e){var f=b.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?p:t(p)},setCompletionCallback:function(b){t=b}}}(window,r),R=function(a){function c(h, -d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&C>=q;){var x= -d[u],r=a[q];if(x!==r||c)if(null==x)u++;else if(null==r)q++;else if(x.key===r.key){var D=null!=p&&u>=d.length-p.length||null==p&&c;u++;q++;m(h,x,r,e,t(d,u,g),D,k);c&&x.tag===r.tag&&b(h,l(x),g)}else if(x=d[w],x!==r||c)if(null==x)w--;else if(null==r)q++;else if(x.key===r.key)D=null!=p&&w>=d.length-p.length||null==p&&c,m(h,x,r,e,t(d,w+1,g),D,k),(c||q=u&&C>=q;){x=d[w];r=a[C];if(x!==r||c)if(null==x)w--;else{if(null!=r)if(x.key=== -r.key)D=null!=p&&w>=d.length-p.length||null==p&&c,m(h,x,r,e,t(d,w+1,g),D,k),c&&x.tag===r.tag&&b(h,l(x),g),null!=x.dom&&(g=x.dom),w--;else{if(!I){I=d;D=w;x={};var v;for(v=0;v=d.length-p.length||null==p&&c,m(h,v,r,e,t(d,w+1,g),D,k),b(h,l(v),g),d[x].skip=!0,null!=v.dom&&(g=v.dom)):g=n(h,r,e,k,g))}C--}else w--,C--;if(Cb.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function q(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||W.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ +Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:y(q)},setCompletionCallback:function(b){z=b}}}(window,p),R=function(a){function c(h, +d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=t&&x>=r;){var w= +d[t],p=a[r];if(w!==p||c)if(null==w)t++;else if(null==p)r++;else if(w.key===p.key){var C=null!=q&&t>=d.length-q.length||null==q&&c;t++;r++;m(h,w,p,e,z(d,t,g),C,k);c&&w.tag===p.tag&&b(h,l(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)r++;else if(w.key===p.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),C,k),(c||r=t&&x>=r;){w=d[v];p=a[x];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key=== +p.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),C,k),c&&w.tag===p.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;C=v;w={};var u;for(u=0;u=d.length-q.length||null==q&&c,m(h,u,p,e,z(d,v+1,g),C,k),b(h,l(u),g),d[w].skip=!0,null!=u.dom&&(g=u.dom)):g=n(h,p,e,k,g))}x--}else v--,x--;if(x Date: Wed, 1 Nov 2017 03:37:51 +0800 Subject: [PATCH 101/301] Trying to fix #1916 (#1918) * Trying to fix #1916 * Remove test for rendering select options. Add back after resolving issue #1978. * Add #1916 fix to change log. * Revert "Remove test for rendering select options. Add back after resolving issue #1978." This reverts commit d4c1be7c2319adf744f78ca787485f52be869208. * Comment on why failing test for #1916 is commented out. --- docs/change-log.md | 1 + render/render.js | 2 +- render/tests/test-attributes.js | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 09b28302..087202a9 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -44,6 +44,7 @@ - core: `xlink:href` attributes are now correctly removed - core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks - render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) +- render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) --- diff --git a/render/render.js b/render/render.js index 37855447..4fabfc45 100644 --- a/render/render.js +++ b/render/render.js @@ -551,7 +551,7 @@ module.exports = function($window) { } } function isFormAttribute(vnode, attr) { - return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement + return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.dom.parentNode === $doc.activeElement } function isLifecycleMethod(attr) { return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate" diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index d54ed9d4..62cb4196 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -462,6 +462,19 @@ o.spec("attributes", function() { {tag:"option", attrs: {value: ""}} ]} } + /* FIXME + This incomplete test is meant for testing #1916. + However it cannot be completed until #1978 is addressed + which is a lack a working select.selected / option.selected + attribute. Ask isiahmeadows. + + o("render select options", function() { + var select = {tag: "select", selectedIndex: 0, children: [ + {tag:"option", attrs: {value: "1", selected: ""}} + ]} + render(root, select) + }) + */ o("can be set as text", function() { var a = makeSelect() var b = makeSelect("2") From 021b11eff070bfcdf97b8f6eb061beb407b59dc7 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 31 Oct 2017 19:43:44 +0000 Subject: [PATCH 102/301] Bundled output for commit db2a12dec97d5b42e353582d3ee09f701d27eb1e [skip ci] --- README.md | 2 +- mithril.js | 2 +- mithril.min.js | 62 +++++++++++++++++++++++++------------------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index d931eeb5..214d677a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.44 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.45 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 3d5c1d1b..57faabb4 100644 --- a/mithril.js +++ b/mithril.js @@ -916,7 +916,7 @@ var coreRenderer = function($window) { } } function isFormAttribute(vnode, attr) { - return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement + return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.dom.parentNode === $doc.activeElement } function isLifecycleMethod(attr) { return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate" diff --git a/mithril.min.js b/mithril.min.js index f9b5258f..417ab72b 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,8 +1,8 @@ -(function(){function u(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function N(a){for(var c in a)if(D.call(a,c))return!1;return!0}function B(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=O[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var q=f[1], -m=f[2];""===q&&""!==m?n=m:"#"===q?g.id=m:"."===q?k.push(m):"["===f[3][0]&&((q=f[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(q):g[f[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try typeof b.user?b.user:void 0,"string"===typeof b.password?b.password:void 0);b.serialize!==JSON.stringify||!f||b.headers&&b.headers.hasOwnProperty("Content-Type")||l.setRequestHeader("Content-Type","application/json; charset=utf-8");b.deserialize!==g||b.headers&&b.headers.hasOwnProperty("Accept")||l.setRequestHeader("Accept","application/json, text/*");b.withCredentials&&(l.withCredentials=b.withCredentials);for(var z in b.headers)({}).hasOwnProperty.call(b.headers,z)&&l.setRequestHeader(z,b.headers[z]); "function"===typeof b.config&&(l=b.config(l,b)||l);l.onreadystatechange=function(){if(!y&&4===l.readyState)try{var a=b.extract!==q?b.extract(l,b):b.deserialize(b.extract(l,b));if(200<=l.status&&300>l.status||304===l.status||W.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:y(q)},setCompletionCallback:function(b){z=b}}}(window,p),R=function(a){function c(h, -d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=t&&x>=r;){var w= -d[t],p=a[r];if(w!==p||c)if(null==w)t++;else if(null==p)r++;else if(w.key===p.key){var C=null!=q&&t>=d.length-q.length||null==q&&c;t++;r++;m(h,w,p,e,z(d,t,g),C,k);c&&w.tag===p.tag&&b(h,l(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)r++;else if(w.key===p.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),C,k),(c||r=t&&x>=r;){w=d[v];p=a[x];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key=== -p.key)C=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),C,k),c&&w.tag===p.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;C=v;w={};var u;for(u=0;u=d.length-q.length||null==q&&c,m(h,u,p,e,z(d,v+1,g),C,k),b(h,l(u),g),d[w].skip=!0,null!=u.dom&&(g=u.dom)):g=n(h,p,e,k,g))}x--}else v--,x--;if(x=u&&D>=r;){var w= +d[u],p=a[r];if(w!==p||c)if(null==w)u++;else if(null==p)r++;else if(w.key===p.key){var t=null!=q&&u>=d.length-q.length||null==q&&c;u++;r++;m(h,w,p,e,z(d,u,g),t,k);c&&w.tag===p.tag&&b(h,l(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)r++;else if(w.key===p.key)t=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),t,k),(c||r=u&&D>=r;){w=d[v];p=a[D];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key=== +p.key)t=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),t,k),c&&w.tag===p.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-q.length||null==q&&c,m(h,B,p,e,z(d,v+1,g),t,k),b(h,l(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=n(h,p,e,k,g))}D--}else v--,D--;if(D Date: Sat, 4 Nov 2017 04:01:19 +1100 Subject: [PATCH 103/301] docs: Feature/testing docs update (#2012) --- docs/testing.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/testing.md b/docs/testing.md index ba850a5b..ead11517 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -74,7 +74,9 @@ var m = require("mithril") module.exports = { view: function() { - return m("div", "Hello world") + return m("div", + m("p", "Hello World") + ) } } ``` @@ -90,7 +92,7 @@ o.spec("MyComponent", function() { o(vnode.tag).equals("div") o(vnode.children.length).equals(1) - o(vnode.children[0].tag).equals("#") + o(vnode.children[0].tag).equals("p") o(vnode.children[0].children).equals("Hello world") }) }) From e90f14ebe0a1005c1bde787bbbf5abea5348340b Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Mon, 13 Nov 2017 17:06:20 +0100 Subject: [PATCH 104/301] docs: Fix mailto link (#2015) --- docs/code-of-conduct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/code-of-conduct.md b/docs/code-of-conduct.md index 50ebe61d..a8875af5 100644 --- a/docs/code-of-conduct.md +++ b/docs/code-of-conduct.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [github@patcavit.com](mailto:github@patcavit.com?subject=Mithril Code of Conduct). All +reported by contacting the project team at [github@patcavit.com](mailto:github@patcavit.com?subject=Mithril%20Code%20of%20Conduct). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. From 80b6a1af0d02309167788ed7a95aa1f275e07653 Mon Sep 17 00:00:00 2001 From: spacejack Date: Mon, 13 Nov 2017 11:08:54 -0500 Subject: [PATCH 105/301] feat: Don't reject m.request Promise if extract callback supplied (#2006) --- docs/change-log.md | 1 + docs/request.md | 6 ++++-- request/request.js | 2 +- request/tests/test-request.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 087202a9..28aabf32 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -20,6 +20,7 @@ - API: `m.redraw()` is always asynchronous ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: `m.mount()` will only render its own root when called, it will not trigger a `redraw()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Assigning to `vnode.state` (as in `vnode.state = ...`) is no longer supported. Instead, an error is thrown if `vnode.state` changes upon the invocation of a lifecycle hook. +- API: `m.request` will no longer reject the Promise on server errors (eg. status >= 400) if the caller supplies an `extract` callback. This gives applications more control over handling server responses. #### News diff --git a/docs/request.md b/docs/request.md index fe962e50..fb013df0 100644 --- a/docs/request.md +++ b/docs/request.md @@ -54,7 +54,7 @@ Argument | Type | Required | Descr `options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). `options.serialize` | `string = Function(any)` | No | A serialization method to be applied to `data`. Defaults to `JSON.stringify`, or if `options.data` is an instance of [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData), defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function) (i.e. `function(value) {return value}`). `options.deserialize` | `any = Function(string)` | No | A deserialization method to be applied to the `xhr.responseText`. Defaults to a small wrapper around `JSON.parse` that returns `null` for empty responses. If `extract` is defined, `deserialize` will be skipped. -`options.extract` | `any = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for processing response data, reading headers and cookies. By default this is a function that returns `xhr.responseText`, which is in turn passed to `deserialize`. If a custom `extract` callback is provided, the `xhr` parameter is the XMLHttpRequest instance used for the request, and `options` is the object that was passed to the `m.request` call. Additionally, `deserialize` will be skipped and the value returned from the extract callback will not automatically be parsed as JSON. +`options.extract` | `any = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for processing response data, reading headers and cookies. By default this is a function that returns `xhr.responseText`, which is in turn passed to `deserialize`. If a custom `extract` callback is provided, the `xhr` parameter is the XMLHttpRequest instance used for the request, and `options` is the object that was passed to the `m.request` call. Additionally, `deserialize` will be skipped and the value returned from the extract callback will be left as-is when the promise resolves. Furthermore, when an extract callback is provided, exceptions are *not* thrown when the server response status code indicates an error. `options.useBody` | `Boolean` | No | Force the use of the HTTP body section for `data` in `GET` requests when set to `true`, or the use of querystring for other HTTP methods when set to `false`. Defaults to `false` for `GET` requests and `true` for other methods. `options.background` | `Boolean` | No | If `false`, redraws mounted components upon completion of the request. If `true`, it does not. Defaults to `false`. **returns** | `Promise` | | A promise that resolves to the response data, after it has been piped through the `extract`, `deserialize` and `type` methods @@ -81,6 +81,8 @@ A call to `m.request` returns a [promise](promise.md) and triggers a redraw upon By default, `m.request` assumes the response is in JSON format and parses it into a Javascript object (or array). +If the HTTP response status code indicates an error, the returned Promise will be rejected. Supplying an extract callback will prevent the promise rejection. + --- ### Typical usage @@ -426,7 +428,7 @@ m.request({ ### Retrieving response details -By default Mithril attempts to parse a response as JSON and returns `xhr.responseText`. It may be useful to inspect a server response in more detail, this can be accomplished by passing a custom `options.extract` function: +By default Mithril attempts to parse `xhr.responseText` as JSON and returns the parsed object. It may be useful to inspect a server response in more detail and process it manually. This can be accomplished by passing a custom `options.extract` function: ```javascript m.request({ diff --git a/request/request.js b/request/request.js index 7e4ec744..b5190ba7 100644 --- a/request/request.js +++ b/request/request.js @@ -88,7 +88,7 @@ module.exports = function($window, Promise) { if (xhr.readyState === 4) { try { var response = (args.extract !== extract) ? args.extract(xhr, args) : args.deserialize(args.extract(xhr, args)) - if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || FILE_PROTOCOL_REGEX.test(args.url)) { + if (args.extract !== extract || (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || FILE_PROTOCOL_REGEX.test(args.url)) { resolve(cast(args.type, response)) } else { diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 94e7e172..5ad5da91 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -519,5 +519,35 @@ o.spec("xhr", function() { o(e instanceof Error).equals(true) }).then(done) }) + o("does not reject on status error code when extract provided", function(done) { + mock.$defineRoutes({ + "GET /item": function() { + return {status: 500, responseText: JSON.stringify({message: "error"})} + } + }) + xhr({ + method: "GET", url: "/item", + extract: function(xhr) {return JSON.parse(xhr.responseText)} + }).then(function(data) { + o(data.message).equals("error") + done() + }) + }) + o("rejects on error in extract", function(done) { + mock.$defineRoutes({ + "GET /item": function() { + return {status: 200, responseText: JSON.stringify({a: 1})} + } + }) + xhr({ + method: "GET", url: "/item", + extract: function() {throw new Error("error")} + }).catch(function(e) { + o(e instanceof Error).equals(true) + o(e.message).equals("error") + }).then(function() { + done() + }) + }) }) }) From a382c85eb0754bc388275a2b8810c7f1c5347d26 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 13 Nov 2017 16:10:41 +0000 Subject: [PATCH 106/301] Bundled output for commit 80b6a1af0d02309167788ed7a95aa1f275e07653 [skip ci] --- README.md | 2 +- mithril.js | 2 +- mithril.min.js | 62 +++++++++++++++++++++++++------------------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 214d677a..0969834e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.45 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.46 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 57faabb4..dd480518 100644 --- a/mithril.js +++ b/mithril.js @@ -304,7 +304,7 @@ var _8 = function($window, Promise) { if (xhr.readyState === 4) { try { var response = (args.extract !== extract) ? args.extract(xhr, args) : args.deserialize(args.extract(xhr, args)) - if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || FILE_PROTOCOL_REGEX.test(args.url)) { + if (args.extract !== extract || (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || FILE_PROTOCOL_REGEX.test(args.url)) { resolve(cast(args.type, response)) } else { diff --git a/mithril.min.js b/mithril.min.js index 417ab72b..53007e6f 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,46 @@ -(function(){function x(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function N(a){for(var c in a)if(C.call(a,c))return!1;return!0}function A(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=O[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var q=f[1], -m=f[2];""===q&&""!==m?n=m:"#"===q?g.id=m:"."===q?k.push(m):"["===f[3][0]&&((q=f[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(q):g[f[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function q(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cb.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function p(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||W.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b,g);var q=new c(function(c,e){var f=b.callbackName||"_mithril_"+ -Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?q:y(q)},setCompletionCallback:function(b){z=b}}}(window,p),R=function(a){function c(h, +"function"===typeof b.config&&(l=b.config(l,b)||l);l.onreadystatechange=function(){if(!y&&4===l.readyState)try{var a=b.extract!==p?b.extract(l,b):b.deserialize(b.extract(l,b));if(b.extract!==p||200<=l.status&&300>l.status||304===l.status||W.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b,g);var p=new c(function(c,e){var f=b.callbackName|| +"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?p:y(p)},setCompletionCallback:function(b){z=b}}}(window,q),R=function(a){function c(h, d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&D>=r;){var w= -d[u],p=a[r];if(w!==p||c)if(null==w)u++;else if(null==p)r++;else if(w.key===p.key){var t=null!=q&&u>=d.length-q.length||null==q&&c;u++;r++;m(h,w,p,e,z(d,u,g),t,k);c&&w.tag===p.tag&&b(h,l(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)r++;else if(w.key===p.key)t=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),t,k),(c||r=u&&D>=r;){w=d[v];p=a[D];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key=== -p.key)t=null!=q&&v>=d.length-q.length||null==q&&c,m(h,w,p,e,z(d,v+1,g),t,k),c&&w.tag===p.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-q.length||null==q&&c,m(h,B,p,e,z(d,v+1,g),t,k),b(h,l(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=n(h,p,e,k,g))}D--}else v--,D--;if(D=u&&D>=r;){var w= +d[u],q=a[r];if(w!==q||c)if(null==w)u++;else if(null==q)r++;else if(w.key===q.key){var t=null!=p&&u>=d.length-p.length||null==p&&c;u++;r++;m(h,w,q,e,z(d,u,g),t,k);c&&w.tag===q.tag&&b(h,l(w),g)}else if(w=d[v],w!==q||c)if(null==w)v--;else if(null==q)r++;else if(w.key===q.key)t=null!=p&&v>=d.length-p.length||null==p&&c,m(h,w,q,e,z(d,v+1,g),t,k),(c||r=u&&D>=r;){w=d[v];q=a[D];if(w!==q||c)if(null==w)v--;else{if(null!=q)if(w.key=== +q.key)t=null!=p&&v>=d.length-p.length||null==p&&c,m(h,w,q,e,z(d,v+1,g),t,k),c&&w.tag===q.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-p.length||null==p&&c,m(h,B,q,e,z(d,v+1,g),t,k),b(h,l(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=n(h,q,e,k,g))}D--}else v--,D--;if(D Date: Tue, 14 Nov 2017 23:47:02 +0100 Subject: [PATCH 107/301] feat: Add support for `timeout` to `m.request` (#1966) --- docs/change-log.md | 1 + docs/request.md | 1 + request/request.js | 2 ++ request/tests/test-request.js | 14 ++++++++++++++ 4 files changed, 18 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 28aabf32..ad28942a 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -27,6 +27,7 @@ - API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) +- API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) #### Ospec improvements: diff --git a/docs/request.md b/docs/request.md index fb013df0..44bb954b 100644 --- a/docs/request.md +++ b/docs/request.md @@ -49,6 +49,7 @@ Argument | Type | Required | Descr `options.user` | `String` | No | A username for HTTP authorization. Defaults to `undefined`. `options.password` | `String` | No | A password for HTTP authorization. Defaults to `undefined`. This option is provided for `XMLHttpRequest` compatibility, but you should avoid using it because it sends the password in plain text over the network. `options.withCredentials` | `Boolean` | No | Whether to send cookies to 3rd party domains. Defaults to `false` +`options.timeout` | `Number` | No | The amount of milliseconds a request can take before automatically being [terminated](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout). Defaults to `undefined`. `options.config` | `xhr = Function(xhr)` | No | Exposes the underlying XMLHttpRequest object for low-level configuration. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). `options.headers` | `Object` | No | Headers to append to the request before sending it (applied right before `options.config`). `options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). diff --git a/request/request.js b/request/request.js index b5190ba7..8424f889 100644 --- a/request/request.js +++ b/request/request.js @@ -75,6 +75,8 @@ module.exports = function($window, Promise) { } if (args.withCredentials) xhr.withCredentials = args.withCredentials + if (args.timeout) xhr.timeout = args.timeout + for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) { xhr.setRequestHeader(key, args.headers[key]) } diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 5ad5da91..5c3c4cce 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -435,6 +435,20 @@ o.spec("xhr", function() { done() }) }) + o("set timeout to xhr instance", function() { + mock.$defineRoutes({ + "GET /item": function() { + return {status: 200, responseText: ''} + } + }) + return xhr({ + method: "GET", url: "/item", + timeout: 42, + config: function(xhr) { + o(xhr.timeout).equals(42) + } + }) + }) /*o("data maintains after interpolate", function() { mock.$defineRoutes({ "PUT /items/:x": function() { From 684a394d97e8a4a4c630a3cd4819ff3779036a4a Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 14 Nov 2017 22:48:49 +0000 Subject: [PATCH 108/301] Bundled output for commit d50d53f31d384b0eac83d4ea24dbe43c96e941fb [skip ci] --- README.md | 2 +- mithril.js | 1 + mithril.min.js | 92 +++++++++++++++++++++++++------------------------- 3 files changed, 48 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 0969834e..b9240f22 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.46 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.48 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index dd480518..182ca224 100644 --- a/mithril.js +++ b/mithril.js @@ -294,6 +294,7 @@ var _8 = function($window, Promise) { xhr.setRequestHeader("Accept", "application/json, text/*") } if (args.withCredentials) xhr.withCredentials = args.withCredentials + if (args.timeout) xhr.timeout = args.timeout for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) { xhr.setRequestHeader(key, args.headers[key]) } diff --git a/mithril.min.js b/mithril.min.js index 53007e6f..8c155377 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,46 @@ -(function(){function x(a,c,e,f,n,k){return{tag:a,key:c,attrs:e,children:f,text:n,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function N(a){for(var c in a)if(C.call(a,c))return!1;return!0}function A(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=O[a])){var n="div";for(var k=[],g={};f=S.exec(a);){var p=f[1], -m=f[2];""===p&&""!==m?n=m:"#"===p?g.id=m:"."===p?k.push(m):"["===f[3][0]&&((p=f[6])&&(p=p.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?k.push(p):g[f[4]]=""===p?p:p||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function p(b){return b.responseText}function m(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;cl.status||304===l.status||W.test(b.url))c(m(b.type,a));else{var f=Error(l.responseText);f.code=l.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?l.send(b.data):l.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b,g);var p=new c(function(c,e){var f=b.callbackName|| -"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(m(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=n(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=k(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?p:y(p)},setCompletionCallback:function(b){z=b}}}(window,q),R=function(a){function c(h, -d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&D>=r;){var w= -d[u],q=a[r];if(w!==q||c)if(null==w)u++;else if(null==q)r++;else if(w.key===q.key){var t=null!=p&&u>=d.length-p.length||null==p&&c;u++;r++;m(h,w,q,e,z(d,u,g),t,k);c&&w.tag===q.tag&&b(h,l(w),g)}else if(w=d[v],w!==q||c)if(null==w)v--;else if(null==q)r++;else if(w.key===q.key)t=null!=p&&v>=d.length-p.length||null==p&&c,m(h,w,q,e,z(d,v+1,g),t,k),(c||r=u&&D>=r;){w=d[v];q=a[D];if(w!==q||c)if(null==w)v--;else{if(null!=q)if(w.key=== -q.key)t=null!=p&&v>=d.length-p.length||null==p&&c,m(h,w,q,e,z(d,v+1,g),t,k),c&&w.tag===q.tag&&b(h,l(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-p.length||null==p&&c,m(h,B,q,e,z(d,v+1,g),t,k),b(h,l(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=n(h,q,e,k,g))}D--}else v--,D--;if(Db.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function n(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;ck.status||304===k.status||W.test(b.url))c(r(b.type,a));else{var f=Error(k.responseText);f.code=k.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b, +g);var n=new c(function(c,e){var f=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+k++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(r(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=m(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=l(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?n:y(n)},setCompletionCallback:function(b){z= +b}}}(window,p),R=function(a){function c(h,d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&D>=q;){var w=d[u],p=a[q];if(w!==p||c)if(null==w)u++;else if(null==p)q++;else if(w.key===p.key){var t=null!=n&&u>=d.length-n.length||null==n&&c;u++;q++;r(h,w,p,e,z(d,u,g),t,l);c&&w.tag===p.tag&&b(h,k(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)q++;else if(w.key===p.key)t=null!=n&&v>=d.length-n.length||null==n&&c,r(h,w,p,e,z(d,v+1,g),t,l),(c||q=u&&D>=q;){w=d[v];p=a[D];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key===p.key)t=null!=n&&v>=d.length-n.length||null==n&&c,r(h,w,p,e,z(d,v+1,g),t,l),c&&w.tag===p.tag&&b(h,k(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-n.length||null==n&&c,r(h,B,p,e,z(d,v+1,g),t,l),b(h,k(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=m(h,p,e, +l,g))}D--}else v--,D--;if(D Date: Mon, 20 Nov 2017 17:30:08 -0500 Subject: [PATCH 109/301] docs: Learning section (#1817) --- docs/learning-mithril.md | 5 +++++ docs/nav-guides.md | 1 + 2 files changed, 6 insertions(+) create mode 100644 docs/learning-mithril.md diff --git a/docs/learning-mithril.md b/docs/learning-mithril.md new file mode 100644 index 00000000..fb599df8 --- /dev/null +++ b/docs/learning-mithril.md @@ -0,0 +1,5 @@ +# Learning Mithril + +Links to Mithril learning content: + +- [Mithril 0-60](https://scrimba.com/playlist/playlist-34) diff --git a/docs/nav-guides.md b/docs/nav-guides.md index 872ce86b..4a5be9df 100644 --- a/docs/nav-guides.md +++ b/docs/nav-guides.md @@ -9,6 +9,7 @@ - [Animation](animation.md) - [Testing](testing.md) - [Examples](examples.md) + - [Learning Mithril](learning-mithril.md) - Key concepts - [Vnodes](vnodes.md) - [Components](components.md) From 78eeb2b365a300905d038b72dd3fcbe369ee77aa Mon Sep 17 00:00:00 2001 From: Sage Gerard Date: Mon, 20 Nov 2017 18:37:07 -0500 Subject: [PATCH 110/301] feat(ospec): Allow custom reporters for CI reasons (#2019) (#2020) --- docs/change-log.md | 1 + ospec/README.md | 84 +++++++++++++++++++++++++++++++++++++-- ospec/ospec.js | 8 +++- ospec/tests/test-ospec.js | 34 ++++++++++++++++ 4 files changed, 121 insertions(+), 6 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index ad28942a..891107fa 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -32,6 +32,7 @@ #### Ospec improvements: - Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) +- Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) - Error handling for async tests with `done` callbacks supports error as first argument - Error messages which include newline characters do not swallow the stack trace ([#1495](https://github.com/MithrilJS/mithril.js/issues/1495)) diff --git a/ospec/README.md b/ospec/README.md index dc3d923e..f2610e0f 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -19,7 +19,7 @@ Noiseless testing framework - `before`/`after`/`beforeEach`/`afterEach` hooks - test exclusivity (i.e. `.only`) - async tests and hooks -- explicitly disallows test-space configuration to encourage focus on testing, and to provide uniform test suites across projects +- explicitly regulates test-space configuration to encourage focus on testing, and to provide uniform test suites across projects ## Usage @@ -437,9 +437,17 @@ The arguments that were passed to the function in the last time it was called --- -### void o.run() +### void o.run([Function reporter]) -Runs the test suite +Runs the test suite. By default passing test results are printed using +`console.log` and failing test results are printed using `console.error`. + +If you have custom continuous integration needs then you can use a +reporter to process [test result data](#result-data) yourself. + +If running in Node.js, ospec will call `process.exit` after reporting +results by default. If you specify a reporter, ospec will not do this +and allow your reporter to respond to results in its own way. --- @@ -455,6 +463,74 @@ $o("a test", function() { $o.run() ``` +--- + +## Result data + +Test results are available by reference for integration purposes. You +can use custom reporters in `o.run()` to process these results. + +```javascript +o.run(function(results) { + // results is an array + + results.forEach(function(result) { + // ... + }) +}) +``` + +--- + +### Boolean result.pass + +True if the test passed. **No other keys will exist on the result if this value is true.** + +--- + +### Error result.error + +The value of the stack property from the `Error` object explaining the reason behind a failure. + +--- + +### String result.message + +If an exception was thrown inside the corresponding test, this will equal that Error's `message`. Otherwise, this will be a preformatted message in [SVO form](https://en.wikipedia.org/wiki/Subject%E2%80%93verb%E2%80%93object). More specifically, `${subject}\n${verb}\n${object}`. + +As an example, the following test's result message will be `"false\nshould equal\ntrue"`. + +```javascript +o.spec("message", function() { + o(false).equals(true) +}) +``` + +If you specify an assertion description, that description will appear two lines above the subject. + +```javascript +o.spec("message", function() { + o(false).equals(true)("Candyland") // result.message === "Candyland\n\nfalse\nshould equal\ntrue" +}) +``` + +--- + +### String result.context + +A `>`-separated string showing the structure of the test specification. +In the below example, `result.context` would be `testing > rocks`. + +```javascript +o.spec("testing", function() { + o.spec("rocks", function() { + o(false).equals(true) + }) +}) +``` + + + --- ## Goals @@ -462,8 +538,8 @@ $o.run() - Do the most common things that the mocha/chai/sinon triad does without having to install 3 different libraries and several dozen dependencies - Disallow configuration in test-space: - Disallow ability to pick between API styles (BDD/TDD/Qunit, assert/should/expect, etc) - - Disallow ability to pick between different reporters - Disallow ability to add custom assertion types + - Provide a default simple reporter - Make assertion code terse, readable and self-descriptive - Have as few assertion types as possible for a workable usage pattern diff --git a/ospec/ospec.js b/ospec/ospec.js index b1036743..5b29ec84 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -2,7 +2,7 @@ "use strict" module.exports = new function init(name) { - var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty + var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", reporter, hasOwn = ({}).hasOwnProperty if (name != null) spec[name] = ctx = {} @@ -52,9 +52,10 @@ module.exports = new function init(name) { o.cleanStackTrace = function(stack) { return stack.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/gm).pop() } - o.run = function() { + o.run = function(_reporter) { results = [] start = new Date + reporter = _reporter test(spec, [], [], report) function test(spec, pre, post, finalize) { @@ -236,6 +237,9 @@ module.exports = new function init(name) { function report() { var status = 0 + + if (typeof reporter === "function") return reporter(results) + for (var i = 0, r; r = results[i]; i++) { if (!r.pass) { var stackTrace = o.cleanStackTrace(r.error) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 4ef4614d..a1894419 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -18,6 +18,40 @@ new function(o) { o.run() }(o) +new function(o) { + var clone = o.new() + + clone.spec("clone", function() { + clone("fail", function() { + clone(true).equals(false) + }) + + clone("pass", function() { + clone(true).equals(true) + }) + }) + + // Predicate test passing on clone results + o.spec("reporting", function() { + o("reports per instance", function(done, timeout) { + timeout(100) // Waiting on clone + + clone.run(function(results) { + o(typeof results).equals("object") + o("length" in results).equals(true) + o(results.length).equals(2)("Two results") + + o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result") + o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result") + o(results[0].pass).equals(false)("Test meant to fail has failed") + o(results[1].pass).equals(true)("Test meant to pass has passed") + + done() + }) + }) + }) +}(o) + o.spec("ospec", function() { o.spec("sync", function() { var a = 0, b = 0, illegalAssertionThrows = false From 1be2c419817d1cbfb2e8a40e6d682c285ed2cd3a Mon Sep 17 00:00:00 2001 From: Andrea Coiutti Date: Fri, 24 Nov 2017 20:12:34 +0100 Subject: [PATCH 111/301] Fix headings displaying over menu on mobile (#2022) --- docs/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/style.css b/docs/style.css index bf0e6874..96efe7d2 100644 --- a/docs/style.css +++ b/docs/style.css @@ -57,7 +57,7 @@ h1 + ul strong + ul {border-left:3px solid #1e5799;} .hamburger:hover {text-decoration:none;} main section {margin:0;} header section {margin:0 0 20px;position:static;width:auto;} - h1 + ul {background:#eee;border:1px solid #ccc;box-sizing:border-box;display:none;height:100%;margin:0;overflow:auto;padding:20px;position:fixed;right:0;top:0;width:100%;} + h1 + ul {background:#eee;border:1px solid #ccc;box-sizing:border-box;display:none;height:100%;margin:0;overflow:auto;padding:20px;position:fixed;right:0;top:0;width:100%;z-index:1} h1 + ul + hr {display:block;} .navigating h1 + ul {display:block;} .navigating {overflow:hidden;} From d116f249db91c8c2ab233af7d93ce894c285e197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 17:08:46 +0100 Subject: [PATCH 112/301] lint: fix quotes --- ospec/tests/test-ospec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index a1894419..e837049d 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -183,13 +183,13 @@ o.spec("ospec", function() { }) }) - o.spec('stack trace cleaner', function() { - o('handles line breaks', function() { + o.spec("stack trace cleaner", function() { + o("handles line breaks", function() { try { - throw new Error('line\nbreak') + throw new Error("line\nbreak") } catch(error) { var trace = o.cleanStackTrace(error.stack) - o(trace).notEquals('break') + o(trace).notEquals("break") o(trace.includes("test-ospec.js")).equals(true) } }) From 4e35aff18881fb9c458d1cb19b5cb043ed593850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 21:39:35 +0100 Subject: [PATCH 113/301] Lint: Fix quotes in m.request tests (#2033) --- request/tests/test-request.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 5c3c4cce..52f840ef 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -230,7 +230,7 @@ o.spec("xhr", function() { } }) xhr({method: "GET", url: "/item", deserialize: deserialize}).then(function(data) { - o(data).equals('{"test":123}') + o(data).equals("{\"test\":123}") }).then(done) }) o("deserialize parameter works in POST", function(done) { @@ -244,7 +244,7 @@ o.spec("xhr", function() { } }) xhr({method: "POST", url: "/item", deserialize: deserialize}).then(function(data) { - o(data).equals('{"test":123}') + o(data).equals("{\"test\":123}") }).then(done) }) o("extract parameter works in GET", function(done) { @@ -258,7 +258,7 @@ o.spec("xhr", function() { } }) xhr({method: "GET", url: "/item", extract: extract}).then(function(data) { - o(data).equals('{"test":123}') + o(data).equals("{\"test\":123}") }).then(done) }) o("extract parameter works in POST", function(done) { @@ -272,7 +272,7 @@ o.spec("xhr", function() { } }) xhr({method: "POST", url: "/item", extract: extract}).then(function(data) { - o(data).equals('{"test":123}') + o(data).equals("{\"test\":123}") }).then(done) }) o("ignores deserialize if extract is defined", function(done) { @@ -438,7 +438,7 @@ o.spec("xhr", function() { o("set timeout to xhr instance", function() { mock.$defineRoutes({ "GET /item": function() { - return {status: 200, responseText: ''} + return {status: 200, responseText: ""} } }) return xhr({ From 12da6ea94af6238e13e125a659b34b9629565678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 22:14:36 +0100 Subject: [PATCH 114/301] Sync change log with v1.1.6 (#2035) --- docs/change-log.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 891107fa..0fccbf1d 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -29,12 +29,6 @@ - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) -#### Ospec improvements: - -- Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) -- Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) -- Error handling for async tests with `done` callbacks supports error as first argument -- Error messages which include newline characters do not swallow the stack trace ([#1495](https://github.com/MithrilJS/mithril.js/issues/1495)) #### Bug fixes @@ -45,12 +39,26 @@ - core: `Object.prototype` properties can no longer interfere with event listener calls. - API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. - core: `xlink:href` attributes are now correctly removed -- core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks - render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) - render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) --- +### v1.1.6 + +- core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks ([#1988](https://github.com/MithrilJS/mithril.js/pull/1988), [@purplecode](https://github.com/purplecode)) +- core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) +- hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) + +#### Ospec improvements + +- Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) +- Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) +- Error handling for async tests with `done` callbacks supports error as first argument +- Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@ RodericDay](https://github.com/RodericDay)) + +--- + ### v1.1.5 - API: If a user sets the Content-Type header within a request's options, that value will be the entire header value rather than being appended to the default value ([#1924](https://github.com/MithrilJS/mithril.js/pull/1924)) @@ -61,9 +69,7 @@ #### Bug fixes: -- core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) -- hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) -- Fix IE bug where active element is null causing render function to throw error. ([1943](https://github.com/MithrilJS/mithril.js/pull/1943)) +- Fix IE bug where active element is null causing render function to throw error ([#1943](https://github.com/MithrilJS/mithril.js/pull/1943), [@JacksonJN](https://github.com/JacksonJN)) #### Ospec improvements: From f06510bb62d44638addb8e1c0f0265584602fd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 21:46:26 +0100 Subject: [PATCH 115/301] Make ospec work natively in browser environments --- ospec/ospec.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 5b29ec84..51e60e55 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -1,7 +1,9 @@ /* eslint-disable global-require, no-bitwise, no-process-exit */ "use strict" - -module.exports = new function init(name) { +;(function(m) { +if (typeof module !== "undefined") module["exports"] = m() +else window.o = m() +})(function init(name) { var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", reporter, hasOwn = ({}).hasOwnProperty if (name != null) spec[name] = ctx = {} @@ -265,4 +267,4 @@ module.exports = new function init(name) { } return o -} +}) From b38ba7c934442289b5e5a3be3e0587b1afe3ca84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 21:50:34 +0100 Subject: [PATCH 116/301] Pop `report()` off the stack (for better Flems output) --- ospec/ospec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 51e60e55..a538515a 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -58,7 +58,7 @@ else window.o = m() results = [] start = new Date reporter = _reporter - test(spec, [], [], report) + test(spec, [], [], function() {setTimeout(report)}) function test(spec, pre, post, finalize) { pre = [].concat(pre, spec["__beforeEach"] || []) From 8eb12454caf66b5a7fdadb0ff2e301f1cc02d179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 29 Nov 2017 22:17:42 +0100 Subject: [PATCH 117/301] update change log for #2034 --- docs/change-log.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/change-log.md b/docs/change-log.md index 0fccbf1d..cfaa74e9 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -56,6 +56,7 @@ - Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) - Error handling for async tests with `done` callbacks supports error as first argument - Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@ RodericDay](https://github.com/RodericDay)) +- Make Ospec more [Flems](https://flems.io)-friendly (#2034) --- From 0873cb53cc9872bf389e0f4356e33508d64710af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 00:27:08 +0100 Subject: [PATCH 118/301] Make the stack trace filter path-independent (auto-detection vs. hardcoded previously) --- ospec/ospec.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index a538515a..29f7fdef 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -8,6 +8,13 @@ else window.o = m() if (name != null) spec[name] = ctx = {} + try {throw new Error} catch (e) { + var stackTraceMatcher = new RegExp( + "^(?:(?!Error|" + + e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] + + ").)*$", "gm" + ) + } function o(subject, predicate) { if (predicate === undefined) { if (results == null) throw new Error("Assertions should not occur outside test definitions") @@ -52,7 +59,7 @@ else window.o = m() return spy } o.cleanStackTrace = function(stack) { - return stack.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/gm).pop() + return stack.match(stackTraceMatcher).pop() } o.run = function(_reporter) { results = [] From cd3c1afca29d872ac8c5f5288157f3485853cacb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 00:27:48 +0100 Subject: [PATCH 119/301] Readme: adjust the LOC count --- ospec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/README.md b/ospec/README.md index f2610e0f..7a257b31 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -7,7 +7,7 @@ Noiseless testing framework ## About -- ~180 LOC +- ~330 LOC including the CLI runner - terser and faster test code than with mocha, jasmine or tape - test code reads like bullet points - assertion code follows [SVO](https://en.wikipedia.org/wiki/Subject–verb–object) structure in present tense for terseness and readability From 9083a325a4ac6b7ebfe2657e8c94ef1663f2a057 Mon Sep 17 00:00:00 2001 From: Milan Lesichkov Date: Thu, 30 Nov 2017 07:05:21 +0000 Subject: [PATCH 120/301] docs: Fixed background issue (#2037) Fixed missing background for body, which causes browser default to apply, resulting in unreadable content --- docs/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/style.css b/docs/style.css index 96efe7d2..f75ea282 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,4 +1,4 @@ -body {-webkit-text-size-adjust: 100%;} +body {bakground:white;-webkit-text-size-adjust: 100%;} body,table,h5 {font:normal 16px 'Open Sans';} header,main {margin:auto;max-width:1000px;} header section {position:absolute;width:250px;} From 2fb828783a1a96794e4deeb0f74ce5bc58b7a5b9 Mon Sep 17 00:00:00 2001 From: Leo Thorp Date: Thu, 30 Nov 2017 02:25:10 -0600 Subject: [PATCH 121/301] fix typo in body background style --- docs/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/style.css b/docs/style.css index f75ea282..3da4e572 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,4 +1,4 @@ -body {bakground:white;-webkit-text-size-adjust: 100%;} +body {background:white;-webkit-text-size-adjust: 100%;} body,table,h5 {font:normal 16px 'Open Sans';} header,main {margin:auto;max-width:1000px;} header section {position:absolute;width:250px;} From b84e09369e6c78b4d6b29991956f81a3823057cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 01:36:47 +0100 Subject: [PATCH 122/301] ospec: better stack trace filter, fix #2036 --- ospec/README.md | 2 +- ospec/ospec.js | 24 ++++++++++++++++-------- ospec/tests/test-ospec.js | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 7a257b31..b3a3ff76 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -490,7 +490,7 @@ True if the test passed. **No other keys will exist on the result if this value ### Error result.error -The value of the stack property from the `Error` object explaining the reason behind a failure. +The `Error` object explaining the reason behind a failure. --- diff --git a/ospec/ospec.js b/ospec/ospec.js index 29f7fdef..1c7cb94c 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -9,11 +9,7 @@ else window.o = m() if (name != null) spec[name] = ctx = {} try {throw new Error} catch (e) { - var stackTraceMatcher = new RegExp( - "^(?:(?!Error|" - + e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] - + ").)*$", "gm" - ) + var ospecFileName = e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] } function o(subject, predicate) { if (predicate === undefined) { @@ -58,8 +54,19 @@ else window.o = m() spy.callCount = 0 return spy } - o.cleanStackTrace = function(stack) { - return stack.match(stackTraceMatcher).pop() + o.cleanStackTrace = function(error) { + var i = 0, header = error.message ? error.name + ": " + error.message : error.name, stack + // some environments add the name and message to the stack trace + if (error.stack.indexOf(header) === 0) { + stack = error.stack.slice(header.length).split(/\r?\n/) + stack.shift() // drop the initial empty string + } else { + stack = error.stack.split(/\r?\n/) + } + // skip ospec-related entries on the stack + while (stack[i].indexOf(ospecFileName) !== -1) i++ + // now we're in user code + return stack[i] } o.run = function(_reporter) { results = [] @@ -230,7 +237,8 @@ else window.o = m() } result.context = subjects.join(" > ") result.message = message - result.error = error.stack + result.error = error + } results.push(result) } diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index e837049d..86218c83 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -188,7 +188,7 @@ o.spec("ospec", function() { try { throw new Error("line\nbreak") } catch(error) { - var trace = o.cleanStackTrace(error.stack) + var trace = o.cleanStackTrace(error) o(trace).notEquals("break") o(trace.includes("test-ospec.js")).equals(true) } From acd08c96dd6c2e6f3dcf3f7016e2ab1241e0ddcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 22:37:16 +0100 Subject: [PATCH 123/301] Make the stack trace cleaner IE9 compatible (err.stack is null) --- ospec/ospec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 1c7cb94c..4ab57ab3 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -9,7 +9,7 @@ else window.o = m() if (name != null) spec[name] = ctx = {} try {throw new Error} catch (e) { - var ospecFileName = e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] + var ospecFileName = e.stack && (/[\/\\](.*?):\d+:\d+/).test(e.stack) ? e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] : null } function o(subject, predicate) { if (predicate === undefined) { @@ -55,6 +55,8 @@ else window.o = m() return spy } o.cleanStackTrace = function(error) { + // For IE 10+ in quirks mode, and IE 9- in any mode, errors don't have a stack + if (error.stack == null) return "" var i = 0, header = error.message ? error.name + ": " + error.message : error.name, stack // some environments add the name and message to the stack trace if (error.stack.indexOf(header) === 0) { @@ -63,6 +65,7 @@ else window.o = m() } else { stack = error.stack.split(/\r?\n/) } + if (ospecFileName == null) return stack.join("\n") // skip ospec-related entries on the stack while (stack[i].indexOf(ospecFileName) !== -1) i++ // now we're in user code From 769c854f8247c9271f404f82869892e62ab1efa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 23:25:31 +0100 Subject: [PATCH 124/301] Expose the reporter as o.report(results), have it return the number of errors --- ospec/ospec.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 4ab57ab3..9769bccd 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -4,7 +4,7 @@ if (typeof module !== "undefined") module["exports"] = m() else window.o = m() })(function init(name) { - var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", reporter, hasOwn = ({}).hasOwnProperty + var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty if (name != null) spec[name] = ctx = {} @@ -71,11 +71,18 @@ else window.o = m() // now we're in user code return stack[i] } - o.run = function(_reporter) { + o.run = function(reporter) { results = [] start = new Date - reporter = _reporter - test(spec, [], [], function() {setTimeout(report)}) + test(spec, [], [], function() { + setTimeout(function () { + if (typeof reporter === "function") reporter(results) + else { + var errCount = o.report(results) + if (hasProcess && errCount !== 0) process.exit(1) + } + }) + }) function test(spec, pre, post, finalize) { pre = [].concat(pre, spec["__beforeEach"] || []) @@ -255,16 +262,13 @@ else window.o = m() return hasProcess ? "\x1b[31m" + message + "\x1b[0m" : "%c" + message + "%c " } - function report() { - var status = 0 - - if (typeof reporter === "function") return reporter(results) - + o.report = function (results) { + var errCount = 0 for (var i = 0, r; r = results[i]; i++) { if (!r.pass) { var stackTrace = o.cleanStackTrace(r.error) console.error(r.context + ":\n" + highlight(r.message) + (stackTrace ? "\n\n" + stackTrace + "\n\n" : ""), hasProcess ? "" : "color:red", hasProcess ? "" : "color:black") - status = 1 + errCount++ } } console.log( @@ -272,10 +276,10 @@ else window.o = m() results.length + " assertions completed in " + Math.round(new Date - start) + "ms, " + "of which " + results.filter(function(result){return result.error}).length + " failed" ) - if (hasProcess && status === 1) process.exit(1) + return errCount } - if(hasProcess) { + if (hasProcess) { nextTickish = process.nextTick } else { nextTickish = function fakeFastNextTick(next) { From 3ac17d0075281f39dc3df0bfa53158ecdd5ff65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 30 Nov 2017 23:49:34 +0100 Subject: [PATCH 125/301] ospec: tests and docs for o.report --- ospec/README.md | 11 ++++++++++- ospec/tests/test-ospec.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/ospec/README.md b/ospec/README.md index b3a3ff76..9b0b416c 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -311,7 +311,9 @@ ospec will automatically evaluate all `*.js` files in any folder named `/tests`. Ospec doesn't work when installed globally. Using global scripts is generally a bad idea since you can end up with different, incompatible versions of the same package installed locally and globally. -To work around this limitation, you can use [`npm-run`](https://www.npmjs.com/package/npm-run) which enables one to run the binaries of locally installed packages. +If you're using a recent version of npm (v5+), you can use run `npx ospec` from your project folder. + +Otherwise, to work around this limitation, you can use [`npm-run`](https://www.npmjs.com/package/npm-run) which enables one to run the binaries of locally installed packages. ``` npm install npm-run -g @@ -449,6 +451,13 @@ If running in Node.js, ospec will call `process.exit` after reporting results by default. If you specify a reporter, ospec will not do this and allow your reporter to respond to results in its own way. + +--- + +### Number o.report(results) + +The default reporter used by `o.run()` when none are provided. Returns the number of failures, doesn't exit Node.js by itself. It expects an array of [test result data](#result-data) as argument. + --- ### Function o.new() diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 86218c83..526671c6 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -49,6 +49,43 @@ new function(o) { done() }) }) + o("o.report() returns the number of failures", function () { + var log = console.log, error = console.error + console.log = o.spy() + console.error = o.spy() + + function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}} + try { + var errCount = o.report([{pass: true}, {pass: true}]) + + o(errCount).equals(0) + o(console.log.callCount).equals(1) + o(console.error.callCount).equals(0) + + errCount = o.report([ + {pass: false, error: makeError("hey"), message: "hey"} + ]) + + o(errCount).equals(1) + o(console.log.callCount).equals(2) + o(console.error.callCount).equals(1) + + errCount = o.report([ + {pass: false, error: makeError("hey"), message: "hey"}, + {pass: true}, + {pass: false, error: makeError("ho"), message: "ho"} + ]) + + o(errCount).equals(2) + o(console.log.callCount).equals(3) + o(console.error.callCount).equals(3) + } catch (e) { + o(1).equals(0)("Error while testing the reporter") + } + + console.log = log + console.error = error + }) }) }(o) From 854021db32ca7a8644c603f639db8eba925cd17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Dec 2017 14:01:55 +0100 Subject: [PATCH 126/301] Detail the upcoming ospec v2 additions --- docs/change-log.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index cfaa74e9..69e49a26 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -52,11 +52,18 @@ #### Ospec improvements -- Added support for async functions and promises in tests - ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) -- Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) -- Error handling for async tests with `done` callbacks supports error as first argument -- Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@ RodericDay](https://github.com/RodericDay)) -- Make Ospec more [Flems](https://flems.io)-friendly (#2034) +- ospec v1.4.0 + - Added support for async functions and promises in tests ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928), [@StephanHoyer](https://github.com/StephanHoyer)) + - Error handling for async tests with `done` callbacks supports error as first argument ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) + - Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@RodericDay](https://github.com/RodericDay)) +- ospec v2.0.0 (to be released) + - Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) + - Make Ospec more [Flems](https://flems.io)-friendly (#2034) + - Works either as a global or in CommonJS environments + - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). + - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) + - expose the default reporter as `o.report(results)` + - Don't try to access the stack traces in IE9 --- From 6f435a55f9232ecaae269a5ee4e2b65cb022f8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Dec 2017 14:12:17 +0100 Subject: [PATCH 127/301] More change log tweaks --- docs/change-log.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 69e49a26..02eb18ac 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,6 +1,7 @@ # Change log - [v2.0.0](#v200-wip) +- [v1.1.6](#v115) - [v1.1.5](#v115) - [v1.1.4](#v114) - [v1.1.3](#v113) @@ -47,8 +48,8 @@ ### v1.1.6 - core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks ([#1988](https://github.com/MithrilJS/mithril.js/pull/1988), [@purplecode](https://github.com/purplecode)) -- core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) -- hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) +- core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [@octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) +- hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [@s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) #### Ospec improvements From 84b729d012e9667dd74357b9c4d4d59065020781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Dec 2017 14:27:32 +0100 Subject: [PATCH 128/301] And some more change log tweaks --- docs/change-log.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 02eb18ac..28e8173c 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -58,13 +58,13 @@ - Error handling for async tests with `done` callbacks supports error as first argument ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) - Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@RodericDay](https://github.com/RodericDay)) - ospec v2.0.0 (to be released) - - Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) - - Make Ospec more [Flems](https://flems.io)-friendly (#2034) - - Works either as a global or in CommonJS environments - - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). - - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) - - expose the default reporter as `o.report(results)` - - Don't try to access the stack traces in IE9 + - Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) + - Make Ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) + - Works either as a global or in CommonJS environments + - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). + - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) + - expose the default reporter as `o.report(results)` + - Don't try to access the stack traces in IE9 --- From 8dc21f4c481a073f18cd33796f863bb9f9aa98bc Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Fri, 1 Dec 2017 17:05:45 +0100 Subject: [PATCH 129/301] docs: Fix anchor target (#2042) --- docs/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 28e8173c..a7d3b220 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -1,7 +1,7 @@ # Change log - [v2.0.0](#v200-wip) -- [v1.1.6](#v115) +- [v1.1.6](#v116) - [v1.1.5](#v115) - [v1.1.4](#v114) - [v1.1.3](#v113) From 12d3540d476ae73d2c46dfa75249b5a1b21b2030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 2 Dec 2017 00:51:32 +0100 Subject: [PATCH 130/301] domMock: implement event propagation --- test-utils/domMock.js | 127 ++++++-- test-utils/tests/test-domMock.js | 542 ++++++++++++++++++++++++++++++- 2 files changed, 648 insertions(+), 21 deletions(-) diff --git a/test-utils/domMock.js b/test-utils/domMock.js index b8f5d1a3..a4c7c598 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -37,6 +37,30 @@ module.exports = function(options) { function isModernEvent(type) { return type === "transitionstart" || type === "transitionend" || type === "animationstart" || type === "animationend" } + function dispatchEvent(e) { + var stopped = false + e.stopImmediatePropagation = function() { + e.stopPropagation() + stopped = true + } + e.currentTarget = this + if (this._events[e.type] != null) { + for (var i = 0; i < this._events[e.type].handlers.length; i++) { + var useCapture = this._events[e.type].options[i].capture + if (useCapture && e.eventPhase < 3 || !useCapture && e.eventPhase > 1) { + var handler = this._events[e.type].handlers[i] + if (typeof handler === "function") try {handler.call(this, e)} catch(e) {setTimeout(function(){throw e})} + else try {handler.handleEvent(e)} catch(e) {setTimeout(function(){throw e})} + if (stopped) return + } + } + } + // this is inaccurate. Normally the event fires in definition order, including legacy events + // this would require getters/setters for each of them though and we haven't gotten around to + // adding them since it would be at a high perf cost or would entail some heavy refactoring of + // the mocks (prototypes instead of closures). + if (e.eventPhase > 1 && typeof this["on" + e.type] === "function" && !isModernEvent(e.type)) try {this["on" + e.type](e)} catch(e) {setTimeout(function(){throw e})} + } function appendChild(child) { var ancestor = this while (ancestor !== child && ancestor !== null) ancestor = ancestor.parentNode @@ -260,35 +284,99 @@ module.exports = function(options) { else this.setAttribute("class", value) }, focus: function() {activeElement = this}, - addEventListener: function(type, callback) { - if (events[type] == null) events[type] = [callback] - else events[type].push(callback) + addEventListener: function(type, handler, options) { + if (arguments.length > 2) { + if (typeof options === "object" && options != null) throw new TypeError("NYI: addEventListener options") + else if (typeof options !== "boolean") throw new TypeError("boolean expected for useCapture") + else options = {capture: options} + } else { + options = {capture: false} + } + if (events[type] == null) events[type] = {handlers: [handler], options: [options]} + else { + var found = false + for (var i = 0; i < events[type].handlers.length; i++) { + if (events[type].handlers[i] === handler && events[type].options[i].capture === options.capture) { + found = true + break + } + } + if (!found) { + events[type].handlers.push(handler) + events[type].options.push(options) + } + } }, - removeEventListener: function(type, callback) { + removeEventListener: function(type, handler, options) { + if (arguments.length > 2) { + if (typeof options === "object" && options != null) throw new TypeError("NYI: addEventListener options") + else if (typeof options !== "boolean") throw new TypeError("boolean expected for useCapture") + else options = {capture: options} + } else { + options = {capture: false} + } if (events[type] != null) { - var index = events[type].indexOf(callback) - if (index > -1) events[type].splice(index, 1) + for (var i = 0; i < events[type].handlers.length; i++) { + if (events[type].handlers[i] === handler && events[type].options[i].capture === options.capture) { + events[type].handlers.splice(i, 1) + events[type].options.splice(i, 1) + break; + } + } } }, dispatchEvent: function(e) { - if (this.nodeName === "INPUT" && this.attributes["type"] != null && this.attributes["type"].value === "checkbox" && e.type === "click") { - this.checked = !this.checked + var parents = [] + if (this.parentNode != null) { + var parent = this.parentNode + do { + parents.push(parent) + parent = parent.parentNode + } while (parent != null) } - e.target = this - if (events[e.type] != null) { - for (var i = 0; i < events[e.type].length; i++) { - var handler = events[e.type][i] - if (typeof handler === "function") handler.call(this, e) - else handler.handleEvent(e) + var prevented = false + e.preventDefault = function() { + prevented = true + } + var stopped = false + e.stopPropagation = function() { + stopped = true + } + e.eventPhase = 1 + try { + for (var i = parents.length - 1; 0 <= i; i--) { + dispatchEvent.call(parents[i], e) + if (stopped) { + return + } + } + e.eventPhase = 2 + dispatchEvent.call(this, e) + if (stopped) { + return + } + e.eventPhase = 3 + for (var i = 0; i < parents.length; i++) { + dispatchEvent.call(parents[i], e) + if (stopped) { + return + } + } + } catch(e) { + throw e + } finally { + e.eventPhase = 0 + if (!prevented) { + if (this.nodeName === "INPUT" && this.attributes["type"] != null && this.attributes["type"].value === "checkbox" && e.type === "click") { + this.checked = !this.checked + } } } - e.preventDefault = function() { - // TODO: should this do something? - } - if (typeof this["on" + e.type] === "function" && !isModernEvent(e.type)) this["on" + e.type](e) + }, onclick: null, + _events: events } if (element.nodeName === "A") { @@ -515,7 +603,8 @@ module.exports = function(options) { }, createEvent: function() { return { - initEvent: function(type) {this.type = type}, + eventPhase: 0, + initEvent: function(type) {this.type = type} } }, get activeElement() {return activeElement}, diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index 3e4a9567..f05d24c9 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -611,13 +611,57 @@ o.spec("domMock", function() { o(spy.args[0].type).equals("click") o(spy.args[0].target).equals(div) }) - o("removeEventListener works", function(done) { + o("removeEventListener works (bubbling phase)", function() { div.addEventListener("click", spy, false) div.removeEventListener("click", spy, false) div.dispatchEvent(e) o(spy.callCount).equals(0) - done() + }) + o("removeEventListener works (capture phase)", function() { + div.addEventListener("click", spy, true) + div.removeEventListener("click", spy, true) + div.dispatchEvent(e) + + o(spy.callCount).equals(0) + }) + o("removeEventListener is selective (bubbling phase)", function() { + var other = o.spy() + div.addEventListener("click", spy, false) + div.addEventListener("click", other, false) + div.removeEventListener("click", spy, false) + div.dispatchEvent(e) + + o(spy.callCount).equals(0) + o(other.callCount).equals(1) + }) + o("removeEventListener is selective (capture phase)", function() { + var other = o.spy() + div.addEventListener("click", spy, true) + div.addEventListener("click", other, true) + div.removeEventListener("click", spy, true) + div.dispatchEvent(e) + + o(spy.callCount).equals(0) + o(other.callCount).equals(1) + }) + o("removeEventListener only removes the handler related to a given phase (1/2)", function() { + spy = o.spy(function(e) {o(e.eventPhase).equals(3)}) + $document.body.addEventListener("click", spy, true) + $document.body.addEventListener("click", spy, false) + $document.body.removeEventListener("click", spy, true) + div.dispatchEvent(e) + + o(spy.callCount).equals(1) + }) + o("removeEventListener only removes the handler related to a given phase (2/2)", function() { + spy = o.spy(function(e) {o(e.eventPhase).equals(1)}) + $document.body.addEventListener("click", spy, true) + $document.body.addEventListener("click", spy, false) + $document.body.removeEventListener("click", spy, false) + div.dispatchEvent(e) + + o(spy.callCount).equals(1) }) o("click fires onclick", function() { div.onclick = spy @@ -655,6 +699,488 @@ o.spec("domMock", function() { done() }) }) + o.spec("capture and bubbling phases", function() { + var div, e + o.beforeEach(function() { + div = $document.createElement("div") + e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + + $document.body.appendChild(div) + }) + o.afterEach(function() { + $document.body.removeChild(div) + }) + o("capture and bubbling events both fire on the target in the order they were defined, regardless of the phase", function () { + var sequence = [] + var capture = o.spy(function(ev){ + sequence.push("capture") + + o(ev).equals(e) + o(ev.eventPhase).equals(2) + o(ev.target).equals(div) + o(ev.currentTarget).equals(div) + }) + var bubble = o.spy(function(ev){ + sequence.push("bubble") + + o(ev).equals(e) + o(ev.eventPhase).equals(2) + o(ev.target).equals(div) + o(ev.currentTarget).equals(div) + }) + + div.addEventListener("click", bubble, false) + div.addEventListener("click", capture, true) + div.dispatchEvent(e) + + o(capture.callCount).equals(1) + o(bubble.callCount).equals(1) + o(sequence).deepEquals(["bubble", "capture"]) + }) + o("capture and bubbling events both fire on the parent", function () { + var sequence = [] + var capture = o.spy(function(ev){ + sequence.push("capture") + + o(ev).equals(e) + o(ev.eventPhase).equals(1) + o(ev.target).equals(div) + o(ev.currentTarget).equals($document.body) + }) + var bubble = o.spy(function(ev){ + sequence.push("bubble") + + o(ev).equals(e) + o(ev.eventPhase).equals(3) + o(ev.target).equals(div) + o(ev.currentTarget).equals($document.body) + }) + + $document.body.addEventListener("click", bubble, false) + $document.body.addEventListener("click", capture, true) + div.dispatchEvent(e) + + o(capture.callCount).equals(1) + o(bubble.callCount).equals(1) + o(sequence).deepEquals(["capture", "bubble"]) + }) + o("useCapture defaults to false", function () { + var sequence = [] + var parent = o.spy(function(ev){ + sequence.push("parent") + + o(ev).equals(e) + o(ev.eventPhase).equals(3) + o(ev.target).equals(div) + o(ev.currentTarget).equals($document.body) + }) + var target = o.spy(function(ev){ + sequence.push("target") + + o(ev).equals(e) + o(ev.eventPhase).equals(2) + o(ev.target).equals(div) + o(ev.currentTarget).equals(div) + }) + + $document.body.addEventListener("click", parent) + div.addEventListener("click", target) + div.dispatchEvent(e) + + o(parent.callCount).equals(1) + o(target.callCount).equals(1) + o(sequence).deepEquals(["target", "parent"]) + }) + o("legacy handlers fire on the bubbling phase", function () { + var sequence = [] + var parent = o.spy(function(ev){ + sequence.push("parent") + + o(ev).equals(e) + o(ev.eventPhase).equals(3) + o(ev.target).equals(div) + o(ev.currentTarget).equals($document.body) + }) + var target = o.spy(function(ev){ + sequence.push("target") + + o(ev).equals(e) + o(ev.eventPhase).equals(2) + o(ev.target).equals(div) + o(ev.currentTarget).equals(div) + }) + + $document.body.addEventListener("click", parent) + $document.body.onclick = parent + div.addEventListener("click", target) + div.dispatchEvent(e) + + o(parent.callCount).equals(2) + o(target.callCount).equals(1) + o(sequence).deepEquals(["target", "parent", "parent"]) + }) + o("events do not propagate to child nodes", function() { + var target = o.spy(function(ev){ + o(ev).equals(e) + o(ev.eventPhase).equals(2) + o(ev.target).equals($document.body) + o(ev.currentTarget).equals($document.body) + }) + var child = o.spy(function(){ + }) + + $document.body.addEventListener("click", target) + div.addEventListener("click", child) + $document.body.dispatchEvent(e) + + o(target.callCount).equals(1) + o(child.callCount).equals(0) + }) + o("e.stopPropagation 1/6", function () { + var capParent = o.spy(function(e){e.stopPropagation()}) + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(0) + o(bubTarget.callCount).equals(0) + o(legacyTarget.callCount).equals(0) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopPropagation 2/6", function () { + var capParent = o.spy() + var capTarget = o.spy(function(e){e.stopPropagation()}) + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + + o("e.stopPropagation 3/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy(function(e){e.stopPropagation()}) + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopPropagation 4/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy(function(e){e.stopPropagation()}) + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopPropagation 5/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy(function(e){e.stopPropagation()}) + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(1) + o(legacyParent.callCount).equals(1) + }) + o("e.stopPropagation 6/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var legacyTarget = o.spy() + var bubTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy(function(e){e.stopPropagation()}) + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(1) + o(legacyParent.callCount).equals(1) + }) + o("e.stopImmediatePropagation 1/6", function () { + var capParent = o.spy(function(e){e.stopImmediatePropagation()}) + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(0) + o(bubTarget.callCount).equals(0) + o(legacyTarget.callCount).equals(0) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopImmediatePropagation 2/6", function () { + var capParent = o.spy() + var capTarget = o.spy(function(e){e.stopImmediatePropagation()}) + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(0) + o(legacyTarget.callCount).equals(0) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + + o("e.stopImmediatePropagation 3/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy(function(e){e.stopImmediatePropagation()}) + var legacyTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(0) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopImmediatePropagation 4/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy(function(e){e.stopImmediatePropagation()}) + var bubParent = o.spy() + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(0) + o(legacyParent.callCount).equals(0) + }) + o("e.stopImmediatePropagation 5/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var bubTarget = o.spy() + var legacyTarget = o.spy() + var bubParent = o.spy(function(e){e.stopImmediatePropagation()}) + var legacyParent = o.spy() + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(1) + o(legacyParent.callCount).equals(0) + }) + o("e.stopImmediatePropagation 6/6", function () { + var capParent = o.spy() + var capTarget = o.spy() + var legacyTarget = o.spy() + var bubTarget = o.spy() + var bubParent = o.spy() + var legacyParent = o.spy(function(e){e.stopImmediatePropagation()}) + + $document.body.addEventListener("click", capParent, true) + $document.body.addEventListener("click", bubParent, false) + $document.body.onclick = legacyParent + + div.addEventListener("click", capTarget, true) + div.addEventListener("click", bubTarget, false) + div.onclick = legacyTarget + + div.dispatchEvent(e) + + o(capParent.callCount).equals(1) + o(capTarget.callCount).equals(1) + o(bubTarget.callCount).equals(1) + o(legacyTarget.callCount).equals(1) + o(bubParent.callCount).equals(1) + o(legacyParent.callCount).equals(1) + }) + o("errors thrown in handlers don't interrupt the chain", function(done) { + var errMsg = "The presence of these six errors in the log is expected in non-Node.js environments" + var handler = o.spy(function(){throw errMsg}) + + $document.body.addEventListener("click", handler, true) + $document.body.addEventListener("click", handler, false) + $document.body.onclick = handler + + div.addEventListener("click", handler, true) + div.addEventListener("click", handler, false) + div.onclick = handler + + div.dispatchEvent(e) + + o(handler.callCount).equals(6) + + // Swallow the async errors in NodeJS + if (typeof process !== "undefined" && typeof process.once === "function"){ + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + process.once("uncaughtException", function(e) { + if (e !== errMsg) throw e + done() + }) + }) + }) + }) + }) + }) + } else { + done() + } + }) + }) }) o.spec("attributes", function() { o.spec("a[href]", function() { @@ -731,6 +1257,18 @@ o.spec("domMock", function() { o(input.checked).equals(true) }) + o("doesn't toggle on click when preventDefault() is used", function() { + var input = $document.createElement("input") + input.setAttribute("type", "checkbox") + input.checked = false + input.onclick = function(e) {e.preventDefault()} + + var e = $document.createEvent("MouseEvents") + e.initEvent("click", true, true) + input.dispatchEvent(e) + + o(input.checked).equals(false) + }) }) o.spec("input[value]", function() { o("only exists in input elements", function() { From 5d1c7d23b95ffb9dfafb0979449359804c6faf24 Mon Sep 17 00:00:00 2001 From: cavemansspa Date: Sun, 3 Dec 2017 15:55:38 -0500 Subject: [PATCH 131/301] docs: Integrating 3rd party libs (#2047) --- docs/integrating-libs.md | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 docs/integrating-libs.md diff --git a/docs/integrating-libs.md b/docs/integrating-libs.md new file mode 100644 index 00000000..42b72bee --- /dev/null +++ b/docs/integrating-libs.md @@ -0,0 +1,57 @@ +# Integrating with Other Libraries +Integration with third party libraries or vanilla javascript code can be achieved via [lifecycle methods](lifecycle-methods.md). + +- [Usage](#usage) + +### Usage +```javascript +var FullCalendar = { + + oncreate: function (vnode) { + console.log('FullCalendar::oncreate') + $(vnode.dom).fullCalendar({ + // put your initial options and callbacks here + }) + + Object.assign(vnode.attrs.parentState, {fullCalendarEl: vnode.dom}) + }, + + // Consider that the lib will modify this parent element in the DOM (e.g. add dependent class attribute and values). + // As long as you return the same view results here, mithril will not + // overwrite the actual DOM because it's always comparing old and new VDOM + // before applying DOM updates. + view: function (vnode) { + return m('div') + }, + + onbeforeremove: function (vnode) { + // Run any destroy / cleanup methods here. + //E.g. $(vnode.state.fullCalendarEl).fullCalendar('destroy') + } +} + +m.mount(document.body, { + view: function (vnode) { + return [ + m('h1', 'Calendar'), + m(FullCalendar, {parentState: vnode.state}), + m('button', {onclick: prev}, 'Mithril Button -'), + m('button', {onclick: next}, 'Mithril Button +') + + ] + + function next() { + $(vnode.state.fullCalendarEl).fullCalendar('next') + } + + function prev() { + $(vnode.state.fullCalendarEl).fullCalendar('prev') + } + + } + +}) + +``` + +Running example [flems: FullCalendar](https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvAHigjQGsACAJxigBeADog4xAJ6w4hGDGKjuhfmBEgSxAA5xEAel3UAJmgBWcfNSi0ArobBQM-C7Sy6MJjAA9d7AEZxdMGsoKGoMWDRDR10AZnwAdnwABkDg0PCmKN58LA4LODhRAD4QAF8KdGxcRAIzShp6RmYagDdHbgAxNIBhDMj2wW5gYTQR4WJ6an4MRkRuILRqYgh6bgAKFrRaQxgASiGxhWI6NDhaWHwrAHM1gHIukN6oft5EREnpxlvdw-GAEg2Wx2+EMLl2+CCjz6WTWw1GR3G+m4mmsxG4EhsvG4HAgy3C3FommW9Dg3AwkW4YRCvgw1E4pNk-F+xFKP1G8PGAHlfCYYEt8BgChArmhAdsYALiMReOZNI4mMQAMrEGYwChDSFQJ6ZRwAUSgc024pBLlZh3KY3hLQgMAA7nMFksVmh1kadvs4eNxvxiNZeC6sHdDBAWt9zRRLeN6L4YGBaPx+FhaC0YA7rItiS6xe6DhziEiAErpsloCTcHbiXi0Mu6SmwcnWTTcHDEQjbBkwJzM-QAt0S8SqiE9aF6qDgzXal5B+DS6th+GlEaL9lYHI2BhrUHUaw4Bj4XzbCTqz3Ea12tMZ52uoF7XNe6XyP0u5DM8aB26EACMt3Vt0nWW+CM8zfNYHi1EdeGPOV+AYZVVUNG98AHRhWSA+8QNuXxUQmNAfzvBEjkmdg6TmTR+BaV8WV-ABZXFlGgbgACFsNWABaQDKPfLCpXoPCT3QnDLAgEjuDQGBPAUYCqO4W5aNbXgGOYniXQAannZkAF1IyOR1M1E8TiDWD1KN7RDkIlCcIP1cdhwiGFbjEiT1KOZdmV0q8yJgFojPw+9TONcyhyhOzRxs4KdV4O5PNDNl71chdLVZMoKhATAcDwfIECoE4mmIPAyg0qh2C4BAUEqdKalyeToHqP1yBqDRtD0XR000TgrmcVwqvoqAAAFP3wAaAFZdG6hSoHwOoqEkTRqhAOpynKuak13PKqDqvBGp0fRWvazrRpcBVeoAJkGgBOfBjoO1bJqykAZrmhaUrSx6AEdrE7CRat4er1ClJqdrQNqOroVwTHez7eriU7P10YNxF0cGPt4CRbvqB68Cepa8E1KkIu+36tua3aQZcVIQjxl4oYSZI4YgBHcYgtHpokWbMYQUoNNKIA) \ No newline at end of file From 4542d2997a60dc09e0b9a065a1d32d99f709d525 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Sun, 3 Dec 2017 16:34:13 +0700 Subject: [PATCH 132/301] issue #1914 docs/support.md should exist --- .github/CONTRIBUTING.md | 3 +++ .github/SUPPORT.md | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/SUPPORT.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..b553c8d1 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,3 @@ +## Contributing + +There's a [Contributing FAQ](https://mithril.js.org/contributing.html) on the mithril site that hopefully helps, but if not definitely hop into the [Gitter Room](https://gitter.im/mithriljs/mithril.js) and ask away! \ No newline at end of file diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 00000000..8ed1ebe1 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,3 @@ +## Getting Help + +Mithril has an active & welcoming community on [Gitter](https://gitter.im/mithriljs/mithril.js), or feel free to ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/mithril.js) using the `mithril.js` tag. \ No newline at end of file From 9f1f0f0094bda8eb3c80c955094313ff03b9dd66 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Sun, 3 Dec 2017 16:37:58 +0700 Subject: [PATCH 133/301] delete CONTRIBUTING.md as it is existed in ./docs folder --- .github/CONTRIBUTING.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index b553c8d1..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,3 +0,0 @@ -## Contributing - -There's a [Contributing FAQ](https://mithril.js.org/contributing.html) on the mithril site that hopefully helps, but if not definitely hop into the [Gitter Room](https://gitter.im/mithriljs/mithril.js) and ask away! \ No newline at end of file From 7179692fc4c1c3b991cd69e81c4b1d16a0e38858 Mon Sep 17 00:00:00 2001 From: thepriefy Date: Mon, 4 Dec 2017 06:53:31 +0700 Subject: [PATCH 134/301] change folder of support.md file --- .github/SUPPORT.md => docs/support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/SUPPORT.md => docs/support.md (84%) diff --git a/.github/SUPPORT.md b/docs/support.md similarity index 84% rename from .github/SUPPORT.md rename to docs/support.md index 8ed1ebe1..ae466e16 100644 --- a/.github/SUPPORT.md +++ b/docs/support.md @@ -1,3 +1,3 @@ ## Getting Help -Mithril has an active & welcoming community on [Gitter](https://gitter.im/mithriljs/mithril.js), or feel free to ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/mithril.js) using the `mithril.js` tag. \ No newline at end of file +Mithril has an active & welcoming community on [Gitter](https://gitter.im/mithriljs/mithril.js), or feel free to ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/mithril.js) using the `mithril.js` tag. From 8950760e857ed8c92269f0834f28862adc15eb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 2 Nov 2017 15:51:06 +0100 Subject: [PATCH 135/301] render: extract pool addtition logic, don't run onremove on nodes that move from pool to pool (fix #1990) --- render/render.js | 22 ++++++--- render/tests/test-updateNodes.js | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/render/render.js b/render/render.js index 4fabfc45..ee7cefe1 100644 --- a/render/render.js +++ b/render/render.js @@ -185,7 +185,7 @@ module.exports = function($window) { } } recycling = recycling || isRecyclable(old, vnodes) - if (recycling) { + if (recycling && old.pool != null) { var pool = old.pool old = old.concat(old.pool) } @@ -250,7 +250,14 @@ module.exports = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, oldEnd + 1, vnodes) + removeNodes(old, oldStart, Math.min(oldEnd + 1, pool == null ? old.length : old.length - pool.length), vnodes) + if (pool != null) { + var limit = Math.max(oldStart, old.length - pool.length) + for (; oldEnd >= limit; oldEnd--) { + if (old[oldEnd].skip) old[oldEnd].skip = false + else addToPool(old[oldEnd], vnodes) + } + } } } function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { @@ -455,10 +462,7 @@ module.exports = function($window) { } } removeNodeFromDOM(vnode.dom) - if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements - if (!context.pool) context.pool = [vnode] - else context.pool.push(vnode) - } + addToPool(vnode, context) } } } @@ -467,6 +471,12 @@ module.exports = function($window) { var parent = node.parentNode if (parent != null) parent.removeChild(node) } + function addToPool(vnode, context) { + if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements + if (!context.pool) context.pool = [vnode] + else context.pool.push(vnode) + } + } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index fa5231ea..5f82281b 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -839,6 +839,19 @@ o.spec("updateNodes", function() { o(root.childNodes[0].nodeName).equals("A") o(root.childNodes[1].nodeName).equals("B") }) + o("onremove doesn't fire from nodes in the pool (#1990)", function () { + var onremove = o.spy() + render(root, [ + {tag: "div", children: [{tag: "div", attrs: {onremove: onremove}}]}, + {tag: "div", children: [{tag: "div", attrs: {onremove: onremove}}]} + ]) + render(root, [ + {tag: "div", children: [{tag: "div", attrs: {onremove: onremove}}]} + ]) + render(root,[]) + + o(onremove.callCount).equals(2) + }) o("cached, non-keyed nodes skip diff", function () { var onupdate = o.spy(); var cached = {tag:"a", attrs:{onupdate: onupdate}} @@ -857,6 +870,72 @@ o.spec("updateNodes", function() { o(onupdate.callCount).equals(0) }) + o("keyed cached elements are re-initialized when brought back from the pool", function () { + var onupdate = o.spy() + var oncreate = o.spy() + var cached = { + tag: "B", key: 1, children: [ + {tag: "A", attrs: {oncreate: oncreate, onupdate: onupdate}, text: "A"} + ] + } + render(root, [{tag: "div", children: [cached]}]) + render(root, []) + render(root, [{tag: "div", children: [cached]}]) + + o(oncreate.callCount).equals(2) + o(onupdate.callCount).equals(0) + }) + + o("uneyed cached elements are re-initialized when brought back from the pool", function () { + var onupdate = o.spy() + var oncreate = o.spy() + var cached = { + tag: "B", children: [ + {tag: "A", attrs: {oncreate: oncreate, onupdate: onupdate}, text: "A"} + ] + } + render(root, [{tag: "div", children: [cached]}]) + render(root, []) + render(root, [{tag: "div", children: [cached]}]) + + o(oncreate.callCount).equals(2) + o(onupdate.callCount).equals(0) + }) + + o("keyed cached elements are re-initialized when brought back from nested pools", function () { + var onupdate = o.spy() + var oncreate = o.spy() + var cached = { + tag: "B", key: 1, children: [ + {tag: "A", attrs: {oncreate: oncreate, onupdate: onupdate}, text: "A"} + ] + } + render(root, [{tag: "div", children: [cached]}]) + render(root, [{tag: "div", children: []}]) + render(root, []) + render(root, [{tag: "div", children: [cached]}]) + + o(oncreate.callCount).equals(2) + o(onupdate.callCount).equals(0) + }) + + o("unkeyed cached elements are re-initialized when brought back from nested pools", function () { + var onupdate = o.spy() + var oncreate = o.spy() + var cached = { + tag: "B", children: [ + {tag: "A", attrs: {oncreate: oncreate, onupdate: onupdate}, text: "A"} + ] + } + render(root, [{tag: "div", children: [cached]}]) + render(root, [{tag: "div", children: []}]) + render(root, []) + render(root, [{tag: "div", children: [cached]}]) + + o(oncreate.callCount).equals(2) + o(onupdate.callCount).equals(0) + }) + o("null stays in place", function() { var create = o.spy() var update = o.spy() From eaa9f589af62462ae95cbbff3f7db87e2dc9fda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 21 Nov 2017 21:05:20 +0100 Subject: [PATCH 136/301] render/updateNodes: recycling, clarify terminology, fix logic fix #2003 partim 1 fix #1991 partim 1 --- render/render.js | 70 +++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/render/render.js b/render/render.js index ee7cefe1..beb84340 100644 --- a/render/render.js +++ b/render/render.js @@ -161,12 +161,13 @@ module.exports = function($window) { } //update - function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) { - if (old === vnodes || old == null && vnodes == null) return + function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { + if (old === vnodes && !recyclingParent || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length, vnodes) else { - if (old.length === vnodes.length) { + var originalOldLength = old.length, hasPool = false + if (originalOldLength === vnodes.length) { var isUnkeyed = false for (var i = 0; i < vnodes.length; i++) { if (vnodes[i] != null && old[i] != null) { @@ -175,56 +176,57 @@ module.exports = function($window) { } } if (isUnkeyed) { - for (var i = 0; i < old.length; i++) { - if (old[i] === vnodes[i]) continue + for (var i = 0; i < originalOldLength; i++) { + if (old[i] === vnodes[i] && !recyclingParent || old[i] == null && vnodes[i] == null) continue else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling)) else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes) - else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recycling, ns) + else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recyclingParent, ns) } return } } - recycling = recycling || isRecyclable(old, vnodes) - if (recycling && old.pool != null) { - var pool = old.pool + if (isRecyclable(old, vnodes)) { + hasPool = true old = old.concat(old.pool) } - var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map + var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool while (oldEnd >= oldStart && end >= start) { - var o = old[oldStart], v = vnodes[start] - if (o === v && !recycling) oldStart++, start++ + o = old[oldStart] + v = vnodes[start] + oFromPool = hasPool && oldStart >= originalOldLength + if (o === v && !oFromPool && !recyclingParent) oldStart++, start++ else if (o == null) oldStart++ else if (v == null) start++ else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldStart >= old.length - pool.length) || ((pool == null) && recycling) oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), shouldRecycle, ns) - if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) } else { - var o = old[oldEnd] - if (o === v && !recycling) oldEnd--, start++ + o = old[oldEnd] + oFromPool = hasPool && oldEnd >= originalOldLength + if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling)) oldEnd--, start++ } else break } } while (oldEnd >= oldStart && end >= start) { - var o = old[oldEnd], v = vnodes[end] - if (o === v && !recycling) oldEnd--, end-- + o = old[oldEnd] + v = vnodes[end] + oFromPool = hasPool && oldEnd >= originalOldLength + if (o === v && !oFromPool && !recyclingParent) oldEnd--, end-- else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- } @@ -233,12 +235,12 @@ module.exports = function($window) { if (v != null) { var oldIndex = map[v.key] if (oldIndex != null) { - var movable = old[oldIndex] - var shouldRecycle = (pool != null && oldIndex >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - insertNode(parent, toFragment(movable), nextSibling) - old[oldIndex].skip = true - if (movable.dom != null) nextSibling = movable.dom + o = old[oldIndex] + oFromPool = hasPool && oldIndex >= originalOldLength + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) + insertNode(parent, toFragment(o), nextSibling) + o.skip = true + if (o.dom != null) nextSibling = o.dom } else { var dom = createNode(parent, v, hooks, ns, nextSibling) @@ -250,9 +252,9 @@ module.exports = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, Math.min(oldEnd + 1, pool == null ? old.length : old.length - pool.length), vnodes) - if (pool != null) { - var limit = Math.max(oldStart, old.length - pool.length) + removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes) + if (hasPool) { + var limit = Math.max(oldStart, originalOldLength) for (; oldEnd >= limit; oldEnd--) { if (old[oldEnd].skip) old[oldEnd].skip = false else addToPool(old[oldEnd], vnodes) From e839c9e80ad0e65d0ec78fcae5e87338606d007f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 21 Nov 2017 21:08:42 +0100 Subject: [PATCH 137/301] render/updateNodes: Don't fetch the next sibling from the pool --- render/render.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/render/render.js b/render/render.js index beb84340..aa2c3d61 100644 --- a/render/render.js +++ b/render/render.js @@ -178,9 +178,9 @@ module.exports = function($window) { if (isUnkeyed) { for (var i = 0; i < originalOldLength; i++) { if (old[i] === vnodes[i] && !recyclingParent || old[i] == null && vnodes[i] == null) continue - else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling)) + else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, originalOldLength, nextSibling)) else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes) - else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recyclingParent, ns) + else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, originalOldLength, nextSibling), recyclingParent, ns) } return } @@ -200,7 +200,7 @@ module.exports = function($window) { else if (v == null) start++ else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) } else { @@ -210,8 +210,8 @@ module.exports = function($window) { else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, originalOldLength, nextSibling)) oldEnd--, start++ } else break @@ -225,7 +225,7 @@ module.exports = function($window) { else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- @@ -237,7 +237,7 @@ module.exports = function($window) { if (oldIndex != null) { o = old[oldIndex] oFromPool = hasPool && oldIndex >= originalOldLength - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) insertNode(parent, toFragment(o), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom @@ -402,8 +402,8 @@ module.exports = function($window) { } else return vnode.dom } - function getNextSibling(vnodes, i, nextSibling) { - for (; i < vnodes.length; i++) { + function getNextSibling(vnodes, i, limit, nextSibling) { + for (; i < limit; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom } return nextSibling From 98c053e12b7e0073d0faea485d5e97b448a5d577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 21 Nov 2017 21:27:12 +0100 Subject: [PATCH 138/301] render/updateNodes: revamp unkeyed list detection, don't skip null nodes in unkeyed lists when old and vnodes don't have the same length Fix #2003 partim 2 --- render/render.js | 64 ++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/render/render.js b/render/render.js index aa2c3d61..1e3f3fef 100644 --- a/render/render.js +++ b/render/render.js @@ -166,44 +166,56 @@ module.exports = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length, vnodes) else { - var originalOldLength = old.length, hasPool = false - if (originalOldLength === vnodes.length) { - var isUnkeyed = false - for (var i = 0; i < vnodes.length; i++) { - if (vnodes[i] != null && old[i] != null) { - isUnkeyed = vnodes[i].key == null && old[i].key == null - break - } + var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed + for(; start < commonLength; start++) { + if (old[start] != null) { + isUnkeyed = old[start].key == null + break } - if (isUnkeyed) { - for (var i = 0; i < originalOldLength; i++) { - if (old[i] === vnodes[i] && !recyclingParent || old[i] == null && vnodes[i] == null) continue - else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, originalOldLength, nextSibling)) - else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes) - else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, originalOldLength, nextSibling), recyclingParent, ns) - } - return + if (vnodes[start] != null) { + isUnkeyed = vnodes[start].key == null + break } } + if (isUnkeyed && originalOldLength === vnodes.length) { + // treat it as a tuple, no pool here + for (; start < originalOldLength; start++) { + if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue + else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) + else if (vnodes[start] == null) removeNodes(old, start, start + 1, null) + else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) + } + return + } + if (isRecyclable(old, vnodes)) { hasPool = true old = old.concat(old.pool) } - var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + var oldStart = start, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] oFromPool = hasPool && oldStart >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldStart++, start++ - else if (o == null) oldStart++ - else if (v == null) start++ - else if (o.key === v.key) { + if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ + else if (o == null) { + if (isUnkeyed) { + createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) + } + oldStart++ + } else if (v == null) { + if (isUnkeyed){ + removeNodes(old, start, start + 1, vnodes) + oldStart++ + } + start++ + } else if (o.key === v.key) { oldStart++, start++ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) - } - else { + } else { o = old[oldEnd] oFromPool = hasPool && oldEnd >= originalOldLength if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ @@ -229,8 +241,7 @@ module.exports = function($window) { if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- - } - else { + } else { if (!map) map = getKeyMap(old, oldEnd) if (v != null) { var oldIndex = map[v.key] @@ -241,8 +252,7 @@ module.exports = function($window) { insertNode(parent, toFragment(o), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom - } - else { + } else { var dom = createNode(parent, v, hooks, ns, nextSibling) nextSibling = dom } From 39ff8d721740ffa8ff038f65055de1f1d2160d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 22 Nov 2017 00:05:34 +0100 Subject: [PATCH 139/301] render: make removeNode aware that it is removing children from an object that's brought back from the pool --- render/render.js | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/render/render.js b/render/render.js index 1e3f3fef..61f8f9a6 100644 --- a/render/render.js +++ b/render/render.js @@ -164,7 +164,7 @@ module.exports = function($window) { function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { if (old === vnodes && !recyclingParent || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length, vnodes) + else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) else { var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed for(; start < commonLength; start++) { @@ -182,7 +182,7 @@ module.exports = function($window) { for (; start < originalOldLength; start++) { if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1, null) + else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) } return @@ -207,7 +207,7 @@ module.exports = function($window) { oldStart++ } else if (v == null) { if (isUnkeyed){ - removeNodes(old, start, start + 1, vnodes) + removeNodes(old, start, start + 1, vnodes, recyclingParent) oldStart++ } start++ @@ -262,7 +262,7 @@ module.exports = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes) + removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes, recyclingParent) if (hasPool) { var limit = Math.max(oldStart, originalOldLength) for (; oldEnd >= limit; oldEnd--) { @@ -296,7 +296,7 @@ module.exports = function($window) { else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) } else { - removeNode(old, null) + removeNode(old, null, recycling) createNode(parent, vnode, hooks, ns, nextSibling) } } @@ -368,7 +368,7 @@ module.exports = function($window) { vnode.domSize = vnode.instance.domSize } else if (old.instance != null) { - removeNode(old.instance, null) + removeNode(old.instance, null, recycling) vnode.dom = undefined vnode.domSize = 0 } @@ -434,37 +434,41 @@ module.exports = function($window) { } //remove - function removeNodes(vnodes, start, end, context) { + function removeNodes(vnodes, start, end, context, recycling) { for (var i = start; i < end; i++) { var vnode = vnodes[i] if (vnode != null) { if (vnode.skip) vnode.skip = false - else removeNode(vnode, context) + else removeNode(vnode, context, recycling) } } } - function removeNode(vnode, context) { + function removeNode(vnode, context, recycling) { var expected = 1, called = 0 var original = vnode.state - if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = callHook.call(vnode.attrs.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) + if (!recycling) { + if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) + } } - } - if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { - var result = callHook.call(vnode.state.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) + } } } continuation() function continuation() { if (++called === expected) { - checkState(vnode, original) - onremove(vnode) + if (!recycling) { + checkState(vnode, original) + onremove(vnode) + } if (vnode.dom) { var count = vnode.domSize || 1 if (count > 1) { From 9c835f4eac43280c48e267cdef8c290781d42fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 22 Nov 2017 00:19:35 +0100 Subject: [PATCH 140/301] render/updateNodes: call toFragment on the new vnodes, solves issues with actual fragments (fix #1991 partim 2) --- render/render.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/render/render.js b/render/render.js index 61f8f9a6..541bfd55 100644 --- a/render/render.js +++ b/render/render.js @@ -214,7 +214,7 @@ module.exports = function($window) { } else if (o.key === v.key) { oldStart++, start++ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) } else { o = old[oldEnd] oFromPool = hasPool && oldEnd >= originalOldLength @@ -223,7 +223,7 @@ module.exports = function($window) { else if (v == null) start++ else if (o.key === v.key) { updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, originalOldLength, nextSibling)) + if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, originalOldLength, nextSibling)) oldEnd--, start++ } else break @@ -238,7 +238,7 @@ module.exports = function($window) { else if (v == null) end-- else if (o.key === v.key) { updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- } else { @@ -249,7 +249,7 @@ module.exports = function($window) { o = old[oldIndex] oFromPool = hasPool && oldIndex >= originalOldLength updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - insertNode(parent, toFragment(o), nextSibling) + insertNode(parent, toFragment(v), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom } else { From fc0240da0ff2860e1364f304243a83e732e386ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 23 Nov 2017 00:24:18 +0100 Subject: [PATCH 141/301] Tests for #1990, #1991 and #2003 --- render/tests/test-onremove.js | 27 +++++++++++++- render/tests/test-updateNodes.js | 64 ++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/render/tests/test-onremove.js b/render/tests/test-onremove.js index f509e704..cc242a25 100644 --- a/render/tests/test-onremove.js +++ b/render/tests/test-onremove.js @@ -101,6 +101,7 @@ o.spec("onremove", function() { render(root, temp) render(root, updated) + o(vnodes[0].dom).equals(updated[0].dom) o(remove.callCount).equals(1) }) o("does not recycle when there's an onremove", function() { @@ -132,7 +133,7 @@ o.spec("onremove", function() { }) render(root, {tag: comp}) render(root, null) - + o(spy.callCount).equals(1) }) o("calls onremove on nested component child", function() { @@ -148,7 +149,7 @@ o.spec("onremove", function() { }) render(root, {tag: comp}) render(root, null) - + o(spy.callCount).equals(1) }) o("doesn't call onremove on children when the corresponding view returns null (after removing the parent)", function() { @@ -191,6 +192,28 @@ o.spec("onremove", function() { o(spy.callCount).equals(0) o(threw).equals(false) }) + o("onremove doesn't fire on nodes that go from pool to pool (#1990)", function() { + var onremove = o.spy(); + + render(root, [m("div", m("div")), m("div", m("div", {onremove: onremove}))]); + render(root, [m("div", m("div"))]); + render(root, []); + + o(onremove.callCount).equals(1) + }) + o("doesn't fire when removing the children of a node that's brought back from the pool (#1991 part 2)", function() { + var onremove = o.spy() + var vnode = {tag: "div", key: 1, children: [{tag: "div", attrs: {onremove: onremove}}]} + var temp = {tag: "div", key: 2} + var updated = {tag: "div", key: 1, children: [{tag: "p"}]} + + render(root, [vnode]) + render(root, [temp]) + render(root, [updated]) + + o(vnode.dom).equals(updated.dom) + o(onremove.callCount).equals(1) + }) }) }) }) \ No newline at end of file diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index 5f82281b..65d81916 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -870,7 +870,7 @@ o.spec("updateNodes", function() { o(onupdate.callCount).equals(0) }) - o("keyed cached elements are re-initialized when brought back from the pool", function () { + o("keyed cached elements are re-initialized when brought back from the pool (#2003)", function () { var onupdate = o.spy() var oncreate = o.spy() var cached = { @@ -886,7 +886,7 @@ o.spec("updateNodes", function() { o(onupdate.callCount).equals(0) }) - o("uneyed cached elements are re-initialized when brought back from the pool", function () { + o("unkeyed cached elements are re-initialized when brought back from the pool (#2003)", function () { var onupdate = o.spy() var oncreate = o.spy() var cached = { @@ -902,7 +902,7 @@ o.spec("updateNodes", function() { o(onupdate.callCount).equals(0) }) - o("keyed cached elements are re-initialized when brought back from nested pools", function () { + o("keyed cached elements are re-initialized when brought back from nested pools (#2003)", function () { var onupdate = o.spy() var oncreate = o.spy() var cached = { @@ -919,7 +919,7 @@ o.spec("updateNodes", function() { o(onupdate.callCount).equals(0) }) - o("unkeyed cached elements are re-initialized when brought back from nested pools", function () { + o("unkeyed cached elements are re-initialized when brought back from nested pools (#2003)", function () { var onupdate = o.spy() var oncreate = o.spy() var cached = { @@ -983,6 +983,62 @@ o.spec("updateNodes", function() { o(vnode.dom).notEquals(updated.dom) }) + o("don't add back elements from fragments that are restored from the pool #1991", function() { + render(root, [ + {tag: "[", children: []}, + {tag: "[", children: []} + ]) + render(root, [ + {tag: "[", children: []}, + {tag: "[", children: [{tag: "div"}]} + ]) + render(root, [ + {tag: "[", children: [null]} + ]) + render(root, [ + {tag: "[", children: []}, + {tag: "[", children: []} + ]) + + o(root.childNodes.length).equals(0) + }) + o("don't add back elements from fragments that are being removed #1991", function() { + render(root, [ + {tag: "[", children: []}, + {tag: "p"}, + ]) + render(root, [ + {tag: "[", children: [{tag: "div", text: 5}]} + ]) + render(root, [ + {tag: "[", children: []}, + {tag: "[", children: []} + ]) + + o(root.childNodes.length).equals(0) + }) + o("handles null values in unkeyed lists of different length (#2003)", function() { + var oncreate = o.spy(); + var onremove = o.spy(); + var onupdate = o.spy(); + function attrs() { + return {oncreate: oncreate, onremove: onremove, onupdate: onupdate} + } + + render(root, [{tag: "div", attrs: attrs()}, null]); + render(root, [null, {tag: "div", attrs: attrs()}, null]); + + o(oncreate.callCount).equals(2) + o(onremove.callCount).equals(1) + o(onupdate.callCount).equals(0) + }) + o("don't fetch the nextSibling from the pool", function() { + render(root, [{tag: "[", children: [{tag: "div", key: 1}, {tag: "div", key: 2}]}, {tag: "p"}]) + render(root, [{tag: "[", children: []}, {tag: "p"}]) + render(root, [{tag: "[", children: [{tag: "div", key: 2}, {tag: "div", key: 1}]}, {tag: "p"}]) + + o([].map.call(root.childNodes, function(el) {return el.nodeName})).deepEquals(["DIV", "DIV", "P"]) + }) components.forEach(function(cmp){ o.spec(cmp.kind, function(){ var createComponent = cmp.create From 02aab654f0b1b02e35234fca9dc47c306ba62bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 23 Nov 2017 15:06:39 +0100 Subject: [PATCH 142/301] render: remove check that may hide bugs --- render/render.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/render.js b/render/render.js index 541bfd55..3936e5ed 100644 --- a/render/render.js +++ b/render/render.js @@ -420,7 +420,7 @@ module.exports = function($window) { } function insertNode(parent, dom, nextSibling) { - if (nextSibling && nextSibling.parentNode) parent.insertBefore(dom, nextSibling) + if (nextSibling) parent.insertBefore(dom, nextSibling) else parent.appendChild(dom) } From 3f37d3d7c06885ad811a6a4307859101d0bd5328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 24 Nov 2017 00:29:15 +0100 Subject: [PATCH 143/301] #2021 change log and docs --- docs/change-log.md | 1 + render/render.js | 125 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index a7d3b220..25e0a231 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -42,6 +42,7 @@ - core: `xlink:href` attributes are now correctly removed - render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) - render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) +- render: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) --- diff --git a/render/render.js b/render/render.js index 3936e5ed..de3d8905 100644 --- a/render/render.js +++ b/render/render.js @@ -161,6 +161,124 @@ module.exports = function($window) { } //update + /** + * @param {Element|Fragment} parent - the parent element + * @param {Vnode[] | null} old - the list of vnodes of the last `render()` call for + * this part of the tree + * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call. + * @param {boolean} recyclingParent - was the parent vnode or one of its ancestor + * fetched from the recycling pool? + * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate) + * @param {Element | null} nextSibling - the next DOM node if we're dealing with a + * fragment that is not the last item in its + * parent + * @param {'svg' | 'math' | String | null} ns) - the current XML namespace, if any + * @returns void + */ + // This function diffs and patches lists of vnodes, both keyed and unkeyed. + // + // We will: + // + // 1. describe its general structure + // 2. focus on the diff algorithm optimizations + // 3. describe how the recycling pool meshes into this + // 4. discuss DOM node operations. + + // ## Overview: + // + // The updateNodes() function: + // - deals with trivial cases + // - determines whether the lists are keyed or unkeyed + // (we take advantage of the fact that mixed diff is not supported and settle on the + // keyedness of the first vnode we find) + // - diffs them and patches the DOM if needed (that's the brunt of the code) + // - manages the leftovers: after diffing, are there: + // - old nodes left to remove? + // - new nodes to insert? + // - nodes left in the recycling pool? + // deal with them! + // + // The lists are only iterated over once, with an exception for the nodes in `old` that + // are visited in the fourth part of the diff and in the `removeNodes` loop. + + // ## Diffing + // + // There's first a simple diff for unkeyed lists of equal length that eschews the pool. + // + // It is followed by a small section that activates the recycling pool if present, we'll + // ignore it for now. + // + // Then comes the main diff algorithm that is split in four parts (simplifying a bit). + // + // The first part goes through both lists top-down as long as the nodes at each level have + // the same key. This is always true for unkeyed lists that are entirely processed by this + // step. + // + // The second part deals with lists reversals, and traverses one list top-down and the other + // bottom-up (as long as the keys match). + // + // The third part goes through both lists bottom up as long as the keys match. + // + // The first and third sections allow us to deal efficiently with situations where one or + // more contiguous nodes were either inserted into, removed from or re-ordered in an otherwise + // sorted list. They may reduce the number of nodes to be processed in the fourth section. + // + // The fourth section does keyed diff for the situations not covered by the other three. It + // builds a {key: oldIndex} dictionary and uses it to find old nodes that match the keys of + // new ones. + // The nodes from the `old` array that have a match in the new `vnodes` one are marked as + // `vnode.skip: true`. + // + // If there are still nodes in the new `vnodes` array that haven't been matched to old ones, + // they are created. + // The range of old nodes that wasn't covered by the first three sections is passed to + // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. + // + // Then some pool business happens. + // + // It should be noted that the description of the four sections above is not perfect, because those + // parts are actually implemented as only two loops, one for the first two parts, and one for + // the other two. I'm not sure it wins us anything except maybe a few bytes of file size. + + // ## The pool + // + // `old.pool` is an optional array that holds the vnodes that have been previously removed + // from the DOM at this level (provided they met the pool eligibility criteria). + // + // If the `old`, `old.pool` and `vnodes` meet some criteria described in `isRecyclable`, the + // elements of the pool are appended to the `old` array, which enables the reconciler to find + // them. + // + // While this is optimal for unkeyed diff and map-based keyed diff (the fourth diff part), + // that strategy clashes with the second and third parts of the main diff algo, because + // the end of the old list is now filled with the nodes of the pool. + // + // To determine if a vnode was brought back from the pool, we look at its position in the + // `old` array (see the various `oFromPool` definitions). That information is important + // in three circumstances: + // - If the old and the new vnodes are the same object (`===`), diff is not performed unless + // the old node comes from the pool (since it must be recycled/re-created). + // - The value of `oFromPool` is passed as the `recycling` parameter of `upateNode()` (whether + // the parent is being recycled is also factred in here) + // - It is used in the DOM node insertion logic (see below) + // + // At the very end of `updateNodes()`, the nodes in the pool that haven't been picked back + // are put in the new pool for the next render phase. + // + // The pool eligibility and `isRecyclable()` criteria are to be updated as part of #1675. + + // ## DOM node operations + // + // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, + // this is not the case if the node moved (second and fourth part of the diff algo), or + // if the node was brough back from the pool and both the old and new nodes have the same + // `.tag` value (when the `.tag` differ, `updateNode()` does the insertion). + // + // The fourth part of the diff currently inserts nodes unconditionally, leading to issues + // like #1791 and #1999. We need to be smarter about those situations where adjascent old + // nodes remain together in the new list in a way that isn't covered by parts one and + // three of the diff algo. + function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { if (old === vnodes && !recyclingParent || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) @@ -178,7 +296,6 @@ module.exports = function($window) { } } if (isUnkeyed && originalOldLength === vnodes.length) { - // treat it as a tuple, no pool here for (; start < originalOldLength; start++) { if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) @@ -272,6 +389,8 @@ module.exports = function($window) { } } } + // when recycling, we're re-using an old DOM node, but firing the oninit/oncreate hooks + // instead of onbeforeupdate/onupdate. function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { @@ -412,6 +531,8 @@ module.exports = function($window) { } else return vnode.dom } + // the vnodes array may hold items that come from the pool (after `limit`) they should + // be ignored function getNextSibling(vnodes, i, limit, nextSibling) { for (; i < limit; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom @@ -443,6 +564,8 @@ module.exports = function($window) { } } } + // when a node is removed from a parent that's brought back from the pool, its hooks should + // not fire. function removeNode(vnode, context, recycling) { var expected = 1, called = 0 var original = vnode.state From 9f09ac069c649560ebe71b8368b03c1dbc82c4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 4 Dec 2017 14:33:21 +0100 Subject: [PATCH 144/301] Address #2021 review comments --- render/render.js | 27 ++++++++++++--------------- render/tests/test-onremove.js | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/render/render.js b/render/render.js index de3d8905..a1478384 100644 --- a/render/render.js +++ b/render/render.js @@ -189,8 +189,9 @@ module.exports = function($window) { // The updateNodes() function: // - deals with trivial cases // - determines whether the lists are keyed or unkeyed - // (we take advantage of the fact that mixed diff is not supported and settle on the - // keyedness of the first vnode we find) + // (Currently we look for the first pair of non-null nodes and deem the lists unkeyed + // if both nodes are unkeyed. TODO (v2) We may later take advantage of the fact that + // mixed diff is not supported and settle on the keyedness of the first vnode we find) // - diffs them and patches the DOM if needed (that's the brunt of the code) // - manages the leftovers: after diffing, are there: // - old nodes left to remove? @@ -258,7 +259,7 @@ module.exports = function($window) { // in three circumstances: // - If the old and the new vnodes are the same object (`===`), diff is not performed unless // the old node comes from the pool (since it must be recycled/re-created). - // - The value of `oFromPool` is passed as the `recycling` parameter of `upateNode()` (whether + // - The value of `oFromPool` is passed as the `recycling` parameter of `updateNode()` (whether // the parent is being recycled is also factred in here) // - It is used in the DOM node insertion logic (see below) // @@ -284,19 +285,15 @@ module.exports = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed + var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed = false for(; start < commonLength; start++) { - if (old[start] != null) { - isUnkeyed = old[start].key == null - break - } - if (vnodes[start] != null) { - isUnkeyed = vnodes[start].key == null + if (old[start] != null && vnodes[start] != null) { + if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true break } } if (isUnkeyed && originalOldLength === vnodes.length) { - for (; start < originalOldLength; start++) { + for (start = 0; start < originalOldLength; start++) { if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) @@ -310,7 +307,7 @@ module.exports = function($window) { old = old.concat(old.pool) } - var oldStart = start, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool while (oldEnd >= oldStart && end >= start) { o = old[oldStart] @@ -318,12 +315,12 @@ module.exports = function($window) { oFromPool = hasPool && oldStart >= originalOldLength if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ else if (o == null) { - if (isUnkeyed) { + if (isUnkeyed || v.key == null) { createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) } oldStart++ } else if (v == null) { - if (isUnkeyed){ + if (isUnkeyed || o.key == null) { removeNodes(old, start, start + 1, vnodes, recyclingParent) oldStart++ } @@ -568,8 +565,8 @@ module.exports = function($window) { // not fire. function removeNode(vnode, context, recycling) { var expected = 1, called = 0 - var original = vnode.state if (!recycling) { + var original = vnode.state if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { var result = callHook.call(vnode.attrs.onbeforeremove, vnode) if (result != null && typeof result.then === "function") { diff --git a/render/tests/test-onremove.js b/render/tests/test-onremove.js index cc242a25..5ab20caf 100644 --- a/render/tests/test-onremove.js +++ b/render/tests/test-onremove.js @@ -195,7 +195,7 @@ o.spec("onremove", function() { o("onremove doesn't fire on nodes that go from pool to pool (#1990)", function() { var onremove = o.spy(); - render(root, [m("div", m("div")), m("div", m("div", {onremove: onremove}))]); + render(root, [m("div", m("div")), m("div", m("div", {onremove: onremove}))]); render(root, [m("div", m("div"))]); render(root, []); From b88e86f6f0cc16dee52d8949e2dc4ec626bdc42f Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 4 Dec 2017 13:40:41 +0000 Subject: [PATCH 145/301] Bundled output for commit 9f09ac069c649560ebe71b8368b03c1dbc82c4aa [skip ci] --- README.md | 2 +- mithril.js | 299 ++++++++++++++++++++++++++++++++++++------------- mithril.min.js | 92 +++++++-------- 3 files changed, 266 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index b9240f22..e797acf0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.48 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.59 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 182ca224..8546f584 100644 --- a/mithril.js +++ b/mithril.js @@ -533,85 +533,204 @@ var coreRenderer = function($window) { } } //update - function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) { - if (old === vnodes || old == null && vnodes == null) return + /** + * @param {Element|Fragment} parent - the parent element + * @param {Vnode[] | null} old - the list of vnodes of the last0 `render()` call for + * this part of the tree + * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call. + * @param {boolean} recyclingParent - was the parent vnode or one of its ancestor + * fetched from the recycling pool? + * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate) + * @param {Element | null} nextSibling - the next0 DOM node if we're dealing with a + * fragment that is not the last0 item in its + * parent + * @param {'svg' | 'math' | String | null} ns) - the current XML namespace, if any + * @returns void + */ + // This function diffs and patches lists of vnodes, both keyed and unkeyed. + // + // We will: + // + // 1. describe its general structure + // 2. focus on the diff algorithm optimizations + // 3. describe how the recycling pool meshes into this + // 4. discuss DOM node operations. + // ## Overview: + // + // The updateNodes() function: + // - deals with trivial cases + // - determines whether the lists are keyed or unkeyed + // (Currently we look for the first pair of non-null nodes and deem the lists unkeyed + // if both nodes are unkeyed. TODO (v2) We may later take advantage of the fact that + // mixed diff is not supported and settle on the keyedness of the first vnode we find) + // - diffs them and patches the DOM if needed (that's the brunt of the code) + // - manages the leftovers: after diffing, are there: + // - old nodes left to remove? + // - new nodes to insert? + // - nodes left in the recycling pool? + // deal with them! + // + // The lists are only iterated over once, with an exception for the nodes in `old` that + // are visited in the fourth part of the diff and in the `removeNodes` loop. + // ## Diffing + // + // There's first a simple diff for unkeyed lists of equal length that eschews the pool. + // + // It is followed by a small section that activates the recycling pool if present, we'll + // ignore it for now. + // + // Then comes the main diff algorithm that is split in four parts (simplifying a bit). + // + // The first part goes through both lists top-down as long as the nodes at each level have + // the same key2. This is always true for unkeyed lists that are entirely processed by this + // step. + // + // The second part deals with lists reversals, and traverses one list top-down and the other + // bottom-up (as long as the keys match1). + // + // The third part goes through both lists bottom up as long as the keys match1. + // + // The first and third sections allow us to deal efficiently with situations where one or + // more contiguous nodes were either inserted into, removed from or re-ordered in an otherwise + // sorted list. They may reduce the number of nodes to be processed in the fourth section. + // + // The fourth section does keyed diff for the situations not covered by the other three. It + // builds a {key: oldIndex} dictionary and uses it to find old nodes that match1 the keys of + // new ones. + // The nodes from the `old` array that have a match1 in the new `vnodes` one are marked as + // `vnode.skip: true`. + // + // If there are still nodes in the new `vnodes` array that haven't been matched to old ones, + // they are created. + // The range of old nodes that wasn't covered by the first three sections is passed to + // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. + // + // Then some pool business happens. + // + // It should be noted that the description of the four sections above is not perfect, because those + // parts are actually implemented as only two loops, one for the first two parts, and one for + // the other two. I'm1 not sure it wins us anything except maybe a few bytes of file size. + // ## The pool + // + // `old.pool` is an optional array that holds the vnodes that have been previously removed + // from the DOM at this level (provided they met the pool eligibility criteria). + // + // If the `old`, `old.pool` and `vnodes` meet some criteria described in `isRecyclable`, the + // elements of the pool are appended to the `old` array, which enables the reconciler to find + // them. + // + // While this is optimal for unkeyed diff and map-based keyed diff (the fourth diff part), + // that strategy clashes with the second and third parts of the main diff algo, because + // the end of the old list is now filled with the nodes of the pool. + // + // To determine if a vnode was brought back from the pool, we look at its position in the + // `old` array (see the various `oFromPool` definitions). That information is important + // in three circumstances: + // - If the old and the new vnodes are the same object (`===`), diff is not performed unless + // the old node comes from the pool (since it must be recycled/re-created). + // - The value of `oFromPool` is passed as the `recycling` parameter of `updateNode()` (whether + // the parent is being recycled is also factred in here) + // - It is used in the DOM node insertion logic (see below) + // + // At the very end of `updateNodes()`, the nodes in the pool that haven't been picked back + // are put in the new pool for the next0 render phase. + // + // The pool eligibility and `isRecyclable()` criteria are to be updated as part of #1675. + // ## DOM node operations + // + // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, + // this is not the case if the node moved (second and fourth part of the diff algo), or + // if the node was brough back from the pool and both the old and new nodes have the same + // `.tag` value (when the `.tag` differ, `updateNode()` does the insertion). + // + // The fourth part of the diff currently inserts nodes unconditionally, leading to issues + // like #1791 and #1999. We need to be smarter about those situations where adjascent old + // nodes remain together in the new list in a way that isn't covered by parts one and + // three of the diff algo. + function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { + if (old === vnodes && !recyclingParent || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length, vnodes) + else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) else { - if (old.length === vnodes.length) { - var isUnkeyed = false - for (var i = 0; i < vnodes.length; i++) { - if (vnodes[i] != null && old[i] != null) { - isUnkeyed = vnodes[i].key == null && old[i].key == null - break - } - } - if (isUnkeyed) { - for (var i = 0; i < old.length; i++) { - if (old[i] === vnodes[i]) continue - else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling)) - else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes) - else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recycling, ns) - } - return + var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed = false + for(; start < commonLength; start++) { + if (old[start] != null && vnodes[start] != null) { + if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true + break } } - recycling = recycling || isRecyclable(old, vnodes) - if (recycling) { - var pool = old.pool + if (isUnkeyed && originalOldLength === vnodes.length) { + for (start = 0; start < originalOldLength; start++) { + if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue + else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) + else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) + else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) + } + return + } + if (isRecyclable(old, vnodes)) { + hasPool = true old = old.concat(old.pool) } - var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map + var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool while (oldEnd >= oldStart && end >= start) { - var o = old[oldStart], v = vnodes[start] - if (o === v && !recycling) oldStart++, start++ - else if (o == null) oldStart++ - else if (v == null) start++ - else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldStart >= old.length - pool.length) || ((pool == null) && recycling) + o = old[oldStart] + v = vnodes[start] + oFromPool = hasPool && oldStart >= originalOldLength + if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ + else if (o == null) { + if (isUnkeyed || v.key == null) { + createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) + } + oldStart++ + } else if (v == null) { + if (isUnkeyed || o.key == null) { + removeNodes(old, start, start + 1, vnodes, recyclingParent) + oldStart++ + } + start++ + } else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), shouldRecycle, ns) - if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) - } - else { - var o = old[oldEnd] - if (o === v && !recycling) oldEnd--, start++ + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + } else { + o = old[oldEnd] + oFromPool = hasPool && oldEnd >= originalOldLength + if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, originalOldLength, nextSibling)) oldEnd--, start++ } else break } } while (oldEnd >= oldStart && end >= start) { - var o = old[oldEnd], v = vnodes[end] - if (o === v && !recycling) oldEnd--, end-- + o = old[oldEnd] + v = vnodes[end] + oFromPool = hasPool && oldEnd >= originalOldLength + if (o === v && !oFromPool && !recyclingParent) oldEnd--, end-- else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- - } - else { + } else { if (!map) map = getKeyMap(old, oldEnd) if (v != null) { var oldIndex = map[v.key] if (oldIndex != null) { - var movable = old[oldIndex] - var shouldRecycle = (pool != null && oldIndex >= old.length - pool.length) || ((pool == null) && recycling) - updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns) - insertNode(parent, toFragment(movable), nextSibling) - old[oldIndex].skip = true - if (movable.dom != null) nextSibling = movable.dom - } - else { + o = old[oldIndex] + oFromPool = hasPool && oldIndex >= originalOldLength + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + insertNode(parent, toFragment(v), nextSibling) + o.skip = true + if (o.dom != null) nextSibling = o.dom + } else { var dom = createNode(parent, v, hooks, ns, nextSibling) nextSibling = dom } @@ -621,9 +740,18 @@ var coreRenderer = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, oldEnd + 1, vnodes) + removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes, recyclingParent) + if (hasPool) { + var limit = Math.max(oldStart, originalOldLength) + for (; oldEnd >= limit; oldEnd--) { + if (old[oldEnd].skip) old[oldEnd].skip = false + else addToPool(old[oldEnd], vnodes) + } + } } } + // when recycling, we're re-using an old DOM node, but firing the oninit/oncreate hooks + // instead of onbeforeupdate/onupdate. function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { @@ -648,7 +776,7 @@ var coreRenderer = function($window) { else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) } else { - removeNode(old, null) + removeNode(old, null, recycling) createNode(parent, vnode, hooks, ns, nextSibling) } } @@ -719,7 +847,7 @@ var coreRenderer = function($window) { vnode.domSize = vnode.instance.domSize } else if (old.instance != null) { - removeNode(old.instance, null) + removeNode(old.instance, null, recycling) vnode.dom = undefined vnode.domSize = 0 } @@ -763,14 +891,16 @@ var coreRenderer = function($window) { } else return vnode.dom } - function getNextSibling(vnodes, i, nextSibling) { - for (; i < vnodes.length; i++) { + // the vnodes array may hold items that come from the pool (after `limit`) they should + // be ignored + function getNextSibling(vnodes, i, limit, nextSibling) { + for (; i < limit; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom } return nextSibling } function insertNode(parent, dom, nextSibling) { - if (nextSibling && nextSibling.parentNode) parent.insertBefore(dom, nextSibling) + if (nextSibling) parent.insertBefore(dom, nextSibling) else parent.appendChild(dom) } function setContentEditable(vnode) { @@ -782,37 +912,43 @@ var coreRenderer = function($window) { else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove - function removeNodes(vnodes, start, end, context) { + function removeNodes(vnodes, start, end, context, recycling) { for (var i = start; i < end; i++) { var vnode = vnodes[i] if (vnode != null) { if (vnode.skip) vnode.skip = false - else removeNode(vnode, context) + else removeNode(vnode, context, recycling) } } } - function removeNode(vnode, context) { + // when a node is removed from a parent that's brought back from the pool, its hooks should + // not fire. + function removeNode(vnode, context, recycling) { var expected = 1, called = 0 - var original = vnode.state - if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = callHook.call(vnode.attrs.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) + if (!recycling) { + var original = vnode.state + if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) + } } - } - if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { - var result = callHook.call(vnode.state.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) + } } } continuation() function continuation() { if (++called === expected) { - checkState(vnode, original) - onremove(vnode) + if (!recycling) { + checkState(vnode, original) + onremove(vnode) + } if (vnode.dom) { var count0 = vnode.domSize || 1 if (count0 > 1) { @@ -822,10 +958,7 @@ var coreRenderer = function($window) { } } removeNodeFromDOM(vnode.dom) - if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements - if (!context.pool) context.pool = [vnode] - else context.pool.push(vnode) - } + addToPool(vnode, context) } } } @@ -834,6 +967,12 @@ var coreRenderer = function($window) { var parent = node.parentNode if (parent != null) parent.removeChild(node) } + function addToPool(vnode, context) { + if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements + if (!context.pool) context.pool = [vnode] + else context.pool.push(vnode) + } + } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { diff --git a/mithril.min.js b/mithril.min.js index 8c155377..3a305535 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,46 @@ -(function(){function x(a,c,e,f,m,l){return{tag:a,key:c,attrs:e,children:f,text:m,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function N(a){for(var c in a)if(C.call(a,c))return!1;return!0}function A(a){var c=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=O[a])){var m="div";for(var l=[],g={};f=S.exec(a);){var n=f[1], -r=f[2];""===n&&""!==r?m=r:"#"===n?g.id=r:"."===n?l.push(r):"["===f[3][0]&&((n=f[6])&&(n=n.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?l.push(n):g[f[4]]=""===n?n:n||!0)}0b.indexOf("?")?"?":"&";b+=e+c}return b}function g(b){try{return""!==b?JSON.parse(b):null}catch(v){throw Error(b);}}function n(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var c=0;ck.status||304===k.status||W.test(b.url))c(r(b.type,a));else{var f=Error(k.responseText);f.code=k.status;f.response=a;e(f)}}catch(X){e(X)}};f&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?v:y(v)},jsonp:function(b,g){var y=e();b=f(b, -g);var n=new c(function(c,e){var f=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+k++,g=a.document.createElement("script");a[f]=function(e){g.parentNode.removeChild(g);c(r(b.type,e));delete a[f]};g.onerror=function(){g.parentNode.removeChild(g);e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=m(b.url,b.data);b.data[b.callbackKey||"callback"]=f;g.src=l(b.url,b.data);a.document.documentElement.appendChild(g)});return!0===b.background?n:y(n)},setCompletionCallback:function(b){z= -b}}}(window,p),R=function(a){function c(h,d){if(h.state!==d)throw Error("`vnode.state` must not be modified");}function e(h){var d=h.state;try{return this.apply(d,arguments)}finally{c(h,d)}}function f(h,d,b,a,c,e,f){for(;b=u&&D>=q;){var w=d[u],p=a[q];if(w!==p||c)if(null==w)u++;else if(null==p)q++;else if(w.key===p.key){var t=null!=n&&u>=d.length-n.length||null==n&&c;u++;q++;r(h,w,p,e,z(d,u,g),t,l);c&&w.tag===p.tag&&b(h,k(w),g)}else if(w=d[v],w!==p||c)if(null==w)v--;else if(null==p)q++;else if(w.key===p.key)t=null!=n&&v>=d.length-n.length||null==n&&c,r(h,w,p,e,z(d,v+1,g),t,l),(c||q=u&&D>=q;){w=d[v];p=a[D];if(w!==p||c)if(null==w)v--;else{if(null!=p)if(w.key===p.key)t=null!=n&&v>=d.length-n.length||null==n&&c,r(h,w,p,e,z(d,v+1,g),t,l),c&&w.tag===p.tag&&b(h,k(w),g),null!=w.dom&&(g=w.dom),v--;else{if(!H){H=d;t=v;w={};var B;for(B=0;B=d.length-n.length||null==n&&c,r(h,B,p,e,z(d,v+1,g),t,l),b(h,k(B),g),d[w].skip=!0,null!=B.dom&&(g=B.dom)):g=m(h,p,e, -l,g))}D--}else v--,D--;if(Dc.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(C){throw Error(c);}}function q(c){return c.responseText}function r(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(c.url))d(r(c.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=c.data?m.send(c.data):m.send()});return!0===c.background?C:A(C)},jsonp:function(c,k){var A=e();c=h(c, +k);var q=new d(function(d,e){var h=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(c.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==c.data&&(c.data={});c.url=p(c.url,c.data);c.data[c.callbackKey||"callback"]=h;k.src=l(c.url,c.data);a.document.documentElement.appendChild(k)});return!0===c.background?q:A(q)},setCompletionCallback:function(c){u= +c}}}(window,B),U=function(a){function d(g,b){if(g.state!==b)throw Error("`vnode.state` must not be modified");}function e(g){var b=g.state;try{return this.apply(b,arguments)}finally{d(g,b)}}function h(g,b,f,c,a,d,e){for(;f=v&&t>=n;)if(w=b[v],z=f[n],y=C&&v>=q,w===z&&!y&&!a||null==w&&null==z)v++,n++;else if(null==w)(E||null==z.key)&&p(g,f[n],d,k,u(b,++n,q,e)),v++;else if(null==z){if(E||null==w.key)A(b,n,n+1,f,a),v++;n++}else if(w.key===z.key)v++,n++,r(g,w,z,d,u(b,v,q,e),y||a,k),y&&w.tag===z.tag&&c(g,m(z),e);else if(w=b[l],y=C&&l>=q,w!==z||y||a)if(null==w)l--;else if(null== +z)n++;else if(w.key===z.key)r(g,w,z,d,u(b,l+1,q,e),y||a,k),(y&&w.tag===z.tag||n=v&&t>=n;){w=b[l];z=f[t];y=C&&l>=q;if(w!==z||y||a)if(null==w)l--;else{if(null!=z)if(w.key===z.key)r(g,w,z,d,u(b,l+1,q,e),y||a,k),y&&w.tag===z.tag&&c(g,m(z),e),null!=w.dom&&(e=w.dom),l--;else{if(!I){I=b;E=l;w={};for(y=0;y=q,r(g,w,z,d,u(b,l+1,q,e),y||a,k), +c(g,m(z),e),w.skip=!0,null!=w.dom&&(e=w.dom)):e=p(g,z,d,k,e))}t--}else l--,t--;if(t=g;l--)b[l].skip?b[l].skip=!1:B(b[l],f)}}}function r(g,b,f,a,c,d,h){var n=b.tag;if(n===f.tag){f.state=b.state;f.events=b.events;var A;if(A=!d){var u,E;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(u=e.call(f.attrs.onbeforeupdate,f,b));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(E=e.call(f.state.onbeforeupdate, +f,b));void 0===u&&void 0===E||u||E?A=!1:(f.dom=b.dom,f.domSize=b.domSize,f.instance=b.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):M(f.attrs,f,a)),n){case "#":b.children.toString()!==f.children.toString()&&(b.dom.nodeValue=f.children);f.dom=b.dom;break;case "<":b.children!==f.children?(m(b),l(g,f,c)):(f.dom=b.dom,f.domSize=b.domSize);break;case "[":q(g,b.children,f.children,d,a,c,h);b=0;a=f.children;f.dom=null;if(null!=a){for(d=0;d Date: Tue, 5 Dec 2017 18:04:29 -0500 Subject: [PATCH 146/301] docs: Add flems version of sample application (#2049) --- docs/simple-application.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/simple-application.md b/docs/simple-application.md index cd943cc8..9ca3a698 100644 --- a/docs/simple-application.md +++ b/docs/simple-application.md @@ -2,6 +2,8 @@ Let's develop a simple application that covers some of the major aspects of Single Page Applications +An interactive running example can be seen here [flems: Simple Application](https://flems.io/#0=N4IgzgpgNhDGAuEAmIBcICGAHLA6AVmCADQgBmAljEagNqgB2GAthGiAKqQBOAsgPZJoBIqVj8GiSewBuGbgAIuERQF4FwADoMFuhVAph4qBbQC6xbXv38MSADKHjCsgFcGCChIAUASg1W1nrcEPCu3DrMuCEAjq4QRt5aOkGprPAAFoImmiAA4gCiACq5limp1uFQOSAZ8PBYYKgA9M0hzAC0IUYd2BS4GSr8ANau2HjizM19za48YKWBFXoA7hSZAMIhQpIUGFBNCvDc8WXLAL6+S0G4mRAM3m4e8F4P3a5Q8P7Jy9bK3LgDEYFOp3p9cEgMPAMNdrJdrucytdYOEQpITMBEdcoLYkCYnp4fBQkN9YcFQuFItEIHEEvAkmS0qEsniFLlCiUSIyglUanUGk1Wu0unTelh+oNuCMxjhcJNpuLZvNmrkFABqBTEs6-XRrTbbe4vfaHY6nbnw8o3O4PAkvHxgr4BS3Lf5y1GGkEKB3mq6WrEMa5gDAyCD49yEh6k53ksIRBRRWLxRI-HXx5nZNkgAAKHE52p1vMz-MaLTaEE63XgYolQ1G4zl-CmMzmKjAKpA6qUPDd3DR8FwWu51kh0JMrpRvcN+d+eoyW2Qhr2BxMpog07hvrh2nOIERjBYbHQ-0cRhEJBA4kkhtk8i7KhP8E9Kd0EgoDHWY+7OLsD+nMgoEArGGzyvH4TrLCEsaRN4uS4C23AdEC8ClHeAJIbgzDYI84Z2g88FRqmXoUnGzAwZgcE8IhTgdOs5YocAGQhGQNTNMg6ztp28EDkgxAKBIsAhFCobxtE-CuIggJvsMiIKFxlDcEYAByB6dqqqoalxUAYEpB6bhUlx6bo5zbruxD7qw7D-AAYvw3BRIQ56XlI8A3oo1m2cwT7XK+77OLaoEyAwggQN8rrfkg3iBcFuBQscYDcb4-rWP+gHARGYHPkEkGUvGZFkB59FDhUEhgK4ABGzAfi4OGgSF4GERUEC4FgIQhpIAAiEBkBgHz0oZDV-N2QYhn4RWpMZ0bjbxtBjbluRaWVwgLdAKG5FZFAKY+TCsLkvjrhUpG5G+WDiQODAnfAtDwAAnlgECqIgAAe8BmLQWBabAEBZFAQjcKo62bQo20QGYhWTb8PkXSYUSzgAgvU3BkXIUDxCh-k+Mj8Shd2E59rg8k6awnqYxAlz7TqJOfioPZ4wT8DKTt4MbuTQSHSAy1QICGCLVAq0gPY2lbQeu0s9YbPHadEuXe9GCfd9v2qALwLA6DJD1QNkPidDuBwwjSP7Kjavow8JPY9TuOGlzhMQMTBuk3ts3JXbVMAhbkhW-TwtM3oZOzWzZXifAEi4AH9QSFdt33aVFXrKrvG5AAysGEAi9yZj9RNO57iAwPsAL11if2DliBIzmuQo+eF15lopUB1UgRjQVCARFTZSRZGYW+XMF+JKEzd7uhs0wMgYfcrh947ehszCauZQNjFdSYADkzRIUvosQx4gmINrUriU1BgMMMk9GfHnDzLts3pxvg9kZAEYoVFQhyhkVBIGi-XWOnCImdnufoPWYuF5S7XnQAmQuTUWpdQoI9bwS8ADES9fTgP3t4JA-AUSsHdmVQQ10z6rycGDawuQCFGFyBibkaJfppVwhlWabdoKV3ErxUix4nC+E-j7BE04SFsXgM0VAxJyHqyyvcah9d0pPzqnPVuxFGEYB7vAFh3h3J2V4lImKCMwAcPNNw7cvhTLmUPCAOUYBRDAKvNIdAOCkB4LOhdYgIdA4SA0PldEQU7L7AUAARgAGxYEegoAAaioSETAADcmFuAAHM3wmAAEwAAYAkTW0N3KuwAomxIYKgbxyTAk9SDpEjAj0OhrCQJkXJiTqkBPCRNUeDBXAaCyXExJCg2kAGZ8l1O0Gk+CVFgTACQh0Iw10YCoCCgwCAxSYmtPaT47pWA7BIDfNE1AiSekMAoioAZVZaKeWAGVWWwxol7wYHieB3UrkYHCTg7g1DvEBIUGAfgBgkAKHgUgL54TxA4m4KgeBHSgXhJWWAGW11UBlRxLAYYMzsnrPmY8x64SllfNWagAAHE87xABWWpT0qxCHENwKErwJkSGmfU-pwz9moCyCGRQwACUdCJbZUlEhUDuF+ofSlvStkcw0KC8FkLoWwpaTktpbS8XIvqVLDQdyHlPJeW8j5XykC3Nsr9LodgKBzFQB02pODSlgAoAAL3RQqnZRqQWGGFVCjBYr5DwslQs2pqKVkMDWXk7F0rwnlMqXkxJABSTZTiw46EOcc05YlzkAogPGjV9yVC5KVa84kqrvmWoQiSlZeqDXIt+bZAFQKOk2rBVpCFb4eUdHtTCuFcy2neuRe69FTafG+uZaykluFyVTNDaHIOOT6UqHlVGs5FyIAYsnZOupu4LDsykjQegOcDzsEqpkbgVBzxVHYMWQUsxzonIbFMddjEqAAAFvG4Cvb45op7N2cyATdO67AHLnDMOcIAA) + First let's create an entry point for the application. Create a file `index.html`: ```markup From 3b94cfebee7e8df5eba73f64ca979c71a0e2cd8c Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Thu, 7 Dec 2017 21:25:50 -0500 Subject: [PATCH 147/301] Fix some immediate/retained mode confusion For future reference: - Immediate mode = define the tree we want to render - Retained mode = mutate the tree to what we want it to be Also, I cleaned up the language a bit. --- docs/vnodes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/vnodes.md b/docs/vnodes.md index 783f432f..a663e197 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -21,11 +21,11 @@ It may seem wasteful to recreate vnodes so frequently, but as it turns out, mode For that reason, Mithril uses a sophisticated and highly optimized virtual DOM diffing algorithm to minimize the amount of DOM updates. Mithril *also* generates carefully crafted vnode data structures that are compiled by Javascript engines for near-native data structure access performance. In addition, Mithril aggressively optimizes the function that creates vnodes as well. -The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide [retained mode rendering](https://en.wikipedia.org/wiki/Retained_mode), a style of rendering that makes it drastically easier to manage UI complexity. +The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide a declarative [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) API, a style of rendering that makes it drastically easier to manage UI complexity. -To illustrate why retained mode is so important, consider the DOM API and HTML. The DOM API is an [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) rendering system and requires writing out exact instructions to assemble a DOM tree procedurally. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances of introducing bugs and more chances to make code harder to understand. +To illustrate why immediate mode is so important, consider the DOM API and HTML. The DOM API is an imperative [retained mode](https://en.wikipedia.org/wiki/Retained_mode) API and requires 1. writing out exact instructions to assemble a DOM tree procedurally, and 2. writing out other instructions to update that tree. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances of introducing bugs and more chances to make code harder to understand. -In contrast, HTML is a retained mode rendering system. With HTML, you can write a DOM tree in a far more natural and readable way, without worrying about forgetting to append a child to a parent, running into stack overflows when rendering extremely deep trees, etc. +In contrast, HTML is closer to an immediate mode rendering system. With HTML, you can write a DOM tree in a far more natural and readable way, without worrying about forgetting to append a child to a parent, running into stack overflows when rendering extremely deep trees, etc. Virtual DOM goes one step further than HTML by allowing you to write *dynamic* DOM trees without having to manually write multiple sets of DOM API calls to efficiently synchronize the UI to arbitrary data changes. From 1782fa8b630d6d1356b485257c04a833f0463093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 8 Dec 2017 21:27:23 +0100 Subject: [PATCH 148/301] render: fix perf regression introduced by #1918 --- docs/change-log.md | 2 +- render/render.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 25e0a231..7bdc0478 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -41,7 +41,7 @@ - API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. - core: `xlink:href` attributes are now correctly removed - render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) -- render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) +- render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) - render: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) --- diff --git a/render/render.js b/render/render.js index a1478384..aed616aa 100644 --- a/render/render.js +++ b/render/render.js @@ -697,7 +697,7 @@ module.exports = function($window) { } } function isFormAttribute(vnode, attr) { - return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.dom.parentNode === $doc.activeElement + return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.tag === "option" && vnode.dom.parentNode === $doc.activeElement } function isLifecycleMethod(attr) { return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate" From 77f1c81eb589490b65a9ca1c170fb7f843153e63 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Sat, 9 Dec 2017 00:47:03 +0000 Subject: [PATCH 149/301] Bundled output for commit 1ad9f84bb461794dd5251704fa6bc9e0cd3e77fa [skip ci] --- mithril.js | 2 +- mithril.min.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mithril.js b/mithril.js index 8546f584..cb668627 100644 --- a/mithril.js +++ b/mithril.js @@ -1056,7 +1056,7 @@ var coreRenderer = function($window) { } } function isFormAttribute(vnode, attr) { - return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.dom.parentNode === $doc.activeElement + return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement || vnode.tag === "option" && vnode.dom.parentNode === $doc.activeElement } function isLifecycleMethod(attr) { return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate" diff --git a/mithril.min.js b/mithril.min.js index 3a305535..f7edd0db 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -29,11 +29,11 @@ f,a)}null!=f.instance?(null==b.instance?p(g,f.instance,a,h,c):r(g,b.instance,f.i g[b]&&null!=g[b].dom)return g[b].dom;return c}function c(g,b,a){a?g.insertBefore(b,a):g.appendChild(b)}function C(g){var b=g.children;if(null!=b&&1===b.length&&"<"===b[0].tag)b=b[0].children,g.dom.innerHTML!==b&&(g.dom.innerHTML=b);else if(null!=g.text||null!=b&&0!==b.length)throw Error("Child node of a contenteditable must be trusted");}function A(g,b,a,c,d){for(;b Date: Thu, 21 Dec 2017 01:25:58 -0500 Subject: [PATCH 150/301] docs: Add Typescript install notes (#2057) --- docs/installation.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 57efabe6..5c204e6a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,6 +2,8 @@ - [CDN](#cdn) - [NPM](#npm) +- [Quick start with Webpack](#quick-start-with-webpack) +- [Typescript](#typescript) ### CDN @@ -15,8 +17,13 @@ If you're new to Javascript or just want a very simple setup to get your feet we ### NPM -#### Quick start with Webpack +```bash +$> npm install mithril --save +``` +--- + +### Quick start with Webpack 1. Initialize the directory as an npm package ```bash @@ -251,3 +258,15 @@ If you don't have the ability to run a bundler script due to company security po // if a CommonJS environment is not detected, Mithril will be created in the global scope m.render(document.body, "hello world") ``` + +--- + +### TypeScript + +TypeScript type definitions are available from DefinitelyTyped. They can be installed with: + +```bash +$> npm install @types/mithril --save-dev +``` + +For example usage, to file issues or to discuss TypeScript related topics visit: https://github.com/MithrilJS/mithril.d.ts From e64a322bcfe9c9c800aa56b338b7744b8146f56a Mon Sep 17 00:00:00 2001 From: magikstm Date: Sat, 30 Dec 2017 04:44:00 -0500 Subject: [PATCH 151/301] Correct test scripts --- api/tests/index.html | 5 ++--- stream/tests/index.html | 3 --- test-utils/tests/index.html | 5 ++--- tests/index.html | 1 + 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/api/tests/index.html b/api/tests/index.html index 37d313f4..e85bd4b7 100644 --- a/api/tests/index.html +++ b/api/tests/index.html @@ -13,8 +13,8 @@ - - + + @@ -28,7 +28,6 @@ - diff --git a/stream/tests/index.html b/stream/tests/index.html index 86cb8947..8db5634b 100644 --- a/stream/tests/index.html +++ b/stream/tests/index.html @@ -8,11 +8,8 @@ - - - diff --git a/test-utils/tests/index.html b/test-utils/tests/index.html index 51b04d73..a0edd42a 100644 --- a/test-utils/tests/index.html +++ b/test-utils/tests/index.html @@ -7,21 +7,20 @@ - - + - + diff --git a/tests/index.html b/tests/index.html index 91db3a04..21f8359b 100644 --- a/tests/index.html +++ b/tests/index.html @@ -9,6 +9,7 @@ + From ba35a75bab74788f9b479231117af968186e403e Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Wed, 3 Jan 2018 17:02:44 +0100 Subject: [PATCH 152/301] docs: Fix wrong link targets and typos (#2066) --- docs/stream.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/stream.md b/docs/stream.md index dc720ef4..34818e12 100644 --- a/docs/stream.md +++ b/docs/stream.md @@ -9,10 +9,10 @@ - [Stream.scanMerge](#streamscanmerge) - [Stream.HALT](#streamhalt) - [Stream["fantasy-land/of"]](#streamfantasy-landof) - - [Instance members](#static-members) + - [Instance members](#instance-members) - [stream.map](#streammap) - [stream.end](#streamend) - - [stream["fantasy-land/of"]](#streamfantasy-landof) + - [stream["fantasy-land/of"]](#streamfantasy-landof-1) - [stream["fantasy-land/map"]](#streamfantasy-landmap) - [stream["fantasy-land/ap"]](#streamfantasy-landap) - [Basic usage](#basic-usage) @@ -159,7 +159,7 @@ A special value that can be returned to stream callbacks to halt execution of do This method is functionally identical to `stream`. It exists to conform to [Fantasy Land's Applicative specification](https://github.com/fantasyland/fantasy-land). For more information, see the [What is Fantasy Land](#what-is-fantasy-land) section. -`stream = stream["fantasy-land/of"](value)` +`stream = Stream["fantasy-land/of"](value)` Argument | Type | Required | Description ----------- | -------------------- | -------- | --- @@ -212,7 +212,7 @@ Creates a dependent stream whose value is set to the result of the callback func This method exists to conform to [Fantasy Land's Applicative specification](https://github.com/fantasyland/fantasy-land). For more information, see the [What is Fantasy Land](#what-is-fantasy-land) section. -`dependentStream = stream()["fantasy-land/of"](callback)` +`dependentStream = stream()["fantasy-land/map"](callback)` Argument | Type | Required | Description ------------ | -------------------- | -------- | --- From fa3bce55059844216e9a910ca9eac875880cc9e3 Mon Sep 17 00:00:00 2001 From: Isiah Meadows Date: Tue, 23 Jan 2018 05:01:31 -0500 Subject: [PATCH 153/301] Update nav-guides.md Since that was somehow missed in #2047 --- docs/nav-guides.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/nav-guides.md b/docs/nav-guides.md index 4a5be9df..d567cfae 100644 --- a/docs/nav-guides.md +++ b/docs/nav-guides.md @@ -9,7 +9,8 @@ - [Animation](animation.md) - [Testing](testing.md) - [Examples](examples.md) - - [Learning Mithril](learning-mithril.md) + - [Integrating with Other Libraries](integrating-libs.md) + - [Learning Mithril](learning-mithril.md) - Key concepts - [Vnodes](vnodes.md) - [Components](components.md) From 94e8d8cafae7e57e5e11044cce55901272315228 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Tue, 23 Jan 2018 09:32:33 -0800 Subject: [PATCH 154/301] docs: fix git commands for releasing --- docs/releasing.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/releasing.md b/docs/releasing.md index ce4a871d..a6134586 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -13,7 +13,7 @@ 1. Ensure your local branch is up to date ```bash -$ git co next +$ git checkout next $ git pull --rebase mithriljs next ``` @@ -37,7 +37,7 @@ $ git push mithriljs next 5. Switch to `master` and make sure it's up to date ```bash -$ git co master +$ git checkout master $ git pull --rebase mithriljs master ``` @@ -74,7 +74,7 @@ This helps to ensure that the `version` field of `package.json` doesn't get out 12. Switch to `next` and make sure it's up to date ```bash -$ git co next +$ git checkout next $ git pull --rebase mithriljs next ``` @@ -103,12 +103,12 @@ Fixes to documentation can land whenever, updates to the site are published via # These steps assume that MithrilJS/mithril.js is a git remote named "mithriljs" # Ensure your next branch is up to date -$ git co next +$ git checkout next $ git pull mithriljs next # Splat the docs folder from next onto master -$ git co master -$ git co next -- ./docs +$ git checkout master +$ git checkout next -- ./docs # Manually ensure that no new feature docs were added @@ -122,7 +122,7 @@ After the Travis build completes the updated docs should appear on https://mithr 1. Ensure your local branch is up to date ```bash -$ git co next +$ git checkout next $ git pull --rebase mithriljs next ``` @@ -146,7 +146,7 @@ $ git push mithriljs next 5. Switch to `master` and make sure it's up to date ```bash -$ git co master +$ git checkout master $ git pull --rebase mithriljs master ``` From 81903cacdbcee1fb8a0d3ac8a0c639159a99015b Mon Sep 17 00:00:00 2001 From: Leo Thorp Date: Fri, 26 Jan 2018 00:06:34 -0600 Subject: [PATCH 155/301] docs: fix typo (#2077) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 22bb9021..64018eff 100644 --- a/docs/index.md +++ b/docs/index.md @@ -225,7 +225,7 @@ var Splash = { As you can see, this component simply renders a link to `#!/hello`. The `#!` part is known as a hashbang, and it's a common convention used in Single Page Applications to indicate that the stuff after it (the `/hello` part) is a route path. -Now that we going to have more than one screen, we use `m.route` instead of `m.mount`. +Now that we're going to have more than one screen, we use `m.route` instead of `m.mount`. ```javascript m.route(root, "/splash", { From 33ff439c73a537628a04f62a7f2c5e29cc752004 Mon Sep 17 00:00:00 2001 From: "Paul D. Fernhout" Date: Wed, 7 Feb 2018 00:07:03 -0500 Subject: [PATCH 156/301] docs: Fix inconsistent path in router.md variadic routes example (#2084) --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index 712c6845..a883e833 100644 --- a/docs/route.md +++ b/docs/route.md @@ -323,7 +323,7 @@ It's also possible to have variadic routes, i.e. a route with an argument that c ```javascript m.route(document.body, "/edit/pictures/image.jpg", { - "/files/:file...": Edit, + "/edit/:file...": Edit, }) ``` From 83884bdc90c62c785061035bcd39c94eb6e90f52 Mon Sep 17 00:00:00 2001 From: Fabiano Taioli Date: Wed, 7 Feb 2018 17:46:39 +0100 Subject: [PATCH 157/301] element value is not cleared when value valor change to undefined --- docs/change-log.md | 1 + render/render.js | 4 ++++ render/tests/test-input.js | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 7bdc0478..5df143f6 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -43,6 +43,7 @@ - render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) - render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) - render: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) +- render: fix element value don't change if new valor is undefined [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) --- diff --git a/render/render.js b/render/render.js index aed616aa..9efbde96 100644 --- a/render/render.js +++ b/render/render.js @@ -638,6 +638,10 @@ module.exports = function($window) { function setAttr(vnode, key, old, value, ns) { if (key === "key" || key === "is" || isLifecycleMethod(key)) return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) + if (typeof value === "undefined" && key === "value" && old !== value) { + vnode.dom.value = "" + return + } if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value === undefined) return var element = vnode.dom if (key.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key, value) diff --git a/render/tests/test-input.js b/render/tests/test-input.js index 1f9a24d7..c443db1a 100644 --- a/render/tests/test-input.js +++ b/render/tests/test-input.js @@ -59,6 +59,16 @@ o.spec("form inputs", function() { o(updated.dom.value).equals("aaa") }) + o("clear element value if vdom value is set to undefined (aka removed)", function() { + var input = {tag: "input", attrs: {value: "aaa", oninput: function() {}}} + var updated = {tag: "input", attrs: {value: undefined, oninput: function() {}}} + + render(root, [input]) + render(root, [updated]) + + o(updated.dom.value).equals("") + }) + o("syncs input checked attribute if DOM value differs from vdom value", function() { var input = {tag: "input", attrs: {type: "checkbox", checked: true, onclick: function() {}}} var updated = {tag: "input", attrs: {type: "checkbox", checked: true, onclick: function() {}}} From 1410e3545676ea245c8c0bb8bff5edebbba3a848 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Thu, 8 Feb 2018 23:49:55 +0000 Subject: [PATCH 158/301] Bundled output for commit 83884bdc90c62c785061035bcd39c94eb6e90f52 [skip ci] --- README.md | 2 +- mithril.js | 4 +++ mithril.min.js | 82 +++++++++++++++++++++++++------------------------- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e797acf0..50a85a33 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.59 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.62 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index cb668627..2bddf8de 100644 --- a/mithril.js +++ b/mithril.js @@ -997,6 +997,10 @@ var coreRenderer = function($window) { function setAttr(vnode, key2, old, value, ns) { if (key2 === "key" || key2 === "is" || isLifecycleMethod(key2)) return if (key2[0] === "o" && key2[1] === "n") return updateEvent(vnode, key2, value) + if (typeof value === "undefined" && key2 === "value" && old !== value) { + vnode.dom.value = "" + return + } if ((old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || value === undefined) return var element = vnode.dom if (key2.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key2, value) diff --git a/mithril.min.js b/mithril.min.js index f7edd0db..f08ea8cf 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,46 @@ (function(){function t(a,d,e,h,p,l){return{tag:a,key:d,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function Q(a){for(var d in a)if(G.call(a,d))return!1;return!0}function x(a){var d=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var h;if(!(h=R[a])){var p="div";for(var l=[],k={};h=V.exec(a);){var q=h[1], r=h[2];""===q&&""!==r?p=r:"#"===q?k.id=r:"."===q?l.push(r):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0c.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(C){throw Error(c);}}function q(c){return c.responseText}function r(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(c.url))d(r(c.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=c.data?m.send(c.data):m.send()});return!0===c.background?C:A(C)},jsonp:function(c,k){var A=e();c=h(c, -k);var q=new d(function(d,e){var h=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(c.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==c.data&&(c.data={});c.url=p(c.url,c.data);c.data[c.callbackKey||"callback"]=h;k.src=l(c.url,c.data);a.document.documentElement.appendChild(k)});return!0===c.background?q:A(q)},setCompletionCallback:function(c){u= -c}}}(window,B),U=function(a){function d(g,b){if(g.state!==b)throw Error("`vnode.state` must not be modified");}function e(g){var b=g.state;try{return this.apply(b,arguments)}finally{d(g,b)}}function h(g,b,f,c,a,d,e){for(;f=v&&t>=n;)if(w=b[v],z=f[n],y=C&&v>=q,w===z&&!y&&!a||null==w&&null==z)v++,n++;else if(null==w)(E||null==z.key)&&p(g,f[n],d,k,u(b,++n,q,e)),v++;else if(null==z){if(E||null==w.key)A(b,n,n+1,f,a),v++;n++}else if(w.key===z.key)v++,n++,r(g,w,z,d,u(b,v,q,e),y||a,k),y&&w.tag===z.tag&&c(g,m(z),e);else if(w=b[l],y=C&&l>=q,w!==z||y||a)if(null==w)l--;else if(null== -z)n++;else if(w.key===z.key)r(g,w,z,d,u(b,l+1,q,e),y||a,k),(y&&w.tag===z.tag||n=v&&t>=n;){w=b[l];z=f[t];y=C&&l>=q;if(w!==z||y||a)if(null==w)l--;else{if(null!=z)if(w.key===z.key)r(g,w,z,d,u(b,l+1,q,e),y||a,k),y&&w.tag===z.tag&&c(g,m(z),e),null!=w.dom&&(e=w.dom),l--;else{if(!I){I=b;E=l;w={};for(y=0;y=q,r(g,w,z,d,u(b,l+1,q,e),y||a,k), -c(g,m(z),e),w.skip=!0,null!=w.dom&&(e=w.dom)):e=p(g,z,d,k,e))}t--}else l--,t--;if(t=g;l--)b[l].skip?b[l].skip=!1:B(b[l],f)}}}function r(g,b,f,a,c,d,h){var n=b.tag;if(n===f.tag){f.state=b.state;f.events=b.events;var A;if(A=!d){var u,E;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(u=e.call(f.attrs.onbeforeupdate,f,b));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(E=e.call(f.state.onbeforeupdate, -f,b));void 0===u&&void 0===E||u||E?A=!1:(f.dom=b.dom,f.domSize=b.domSize,f.instance=b.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):M(f.attrs,f,a)),n){case "#":b.children.toString()!==f.children.toString()&&(b.dom.nodeValue=f.children);f.dom=b.dom;break;case "<":b.children!==f.children?(m(b),l(g,f,c)):(f.dom=b.dom,f.domSize=b.domSize);break;case "[":q(g,b.children,f.children,d,a,c,h);b=0;a=f.children;f.dom=null;if(null!=a){for(d=0;db.indexOf("?")?"?":"&";b+=e+d}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(C){throw Error(b);}}function q(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(b.url))d(r(b.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=b.data?m.send(b.data):m.send()});return!0===b.background?C:A(C)},jsonp:function(b,k){var A=e();b=h(b, +k);var q=new d(function(d,e){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(b.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=p(b.url,b.data);b.data[b.callbackKey||"callback"]=h;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?q:A(q)},setCompletionCallback:function(b){u= +b}}}(window,B),U=function(a){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,b,a,d,e){for(;f=v&&t>=n;)if(w=c[v],z=f[n],y=C&&v>=q,w===z&&!y&&!a||null==w&&null==z)v++,n++;else if(null==w)(E||null==z.key)&&p(g,f[n],d,k,u(c,++n,q,e)),v++;else if(null==z){if(E||null==w.key)A(c,n,n+1,f,a),v++;n++}else if(w.key===z.key)v++,n++,r(g,w,z,d,u(c,v,q,e),y||a,k),y&&w.tag===z.tag&&b(g,m(z),e);else if(w=c[l],y=C&&l>=q,w!==z||y||a)if(null==w)l--;else if(null== +z)n++;else if(w.key===z.key)r(g,w,z,d,u(c,l+1,q,e),y||a,k),(y&&w.tag===z.tag||n=v&&t>=n;){w=c[l];z=f[t];y=C&&l>=q;if(w!==z||y||a)if(null==w)l--;else{if(null!=z)if(w.key===z.key)r(g,w,z,d,u(c,l+1,q,e),y||a,k),y&&w.tag===z.tag&&b(g,m(z),e),null!=w.dom&&(e=w.dom),l--;else{if(!I){I=c;E=l;w={};for(y=0;y=q,r(g,w,z,d,u(c,l+1,q,e),y||a,k), +b(g,m(z),e),w.skip=!0,null!=w.dom&&(e=w.dom)):e=p(g,z,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:B(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var u,E;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(u=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(E=e.call(f.state.onbeforeupdate, +f,c));void 0===u&&void 0===E||u||E?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):M(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;d Date: Sun, 18 Feb 2018 20:18:13 -0500 Subject: [PATCH 159/301] Add Promise finally method to polyfill --- promise/promise.js | 26 ++++++++++++++++++++++++-- promise/tests/test-promise.js | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/promise/promise.js b/promise/promise.js index 53aefecc..51d124e8 100644 --- a/promise/promise.js +++ b/promise/promise.js @@ -61,6 +61,20 @@ PromisePolyfill.prototype.then = function(onFulfilled, onRejection) { PromisePolyfill.prototype.catch = function(onRejection) { return this.then(null, onRejection) } +PromisePolyfill.prototype.finally = function(callback) { + return this.then( + function(value) { + return PromisePolyfill.resolve(callback()).then(function() { + return value + }) + }, + function(reason) { + return PromisePolyfill.resolve(callback()).then(function() { + return PromisePolyfill.reject(reason); + }) + } + ) +} PromisePolyfill.resolve = function(value) { if (value instanceof PromisePolyfill) return value return new PromisePolyfill(function(resolve) {resolve(value)}) @@ -96,10 +110,18 @@ PromisePolyfill.race = function(list) { } if (typeof window !== "undefined") { - if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill + if (typeof window.Promise === "undefined") { + window.Promise = PromisePolyfill + } else if (!window.Promise.prototype.finally) { + window.Promise.prototype.finally = PromisePolyfill.prototype.finally + } module.exports = window.Promise } else if (typeof global !== "undefined") { - if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill + if (typeof global.Promise === "undefined") { + global.Promise = PromisePolyfill + } else if (!global.Promise.prototype.finally) { + global.Promise.prototype.finally = PromisePolyfill.prototype.finally + } module.exports = global.Promise } else { module.exports = PromisePolyfill diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index e368165c..7798293f 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -15,6 +15,7 @@ o.spec("promise", function() { o("constructor has correct methods", function() { o(typeof Promise.prototype.then).equals("function") o(typeof Promise.prototype.catch).equals("function") + o(typeof Promise.prototype.finally).equals("function") o(typeof Promise.resolve).equals("function") o(typeof Promise.reject).equals("function") o(typeof Promise.race).equals("function") @@ -53,6 +54,24 @@ o.spec("promise", function() { o(value).equals(1) }).then(done) }) + o("finally after then returns promise", function(done) { + var promise = Promise.resolve(1) + + promise.then(function(value) { + o(value).equals(1) + }).finally(function(value) { + o(value).equals(undefined) + }).then(done) + }) + o("finally after catch returns promise", function(done) { + var promise = Promise.reject(1) + + promise.catch(function(value) { + o(value).equals(1) + }).finally(function(value) { + o(value).equals(undefined) + }).then(done) + }) }) o.spec("resolve", function() { o("resolves once", function(done) { From 17c7855d913704f989d99c1343d5e7daa9f4fcd4 Mon Sep 17 00:00:00 2001 From: spacejack Date: Mon, 19 Feb 2018 15:03:53 -0500 Subject: [PATCH 160/301] Add another simple finally test --- promise/tests/test-promise.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index 7798293f..7bddbb5d 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -54,6 +54,13 @@ o.spec("promise", function() { o(value).equals(1) }).then(done) }) + o("finally returns promise", function(done) { + var promise = Promise.resolve(1) + + promise.finally(function(value) { + o(value).equals(undefined) + }).finally(done) + }) o("finally after then returns promise", function(done) { var promise = Promise.resolve(1) From d283b243371ec5e440fb05e9689944b5340663fe Mon Sep 17 00:00:00 2001 From: spacejack Date: Mon, 19 Feb 2018 16:28:28 -0500 Subject: [PATCH 161/301] Separate Promise implementation from polyfilling --- docs/change-log.md | 7 +++ docs/promise.md | 2 + index.js | 1 + promise/polyfill.js | 98 +++++++++++++++++++++++++++++++++++ promise/promise.js | 95 +-------------------------------- promise/tests/test-promise.js | 2 +- 6 files changed, 110 insertions(+), 95 deletions(-) create mode 100644 promise/polyfill.js diff --git a/docs/change-log.md b/docs/change-log.md index 5df143f6..f49329ec 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -47,6 +47,13 @@ --- +### v1.1.7 + +- Promise polyfill implementation separated from polyfilling logic. +- `PromisePolyfill` is now available on the exported/global `m`. + +--- + ### v1.1.6 - core: render() function can no longer prevent from changing `document.activeElement` in lifecycle hooks ([#1988](https://github.com/MithrilJS/mithril.js/pull/1988), [@purplecode](https://github.com/purplecode)) diff --git a/docs/promise.md b/docs/promise.md index 8091c2e2..dc93f92d 100644 --- a/docs/promise.md +++ b/docs/promise.md @@ -26,6 +26,8 @@ A [ES6 Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/G A Promise is a mechanism for working with asynchronous computations. +Mithril provides a polyfill when the environment does not support Promises. The polyfill can also be referenced specifically via `m.PromisePolyfill`. + --- ### Signature diff --git a/index.js b/index.js index 6e69cea4..123ba4ca 100644 --- a/index.js +++ b/index.js @@ -17,5 +17,6 @@ m.parseQueryString = require("./querystring/parse") m.buildQueryString = require("./querystring/build") m.version = "bleeding-edge" m.vnode = require("./render/vnode") +m.PromisePolyfill = require("./promise/polyfill") module.exports = m diff --git a/promise/polyfill.js b/promise/polyfill.js new file mode 100644 index 00000000..4d990dcd --- /dev/null +++ b/promise/polyfill.js @@ -0,0 +1,98 @@ +"use strict" +/** @constructor */ +var PromisePolyfill = function(executor) { + if (!(this instanceof PromisePolyfill)) throw new Error("Promise must be called with `new`") + if (typeof executor !== "function") throw new TypeError("executor must be a function") + + var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false) + var instance = self._instance = {resolvers: resolvers, rejectors: rejectors} + var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout + function handler(list, shouldAbsorb) { + return function execute(value) { + var then + try { + if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") { + if (value === self) throw new TypeError("Promise can't be resolved w/ itself") + executeOnce(then.bind(value)) + } + else { + callAsync(function() { + if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value) + for (var i = 0; i < list.length; i++) list[i](value) + resolvers.length = 0, rejectors.length = 0 + instance.state = shouldAbsorb + instance.retry = function() {execute(value)} + }) + } + } + catch (e) { + rejectCurrent(e) + } + } + } + function executeOnce(then) { + var runs = 0 + function run(fn) { + return function(value) { + if (runs++ > 0) return + fn(value) + } + } + var onerror = run(rejectCurrent) + try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)} + } + + executeOnce(executor) +} +PromisePolyfill.prototype.then = function(onFulfilled, onRejection) { + var self = this, instance = self._instance + function handle(callback, list, next, state) { + list.push(function(value) { + if (typeof callback !== "function") next(value) + else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)} + }) + if (typeof instance.retry === "function" && state === instance.state) instance.retry() + } + var resolveNext, rejectNext + var promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject}) + handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false) + return promise +} +PromisePolyfill.prototype.catch = function(onRejection) { + return this.then(null, onRejection) +} +PromisePolyfill.resolve = function(value) { + if (value instanceof PromisePolyfill) return value + return new PromisePolyfill(function(resolve) {resolve(value)}) +} +PromisePolyfill.reject = function(value) { + return new PromisePolyfill(function(resolve, reject) {reject(value)}) +} +PromisePolyfill.all = function(list) { + return new PromisePolyfill(function(resolve, reject) { + var total = list.length, count = 0, values = [] + if (list.length === 0) resolve([]) + else for (var i = 0; i < list.length; i++) { + (function(i) { + function consume(value) { + count++ + values[i] = value + if (count === total) resolve(values) + } + if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") { + list[i].then(consume, reject) + } + else consume(list[i]) + })(i) + } + }) +} +PromisePolyfill.race = function(list) { + return new PromisePolyfill(function(resolve, reject) { + for (var i = 0; i < list.length; i++) { + list[i].then(resolve, reject) + } + }) +} + +module.exports = PromisePolyfill diff --git a/promise/promise.js b/promise/promise.js index 53aefecc..1f19bc33 100644 --- a/promise/promise.js +++ b/promise/promise.js @@ -1,99 +1,6 @@ "use strict" -/** @constructor */ -var PromisePolyfill = function(executor) { - if (!(this instanceof PromisePolyfill)) throw new Error("Promise must be called with `new`") - if (typeof executor !== "function") throw new TypeError("executor must be a function") - var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false) - var instance = self._instance = {resolvers: resolvers, rejectors: rejectors} - var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout - function handler(list, shouldAbsorb) { - return function execute(value) { - var then - try { - if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") { - if (value === self) throw new TypeError("Promise can't be resolved w/ itself") - executeOnce(then.bind(value)) - } - else { - callAsync(function() { - if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value) - for (var i = 0; i < list.length; i++) list[i](value) - resolvers.length = 0, rejectors.length = 0 - instance.state = shouldAbsorb - instance.retry = function() {execute(value)} - }) - } - } - catch (e) { - rejectCurrent(e) - } - } - } - function executeOnce(then) { - var runs = 0 - function run(fn) { - return function(value) { - if (runs++ > 0) return - fn(value) - } - } - var onerror = run(rejectCurrent) - try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)} - } - - executeOnce(executor) -} -PromisePolyfill.prototype.then = function(onFulfilled, onRejection) { - var self = this, instance = self._instance - function handle(callback, list, next, state) { - list.push(function(value) { - if (typeof callback !== "function") next(value) - else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)} - }) - if (typeof instance.retry === "function" && state === instance.state) instance.retry() - } - var resolveNext, rejectNext - var promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject}) - handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false) - return promise -} -PromisePolyfill.prototype.catch = function(onRejection) { - return this.then(null, onRejection) -} -PromisePolyfill.resolve = function(value) { - if (value instanceof PromisePolyfill) return value - return new PromisePolyfill(function(resolve) {resolve(value)}) -} -PromisePolyfill.reject = function(value) { - return new PromisePolyfill(function(resolve, reject) {reject(value)}) -} -PromisePolyfill.all = function(list) { - return new PromisePolyfill(function(resolve, reject) { - var total = list.length, count = 0, values = [] - if (list.length === 0) resolve([]) - else for (var i = 0; i < list.length; i++) { - (function(i) { - function consume(value) { - count++ - values[i] = value - if (count === total) resolve(values) - } - if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") { - list[i].then(consume, reject) - } - else consume(list[i]) - })(i) - } - }) -} -PromisePolyfill.race = function(list) { - return new PromisePolyfill(function(resolve, reject) { - for (var i = 0; i < list.length; i++) { - list[i].then(resolve, reject) - } - }) -} +var PromisePolyfill = require("./polyfill") if (typeof window !== "undefined") { if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index e368165c..2905d694 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -2,7 +2,7 @@ var o = require("../../ospec/ospec") var callAsync = require("../../test-utils/callAsync") -var Promise = require("../../promise/promise") +var Promise = require("../../promise/polyfill") o.spec("promise", function() { o.spec("constructor", function() { From 560eade284a16d58cd28cb0b3572e5e35446bd9f Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 19 Feb 2018 22:35:24 +0000 Subject: [PATCH 162/301] Bundled output for commit d283b243371ec5e440fb05e9689944b5340663fe [skip ci] --- README.md | 2 +- mithril.js | 21 +++++++------ mithril.min.js | 84 +++++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 50a85a33..67391d79 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.62 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.63 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 2bddf8de..1cf7bd5c 100644 --- a/mithril.js +++ b/mithril.js @@ -237,7 +237,7 @@ var buildQueryString = function(object) { } } var FILE_PROTOCOL_REGEX = new RegExp("^file://", "i") -var _8 = function($window, Promise) { +var _9 = function($window, Promise) { var callbackCount = 0 var oncompletion function setCompletionCallback(callback) {oncompletion = callback} @@ -386,7 +386,7 @@ var _8 = function($window, Promise) { } return {request: request, jsonp: jsonp, setCompletionCallback: setCompletionCallback} } -var requestService = _8(window, PromisePolyfill) +var requestService = _9(window, PromisePolyfill) var coreRenderer = function($window) { var $doc = $window.document var $emptyFragment = $doc.createDocumentFragment() @@ -1188,7 +1188,7 @@ function throttle(callback) { } } } -var _11 = function($window, throttleMock) { +var _12 = function($window, throttleMock) { var renderService = coreRenderer($window) renderService.setEventCallback(function(e) { if (e.redraw === false) e.redraw = undefined @@ -1214,9 +1214,9 @@ var _11 = function($window, throttleMock) { redraw.sync = sync return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render} } -var redrawService = _11(window) +var redrawService = _12(window) requestService.setCompletionCallback(redrawService.redraw) -var _16 = function(redrawService0) { +var _17 = function(redrawService0) { return function(root, component) { if (component === null) { redrawService0.render(root, []) @@ -1233,7 +1233,7 @@ var _16 = function(redrawService0) { run0() } } -m.mount = _16(redrawService) +m.mount = _17(redrawService) var Promise = PromisePolyfill var parseQueryString = function(string) { if (string === "" || string == null) return {} @@ -1361,7 +1361,7 @@ var coreRouter = function($window) { } return router } -var _20 = function($window, redrawService0) { +var _21 = function($window, redrawService0) { var routeService = coreRouter($window) var identity = function(v) {return v} var render1, component, attrs3, currentPath, lastUpdate @@ -1429,14 +1429,14 @@ var _20 = function($window, redrawService0) { } return route } -m.route = _20(window, redrawService) +m.route = _21(window, redrawService) m.withAttr = function(attrName, callback, context) { return function(e) { callback.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) } } -var _28 = coreRenderer(window) -m.render = _28.render +var _29 = coreRenderer(window) +m.render = _29.render m.redraw = redrawService.redraw m.request = requestService.request m.jsonp = requestService.jsonp @@ -1444,6 +1444,7 @@ m.parseQueryString = parseQueryString m.buildQueryString = buildQueryString m.version = "1.1.3" m.vnode = Vnode +m.PromisePolyfill = PromisePolyfill if (typeof module !== "undefined") module["exports"] = m else window.m = m }()); \ No newline at end of file diff --git a/mithril.min.js b/mithril.min.js index f08ea8cf..06d9a17a 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,46 @@ -(function(){function t(a,d,e,h,p,l){return{tag:a,key:d,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function Q(a){for(var d in a)if(G.call(a,d))return!1;return!0}function x(a){var d=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var h;if(!(h=R[a])){var p="div";for(var l=[],k={};h=V.exec(a);){var q=h[1], -r=h[2];""===q&&""!==r?p=r:"#"===q?k.id=r:"."===q?l.push(r):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+d}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(C){throw Error(b);}}function q(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(b.url))d(r(b.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=b.data?m.send(b.data):m.send()});return!0===b.background?C:A(C)},jsonp:function(b,k){var A=e();b=h(b, -k);var q=new d(function(d,e){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(b.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=p(b.url,b.data);b.data[b.callbackKey||"callback"]=h;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?q:A(q)},setCompletionCallback:function(b){u= -b}}}(window,B),U=function(a){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,b,a,d,e){for(;fb.indexOf("?")?"?":"&";b+=e+d}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(B){throw Error(b);}}function q(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(b.url))d(r(b.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=b.data?m.send(b.data):m.send()});return!0===b.background?B:A(B)},jsonp:function(b,k){var A=e();b=h(b, +k);var q=new d(function(d,e){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(b.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=p(b.url,b.data);b.data[b.callbackKey||"callback"]=h;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?q:A(q)},setCompletionCallback:function(b){z= +b}}}(window,t),V=function(a){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,b,a,d,e){for(;f=v&&t>=n;)if(w=c[v],z=f[n],y=C&&v>=q,w===z&&!y&&!a||null==w&&null==z)v++,n++;else if(null==w)(E||null==z.key)&&p(g,f[n],d,k,u(c,++n,q,e)),v++;else if(null==z){if(E||null==w.key)A(c,n,n+1,f,a),v++;n++}else if(w.key===z.key)v++,n++,r(g,w,z,d,u(c,v,q,e),y||a,k),y&&w.tag===z.tag&&b(g,m(z),e);else if(w=c[l],y=C&&l>=q,w!==z||y||a)if(null==w)l--;else if(null== -z)n++;else if(w.key===z.key)r(g,w,z,d,u(c,l+1,q,e),y||a,k),(y&&w.tag===z.tag||n=v&&t>=n;){w=c[l];z=f[t];y=C&&l>=q;if(w!==z||y||a)if(null==w)l--;else{if(null!=z)if(w.key===z.key)r(g,w,z,d,u(c,l+1,q,e),y||a,k),y&&w.tag===z.tag&&b(g,m(z),e),null!=w.dom&&(e=w.dom),l--;else{if(!I){I=c;E=l;w={};for(y=0;y=q,r(g,w,z,d,u(c,l+1,q,e),y||a,k), -b(g,m(z),e),w.skip=!0,null!=w.dom&&(e=w.dom)):e=p(g,z,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:B(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var u,E;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(u=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(E=e.call(f.state.onbeforeupdate, -f,c));void 0===u&&void 0===E||u||E?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):M(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;d=E&&t>=n;)if(v=c[E],y=f[n],u=B&&E>=q,v===y&&!u&&!a||null==v&&null==y)E++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],d,k,z(c,++n,q,e)),E++;else if(null==y){if(D||null==v.key)A(c,n,n+1,f,a),E++;n++}else if(v.key===y.key)E++,n++,r(g,v,y,d,z(c,E,q,e),u||a,k),u&&v.tag===y.tag&&b(g,m(y),e);else if(v=c[l],u=B&&l>=q,v!==y||u||a)if(null==v)l--;else if(null== +y)n++;else if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||a,k),(u&&v.tag===y.tag||n=E&&t>=n;){v=c[l];y=f[t];u=B&&l>=q;if(v!==y||u||a)if(null==v)l--;else{if(null!=y)if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||a,k),u&&v.tag===y.tag&&b(g,m(y),e),null!=v.dom&&(e=v.dom),l--;else{if(!x){x=c;D=l;v={};for(u=0;u=q,r(g,v,y,d,z(c,l+1,q,e),u||a,k), +b(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:I(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var z,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(z=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate, +f,c));void 0===z&&void 0===D||z||D?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):N(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;d Date: Tue, 20 Feb 2018 00:27:39 +0100 Subject: [PATCH 163/301] Better tests for Promise.prototype.finally --- promise/tests/test-promise.js | 83 +++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index 4e85c9a4..7dcc21f6 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -54,30 +54,77 @@ o.spec("promise", function() { o(value).equals(1) }).then(done) }) - o("finally returns promise", function(done) { + o("finally lets a fulfilled value pass though", function(done) { var promise = Promise.resolve(1) + var spy = o.spy(function(){return 2}) - promise.finally(function(value) { - o(value).equals(undefined) - }).finally(done) - }) - o("finally after then returns promise", function(done) { - var promise = Promise.resolve(1) - - promise.then(function(value) { + promise.finally(spy).then(function(value){ o(value).equals(1) - }).finally(function(value) { - o(value).equals(undefined) - }).then(done) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) }) - o("finally after catch returns promise", function(done) { + o("finally lets a rejected reason pass though", function(done) { var promise = Promise.reject(1) + var spy = o.spy(function(){return 2}) - promise.catch(function(value) { - o(value).equals(1) - }).finally(function(value) { - o(value).equals(undefined) - }).then(done) + promise.finally(spy).catch(function(reason){ + o(reason).equals(1) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a fulfilled value when it throws", function(done) { + var promise = Promise.resolve(1) + var spy = o.spy(function(){throw 2}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a fulfilled value when it returns a rejected Promise", function(done) { + var promise = Promise.resolve(1) + var spy = o.spy(function(){return Promise.reject(2)}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a rejected reason when it throws", function(done) { + var promise = Promise.reject(1) + var spy = o.spy(function(){throw 2}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a rejected reason when it returns a rejected Promise", function(done) { + var promise = Promise.reject(1) + var spy = o.spy(function(){return Promise.reject(2)}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) }) }) o.spec("resolve", function() { From 7699b4515d7eb2f9fd5e96f809a3baf4ca61553d Mon Sep 17 00:00:00 2001 From: Cassidy Williams Date: Mon, 26 Feb 2018 08:04:13 -0800 Subject: [PATCH 164/301] docs: Minor casing changes (#2093) --- docs/installation.md | 3 ++- docs/layout.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 5c204e6a..e7ba633d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -3,7 +3,7 @@ - [CDN](#cdn) - [NPM](#npm) - [Quick start with Webpack](#quick-start-with-webpack) -- [Typescript](#typescript) +- [TypeScript](#typescript) ### CDN @@ -64,6 +64,7 @@ m.render(document.body, "hello world"); ```bash $> npm start ``` + 6. open `index.html` in your (default) browser #### Step by step diff --git a/docs/layout.html b/docs/layout.html index 110a890b..fa06f4f1 100644 --- a/docs/layout.html +++ b/docs/layout.html @@ -16,7 +16,7 @@ Guide API Chat - Github + GitHub From 9d153a02e97b390209e4a299b0a7bbc740acda79 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Mon, 26 Feb 2018 08:09:15 -0800 Subject: [PATCH 165/301] Add docs checkbox Since we get a fair number of those --- .github/PULL_REQUEST_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b60b2e54..f85840f2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -17,6 +17,7 @@ - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) +- [ ] Documentation change ## Checklist: From e25f086061ab0495ea099593f931be0620925f63 Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Wed, 28 Feb 2018 08:13:07 -0800 Subject: [PATCH 166/301] docs: correct some webpack bitrot (#2094) --- docs/installation.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index e7ba633d..2ce6bccb 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -33,15 +33,15 @@ $> npm init --yes 2. install required tools ```bash $> npm install mithril --save -$> npm install webpack --save +$> npm install webpack webpack-cli --save-dev ``` -3. Add a "start" entry to the scripts section in `package.json` +3. Add a "start" entry to the scripts section in `package.json`. ```js { // ... "scripts": { - "start": "webpack src/index.js bin/app.js --watch" + "start": "webpack src/index.js --output bin/app.js -d --watch" } } ``` @@ -56,8 +56,9 @@ m.render(document.body, "hello world"); 4. create `index.html` ```html - - + + + ``` 5. run bundler @@ -65,7 +66,7 @@ m.render(document.body, "hello world"); $> npm start ``` -6. open `index.html` in your (default) browser +6. open `index.html` in a browser #### Step by step @@ -106,7 +107,7 @@ Most browser today do not natively support modularization systems (CommonJS or E A popular way for creating a bundle is to setup an NPM script for [Webpack](https://webpack.js.org/). To install Webpack, run this from the command line: ```bash -npm install webpack --save-dev +npm install webpack webpack-cli --save-dev ``` Open the `package.json` that you created earlier, and add an entry to the `scripts` section: @@ -115,7 +116,7 @@ Open the `package.json` that you created earlier, and add an entry to the `scrip { "name": "my-project", "scripts": { - "start": "webpack src/index.js bin/app.js -d --watch" + "start": "webpack src/index.js --output bin/app.js -d --watch" } } ``` @@ -177,8 +178,8 @@ If you open bin/app.js, you'll notice that the Webpack bundle is not minified, s { "name": "my-project", "scripts": { - "start": "webpack src/index.js bin/app.js -d --watch", - "build": "webpack src/index.js bin/app.js -p", + "start": "webpack src/index.js --output bin/app.js -d --watch", + "build": "webpack src/index.js --output bin/app.js -p", } } ``` From 0fc9b6ed07f89022a4d1298a68b16dd446cc7762 Mon Sep 17 00:00:00 2001 From: Scotty Simpson Date: Sat, 3 Mar 2018 20:44:34 -0800 Subject: [PATCH 167/301] typo fix --- docs/stream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stream.md b/docs/stream.md index 34818e12..0f5bea9e 100644 --- a/docs/stream.md +++ b/docs/stream.md @@ -384,7 +384,7 @@ var added = stream.combine(function(a, b) { console.log(added()) // logs 12 ``` -A stream can depend on any number of streams and it's guaranteed to update atomically. For example, if a stream A has two dependent streams B and C, and a fourth stream D is dependent on both B and C, the stream D will only update once if the value of A changes. This guarantees that the callback for stream D is never called with unstable values such as when B has a new value but C has the old value. Atomicity also bring the performance benefits of not recomputing downstreams unnecessarily. +A stream can depend on any number of streams and it's guaranteed to update atomically. For example, if a stream A has two dependent streams B and C, and a fourth stream D is dependent on both B and C, the stream D will only update once if the value of A changes. This guarantees that the callback for stream D is never called with unstable values such as when B has a new value but C has the old value. Atomicity also brings the performance benefits of not recomputing downstreams unnecessarily. You can prevent dependent streams from being updated by returning the special value `stream.HALT` From fdd34f97260ecd846c57a59079175ec5de622915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 2 Mar 2018 14:05:29 +0100 Subject: [PATCH 168/301] [mocks] Add some support for parsing SVG using the DOMParser API and innerHTML --- docs/change-log.md | 2 +- test-utils/domMock.js | 72 ++++++++++++++-------- test-utils/tests/test-domMock.js | 102 ++++++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 28 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index f49329ec..87343422 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -29,7 +29,7 @@ - API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) - +- Mocks: add limited support for the DOMParser API #### Bug fixes diff --git a/test-utils/domMock.js b/test-utils/domMock.js index a4c7c598..99bfff9a 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -2,7 +2,7 @@ /* Known limitations: - +- the innerHTML setter and the DOMParser only support a small subset of the true HTML/XML syntax. - `option.selected` can't be set/read when the option doesn't have a `select` parent - `element.attributes` is just a map of attribute names => Attr objects stubs - ... @@ -183,9 +183,43 @@ module.exports = function(options) { res.unshift(declList) return res } - + function parseMarkup(value, root, voidElements, xmlns) { + var depth = 0, stack = [root] + value.replace(/<([a-z0-9\-]+?)((?:\s+?[^=]+?=(?:"[^"]*?"|'[^']*?'|[^\s>]*))*?)(\s*\/)?>|<\/([a-z0-9\-]+?)>|([^<]+)/g, function(match, startTag, attrs, selfClosed, endTag, text) { + if (startTag) { + var element = xmlns == null ? $window.document.createElement(startTag) : $window.document.createElementNS(xmlns, startTag) + attrs.replace(/\s+?([^=]+?)=(?:"([^"]*?)"|'([^']*?)'|([^\s>]*))/g, function(match, key, doubleQuoted, singleQuoted, unquoted) { + var keyParts = key.split(":") + var name = keyParts.pop() + var ns = keyParts[0] + var value = doubleQuoted || singleQuoted || unquoted || "" + if (ns != null) element.setAttributeNS(ns, name, value) + else element.setAttribute(name, value) + }) + stack[depth].appendChild(element) + if (!selfClosed && voidElements.indexOf(startTag.toLowerCase()) < 0) stack[++depth] = element + } + else if (endTag) { + depth-- + } + else if (text) { + stack[depth].appendChild($window.document.createTextNode(text)) // FIXME handle html entities + } + }) + } + function DOMParser() {} + DOMParser.prototype.parseFromString = function(src, mime) { + if (mime !== "image/svg+xml") throw new Error("The DOMParser mock only supports the \"image/svg+xml\" MIME type") + var match = src.match(/^(.*)<\/svg>$/) + if (!match) throw new Error("Please provide a bare SVG tag with the xmlns as only attribute") + var value = match[1] + var root = $window.document.createElementNS("http://www.w3.org/2000/svg", "svg") + parseMarkup(value, root, [], "http://www.w3.org/2000/svg") + return {documentElement: root} + } var activeElement var $window = { + DOMParser: DOMParser, document: { createElement: function(tag) { var cssText = "" @@ -244,30 +278,18 @@ module.exports = function(options) { if (value !== "") this.appendChild($window.document.createTextNode(value)) }, set innerHTML(value) { + var voidElements = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"] while (this.firstChild) this.removeChild(this.firstChild) - - var stack = [this], depth = 0, voidElements = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"] - value.replace(/<([a-z0-9\-]+?)((?:\s+?[^=]+?=(?:"[^"]*?"|'[^']*?'|[^\s>]*))*?)(\s*\/)?>|<\/([a-z0-9\-]+?)>|([^<]+)/g, function(match, startTag, attrs, selfClosed, endTag, text) { - if (startTag) { - var element = $window.document.createElement(startTag) - attrs.replace(/\s+?([^=]+?)=(?:"([^"]*?)"|'([^']*?)'|([^\s>]*))/g, function(match, key, doubleQuoted, singleQuoted, unquoted) { - var keyParts = key.split(":") - var name = keyParts.pop() - var ns = keyParts[0] - var value = doubleQuoted || singleQuoted || unquoted || "" - if (ns != null) element.setAttributeNS(ns, name, value) - else element.setAttribute(name, value) - }) - stack[depth].appendChild(element) - if (!selfClosed && voidElements.indexOf(startTag.toLowerCase()) < 0) stack[++depth] = element - } - else if (endTag) { - depth-- - } - else if (text) { - stack[depth].appendChild($window.document.createTextNode(text)) // FIXME handle html entities - } - }) + var match = value.match(/^(.*)<\/svg>$/), root, ns + if (match) { + var value = match[1] + root = $window.document.createElementNS("http://www.w3.org/2000/svg", "svg") + ns = "http://www.w3.org/2000/svg" + this.appendChild(root) + } else { + root = this + } + parseMarkup(value, root, voidElements, ns) }, get style() { return style diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index f05d24c9..5540bb86 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -4,9 +4,10 @@ var o = require("../../ospec/ospec") var domMock = require("../../test-utils/domMock") o.spec("domMock", function() { - var $document + var $document, $window o.beforeEach(function() { - $document = domMock().document + $window = domMock() + $document = $window.document }) o.spec("createElement", function() { @@ -497,6 +498,45 @@ o.spec("domMock", function() { o(a.parentNode).equals(null) }) + o("empty SVG document", function() { + var div = $document.createElement("div") + div.innerHTML = "" + + o(typeof div.firstChild).notEquals(undefined) + o(div.firstChild.nodeName).equals("svg") + o(div.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg") + o(div.firstChild.childNodes.length).equals(0) + }) + o("text elements", function() { + var div = $document.createElement("div") + div.innerHTML = + "" + + "hello" + + " " + + "world" + + "" + + o(div.firstChild.nodeName).equals("svg") + o(div.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg") + + var nodes = div.firstChild.childNodes + o(nodes.length).equals(3) + o(nodes[0].nodeName).equals("text") + o(nodes[0].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[0].childNodes.length).equals(1) + o(nodes[0].childNodes[0].nodeName).equals("#text") + o(nodes[0].childNodes[0].nodeValue).equals("hello") + o(nodes[1].nodeName).equals("text") + o(nodes[1].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[1].childNodes.length).equals(1) + o(nodes[1].childNodes[0].nodeName).equals("#text") + o(nodes[1].childNodes[0].nodeValue).equals(" ") + o(nodes[2].nodeName).equals("text") + o(nodes[2].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[2].childNodes.length).equals(1) + o(nodes[2].childNodes[0].nodeName).equals("#text") + o(nodes[2].childNodes[0].nodeValue).equals("world") + }) }) o.spec("focus", function() { o("body is active by default", function() { @@ -1792,4 +1832,62 @@ o.spec("domMock", function() { o(spies.valueSetter.args[0]).equals("aaa") }) }) + o.spec("DOMParser for SVG", function(){ + var $DOMParser + o.beforeEach(function() { + $DOMParser = $window.DOMParser + }) + o("basics", function(){ + o(typeof $DOMParser).equals("function") + + var parser = new $DOMParser() + + o(parser instanceof $DOMParser).equals(true) + o(typeof parser.parseFromString).equals("function") + }) + o("empty document", function() { + var parser = new $DOMParser() + var doc = parser.parseFromString( + "", + "image/svg+xml" + ) + + o(typeof doc.documentElement).notEquals(undefined) + o(doc.documentElement.nodeName).equals("svg") + o(doc.documentElement.namespaceURI).equals("http://www.w3.org/2000/svg") + o(doc.documentElement.childNodes.length).equals(0) + }) + o("text elements", function() { + var parser = new $DOMParser() + var doc = parser.parseFromString( + "" + + "hello" + + " " + + "world" + + "", + "image/svg+xml" + ) + + o(doc.documentElement.nodeName).equals("svg") + o(doc.documentElement.namespaceURI).equals("http://www.w3.org/2000/svg") + + var nodes = doc.documentElement.childNodes + o(nodes.length).equals(3) + o(nodes[0].nodeName).equals("text") + o(nodes[0].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[0].childNodes.length).equals(1) + o(nodes[0].childNodes[0].nodeName).equals("#text") + o(nodes[0].childNodes[0].nodeValue).equals("hello") + o(nodes[1].nodeName).equals("text") + o(nodes[1].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[1].childNodes.length).equals(1) + o(nodes[1].childNodes[0].nodeName).equals("#text") + o(nodes[1].childNodes[0].nodeValue).equals(" ") + o(nodes[2].nodeName).equals("text") + o(nodes[2].namespaceURI).equals("http://www.w3.org/2000/svg") + o(nodes[2].childNodes.length).equals(1) + o(nodes[2].childNodes[0].nodeName).equals("#text") + o(nodes[2].childNodes[0].nodeValue).equals("world") + }) + }) }) From ad46a21a7d454860e757cb15cee9bdb65591ea3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 2 Mar 2018 14:41:49 +0100 Subject: [PATCH 169/301] [render] add support for SVG in `m.trust()` strings --- docs/change-log.md | 3 ++- docs/trust.md | 4 ++-- render/render.js | 22 +++++++++++++--------- render/tests/test-createHTML.js | 32 +++++++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 87343422..19b701a9 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -29,7 +29,8 @@ - API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) -- Mocks: add limited support for the DOMParser API +- Mocks: add limited support for the DOMParser API ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) +- API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) #### Bug fixes diff --git a/docs/trust.md b/docs/trust.md index d960e743..34e6ace8 100644 --- a/docs/trust.md +++ b/docs/trust.md @@ -11,7 +11,7 @@ ### Description -Turns an HTML string into unescaped HTML. **Do not use `m.trust` on unsanitized user input.** +Turns an HTML or SVG string into unescaped HTML or SVG. **Do not use `m.trust` on unsanitized user input.** Always try to use an [alternative method](#avoid-trusting-html) first, before considering using `m.trust`. @@ -23,7 +23,7 @@ Always try to use an [alternative method](#avoid-trusting-html) first, before co Argument | Type | Required | Description ----------- | -------------------- | -------- | --- -`html` | `String` | Yes | A string containing HTML text +`html` | `String` | Yes | A string containing HTML or SVG text **returns** | `Vnode` | | A trusted HTML [vnode](vnodes.md) that represents the input string [How to read signatures](signatures.md) diff --git a/render/render.js b/render/render.js index 9efbde96..98e0f4d1 100644 --- a/render/render.js +++ b/render/render.js @@ -52,7 +52,7 @@ module.exports = function($window) { if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) switch (tag) { case "#": return createText(parent, vnode, nextSibling) - case "<": return createHTML(parent, vnode, nextSibling) + case "<": return createHTML(parent, vnode, ns, nextSibling) case "[": return createFragment(parent, vnode, hooks, ns, nextSibling) default: return createElement(parent, vnode, hooks, ns, nextSibling) } @@ -64,12 +64,16 @@ module.exports = function($window) { insertNode(parent, vnode.dom, nextSibling) return vnode.dom } - function createHTML(parent, vnode, nextSibling) { + var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} + function createHTML(parent, vnode, ns, nextSibling) { var match = vnode.children.match(/^\s*?<(\w+)/im) || [] - var parent1 = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match[1]] || "div" - var temp = $doc.createElement(parent1) - - temp.innerHTML = vnode.children + var temp = $doc.createElement(possibleParents[match[1]] || "div") + if (ns === "http://www.w3.org/2000/svg") { + temp.innerHTML = "" + vnode.children + "" + temp = temp.firstChild + } else { + temp.innerHTML = vnode.children + } vnode.dom = temp.firstChild vnode.domSize = temp.childNodes.length var fragment = $doc.createDocumentFragment() @@ -404,7 +408,7 @@ module.exports = function($window) { } switch (oldTag) { case "#": updateText(old, vnode); break - case "<": updateHTML(parent, old, vnode, nextSibling); break + case "<": updateHTML(parent, old, vnode, ns, nextSibling); break case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break default: updateElement(old, vnode, recycling, hooks, ns) } @@ -422,10 +426,10 @@ module.exports = function($window) { } vnode.dom = old.dom } - function updateHTML(parent, old, vnode, nextSibling) { + function updateHTML(parent, old, vnode, ns, nextSibling) { if (old.children !== vnode.children) { toFragment(old) - createHTML(parent, vnode, nextSibling) + createHTML(parent, vnode, ns, nextSibling) } else vnode.dom = old.dom, vnode.domSize = old.domSize } diff --git a/render/tests/test-createHTML.js b/render/tests/test-createHTML.js index bb0d508c..a337213b 100644 --- a/render/tests/test-createHTML.js +++ b/render/tests/test-createHTML.js @@ -31,7 +31,7 @@ o.spec("createHTML", function() { o(vnode.dom).equals(null) o(vnode.domSize).equals(0) }) - o("handles multiple children", function() { + o("handles multiple children in HTML", function() { var vnode = {tag: "<", children: ""} render(root, [vnode]) @@ -51,4 +51,34 @@ o.spec("createHTML", function() { o(vnode.dom.nodeName).equals(tag.toUpperCase()) }) }) + o("creates SVG", function() { + var vnode = {tag: "<", children: ""} + render(root, [{tag:"svg", children: [vnode]}]) + + o(vnode.dom.nodeName).equals("g") + o(vnode.dom.namespaceURI).equals("http://www.w3.org/2000/svg") + }) + o("creates text SVG", function() { + var vnode = {tag: "<", children: "a"} + render(root, [{tag:"svg", children: [vnode]}]) + + o(vnode.dom.nodeValue).equals("a") + }) + o("handles empty SVG", function() { + var vnode = {tag: "<", children: ""} + render(root, [{tag:"svg", children: [vnode]}]) + + o(vnode.dom).equals(null) + o(vnode.domSize).equals(0) + }) + o("handles multiple children in SVG", function() { + var vnode = {tag: "<", children: ""} + render(root, [{tag:"svg", children: [vnode]}]) + + o(vnode.domSize).equals(2) + o(vnode.dom.nodeName).equals("g") + o(vnode.dom.namespaceURI).equals("http://www.w3.org/2000/svg") + o(vnode.dom.nextSibling.nodeName).equals("text") + o(vnode.dom.nextSibling.namespaceURI).equals("http://www.w3.org/2000/svg") + }) }) From 9ece9a9297326f6cd2723c449777db85dcf538b1 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 6 Mar 2018 00:14:15 +0000 Subject: [PATCH 170/301] Bundled output for commit ad46a21a7d454860e757cb15cee9bdb65591ea3f [skip ci] --- README.md | 2 +- mithril.js | 21 ++++++++----- mithril.min.js | 83 +++++++++++++++++++++++++------------------------- 3 files changed, 56 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 67391d79..6860df3a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.63 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.68 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 1cf7bd5c..093990bf 100644 --- a/mithril.js +++ b/mithril.js @@ -431,7 +431,7 @@ var coreRenderer = function($window) { if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) switch (tag) { case "#": return createText(parent, vnode, nextSibling) - case "<": return createHTML(parent, vnode, nextSibling) + case "<": return createHTML(parent, vnode, ns, nextSibling) case "[": return createFragment(parent, vnode, hooks, ns, nextSibling) default: return createElement(parent, vnode, hooks, ns, nextSibling) } @@ -443,11 +443,16 @@ var coreRenderer = function($window) { insertNode(parent, vnode.dom, nextSibling) return vnode.dom } - function createHTML(parent, vnode, nextSibling) { + var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} + function createHTML(parent, vnode, ns, nextSibling) { var match1 = vnode.children.match(/^\s*?<(\w+)/im) || [] - var parent1 = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div" - var temp = $doc.createElement(parent1) - temp.innerHTML = vnode.children + var temp = $doc.createElement(possibleParents[match1[1]] || "div") + if (ns === "http://www.w3.org/2000/svg") { + temp.innerHTML = "" + vnode.children + "" + temp = temp.firstChild + } else { + temp.innerHTML = vnode.children + } vnode.dom = temp.firstChild vnode.domSize = temp.childNodes.length var fragment = $doc.createDocumentFragment() @@ -768,7 +773,7 @@ var coreRenderer = function($window) { } switch (oldTag) { case "#": updateText(old, vnode); break - case "<": updateHTML(parent, old, vnode, nextSibling); break + case "<": updateHTML(parent, old, vnode, ns, nextSibling); break case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break default: updateElement(old, vnode, recycling, hooks, ns) } @@ -786,10 +791,10 @@ var coreRenderer = function($window) { } vnode.dom = old.dom } - function updateHTML(parent, old, vnode, nextSibling) { + function updateHTML(parent, old, vnode, ns, nextSibling) { if (old.children !== vnode.children) { toFragment(old) - createHTML(parent, vnode, nextSibling) + createHTML(parent, vnode, ns, nextSibling) } else vnode.dom = old.dom, vnode.domSize = old.domSize } diff --git a/mithril.min.js b/mithril.min.js index 06d9a17a..4b3ed3ed 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,46 +1,47 @@ -(function(){function x(a,d,e,h,p,l){return{tag:a,key:d,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function R(a){for(var d in a)if(G.call(a,d))return!1;return!0}function w(a){var d=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var h;if(!(h=S[a])){var p="div";for(var l=[],k={};h=W.exec(a);){var q=h[1], -r=h[2];""===q&&""!==r?p=r:"#"===q?k.id=r:"."===q?l.push(r):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0b.indexOf("?")?"?":"&";b+=e+d}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(B){throw Error(b);}}function q(b){return b.responseText}function r(b,a){if("function"===typeof b)if(Array.isArray(a))for(var d=0;dm.status||304===m.status||Z.test(b.url))d(r(b.type,a));else{var h=Error(m.responseText);h.code=m.status;h.response=a;e(h)}}catch(H){e(H)}};h&&null!=b.data?m.send(b.data):m.send()});return!0===b.background?B:A(B)},jsonp:function(b,k){var A=e();b=h(b, -k);var q=new d(function(d,e){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[h]=function(e){k.parentNode.removeChild(k);d(r(b.type,e));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=p(b.url,b.data);b.data[b.callbackKey||"callback"]=h;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?q:A(q)},setCompletionCallback:function(b){z= -b}}}(window,t),V=function(a){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,b,a,d,e){for(;f=E&&t>=n;)if(v=c[E],y=f[n],u=B&&E>=q,v===y&&!u&&!a||null==v&&null==y)E++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],d,k,z(c,++n,q,e)),E++;else if(null==y){if(D||null==v.key)A(c,n,n+1,f,a),E++;n++}else if(v.key===y.key)E++,n++,r(g,v,y,d,z(c,E,q,e),u||a,k),u&&v.tag===y.tag&&b(g,m(y),e);else if(v=c[l],u=B&&l>=q,v!==y||u||a)if(null==v)l--;else if(null== -y)n++;else if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||a,k),(u&&v.tag===y.tag||n=E&&t>=n;){v=c[l];y=f[t];u=B&&l>=q;if(v!==y||u||a)if(null==v)l--;else{if(null!=y)if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||a,k),u&&v.tag===y.tag&&b(g,m(y),e),null!=v.dom&&(e=v.dom),l--;else{if(!x){x=c;D=l;v={};for(u=0;u=q,r(g,v,y,d,z(c,l+1,q,e),u||a,k), -b(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:I(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var z,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(z=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate, -f,c));void 0===z&&void 0===D||z||D?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},K(f.attrs,f,a)):N(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;da.indexOf("?")?"?":"&";a+=e+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(B){throw Error(a);}}function q(a){return a.responseText}function r(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||Z.test(a.url))d(r(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(I){e(I)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?B:A(B)},jsonp:function(a,k){var A=e();a=h(a, +k);var q=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[h]=function(e){k.parentNode.removeChild(k);d(r(a.type,e));delete b[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?q:A(q)},setCompletionCallback:function(a){z= +a}}}(window,t),V=function(b){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,a,b,d,e){for(;f'+c.children+"",d=d.firstChild):d.innerHTML=c.children;c.dom=d.firstChild;c.domSize=d.childNodes.length;for(c=C.createDocumentFragment();f=d.firstChild;)c.appendChild(f);a(g,c,b);return c}function k(g,c){if("function"===typeof g.tag.view){g.state=Object.create(g.tag);var f=g.state.view;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0}else{g.state=void 0;f=g.tag;if(null!=f.$$reentrantLock$$)return I; +f.$$reentrantLock$$=!0;g.state=null!=g.tag.prototype&&"function"===typeof g.tag.prototype.view?new g.tag(g):g.tag(g)}null!=g.attrs&&L(g.attrs,g,c);L(g.state,g,c);g.instance=x.normalize(e.call(g.state.view,g));if(g.instance===g)throw Error("A view cannot return the vnode it received as argument");f.$$reentrantLock$$=null}function q(g,c,f,b,d,e,k){if(!(c===f&&!b||null==c&&null==f))if(null==c)h(g,f,0,f.length,d,e,k);else if(null==f)A(c,0,c.length,f,b);else{for(var n=0,l=Math.min(c.length,f.length),q= +c.length,B=!1,D=!1;n=E&&t>=n;)if(v=c[E],y=f[n],u=B&&E>=q,v===y&&!u&&!b||null==v&&null==y)E++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],d,k,z(c,++n,q,e)),E++;else if(null==y){if(D||null==v.key)A(c,n,n+1,f,b),E++;n++}else if(v.key===y.key)E++,n++,r(g,v,y,d,z(c,E,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e);else if(v=c[l],u=B&&l>=q,v!==y||u||b)if(null==v)l--;else if(null== +y)n++;else if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||b,k),(u&&v.tag===y.tag||n=E&&t>=n;){v=c[l];y=f[t];u=B&&l>=q;if(v!==y||u||b)if(null==v)l--;else{if(null!=y)if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e),null!=v.dom&&(e=v.dom),l--;else{if(!x){x=c;D=l;v={};for(u=0;u=q,r(g,v,y,d,z(c,l+1,q,e),u||b,k), +a(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:J(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var z,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(z=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate, +f,c));void 0===z&&void 0===D||z||D?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},L(f.attrs,f,a)):N(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,h,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;d Date: Tue, 6 Mar 2018 02:12:02 +0100 Subject: [PATCH 171/301] Document the reason for the possibleParents map --- render/render.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/render/render.js b/render/render.js index 98e0f4d1..7a674c3c 100644 --- a/render/render.js +++ b/render/render.js @@ -67,6 +67,11 @@ module.exports = function($window) { var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} function createHTML(parent, vnode, ns, nextSibling) { var match = vnode.children.match(/^\s*?<(\w+)/im) || [] + // not using the proper parent makes the child element(s) vanish. + // var div = document.createElement("div") + // div.innerHTML = "ij" + // console.log(div.innerHTML) + // --> "ij", no in sight. var temp = $doc.createElement(possibleParents[match[1]] || "div") if (ns === "http://www.w3.org/2000/svg") { temp.innerHTML = "" + vnode.children + "" From 8e8194bca5dc8248273dc095ee387947137c2919 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 6 Mar 2018 01:14:52 +0000 Subject: [PATCH 172/301] Bundled output for commit d21ba5ee6a8921e48cb89cbbc4f05547d039d6e8 [skip ci] --- mithril.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mithril.js b/mithril.js index 093990bf..87176674 100644 --- a/mithril.js +++ b/mithril.js @@ -446,6 +446,11 @@ var coreRenderer = function($window) { var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} function createHTML(parent, vnode, ns, nextSibling) { var match1 = vnode.children.match(/^\s*?<(\w+)/im) || [] + // not using the proper parent makes the child element(s) vanish. + // var div = document.createElement("div") + // div.innerHTML = "ij" + // console.log(div.innerHTML) + // --> "ij", no in sight. var temp = $doc.createElement(possibleParents[match1[1]] || "div") if (ns === "http://www.w3.org/2000/svg") { temp.innerHTML = "" + vnode.children + "" From 550ad86ec5fd46a86d3a5acfcbf5be4ebe29a955 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 6 Mar 2018 15:59:33 +0000 Subject: [PATCH 173/301] Bundled output for commit 0b83c29ab6e6ae96a139fe8c9afc7e532e2b78f2 [skip ci] --- README.md | 2 +- mithril.js | 26 ++++++++++++-- mithril.min.js | 94 +++++++++++++++++++++++++------------------------- 3 files changed, 72 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 6860df3a..e438ae20 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.68 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.74 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 87176674..4f50a73e 100644 --- a/mithril.js +++ b/mithril.js @@ -174,6 +174,20 @@ PromisePolyfill.prototype.then = function(onFulfilled, onRejection) { PromisePolyfill.prototype.catch = function(onRejection) { return this.then(null, onRejection) } +PromisePolyfill.prototype.finally = function(callback) { + return this.then( + function(value) { + return PromisePolyfill.resolve(callback()).then(function() { + return value + }) + }, + function(reason) { + return PromisePolyfill.resolve(callback()).then(function() { + return PromisePolyfill.reject(reason); + }) + } + ) +} PromisePolyfill.resolve = function(value) { if (value instanceof PromisePolyfill) return value return new PromisePolyfill(function(resolve) {resolve(value)}) @@ -208,10 +222,18 @@ PromisePolyfill.race = function(list) { }) } if (typeof window !== "undefined") { - if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill + if (typeof window.Promise === "undefined") { + window.Promise = PromisePolyfill + } else if (!window.Promise.prototype.finally) { + window.Promise.prototype.finally = PromisePolyfill.prototype.finally + } var PromisePolyfill = window.Promise } else if (typeof global !== "undefined") { - if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill + if (typeof global.Promise === "undefined") { + global.Promise = PromisePolyfill + } else if (!global.Promise.prototype.finally) { + global.Promise.prototype.finally = PromisePolyfill.prototype.finally + } var PromisePolyfill = global.Promise } else { } diff --git a/mithril.min.js b/mithril.min.js index 4b3ed3ed..3b95ad15 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,47 +1,47 @@ -(function(){function x(b,d,e,h,p,l){return{tag:b,key:d,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function R(b){for(var d in b)if(G.call(b,d))return!1;return!0}function w(b){var d=arguments[1],e=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b){var h;if(!(h=S[b])){var p="div";for(var l=[],k={};h=W.exec(b);){var q=h[1], -r=h[2];""===q&&""!==r?p=r:"#"===q?k.id=r:"."===q?l.push(r):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(B){throw Error(a);}}function q(a){return a.responseText}function r(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||Z.test(a.url))d(r(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(I){e(I)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?B:A(B)},jsonp:function(a,k){var A=e();a=h(a, -k);var q=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[h]=function(e){k.parentNode.removeChild(k);d(r(a.type,e));delete b[h]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?q:A(q)},setCompletionCallback:function(a){z= -a}}}(window,t),V=function(b){function d(g,c){if(g.state!==c)throw Error("`vnode.state` must not be modified");}function e(g){var c=g.state;try{return this.apply(c,arguments)}finally{d(g,c)}}function h(g,c,f,a,b,d,e){for(;f'+c.children+"",d=d.firstChild):d.innerHTML=c.children;c.dom=d.firstChild;c.domSize=d.childNodes.length;for(c=C.createDocumentFragment();f=d.firstChild;)c.appendChild(f);a(g,c,b);return c}function k(g,c){if("function"===typeof g.tag.view){g.state=Object.create(g.tag);var f=g.state.view;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0}else{g.state=void 0;f=g.tag;if(null!=f.$$reentrantLock$$)return I; -f.$$reentrantLock$$=!0;g.state=null!=g.tag.prototype&&"function"===typeof g.tag.prototype.view?new g.tag(g):g.tag(g)}null!=g.attrs&&L(g.attrs,g,c);L(g.state,g,c);g.instance=x.normalize(e.call(g.state.view,g));if(g.instance===g)throw Error("A view cannot return the vnode it received as argument");f.$$reentrantLock$$=null}function q(g,c,f,b,d,e,k){if(!(c===f&&!b||null==c&&null==f))if(null==c)h(g,f,0,f.length,d,e,k);else if(null==f)A(c,0,c.length,f,b);else{for(var n=0,l=Math.min(c.length,f.length),q= -c.length,B=!1,D=!1;n=E&&t>=n;)if(v=c[E],y=f[n],u=B&&E>=q,v===y&&!u&&!b||null==v&&null==y)E++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],d,k,z(c,++n,q,e)),E++;else if(null==y){if(D||null==v.key)A(c,n,n+1,f,b),E++;n++}else if(v.key===y.key)E++,n++,r(g,v,y,d,z(c,E,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e);else if(v=c[l],u=B&&l>=q,v!==y||u||b)if(null==v)l--;else if(null== -y)n++;else if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||b,k),(u&&v.tag===y.tag||n=E&&t>=n;){v=c[l];y=f[t];u=B&&l>=q;if(v!==y||u||b)if(null==v)l--;else{if(null!=y)if(v.key===y.key)r(g,v,y,d,z(c,l+1,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e),null!=v.dom&&(e=v.dom),l--;else{if(!x){x=c;D=l;v={};for(u=0;u=q,r(g,v,y,d,z(c,l+1,q,e),u||b,k), -a(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,d,k,e))}t--}else l--,t--;if(t=g;l--)c[l].skip?c[l].skip=!1:J(c[l],f)}}}function r(g,c,f,a,b,d,h){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var A;if(A=!d){var z,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(z=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate, -f,c));void 0===z&&void 0===D||z||D?A=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,A=!0)}if(!A)if("string"===typeof n)switch(null!=f.attrs&&(d?(f.state={},L(f.attrs,f,a)):N(f.attrs,f,a)),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(m(c),l(g,f,h,b)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":q(g,c.children,f.children,d,a,b,h);c=0;a=f.children;f.dom=null;if(null!=a){for(d=0;da.indexOf("?")?"?":"&";a+=e+c}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(B){throw Error(a);}}function q(a){return a.responseText}function t(a,b){if("function"=== +typeof a)if(Array.isArray(b))for(var c=0;cm.status||304===m.status||Z.test(a.url))c(t(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(I){e(I)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?B:z(B)},jsonp:function(a,k){var z=e();a=h(a,k);var q=new c(function(c,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[h]=function(e){k.parentNode.removeChild(k);c(t(a.type,e));delete b[h]};k.onerror=function(){k.parentNode.removeChild(k); +e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?q:z(q)},setCompletionCallback:function(a){A=a}}}(window,r),V=function(b){function c(g,d){if(g.state!==d)throw Error("`vnode.state` must not be modified");}function e(g){var d=g.state;try{return this.apply(d,arguments)}finally{c(g,d)}}function h(g,d,f,a,b,c,e){for(;f'+d.children+"",c=c.firstChild):c.innerHTML=d.children;d.dom=c.firstChild;d.domSize=c.childNodes.length;for(d=C.createDocumentFragment();f= +c.firstChild;)d.appendChild(f);a(g,d,b);return d}function k(g,d){if("function"===typeof g.tag.view){g.state=Object.create(g.tag);var f=g.state.view;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0}else{g.state=void 0;f=g.tag;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0;g.state=null!=g.tag.prototype&&"function"===typeof g.tag.prototype.view?new g.tag(g):g.tag(g)}null!=g.attrs&&L(g.attrs,g,d);L(g.state,g,d);g.instance=x.normalize(e.call(g.state.view,g));if(g.instance===g)throw Error("A view cannot return the vnode it received as argument"); +f.$$reentrantLock$$=null}function q(g,d,f,b,c,e,k){if(!(d===f&&!b||null==d&&null==f))if(null==d)h(g,f,0,f.length,c,e,k);else if(null==f)z(d,0,d.length,f,b);else{for(var n=0,l=Math.min(d.length,f.length),q=d.length,B=!1,D=!1;n=r&&F>=n;)if(v=d[r],y=f[n],u=B&&r>=q,v===y&&!u&&!b||null==v&&null==y)r++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],c,k,A(d,++n,q,e)),r++;else if(null== +y){if(D||null==v.key)z(d,n,n+1,f,b),r++;n++}else if(v.key===y.key)r++,n++,t(g,v,y,c,A(d,r,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e);else if(v=d[l],u=B&&l>=q,v!==y||u||b)if(null==v)l--;else if(null==y)n++;else if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),(u&&v.tag===y.tag||n=r&&F>=n;){v=d[l];y=f[F];u=B&&l>=q;if(v!==y||u||b)if(null==v)l--;else{if(null!=y)if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e), +null!=v.dom&&(e=v.dom),l--;else{if(!x){x=d;D=l;v={};for(u=0;u=q,t(g,v,y,c,A(d,l+1,q,e),u||b,k),a(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,c,k,e))}F--}else l--,F--;if(F=g;l--)d[l].skip?d[l].skip=!1:J(d[l],f)}}}function t(g,d,f,b,a,c,h){var n=d.tag;if(n===f.tag){f.state=d.state;f.events=d.events;var z;if(z= +!c){var A,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(A=e.call(f.attrs.onbeforeupdate,f,d));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate,f,d));void 0===A&&void 0===D||A||D?z=!1:(f.dom=d.dom,f.domSize=d.domSize,f.instance=d.instance,z=!0)}if(!z)if("string"===typeof n)switch(null!=f.attrs&&(c?(f.state={},L(f.attrs,f,b)):N(f.attrs,f,b)),n){case "#":d.children.toString()!==f.children.toString()&&(d.dom.nodeValue=f.children);f.dom= +d.dom;break;case "<":d.children!==f.children?(m(d),l(g,f,h,a)):(f.dom=d.dom,f.domSize=d.domSize);break;case "[":q(g,d.children,f.children,c,b,a,h);d=0;b=f.children;f.dom=null;if(null!=b){for(c=0;c Date: Mon, 12 Mar 2018 16:33:06 -0600 Subject: [PATCH 174/301] doc: add missing parenthesis (#2104) * closing parenthese missing [### How it works](#howitworks) * update changelog --- docs/change-log.md | 1 + docs/render.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 19b701a9..81b48762 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -45,6 +45,7 @@ - render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) - render: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) - render: fix element value don't change if new valor is undefined [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) +- render: fix typo, missing `)` --- diff --git a/docs/render.md b/docs/render.md index aefbb172..534a9d45 100644 --- a/docs/render.md +++ b/docs/render.md @@ -36,7 +36,7 @@ Argument | Type | Required | Description ### How it works -The `m.render(element, vnodes)` method takes a virtual DOM tree (typically generated via the [`m()` hyperscript function](hyperscript.md), generates a DOM tree and mounts it on `element`. If `element` already has a DOM tree mounted via a previous `m.render()` call, `vnodes` is diffed against the previous `vnodes` tree and the existing DOM tree is modified only where needed to reflect the changes. Unchanged DOM nodes are not touched at all. +The `m.render(element, vnodes)` method takes a virtual DOM tree (typically generated via the [`m()` hyperscript function](hyperscript.md)), generates a DOM tree and mounts it on `element`. If `element` already has a DOM tree mounted via a previous `m.render()` call, `vnodes` is diffed against the previous `vnodes` tree and the existing DOM tree is modified only where needed to reflect the changes. Unchanged DOM nodes are not touched at all. `m.render` is synchronous. From 02f2732706b73cbed569dea803d5f90585532708 Mon Sep 17 00:00:00 2001 From: Vasil Rimar Date: Wed, 28 Mar 2018 02:40:11 -0400 Subject: [PATCH 175/301] docs: Fix webpack example (#2110) --- docs/jsx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/jsx.md b/docs/jsx.md index 826d8ce0..8c715072 100644 --- a/docs/jsx.md +++ b/docs/jsx.md @@ -121,7 +121,7 @@ module.exports = { filename: 'app.js', }, module: { - loaders: [{ + rules: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' From 0c54409d41fd023ad6f314da53612a7b5870523f Mon Sep 17 00:00:00 2001 From: Pat Cavit Date: Fri, 13 Apr 2018 00:15:03 -0700 Subject: [PATCH 176/301] docs: Fix some site weirdness Fixes #2117 --- docs/installation.md | 29 ++++++++++++++--------------- docs/integrating-libs.md | 10 +++++----- docs/learning-mithril.md | 2 +- docs/nav-guides.md | 9 +++++---- docs/support.md | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 2ce6bccb..5689bc25 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -18,7 +18,7 @@ If you're new to Javascript or just want a very simple setup to get your feet we ### NPM ```bash -$> npm install mithril --save +$ npm install mithril --save ``` --- @@ -27,33 +27,32 @@ $> npm install mithril --save 1. Initialize the directory as an npm package ```bash -$> npm init --yes +$ npm init --yes ``` 2. install required tools ```bash -$> npm install mithril --save -$> npm install webpack webpack-cli --save-dev +$ npm install mithril --save +$ npm install webpack webpack-cli --save-dev ``` 3. Add a "start" entry to the scripts section in `package.json`. ```js { - // ... - "scripts": { - "start": "webpack src/index.js --output bin/app.js -d --watch" - } + // ... + "scripts": { + "start": "webpack src/index.js --output bin/app.js -d --watch" + } } ``` -3. Create `src/index.js` +4. Create `src/index.js` file. ```js import m from "mithril"; - m.render(document.body, "hello world"); ``` -4. create `index.html` +5. create `index.html` ```html @@ -61,12 +60,12 @@ m.render(document.body, "hello world"); ``` -5. run bundler +6. run bundler ```bash -$> npm start +$ npm start ``` -6. open `index.html` in a browser +7. open `index.html` in a browser #### Step by step @@ -268,7 +267,7 @@ m.render(document.body, "hello world") TypeScript type definitions are available from DefinitelyTyped. They can be installed with: ```bash -$> npm install @types/mithril --save-dev +$ npm install @types/mithril --save-dev ``` For example usage, to file issues or to discuss TypeScript related topics visit: https://github.com/MithrilJS/mithril.d.ts diff --git a/docs/integrating-libs.md b/docs/integrating-libs.md index 42b72bee..cf0753de 100644 --- a/docs/integrating-libs.md +++ b/docs/integrating-libs.md @@ -1,9 +1,9 @@ -# Integrating with Other Libraries +# 3rd Party Integration + Integration with third party libraries or vanilla javascript code can be achieved via [lifecycle methods](lifecycle-methods.md). -- [Usage](#usage) +## Example -### Usage ```javascript var FullCalendar = { @@ -19,7 +19,7 @@ var FullCalendar = { // Consider that the lib will modify this parent element in the DOM (e.g. add dependent class attribute and values). // As long as you return the same view results here, mithril will not // overwrite the actual DOM because it's always comparing old and new VDOM - // before applying DOM updates. + // before applying DOM updates. view: function (vnode) { return m('div') }, @@ -54,4 +54,4 @@ m.mount(document.body, { ``` -Running example [flems: FullCalendar](https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvAHigjQGsACAJxigBeADog4xAJ6w4hGDGKjuhfmBEgSxAA5xEAel3UAJmgBWcfNSi0ArobBQM-C7Sy6MJjAA9d7AEZxdMGsoKGoMWDRDR10AZnwAdnwABkDg0PCmKN58LA4LODhRAD4QAF8KdGxcRAIzShp6RmYagDdHbgAxNIBhDMj2wW5gYTQR4WJ6an4MRkRuILRqYgh6bgAKFrRaQxgASiGxhWI6NDhaWHwrAHM1gHIukN6oft5EREnpxlvdw-GAEg2Wx2+EMLl2+CCjz6WTWw1GR3G+m4mmsxG4EhsvG4HAgy3C3FommW9Dg3AwkW4YRCvgw1E4pNk-F+xFKP1G8PGAHlfCYYEt8BgChArmhAdsYALiMReOZNI4mMQAMrEGYwChDSFQJ6ZRwAUSgc024pBLlZh3KY3hLQgMAA7nMFksVmh1kadvs4eNxvxiNZeC6sHdDBAWt9zRRLeN6L4YGBaPx+FhaC0YA7rItiS6xe6DhziEiAErpsloCTcHbiXi0Mu6SmwcnWTTcHDEQjbBkwJzM-QAt0S8SqiE9aF6qDgzXal5B+DS6th+GlEaL9lYHI2BhrUHUaw4Bj4XzbCTqz3Ea12tMZ52uoF7XNe6XyP0u5DM8aB26EACMt3Vt0nWW+CM8zfNYHi1EdeGPOV+AYZVVUNG98AHRhWSA+8QNuXxUQmNAfzvBEjkmdg6TmTR+BaV8WV-ABZXFlGgbgACFsNWABaQDKPfLCpXoPCT3QnDLAgEjuDQGBPAUYCqO4W5aNbXgGOYniXQAannZkAF1IyOR1M1E8TiDWD1KN7RDkIlCcIP1cdhwiGFbjEiT1KOZdmV0q8yJgFojPw+9TONcyhyhOzRxs4KdV4O5PNDNl71chdLVZMoKhATAcDwfIECoE4mmIPAyg0qh2C4BAUEqdKalyeToHqP1yBqDRtD0XR000TgrmcVwqvoqAAAFP3wAaAFZdG6hSoHwOoqEkTRqhAOpynKuak13PKqDqvBGp0fRWvazrRpcBVeoAJkGgBOfBjoO1bJqykAZrmhaUrSx6AEdrE7CRat4er1ClJqdrQNqOroVwTHez7eriU7P10YNxF0cGPt4CRbvqB68Cepa8E1KkIu+36tua3aQZcVIQjxl4oYSZI4YgBHcYgtHpokWbMYQUoNNKIA) \ No newline at end of file +Running example [flems: FullCalendar](https://flems.io/#0=N4IgZglgNgpgziAXAbVAOwIYFsZJAOgAsAXLKEAGhAGMB7NYmBvAHigjQGsACAJxigBeADog4xAJ6w4hGDGKjuhfmBEgSxAA5xEAel3UAJmgBWcfNSi0ArobBQM-C7Sy6MJjAA9d7AEZxdMGsoKGoMWDRDR10AZnwAdnwABkDg0PCmKN58LA4LODhRAD4QAF8KdGxcRAIzShp6RmYagDdHbgAxNIBhDMj2wW5gYTQR4WJ6an4MRkRuILRqYgh6bgAKFrRaQxgASiGxhWI6NDhaWHwrAHM1gHIukN6oft5EREnpxlvdw-GAEg2Wx2+EMLl2+CCjz6WTWw1GR3G+m4mmsxG4EhsvG4HAgy3C3FommW9Dg3AwkW4YRCvgw1E4pNk-F+xFKP1G8PGAHlfCYYEt8BgChArmhAdsYALiMReOZNI4mMQAMrEGYwChDSFQJ6ZRwAUSgc024pBLlZh3KY3hLQgMAA7nMFksVmh1kadvs4eNxvxiNZeC6sHdDBAWt9zRRLeN6L4YGBaPx+FhaC0YA7rItiS6xe6DhziEiAErpsloCTcHbiXi0Mu6SmwcnWTTcHDEQjbBkwJzM-QAt0S8SqiE9aF6qDgzXal5B+DS6th+GlEaL9lYHI2BhrUHUaw4Bj4XzbCTqz3Ea12tMZ52uoF7XNe6XyP0u5DM8aB26EACMt3Vt0nWW+CM8zfNYHi1EdeGPOV+AYZVVUNG98AHRhWSA+8QNuXxUQmNAfzvBEjkmdg6TmTR+BaV8WV-ABZXFlGgbgACFsNWABaQDKPfLCpXoPCT3QnDLAgEjuDQGBPAUYCqO4W5aNbXgGOYniXQAannZkAF1IyOR1M1E8TiDWD1KN7RDkIlCcIP1cdhwiGFbjEiT1KOZdmV0q8yJgFojPw+9TONcyhyhOzRxs4KdV4O5PNDNl71chdLVZMoKhATAcDwfIECoE4mmIPAyg0qh2C4BAUEqdKalyeToHqP1yBqDRtD0XR000TgrmcVwqvoqAAAFP3wAaAFZdG6hSoHwOoqEkTRqhAOpynKuak13PKqDqvBGp0fRWvazrRpcBVeoAJkGgBOfBjoO1bJqykAZrmhaUrSx6AEdrE7CRat4er1ClJqdrQNqOroVwTHez7eriU7P10YNxF0cGPt4CRbvqB68Cepa8E1KkIu+36tua3aQZcVIQjxl4oYSZI4YgBHcYgtHpokWbMYQUoNNKIA) diff --git a/docs/learning-mithril.md b/docs/learning-mithril.md index fb599df8..049b11b9 100644 --- a/docs/learning-mithril.md +++ b/docs/learning-mithril.md @@ -1,4 +1,4 @@ -# Learning Mithril +# Learning Resources Links to Mithril learning content: diff --git a/docs/nav-guides.md b/docs/nav-guides.md index d567cfae..0a954c4d 100644 --- a/docs/nav-guides.md +++ b/docs/nav-guides.md @@ -1,7 +1,9 @@ -- Tutorials - - [Installation](installation.md) +- Getting Started - [Introduction](index.md) + - [Installation](installation.md) - [Tutorial](simple-application.md) + - [Learning Resources](learning-mithril.md) + - [Getting Help](support.md) - Resources - [JSX](jsx.md) - [ES6](es6.md) @@ -9,8 +11,7 @@ - [Animation](animation.md) - [Testing](testing.md) - [Examples](examples.md) - - [Integrating with Other Libraries](integrating-libs.md) - - [Learning Mithril](learning-mithril.md) + - [3rd Party Integration](integrating-libs.md) - Key concepts - [Vnodes](vnodes.md) - [Components](components.md) diff --git a/docs/support.md b/docs/support.md index ae466e16..b157a5a4 100644 --- a/docs/support.md +++ b/docs/support.md @@ -1,3 +1,3 @@ -## Getting Help +# Getting Help Mithril has an active & welcoming community on [Gitter](https://gitter.im/mithriljs/mithril.js), or feel free to ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/mithril.js) using the `mithril.js` tag. From 6f7f543b07d9e2f42d6d09eda3a2dbfb3baada34 Mon Sep 17 00:00:00 2001 From: Scotty Simpson Date: Fri, 13 Apr 2018 22:35:04 -0700 Subject: [PATCH 177/301] docs: awkward/redundant fix (#2120) --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index a883e833..0f253f5b 100644 --- a/docs/route.md +++ b/docs/route.md @@ -475,7 +475,7 @@ m.route(document.body, "/", { }) ``` -Note that in this case, if the Layout component the `oninit` and `oncreate` lifecycle methods would only fire on the Layout component on the first route change (assuming all routes use the same layout). +Note that in this case, if the Layout component has `oninit` and `oncreate` lifecycle methods, they would only fire on the first route change (assuming all routes use the same layout). To clarify the difference between the two examples, example 1 is equivalent to this code: From 203df39c304b5f89f4efa591d0e563bcb5d94155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 15 Apr 2018 18:34:08 +0200 Subject: [PATCH 178/301] Remove the DOM nodes recycling pool (fix #1653, fix #2023) --- docs/change-log.md | 1 + performance/test-perf.js | 9 +- render/render.js | 222 ++++++++-------------------- render/tests/test-component.js | 4 +- render/tests/test-onbeforeupdate.js | 2 +- render/tests/test-onremove.js | 6 +- render/tests/test-updateElement.js | 8 +- render/tests/test-updateNodes.js | 15 +- 8 files changed, 84 insertions(+), 183 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 81b48762..efd51c4b 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -31,6 +31,7 @@ - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) - Mocks: add limited support for the DOMParser API ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) - API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) +- Internals: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122)) #### Bug fixes diff --git a/performance/test-perf.js b/performance/test-perf.js index 89160a05..a2b79421 100644 --- a/performance/test-perf.js +++ b/performance/test-perf.js @@ -358,16 +358,9 @@ var Root = { } } -suite.add({ - name : "repeated trees (recycling)", - fn : function () { - m.render(scratch, [m(Root)]) - m.render(scratch, []) - } -}) suite.add({ - name : "repeated trees (no recycling)", + name : "repeated trees", fn : function () { m.render(scratch, [m(Root)]) m.render(scratch, []) diff --git a/render/render.js b/render/render.js index 7a674c3c..2b05a00a 100644 --- a/render/render.js +++ b/render/render.js @@ -175,8 +175,6 @@ module.exports = function($window) { * @param {Vnode[] | null} old - the list of vnodes of the last `render()` call for * this part of the tree * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call. - * @param {boolean} recyclingParent - was the parent vnode or one of its ancestor - * fetched from the recycling pool? * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate) * @param {Element | null} nextSibling - the next DOM node if we're dealing with a * fragment that is not the last item in its @@ -190,8 +188,7 @@ module.exports = function($window) { // // 1. describe its general structure // 2. focus on the diff algorithm optimizations - // 3. describe how the recycling pool meshes into this - // 4. discuss DOM node operations. + // 3. discuss DOM node operations. // ## Overview: // @@ -205,7 +202,6 @@ module.exports = function($window) { // - manages the leftovers: after diffing, are there: // - old nodes left to remove? // - new nodes to insert? - // - nodes left in the recycling pool? // deal with them! // // The lists are only iterated over once, with an exception for the nodes in `old` that @@ -213,10 +209,7 @@ module.exports = function($window) { // ## Diffing // - // There's first a simple diff for unkeyed lists of equal length that eschews the pool. - // - // It is followed by a small section that activates the recycling pool if present, we'll - // ignore it for now. + // There's first a simple diff for unkeyed lists of equal length. // // Then comes the main diff algorithm that is split in four parts (simplifying a bit). // @@ -244,109 +237,69 @@ module.exports = function($window) { // The range of old nodes that wasn't covered by the first three sections is passed to // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. // - // Then some pool business happens. - // // It should be noted that the description of the four sections above is not perfect, because those // parts are actually implemented as only two loops, one for the first two parts, and one for // the other two. I'm not sure it wins us anything except maybe a few bytes of file size. - // ## The pool - // - // `old.pool` is an optional array that holds the vnodes that have been previously removed - // from the DOM at this level (provided they met the pool eligibility criteria). - // - // If the `old`, `old.pool` and `vnodes` meet some criteria described in `isRecyclable`, the - // elements of the pool are appended to the `old` array, which enables the reconciler to find - // them. - // - // While this is optimal for unkeyed diff and map-based keyed diff (the fourth diff part), - // that strategy clashes with the second and third parts of the main diff algo, because - // the end of the old list is now filled with the nodes of the pool. - // - // To determine if a vnode was brought back from the pool, we look at its position in the - // `old` array (see the various `oFromPool` definitions). That information is important - // in three circumstances: - // - If the old and the new vnodes are the same object (`===`), diff is not performed unless - // the old node comes from the pool (since it must be recycled/re-created). - // - The value of `oFromPool` is passed as the `recycling` parameter of `updateNode()` (whether - // the parent is being recycled is also factred in here) - // - It is used in the DOM node insertion logic (see below) - // - // At the very end of `updateNodes()`, the nodes in the pool that haven't been picked back - // are put in the new pool for the next render phase. - // - // The pool eligibility and `isRecyclable()` criteria are to be updated as part of #1675. - // ## DOM node operations // // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, - // this is not the case if the node moved (second and fourth part of the diff algo), or - // if the node was brough back from the pool and both the old and new nodes have the same - // `.tag` value (when the `.tag` differ, `updateNode()` does the insertion). + // this is not the case if the node moved (second and fourth part of the diff algo). // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues // like #1791 and #1999. We need to be smarter about those situations where adjascent old // nodes remain together in the new list in a way that isn't covered by parts one and // three of the diff algo. - function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { - if (old === vnodes && !recyclingParent || old == null && vnodes == null) return + function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { + if (old === vnodes || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) + else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed = false + var start = 0, commonLength = Math.min(old.length, vnodes.length), isUnkeyed = false for(; start < commonLength; start++) { if (old[start] != null && vnodes[start] != null) { if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true break } } - if (isUnkeyed && originalOldLength === vnodes.length) { - for (start = 0; start < originalOldLength; start++) { - if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue - else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) - else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) + if (isUnkeyed && old.length === vnodes.length) { + for (start = 0; start < vnodes.length; start++) { + if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue + else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) + else if (vnodes[start] == null) removeNodes(old, start, start + 1) + else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) } return } - - if (isRecyclable(old, vnodes)) { - hasPool = true - old = old.concat(old.pool) - } - - var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] - oFromPool = hasPool && oldStart >= originalOldLength - if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ + if (o === v || o == null && v == null) oldStart++, start++ else if (o == null) { if (isUnkeyed || v.key == null) { - createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) + createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, nextSibling)) } oldStart++ } else if (v == null) { if (isUnkeyed || o.key == null) { - removeNodes(old, start, start + 1, vnodes, recyclingParent) + removeNodes(old, start, start + 1) oldStart++ } start++ } else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { o = old[oldEnd] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ + if (o === v) oldEnd--, start++ else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, originalOldLength, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) + if (start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, nextSibling)) oldEnd--, start++ } else break @@ -355,13 +308,11 @@ module.exports = function($window) { while (oldEnd >= oldStart && end >= start) { o = old[oldEnd] v = vnodes[end] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, end-- + if (o === v) oldEnd--, end-- else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- } else { @@ -370,8 +321,7 @@ module.exports = function($window) { var oldIndex = map[v.key] if (oldIndex != null) { o = old[oldIndex] - oFromPool = hasPool && oldIndex >= originalOldLength - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) insertNode(parent, toFragment(v), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom @@ -385,43 +335,30 @@ module.exports = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes, recyclingParent) - if (hasPool) { - var limit = Math.max(oldStart, originalOldLength) - for (; oldEnd >= limit; oldEnd--) { - if (old[oldEnd].skip) old[oldEnd].skip = false - else addToPool(old[oldEnd], vnodes) - } - } + removeNodes(old, oldStart, oldEnd + 1) } } - // when recycling, we're re-using an old DOM node, but firing the oninit/oncreate hooks - // instead of onbeforeupdate/onupdate. - function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { + function updateNode(parent, old, vnode, hooks, nextSibling, ns) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { vnode.state = old.state vnode.events = old.events - if (!recycling && shouldNotUpdate(vnode, old)) return + if (shouldNotUpdate(vnode, old)) return if (typeof oldTag === "string") { if (vnode.attrs != null) { - if (recycling) { - vnode.state = {} - initLifecycle(vnode.attrs, vnode, hooks) - } - else updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.attrs, vnode, hooks) } switch (oldTag) { case "#": updateText(old, vnode); break case "<": updateHTML(parent, old, vnode, ns, nextSibling); break - case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break - default: updateElement(old, vnode, recycling, hooks, ns) + case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break + default: updateElement(old, vnode, hooks, ns) } } - else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) + else updateComponent(parent, old, vnode, hooks, nextSibling, ns) } else { - removeNode(old, null, recycling) + removeNode(old) createNode(parent, vnode, hooks, ns, nextSibling) } } @@ -438,8 +375,8 @@ module.exports = function($window) { } else vnode.dom = old.dom, vnode.domSize = old.domSize } - function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) { - updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns) + function updateFragment(parent, old, vnode, hooks, nextSibling, ns) { + updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns) var domSize = 0, children = vnode.children vnode.dom = null if (children != null) { @@ -453,7 +390,7 @@ module.exports = function($window) { if (domSize !== 1) vnode.domSize = domSize } } - function updateElement(old, vnode, recycling, hooks, ns) { + function updateElement(old, vnode, hooks, ns) { var element = vnode.dom = old.dom ns = getNameSpace(vnode) || ns @@ -474,26 +411,22 @@ module.exports = function($window) { else { if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)] if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)] - updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns) + updateNodes(element, old.children, vnode.children, hooks, null, ns) } } - function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) { - if (recycling) { - initComponent(vnode, hooks) - } else { - vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) - if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") - if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) - updateLifecycle(vnode.state, vnode, hooks) - } + function updateComponent(parent, old, vnode, hooks, nextSibling, ns) { + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) + if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") + if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.state, vnode, hooks) if (vnode.instance != null) { if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling) - else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns) + else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, ns) vnode.dom = vnode.instance.dom vnode.domSize = vnode.instance.domSize } else if (old.instance != null) { - removeNode(old.instance, null, recycling) + removeNode(old.instance) vnode.dom = undefined vnode.domSize = 0 } @@ -502,17 +435,6 @@ module.exports = function($window) { vnode.domSize = old.domSize } } - function isRecyclable(old, vnodes) { - if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) { - var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0 - var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0 - var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0 - if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) { - return true - } - } - return false - } function getKeyMap(vnodes, end) { var map = {}, i = 0 for (var i = 0; i < end; i++) { @@ -537,10 +459,8 @@ module.exports = function($window) { } else return vnode.dom } - // the vnodes array may hold items that come from the pool (after `limit`) they should - // be ignored - function getNextSibling(vnodes, i, limit, nextSibling) { - for (; i < limit; i++) { + function getNextSibling(vnodes, i, nextSibling) { + for (; i < vnodes.length; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom } return nextSibling @@ -561,43 +481,37 @@ module.exports = function($window) { } //remove - function removeNodes(vnodes, start, end, context, recycling) { + function removeNodes(vnodes, start, end) { for (var i = start; i < end; i++) { var vnode = vnodes[i] if (vnode != null) { if (vnode.skip) vnode.skip = false - else removeNode(vnode, context, recycling) + else removeNode(vnode) } } } - // when a node is removed from a parent that's brought back from the pool, its hooks should - // not fire. - function removeNode(vnode, context, recycling) { + function removeNode(vnode) { var expected = 1, called = 0 - if (!recycling) { - var original = vnode.state - if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = callHook.call(vnode.attrs.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + var original = vnode.state + if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } - if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { - var result = callHook.call(vnode.state.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + } + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } } continuation() function continuation() { if (++called === expected) { - if (!recycling) { - checkState(vnode, original) - onremove(vnode) - } + checkState(vnode, original) + onremove(vnode) if (vnode.dom) { var count = vnode.domSize || 1 if (count > 1) { @@ -607,7 +521,6 @@ module.exports = function($window) { } } removeNodeFromDOM(vnode.dom) - addToPool(vnode, context) } } } @@ -616,12 +529,6 @@ module.exports = function($window) { var parent = node.parentNode if (parent != null) parent.removeChild(node) } - function addToPool(vnode, context) { - if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements - if (!context.pool) context.pool = [vnode] - else context.pool.push(vnode) - } - } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { @@ -721,9 +628,6 @@ module.exports = function($window) { function isCustomElement(vnode){ return vnode.attrs.is || vnode.tag.indexOf("-") > -1 } - function hasIntegrationMethods(source) { - return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove) - } //style function updateStyle(element, old, style) { @@ -821,7 +725,7 @@ module.exports = function($window) { if (dom.vnodes == null) dom.textContent = "" if (!Array.isArray(vnodes)) vnodes = [vnodes] - updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) + updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active != null && $doc.activeElement !== active) active.focus() diff --git a/render/tests/test-component.js b/render/tests/test-component.js index ea3d1624..dd27ef10 100644 --- a/render/tests/test-component.js +++ b/render/tests/test-component.js @@ -808,7 +808,7 @@ o.spec("component", function() { o(methods[hook].args.length).equals(attrs[hook].args.length)(hook) }) }) - o("recycled components get a fresh state", function() { + o("no recycling occurs (was: recycled components get a fresh state)", function() { var step = 0 var firstState var view = o.spy(function(vnode) { @@ -827,7 +827,7 @@ o.spec("component", function() { step = 1 render(root, [{tag: "div", children: [{tag: component, key: 1}]}]) - o(child).equals(root.firstChild.firstChild) + o(child).notEquals(root.firstChild.firstChild) // this used to be a recycling pool test o(view.callCount).equals(2) }) }) diff --git a/render/tests/test-onbeforeupdate.js b/render/tests/test-onbeforeupdate.js index d8b2f2d6..d0b1ecab 100644 --- a/render/tests/test-onbeforeupdate.js +++ b/render/tests/test-onbeforeupdate.js @@ -129,7 +129,7 @@ o.spec("onbeforeupdate", function() { render(root, temp) render(root, updated) - o(vnodes[0].dom).equals(updated[0].dom) + o(vnodes[0].dom).notEquals(updated[0].dom) // this used to be a recycling pool test o(updated[0].dom.nodeName).equals("DIV") o(onbeforeupdate.callCount).equals(0) }) diff --git a/render/tests/test-onremove.js b/render/tests/test-onremove.js index 5ab20caf..9b4c4e23 100644 --- a/render/tests/test-onremove.js +++ b/render/tests/test-onremove.js @@ -91,7 +91,7 @@ o.spec("onremove", function() { o(vnode.dom.attributes["onremove"]).equals(undefined) o(vnode.events).equals(undefined) }) - o("calls onremove on recycle", function() { + o("calls onremove on keyed nodes", function() { var remove = o.spy() var vnodes = [{tag: "div", key: 1}] var temp = [{tag: "div", key: 2, attrs: {onremove: remove}}] @@ -101,7 +101,7 @@ o.spec("onremove", function() { render(root, temp) render(root, updated) - o(vnodes[0].dom).equals(updated[0].dom) + o(vnodes[0].dom).notEquals(updated[0].dom) // this used to be a recycling pool test o(remove.callCount).equals(1) }) o("does not recycle when there's an onremove", function() { @@ -211,7 +211,7 @@ o.spec("onremove", function() { render(root, [temp]) render(root, [updated]) - o(vnode.dom).equals(updated.dom) + o(vnode.dom).notEquals(updated.dom) // this used to be a recycling pool test o(onremove.callCount).equals(1) }) }) diff --git a/render/tests/test-updateElement.js b/render/tests/test-updateElement.js index a2ae0fcb..0e0332b7 100644 --- a/render/tests/test-updateElement.js +++ b/render/tests/test-updateElement.js @@ -237,7 +237,7 @@ o.spec("updateElement", function() { o(updated.dom.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg") }) - o("restores correctly when recycling", function() { + o("doesn't restore since we're not recycling", function() { var vnode = {tag: "div", key: 1} var updated = {tag: "div", key: 2} @@ -250,9 +250,9 @@ o.spec("updateElement", function() { var c = vnode.dom o(root.childNodes.length).equals(1) - o(a).equals(c) + o(a).notEquals(c) // this used to be a recycling pool test }) - o("restores correctly when recycling via map", function() { + o("doesn't restore since we're not recycling (via map)", function() { var a = {tag: "div", key: 1} var b = {tag: "div", key: 2} var c = {tag: "div", key: 3} @@ -269,6 +269,6 @@ o.spec("updateElement", function() { var y = root.childNodes[1] o(root.childNodes.length).equals(3) - o(x).equals(y) + o(x).notEquals(y) // this used to be a recycling pool test }) }) diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index 65d81916..6983766e 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -776,7 +776,7 @@ o.spec("updateNodes", function() { o(root.childNodes[0].childNodes[1].childNodes.length).equals(1) o(root.childNodes[1].childNodes.length).equals(0) }) - o("recycles", function() { + o("doesn't recycle", function() { var vnodes = [{tag: "div", key: 1}] var temp = [] var updated = [{tag: "div", key: 1}] @@ -785,10 +785,10 @@ o.spec("updateNodes", function() { render(root, temp) render(root, updated) - o(vnodes[0].dom).equals(updated[0].dom) + o(vnodes[0].dom).notEquals(updated[0].dom) // this used to be a recycling pool test o(updated[0].dom.nodeName).equals("DIV") }) - o("recycles when not keyed", function() { + o("doesn't recycle when not keyed", function() { var vnodes = [{tag: "div"}] var temp = [] var updated = [{tag: "div"}] @@ -798,19 +798,22 @@ o.spec("updateNodes", function() { render(root, updated) o(root.childNodes.length).equals(1) - o(vnodes[0].dom).equals(updated[0].dom) + o(vnodes[0].dom).notEquals(updated[0].dom) // this used to be a recycling pool test o(updated[0].dom.nodeName).equals("DIV") }) - o("recycles deep", function() { + o("doesn't recycle deep", function() { var vnodes = [{tag: "div", children: [{tag: "a", key: 1}]}] var temp = [{tag: "div"}] var updated = [{tag: "div", children: [{tag: "a", key: 1}]}] render(root, vnodes) + + var oldChild = vnodes[0].dom.firstChild + render(root, temp) render(root, updated) - o(vnodes[0].dom.firstChild).equals(updated[0].dom.firstChild) + o(oldChild).notEquals(updated[0].dom.firstChild) // this used to be a recycling pool test o(updated[0].dom.firstChild.nodeName).equals("A") }) o("mixed unkeyed tags are not broken by recycle", function() { From ec43ca089c67b1af3bc3f729d18dd5eaa283ea53 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 16 Apr 2018 07:47:53 +0000 Subject: [PATCH 179/301] Bundled output for commit 203df39c304b5f89f4efa591d0e563bcb5d94155 [skip ci] --- README.md | 2 +- mithril.js | 219 ++++++++++++++----------------------------------- mithril.min.js | 92 ++++++++++----------- 3 files changed, 109 insertions(+), 204 deletions(-) diff --git a/README.md b/README.md index e438ae20..5b67f110 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.74 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.34 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 4f50a73e..769801aa 100644 --- a/mithril.js +++ b/mithril.js @@ -570,8 +570,6 @@ var coreRenderer = function($window) { * @param {Vnode[] | null} old - the list of vnodes of the last0 `render()` call for * this part of the tree * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call. - * @param {boolean} recyclingParent - was the parent vnode or one of its ancestor - * fetched from the recycling pool? * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate) * @param {Element | null} nextSibling - the next0 DOM node if we're dealing with a * fragment that is not the last0 item in its @@ -585,8 +583,7 @@ var coreRenderer = function($window) { // // 1. describe its general structure // 2. focus on the diff algorithm optimizations - // 3. describe how the recycling pool meshes into this - // 4. discuss DOM node operations. + // 3. discuss DOM node operations. // ## Overview: // // The updateNodes() function: @@ -599,17 +596,13 @@ var coreRenderer = function($window) { // - manages the leftovers: after diffing, are there: // - old nodes left to remove? // - new nodes to insert? - // - nodes left in the recycling pool? // deal with them! // // The lists are only iterated over once, with an exception for the nodes in `old` that // are visited in the fourth part of the diff and in the `removeNodes` loop. // ## Diffing // - // There's first a simple diff for unkeyed lists of equal length that eschews the pool. - // - // It is followed by a small section that activates the recycling pool if present, we'll - // ignore it for now. + // There's first a simple diff for unkeyed lists of equal length. // // Then comes the main diff algorithm that is split in four parts (simplifying a bit). // @@ -637,103 +630,66 @@ var coreRenderer = function($window) { // The range of old nodes that wasn't covered by the first three sections is passed to // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. // - // Then some pool business happens. - // // It should be noted that the description of the four sections above is not perfect, because those // parts are actually implemented as only two loops, one for the first two parts, and one for // the other two. I'm1 not sure it wins us anything except maybe a few bytes of file size. - // ## The pool - // - // `old.pool` is an optional array that holds the vnodes that have been previously removed - // from the DOM at this level (provided they met the pool eligibility criteria). - // - // If the `old`, `old.pool` and `vnodes` meet some criteria described in `isRecyclable`, the - // elements of the pool are appended to the `old` array, which enables the reconciler to find - // them. - // - // While this is optimal for unkeyed diff and map-based keyed diff (the fourth diff part), - // that strategy clashes with the second and third parts of the main diff algo, because - // the end of the old list is now filled with the nodes of the pool. - // - // To determine if a vnode was brought back from the pool, we look at its position in the - // `old` array (see the various `oFromPool` definitions). That information is important - // in three circumstances: - // - If the old and the new vnodes are the same object (`===`), diff is not performed unless - // the old node comes from the pool (since it must be recycled/re-created). - // - The value of `oFromPool` is passed as the `recycling` parameter of `updateNode()` (whether - // the parent is being recycled is also factred in here) - // - It is used in the DOM node insertion logic (see below) - // - // At the very end of `updateNodes()`, the nodes in the pool that haven't been picked back - // are put in the new pool for the next0 render phase. - // - // The pool eligibility and `isRecyclable()` criteria are to be updated as part of #1675. // ## DOM node operations // // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, - // this is not the case if the node moved (second and fourth part of the diff algo), or - // if the node was brough back from the pool and both the old and new nodes have the same - // `.tag` value (when the `.tag` differ, `updateNode()` does the insertion). + // this is not the case if the node moved (second and fourth part of the diff algo). // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues // like #1791 and #1999. We need to be smarter about those situations where adjascent old // nodes remain together in the new list in a way that isn't covered by parts one and // three of the diff algo. - function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { - if (old === vnodes && !recyclingParent || old == null && vnodes == null) return + function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { + if (old === vnodes || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) + else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed = false + var start = 0, commonLength = Math.min(old.length, vnodes.length), isUnkeyed = false for(; start < commonLength; start++) { if (old[start] != null && vnodes[start] != null) { if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true break } } - if (isUnkeyed && originalOldLength === vnodes.length) { - for (start = 0; start < originalOldLength; start++) { - if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue - else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) - else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) + if (isUnkeyed && old.length === vnodes.length) { + for (start = 0; start < vnodes.length; start++) { + if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue + else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) + else if (vnodes[start] == null) removeNodes(old, start, start + 1) + else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) } return } - if (isRecyclable(old, vnodes)) { - hasPool = true - old = old.concat(old.pool) - } - var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] - oFromPool = hasPool && oldStart >= originalOldLength - if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ + if (o === v || o == null && v == null) oldStart++, start++ else if (o == null) { if (isUnkeyed || v.key == null) { - createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) + createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, nextSibling)) } oldStart++ } else if (v == null) { if (isUnkeyed || o.key == null) { - removeNodes(old, start, start + 1, vnodes, recyclingParent) + removeNodes(old, start, start + 1) oldStart++ } start++ } else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { o = old[oldEnd] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ + if (o === v) oldEnd--, start++ else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, originalOldLength, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) + if (start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, nextSibling)) oldEnd--, start++ } else break @@ -742,13 +698,11 @@ var coreRenderer = function($window) { while (oldEnd >= oldStart && end >= start) { o = old[oldEnd] v = vnodes[end] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, end-- + if (o === v) oldEnd--, end-- else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- } else { @@ -757,8 +711,7 @@ var coreRenderer = function($window) { var oldIndex = map[v.key] if (oldIndex != null) { o = old[oldIndex] - oFromPool = hasPool && oldIndex >= originalOldLength - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) insertNode(parent, toFragment(v), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom @@ -772,43 +725,30 @@ var coreRenderer = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes, recyclingParent) - if (hasPool) { - var limit = Math.max(oldStart, originalOldLength) - for (; oldEnd >= limit; oldEnd--) { - if (old[oldEnd].skip) old[oldEnd].skip = false - else addToPool(old[oldEnd], vnodes) - } - } + removeNodes(old, oldStart, oldEnd + 1) } } - // when recycling, we're re-using an old DOM node, but firing the oninit/oncreate hooks - // instead of onbeforeupdate/onupdate. - function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { + function updateNode(parent, old, vnode, hooks, nextSibling, ns) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { vnode.state = old.state vnode.events = old.events - if (!recycling && shouldNotUpdate(vnode, old)) return + if (shouldNotUpdate(vnode, old)) return if (typeof oldTag === "string") { if (vnode.attrs != null) { - if (recycling) { - vnode.state = {} - initLifecycle(vnode.attrs, vnode, hooks) - } - else updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.attrs, vnode, hooks) } switch (oldTag) { case "#": updateText(old, vnode); break case "<": updateHTML(parent, old, vnode, ns, nextSibling); break - case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break - default: updateElement(old, vnode, recycling, hooks, ns) + case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break + default: updateElement(old, vnode, hooks, ns) } } - else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) + else updateComponent(parent, old, vnode, hooks, nextSibling, ns) } else { - removeNode(old, null, recycling) + removeNode(old) createNode(parent, vnode, hooks, ns, nextSibling) } } @@ -825,8 +765,8 @@ var coreRenderer = function($window) { } else vnode.dom = old.dom, vnode.domSize = old.domSize } - function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) { - updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns) + function updateFragment(parent, old, vnode, hooks, nextSibling, ns) { + updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns) var domSize = 0, children = vnode.children vnode.dom = null if (children != null) { @@ -840,7 +780,7 @@ var coreRenderer = function($window) { if (domSize !== 1) vnode.domSize = domSize } } - function updateElement(old, vnode, recycling, hooks, ns) { + function updateElement(old, vnode, hooks, ns) { var element = vnode.dom = old.dom ns = getNameSpace(vnode) || ns if (vnode.tag === "textarea") { @@ -860,26 +800,22 @@ var coreRenderer = function($window) { else { if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)] if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)] - updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns) + updateNodes(element, old.children, vnode.children, hooks, null, ns) } } - function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) { - if (recycling) { - initComponent(vnode, hooks) - } else { - vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) - if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") - if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) - updateLifecycle(vnode.state, vnode, hooks) - } + function updateComponent(parent, old, vnode, hooks, nextSibling, ns) { + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) + if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") + if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.state, vnode, hooks) if (vnode.instance != null) { if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling) - else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns) + else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, ns) vnode.dom = vnode.instance.dom vnode.domSize = vnode.instance.domSize } else if (old.instance != null) { - removeNode(old.instance, null, recycling) + removeNode(old.instance) vnode.dom = undefined vnode.domSize = 0 } @@ -888,17 +824,6 @@ var coreRenderer = function($window) { vnode.domSize = old.domSize } } - function isRecyclable(old, vnodes) { - if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) { - var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0 - var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0 - var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0 - if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) { - return true - } - } - return false - } function getKeyMap(vnodes, end) { var map = {}, i = 0 for (var i = 0; i < end; i++) { @@ -923,10 +848,8 @@ var coreRenderer = function($window) { } else return vnode.dom } - // the vnodes array may hold items that come from the pool (after `limit`) they should - // be ignored - function getNextSibling(vnodes, i, limit, nextSibling) { - for (; i < limit; i++) { + function getNextSibling(vnodes, i, nextSibling) { + for (; i < vnodes.length; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom } return nextSibling @@ -944,43 +867,37 @@ var coreRenderer = function($window) { else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove - function removeNodes(vnodes, start, end, context, recycling) { + function removeNodes(vnodes, start, end) { for (var i = start; i < end; i++) { var vnode = vnodes[i] if (vnode != null) { if (vnode.skip) vnode.skip = false - else removeNode(vnode, context, recycling) + else removeNode(vnode) } } } - // when a node is removed from a parent that's brought back from the pool, its hooks should - // not fire. - function removeNode(vnode, context, recycling) { + function removeNode(vnode) { var expected = 1, called = 0 - if (!recycling) { - var original = vnode.state - if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = callHook.call(vnode.attrs.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + var original = vnode.state + if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } - if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { - var result = callHook.call(vnode.state.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + } + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } } continuation() function continuation() { if (++called === expected) { - if (!recycling) { - checkState(vnode, original) - onremove(vnode) - } + checkState(vnode, original) + onremove(vnode) if (vnode.dom) { var count0 = vnode.domSize || 1 if (count0 > 1) { @@ -990,7 +907,6 @@ var coreRenderer = function($window) { } } removeNodeFromDOM(vnode.dom) - addToPool(vnode, context) } } } @@ -999,12 +915,6 @@ var coreRenderer = function($window) { var parent = node.parentNode if (parent != null) parent.removeChild(node) } - function addToPool(vnode, context) { - if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements - if (!context.pool) context.pool = [vnode] - else context.pool.push(vnode) - } - } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { @@ -1103,9 +1013,6 @@ var coreRenderer = function($window) { function isCustomElement(vnode){ return vnode.attrs.is || vnode.tag.indexOf("-") > -1 } - function hasIntegrationMethods(source) { - return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove) - } //style function updateStyle(element, old, style) { if (old != null && style != null && typeof old === "object" && typeof style === "object" && style !== old) { @@ -1196,7 +1103,7 @@ var coreRenderer = function($window) { // First time rendering0 into a node clears it out if (dom.vnodes == null) dom.textContent = "" if (!Array.isArray(vnodes)) vnodes = [vnodes] - updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) + updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active != null && $doc.activeElement !== active) active.focus() diff --git a/mithril.min.js b/mithril.min.js index 3b95ad15..d34e10e7 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,47 +1,45 @@ -(function(){function x(b,c,e,h,p,l){return{tag:b,key:c,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function R(b){for(var c in b)if(G.call(b,c))return!1;return!0}function w(b){var c=arguments[1],e=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b){var h;if(!(h=S[b])){var p="div";for(var l=[],k={};h=W.exec(b);){var q=h[1], -t=h[2];""===q&&""!==t?p=t:"#"===q?k.id=t:"."===q?l.push(t):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0a.indexOf("?")?"?":"&";a+=e+c}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(B){throw Error(a);}}function q(a){return a.responseText}function t(a,b){if("function"=== -typeof a)if(Array.isArray(b))for(var c=0;cm.status||304===m.status||Z.test(a.url))c(t(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(I){e(I)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?B:z(B)},jsonp:function(a,k){var z=e();a=h(a,k);var q=new c(function(c,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[h]=function(e){k.parentNode.removeChild(k);c(t(a.type,e));delete b[h]};k.onerror=function(){k.parentNode.removeChild(k); -e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?q:z(q)},setCompletionCallback:function(a){A=a}}}(window,r),V=function(b){function c(g,d){if(g.state!==d)throw Error("`vnode.state` must not be modified");}function e(g){var d=g.state;try{return this.apply(d,arguments)}finally{c(g,d)}}function h(g,d,f,a,b,c,e){for(;f'+d.children+"",c=c.firstChild):c.innerHTML=d.children;d.dom=c.firstChild;d.domSize=c.childNodes.length;for(d=C.createDocumentFragment();f= -c.firstChild;)d.appendChild(f);a(g,d,b);return d}function k(g,d){if("function"===typeof g.tag.view){g.state=Object.create(g.tag);var f=g.state.view;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0}else{g.state=void 0;f=g.tag;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0;g.state=null!=g.tag.prototype&&"function"===typeof g.tag.prototype.view?new g.tag(g):g.tag(g)}null!=g.attrs&&L(g.attrs,g,d);L(g.state,g,d);g.instance=x.normalize(e.call(g.state.view,g));if(g.instance===g)throw Error("A view cannot return the vnode it received as argument"); -f.$$reentrantLock$$=null}function q(g,d,f,b,c,e,k){if(!(d===f&&!b||null==d&&null==f))if(null==d)h(g,f,0,f.length,c,e,k);else if(null==f)z(d,0,d.length,f,b);else{for(var n=0,l=Math.min(d.length,f.length),q=d.length,B=!1,D=!1;n=r&&F>=n;)if(v=d[r],y=f[n],u=B&&r>=q,v===y&&!u&&!b||null==v&&null==y)r++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],c,k,A(d,++n,q,e)),r++;else if(null== -y){if(D||null==v.key)z(d,n,n+1,f,b),r++;n++}else if(v.key===y.key)r++,n++,t(g,v,y,c,A(d,r,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e);else if(v=d[l],u=B&&l>=q,v!==y||u||b)if(null==v)l--;else if(null==y)n++;else if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),(u&&v.tag===y.tag||n=r&&F>=n;){v=d[l];y=f[F];u=B&&l>=q;if(v!==y||u||b)if(null==v)l--;else{if(null!=y)if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e), -null!=v.dom&&(e=v.dom),l--;else{if(!x){x=d;D=l;v={};for(u=0;u=q,t(g,v,y,c,A(d,l+1,q,e),u||b,k),a(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,c,k,e))}F--}else l--,F--;if(F=g;l--)d[l].skip?d[l].skip=!1:J(d[l],f)}}}function t(g,d,f,b,a,c,h){var n=d.tag;if(n===f.tag){f.state=d.state;f.events=d.events;var z;if(z= -!c){var A,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(A=e.call(f.attrs.onbeforeupdate,f,d));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate,f,d));void 0===A&&void 0===D||A||D?z=!1:(f.dom=d.dom,f.domSize=d.domSize,f.instance=d.instance,z=!0)}if(!z)if("string"===typeof n)switch(null!=f.attrs&&(c?(f.state={},L(f.attrs,f,b)):N(f.attrs,f,b)),n){case "#":d.children.toString()!==f.children.toString()&&(d.dom.nodeValue=f.children);f.dom= -d.dom;break;case "<":d.children!==f.children?(m(d),l(g,f,h,a)):(f.dom=d.dom,f.domSize=d.domSize);break;case "[":q(g,d.children,f.children,c,b,a,h);d=0;b=f.children;f.dom=null;if(null!=b){for(c=0;cd.indexOf("?")?"?":"&";d+=f+b}return d}function k(d){try{return""!==d?JSON.parse(d):null}catch(A){throw Error(d);}}function m(d){return d.responseText}function t(d,a){if("function"=== +typeof d)if(Array.isArray(a))for(var b=0;be.status||304===e.status||U.test(d.url))b(t(d.type,a));else{var g=Error(e.responseText);g.code=e.status;g.response=a;f(g)}}catch(E){f(E)}};g&&null!=d.data?e.send(d.data):e.send()});return!0===d.background?A:x(A)},jsonp:function(d,m){var x=f();d=g(d,m);var k=new b(function(b,f){var g=d.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+e++,m=a.document.createElement("script");a[g]=function(f){m.parentNode.removeChild(m);b(t(d.type,f));delete a[g]};m.onerror=function(){m.parentNode.removeChild(m); +f(Error("JSONP request failed"));delete a[g]};null==d.data&&(d.data={});d.url=r(d.url,d.data);d.data[d.callbackKey||"callback"]=g;m.src=l(d.url,d.data);a.document.documentElement.appendChild(m)});return!0===d.background?k:x(k)},setCompletionCallback:function(d){y=d}}}(window,h),Q=function(a){function b(q,c){if(q.state!==c)throw Error("`vnode.state` must not be modified");}function f(q){var c=q.state;try{return this.apply(c,arguments)}finally{b(q,c)}}function g(q,c,d,a,b,f,g){for(;d'+c.children+"",q=q.firstChild):q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;for(c=p.createDocumentFragment();a= +q.firstChild;)c.appendChild(a);y(d,c,b);return c}function k(q,c,d,a,b,f){if(c!==d&&(null!=c||null!=d))if(null==c)g(q,d,0,d.length,a,b,f);else if(null==d)A(c,0,c.length);else{for(var n=0,v=Math.min(c.length,d.length),l=!1;n=v&&x>=n;)if(h=c[v],p=d[n],h===p||null==h&&null==p)v++,n++;else if(null==h)(l||null==p.key)&&r(q,d[n],a,f,e(c,++n,b)),v++;else if(null==p){if(l||null==h.key)A(c,n,n+1),v++;n++}else if(h.key===p.key)v++,n++,m(q,h,p,a,e(c,v,b),f);else if(h=c[k],h===p)k--,n++;else if(null==h)k--;else if(null==p)n++;else if(h.key===p.key)m(q,h,p,a,e(c,k+1,b),f),n=v&&x>=n;){h=c[k];p=d[x];if(h===p)k--,x--;else if(null==h)k--;else{if(null!=p)if(h.key=== +p.key)m(q,h,p,a,e(c,k+1,b),f),null!=h.dom&&(b=h.dom),k--;else{if(!F){F=c;l=k;h={};var w;for(w=0;w Date: Fri, 20 Apr 2018 20:08:31 -0400 Subject: [PATCH 180/301] Disown myself from render-related fixes [ci skip] --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6485e4d6..7714f3da 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,4 +6,4 @@ package.json @tivac README.md @tivac docs/ @tivac performance/ @tivac -render/ @isiahmeadows @pygy +render/ @pygy From f375bdc02e457288806ab7fee607415d81fc00c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1r=20=C3=96rlygsson?= Date: Sat, 21 Apr 2018 21:47:38 +0000 Subject: [PATCH 181/301] fix: Bundler tests only pass when run from project root --- bundler/tests/test-bundler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundler/tests/test-bundler.js b/bundler/tests/test-bundler.js index 15e7f932..ff8bb32e 100644 --- a/bundler/tests/test-bundler.js +++ b/bundler/tests/test-bundler.js @@ -5,7 +5,7 @@ var bundle = require("../bundle") var fs = require("fs") -var ns = "bundler/tests/" +var ns = "./" function read(filepath) { try {return fs.readFileSync(ns + filepath, "utf8")} catch (e) {/* ignore */} } From 898d0aec82e8b73b360d39dc8480a3219d28f3f5 Mon Sep 17 00:00:00 2001 From: soulofmischief <30357883+soulofmischief@users.noreply.github.com> Date: Sat, 21 Apr 2018 13:08:05 -0500 Subject: [PATCH 182/301] Fix url in vnodes.md URL was being incorrectly parsed due to parentheses. The parenthesis have been replaced with UTF-8 encodings. --- docs/vnodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/vnodes.md b/docs/vnodes.md index a663e197..339b6175 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -21,7 +21,7 @@ It may seem wasteful to recreate vnodes so frequently, but as it turns out, mode For that reason, Mithril uses a sophisticated and highly optimized virtual DOM diffing algorithm to minimize the amount of DOM updates. Mithril *also* generates carefully crafted vnode data structures that are compiled by Javascript engines for near-native data structure access performance. In addition, Mithril aggressively optimizes the function that creates vnodes as well. -The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide a declarative [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) API, a style of rendering that makes it drastically easier to manage UI complexity. +The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide a declarative [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_%28computer_graphics%29) API, a style of rendering that makes it drastically easier to manage UI complexity. To illustrate why immediate mode is so important, consider the DOM API and HTML. The DOM API is an imperative [retained mode](https://en.wikipedia.org/wiki/Retained_mode) API and requires 1. writing out exact instructions to assemble a DOM tree procedurally, and 2. writing out other instructions to update that tree. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances of introducing bugs and more chances to make code harder to understand. From c6693aa3611dd969f73d627dc6e8f3e6db3c1b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 15 Apr 2018 23:08:12 +0200 Subject: [PATCH 183/301] Disentangle keyed and unkeyed diff --- render/render.js | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/render/render.js b/render/render.js index 2b05a00a..7e005290 100644 --- a/render/render.js +++ b/render/render.js @@ -256,40 +256,47 @@ module.exports = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), isUnkeyed = false - for(; start < commonLength; start++) { - if (old[start] != null && vnodes[start] != null) { - if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true + var start = 0, oldStart = 0, isUnkeyed = false, isOldUnkeyed = false + for(; oldStart < old.length; oldStart++) { + if (old[oldStart] != null) { + isOldUnkeyed = old[oldStart].key == null break } } - if (isUnkeyed && old.length === vnodes.length) { - for (start = 0; start < vnodes.length; start++) { + for(; start < vnodes.length; start++) { + if (vnodes[start] != null) { + isUnkeyed = vnodes[start].key == null + break + } + } + if (isOldUnkeyed !== isUnkeyed) { + removeNodes(old, oldStart, old.length) + createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) + return + } + if (isUnkeyed) { + var commonLength = old.length < vnodes.length ? old.length : vnodes.length + start = start < oldStart ? start : oldStart + for (; start < commonLength; start++) { if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) else if (vnodes[start] == null) removeNodes(old, start, start + 1) else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) } + if (old.length > commonLength) removeNodes(old, start, old.length) + if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) return } - var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v + // keyed diff + var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] if (o === v || o == null && v == null) oldStart++, start++ - else if (o == null) { - if (isUnkeyed || v.key == null) { - createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, nextSibling)) - } - oldStart++ - } else if (v == null) { - if (isUnkeyed || o.key == null) { - removeNodes(old, start, start + 1) - oldStart++ - } - start++ - } else if (o.key === v.key) { + else if (o == null) oldStart++ + else if (v == null) start++ + else if (o.key === v.key) { oldStart++, start++ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { From 9136585fe4fdea3e0b90cf7283dc305de76495b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 20 Apr 2018 23:00:50 +0200 Subject: [PATCH 184/301] [DOM Mock] Fix insertBefore when the reference node follows the moving child in a nodeList --- test-utils/domMock.js | 1 + test-utils/tests/test-domMock.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/test-utils/domMock.js b/test-utils/domMock.js index 99bfff9a..e5c1f68c 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -101,6 +101,7 @@ module.exports = function(options) { if (index > -1) this.childNodes.splice(index, 1) if (reference === null) this.appendChild(child) else { + if (index !== -1 && refIndex > index) refIndex-- if (child.nodeType === 11) { this.childNodes.splice.apply(this.childNodes, [refIndex, 0].concat(child.childNodes)) while (child.firstChild) { diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index 5540bb86..e27d0bee 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -242,6 +242,28 @@ o.spec("domMock", function() { o(a.parentNode).equals(parent) o(b.parentNode).equals(parent) }) + o("moves existing node forward but not at the end", function() { + var parent = $document.createElement("div") + var a = $document.createElement("a") + var b = $document.createElement("b") + var c = $document.createElement("c") + parent.appendChild(a) + parent.appendChild(b) + parent.appendChild(c) + parent.insertBefore(a, c) + + o(parent.childNodes.length).equals(3) + o(parent.childNodes[0]).equals(b) + o(parent.childNodes[1]).equals(a) + o(parent.childNodes[2]).equals(c) + o(parent.firstChild).equals(b) + o(parent.firstChild.nextSibling).equals(a) + o(parent.firstChild.nextSibling.nextSibling).equals(c) + o(a.parentNode).equals(parent) + o(b.parentNode).equals(parent) + o(c.parentNode).equals(parent) + + }) o("removes from old parent", function() { var parent = $document.createElement("div") var source = $document.createElement("span") From dd6ceca31d2c731b20e2ad00f679c11a66e885c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 20 Apr 2018 18:39:45 +0200 Subject: [PATCH 185/301] tests for #2128 --- render/tests/test-updateNodes.js | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index 6983766e..43b9c960 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -1035,6 +1035,32 @@ o.spec("updateNodes", function() { o(onremove.callCount).equals(1) o(onupdate.callCount).equals(0) }) + o("supports changing the element of a keyed element in a list when traversed bottom-up", function() { + try { + render(root, [{tag: "a", key: 2}]) + render(root, [{tag: "b", key: 1}, {tag: "b", key: 2}]) + + o(root.childNodes.length).equals(2) + o(root.childNodes[0].nodeName).equals("B") + o(root.childNodes[1].nodeName).equals("B") + } catch (e) { + o(e).equals(null) + } + }) + o("supports changing the element of a keyed element in a list when looking up nodes using the map", function() { + try { + render(root, [{tag: "x", key: 1}, {tag: "y", key: 2}, {tag: "z", key: 3}]) + render(root, [{tag: "b", key: 2}, {tag: "c", key: 1}, {tag: "d", key: 4}, {tag: "e", key: 3}]) + + o(root.childNodes.length).equals(4) + o(root.childNodes[0].nodeName).equals("B") + o(root.childNodes[1].nodeName).equals("C") + o(root.childNodes[2].nodeName).equals("D") + o(root.childNodes[3].nodeName).equals("E") + } catch (e) { + o(e).equals(null) + } + }) o("don't fetch the nextSibling from the pool", function() { render(root, [{tag: "[", children: [{tag: "div", key: 1}, {tag: "div", key: 2}]}, {tag: "p"}]) render(root, [{tag: "[", children: []}, {tag: "p"}]) @@ -1078,6 +1104,19 @@ o.spec("updateNodes", function() { o(root.childNodes[0].nodeName).equals("A") o(root.childNodes[1].nodeName).equals("S") }) + o("removing a component that returns a fragment doesn't throw (regression test for incidental bug introduced while debugging some Flems)", function() { + var component = createComponent({ + view: function() {return {tag: "[", children:[{tag: "a"}, {tag: "b"}]}} + }) + try { + render(root, [{tag: component}]) + render(root, []) + + o(root.childNodes.length).equals(0) + } catch (e) { + o(e).equals(null) + } + }) }) }) }) From 9490950c30a6a16fa660949b6aabaa86f6b77954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 20 Apr 2018 21:27:22 +0200 Subject: [PATCH 186/301] [render/render] Simplify updateNodes, fix #2128 --- docs/change-log.md | 25 +++++++++--------- render/render.js | 64 ++++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index efd51c4b..e0278c04 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -36,18 +36,19 @@ #### Bug fixes - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) -- API: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. -- core: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. -- core: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. -- core: `Object.prototype` properties can no longer interfere with event listener calls. -- API: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. -- core: `xlink:href` attributes are now correctly removed -- render: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) -- render: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) -- render: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) -- render: fix element value don't change if new valor is undefined [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) -- render: fix typo, missing `)` - +- render/attrs: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. +- render/attrs: `xlink:href` attributes are now correctly removed +- render/attrs: fix element value don't change if new value is undefined [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) +(https://github.com/MithrilJS/mithril.js/pull/2130) +- render/core: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) +- render/core: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) +- render/core: fix crashes when the keyed vnodes with the same `key` had different `tag` values [#2128](https://github.com/MithrilJS/mithril.js/issues/2128) [@JacksonJN](https://github.com/JacksonJN) ([#2130] +- render/events: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. +- render/events: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. +- render/events: `Object.prototype` properties can no longer interfere with event listener calls. +- render/events: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. +- render/hooks: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) +- docs: fix typo ([#2104](https://github.com/MithrilJS/mithril.js/pull/2104) [@mikeyb](https://github.com/mikeyb)) --- ### v1.1.7 diff --git a/render/render.js b/render/render.js index 7e005290..72dba419 100644 --- a/render/render.js +++ b/render/render.js @@ -51,18 +51,17 @@ module.exports = function($window) { vnode.state = {} if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) switch (tag) { - case "#": return createText(parent, vnode, nextSibling) - case "<": return createHTML(parent, vnode, ns, nextSibling) - case "[": return createFragment(parent, vnode, hooks, ns, nextSibling) - default: return createElement(parent, vnode, hooks, ns, nextSibling) + case "#": createText(parent, vnode, nextSibling); break + case "<": createHTML(parent, vnode, ns, nextSibling); break + case "[": createFragment(parent, vnode, hooks, ns, nextSibling); break + default: createElement(parent, vnode, hooks, ns, nextSibling) } } - else return createComponent(parent, vnode, hooks, ns, nextSibling) + else createComponent(parent, vnode, hooks, ns, nextSibling) } function createText(parent, vnode, nextSibling) { vnode.dom = $doc.createTextNode(vnode.children) insertNode(parent, vnode.dom, nextSibling) - return vnode.dom } var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} function createHTML(parent, vnode, ns, nextSibling) { @@ -87,7 +86,6 @@ module.exports = function($window) { fragment.appendChild(child) } insertNode(parent, fragment, nextSibling) - return fragment } function createFragment(parent, vnode, hooks, ns, nextSibling) { var fragment = $doc.createDocumentFragment() @@ -98,7 +96,6 @@ module.exports = function($window) { vnode.dom = fragment.firstChild vnode.domSize = fragment.childNodes.length insertNode(parent, fragment, nextSibling) - return fragment } function createElement(parent, vnode, hooks, ns, nextSibling) { var tag = vnode.tag @@ -132,7 +129,6 @@ module.exports = function($window) { setLateAttrs(vnode) } } - return element } function initComponent(vnode, hooks) { var sentinel @@ -157,15 +153,12 @@ module.exports = function($window) { function createComponent(parent, vnode, hooks, ns, nextSibling) { initComponent(vnode, hooks) if (vnode.instance != null) { - var element = createNode(parent, vnode.instance, hooks, ns, nextSibling) + createNode(parent, vnode.instance, hooks, ns, nextSibling) vnode.dom = vnode.instance.dom vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0 - insertNode(parent, element, nextSibling) - return element } else { vnode.domSize = 0 - return $emptyFragment } } @@ -241,10 +234,20 @@ module.exports = function($window) { // parts are actually implemented as only two loops, one for the first two parts, and one for // the other two. I'm not sure it wins us anything except maybe a few bytes of file size. - // ## DOM node operations + // ## Finding the next sibling. + // + // `updateNode()` and `createNode()` expect a nextSibling parameter. When the list is being + // traversed top-down, the next sibling must be looked for in the old list using + // `getNextSibling()`. In the other scenarios (swaps, upwards traversal, map-based diff), + // the new vnodes list is traversed upwards, which enables us to fetch the `nextSibling` + // parameter on the go (set to the last `v.dom` when present). + + // ## DOM node moves // // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, - // this is not the case if the node moved (second and fourth part of the diff algo). + // this is not the case if the node moved (second and fourth part of the diff algo). We move + // the old DOM nodes before updateNode runs because it enables us to use the cached `nextSibling` + // variable rather than fetching it using `getNextSibling()`. // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues // like #1791 and #1999. We need to be smarter about those situations where adjascent old @@ -300,14 +303,15 @@ module.exports = function($window) { oldStart++, start++ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { - o = old[oldEnd] - if (o === v) oldEnd--, start++ - else if (o == null) oldEnd-- - else if (v == null) start++ + v = vnodes[end] + if (o === v) oldStart++, end-- + else if (o == null) oldStart++ + else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - if (start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, nextSibling)) - oldEnd--, start++ + oldStart++ + if (start < end--) insertNode(parent, toFragment(o), nextSibling) + updateNode(parent, o, v, hooks, nextSibling, ns) + if(v.dom != null) nextSibling = v.dom } else break } @@ -319,8 +323,8 @@ module.exports = function($window) { else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - if (o.dom != null) nextSibling = o.dom + updateNode(parent, o, v, hooks, nextSibling, ns) + if (v.dom != null) nextSibling = v.dom oldEnd--, end-- } else { if (!map) map = getKeyMap(old, oldEnd) @@ -328,13 +332,13 @@ module.exports = function($window) { var oldIndex = map[v.key] if (oldIndex != null) { o = old[oldIndex] - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - insertNode(parent, toFragment(v), nextSibling) + insertNode(parent, toFragment(o), nextSibling) + updateNode(parent, o, v, hooks, nextSibling, ns) o.skip = true - if (o.dom != null) nextSibling = o.dom + if (v.dom != null) nextSibling = v.dom } else { - var dom = createNode(parent, v, hooks, ns, nextSibling) - nextSibling = dom + createNode(parent, v, hooks, ns, nextSibling) + if (v.dom != null) nextSibling = v.dom } } end-- @@ -474,7 +478,7 @@ module.exports = function($window) { } function insertNode(parent, dom, nextSibling) { - if (nextSibling) parent.insertBefore(dom, nextSibling) + if (nextSibling != null) parent.insertBefore(dom, nextSibling) else parent.appendChild(dom) } From 878e4958dc08a6b5fae8328779f857b0bcbc1cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 21 Apr 2018 22:15:51 +0200 Subject: [PATCH 187/301] tests for #2132 --- render/tests/test-updateNodes.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index 43b9c960..85a5ffd3 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -614,6 +614,38 @@ o.spec("updateNodes", function() { o(updated[0].dom.nodeName).equals("I") o(updated[0].dom).equals(root.childNodes[0]) }) + o("cached keyed nodes move when the list is reversed", function(){ + var a = {tag: "a", key: "a"} + var b = {tag: "b", key: "b"} + var c = {tag: "c", key: "c"} + var d = {tag: "d", key: "d"} + + render(root, [a, b, c, d]) + render(root, [d, c, b, a]) + + o(root.childNodes.length).equals(4) + o(root.childNodes[0].nodeName).equals("D") + o(root.childNodes[1].nodeName).equals("C") + o(root.childNodes[2].nodeName).equals("B") + o(root.childNodes[3].nodeName).equals("A") + }) + o("cached keyed nodes move when diffed via the map", function() { + var onupdate = o.spy() + var a = {tag: "a", key: "a", attrs: {onupdate: onupdate}} + var b = {tag: "b", key: "b", attrs: {onupdate: onupdate}} + var c = {tag: "c", key: "c", attrs: {onupdate: onupdate}} + var d = {tag: "d", key: "d", attrs: {onupdate: onupdate}} + + render(root, [a, b, c, d]) + render(root, [b, d, a, c]) + + o(root.childNodes.length).equals(4) + o(root.childNodes[0].nodeName).equals("B") + o(root.childNodes[1].nodeName).equals("D") + o(root.childNodes[2].nodeName).equals("A") + o(root.childNodes[3].nodeName).equals("C") + o(onupdate.callCount).equals(0) + }) o("removes then create different bigger", function() { var vnodes = [{tag: "a", key: 1}, {tag: "b", key: 2}] var temp = [] From 801bde219e2abaac99fccea5036243e4f0d704d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 21 Apr 2018 22:17:17 +0200 Subject: [PATCH 188/301] [render/render] move keyed cached nodes when needed, fix diff semantics for cached nodes, fix #2132 --- docs/change-log.md | 3 ++- render/render.js | 17 +++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index e0278c04..687849e2 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -42,7 +42,8 @@ (https://github.com/MithrilJS/mithril.js/pull/2130) - render/core: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) - render/core: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) -- render/core: fix crashes when the keyed vnodes with the same `key` had different `tag` values [#2128](https://github.com/MithrilJS/mithril.js/issues/2128) [@JacksonJN](https://github.com/JacksonJN) ([#2130] +- render/core: fix crashes when the keyed vnodes with the same `key` had different `tag` values [#2128](https://github.com/MithrilJS/mithril.js/issues/2128) [@JacksonJN](https://github.com/JacksonJN) ([#2130](https://github.com/MithrilJS/mithril.js/pull/2130)) +- render/core: fix cached nodes behavior in some keyed diff scenarios [#2132](https://github.com/MithrilJS/mithril.js/issues/2132) ([#2130](https://github.com/MithrilJS/mithril.js/pull/2130)) - render/events: `addEventListener` and `removeEventListener` are always used to manage event subscriptions, preventing external interference. - render/events: Event listeners allocate less memory, swap at low cost, and are properly diffed now when rendered via `m.mount()`/`m.redraw()`. - render/events: `Object.prototype` properties can no longer interfere with event listener calls. diff --git a/render/render.js b/render/render.js index 72dba419..6980ece9 100644 --- a/render/render.js +++ b/render/render.js @@ -296,21 +296,19 @@ module.exports = function($window) { while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] - if (o === v || o == null && v == null) oldStart++, start++ - else if (o == null) oldStart++ + if (o == null) oldStart++ else if (v == null) start++ else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) + if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { v = vnodes[end] - if (o === v) oldStart++, end-- - else if (o == null) oldStart++ + if (o == null) oldStart++ else if (v == null) end-- else if (o.key === v.key) { oldStart++ if (start < end--) insertNode(parent, toFragment(o), nextSibling) - updateNode(parent, o, v, hooks, nextSibling, ns) + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) if(v.dom != null) nextSibling = v.dom } else break @@ -319,11 +317,10 @@ module.exports = function($window) { while (oldEnd >= oldStart && end >= start) { o = old[oldEnd] v = vnodes[end] - if (o === v) oldEnd--, end-- - else if (o == null) oldEnd-- + if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, nextSibling, ns) + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) if (v.dom != null) nextSibling = v.dom oldEnd--, end-- } else { @@ -333,7 +330,7 @@ module.exports = function($window) { if (oldIndex != null) { o = old[oldIndex] insertNode(parent, toFragment(o), nextSibling) - updateNode(parent, o, v, hooks, nextSibling, ns) + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) o.skip = true if (v.dom != null) nextSibling = v.dom } else { From f7a95d8c12c8c410b4665c69df7aa22af439fd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 22 Apr 2018 13:05:47 +0200 Subject: [PATCH 189/301] Cleanup, comments, and optimize getKeyMap --- render/render.js | 88 ++++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/render/render.js b/render/render.js index 6980ece9..54ed3cb2 100644 --- a/render/render.js +++ b/render/render.js @@ -202,13 +202,14 @@ module.exports = function($window) { // ## Diffing // - // There's first a simple diff for unkeyed lists of equal length. + // If one list is keyed and the other is unkeyed, the old is removed, and the new one is + // inserted (since the keys are guaranteed to differ). // - // Then comes the main diff algorithm that is split in four parts (simplifying a bit). + // Then comes the unkeyed diff algo, and at last, the keyed diff algorithm that is split + // in four parts (simplifying a bit). // // The first part goes through both lists top-down as long as the nodes at each level have - // the same key. This is always true for unkeyed lists that are entirely processed by this - // step. + // the same key. // // The second part deals with lists reversals, and traverses one list top-down and the other // bottom-up (as long as the keys match). @@ -236,15 +237,20 @@ module.exports = function($window) { // ## Finding the next sibling. // - // `updateNode()` and `createNode()` expect a nextSibling parameter. When the list is being - // traversed top-down, the next sibling must be looked for in the old list using - // `getNextSibling()`. In the other scenarios (swaps, upwards traversal, map-based diff), - // the new vnodes list is traversed upwards, which enables us to fetch the `nextSibling` - // parameter on the go (set to the last `v.dom` when present). + // `updateNode()` and `createNode()` expect a nextSibling parameter to perform DOM operations. + // When the list is being traversed top-down, at any index, the DOM nodes up to the previous + // vnode reflect the content of the new list, whereas the rest of the DOM nodes reflect the old + // list. The next sibling must be looked for in the old list using `getNextSibling(... oldStart + 1 ...)`. + // + // In the other scenarios (swaps, upwards traversal, map-based diff), + // the new vnodes list is traversed upwards. The DOM nodes at the bottom of the list reflect the + // bottom part of the new vnodes list, and we can use the `v.dom` value of the previous node + // as the next sibling (cached in the `nextSibling` variable). + // ## DOM node moves // - // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, + // In most scenarios `updateNode()` and `createNode()` perform the DOM operations. However, // this is not the case if the node moved (second and fourth part of the diff algo). We move // the old DOM nodes before updateNode runs because it enables us to use the cached `nextSibling` // variable rather than fetching it using `getNextSibling()`. @@ -259,32 +265,40 @@ module.exports = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, oldStart = 0, isUnkeyed = false, isOldUnkeyed = false - for(; oldStart < old.length; oldStart++) { + // default to keyed because, when either list isfull of null nodes, it has fewer branches + var start = 0, oldStart = 0, isOldKeyed = true, isKeyed = true + for (; oldStart < old.length; oldStart++) { if (old[oldStart] != null) { - isOldUnkeyed = old[oldStart].key == null + isOldKeyed = old[oldStart].key != null break } } - for(; start < vnodes.length; start++) { + for (; start < vnodes.length; start++) { if (vnodes[start] != null) { - isUnkeyed = vnodes[start].key == null + isKeyed = vnodes[start].key != null break } } - if (isOldUnkeyed !== isUnkeyed) { + if (isOldKeyed !== isKeyed) { removeNodes(old, oldStart, old.length) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) return } - if (isUnkeyed) { + if (!isKeyed) { + // Don't index past the end of either list (causes deopts). var commonLength = old.length < vnodes.length ? old.length : vnodes.length + // Rewind if necessary to the first non-null index on either side. + // We could also either create or remove nodes when start !== oldStart + // but that would be optimizing for sparse lists which are more rare + // than dense ones. start = start < oldStart ? start : oldStart for (; start < commonLength; start++) { - if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue - else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1) - else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) + o = old[start] + v = vnodes[start] + if (o === v || o == null && v == null) continue + else if (o == null) createNode(parent, v, hooks, ns, getNextSibling(old, start + 1, nextSibling)) + else if (v == null) removeNode(o) + else updateNode(parent, o, v, hooks, getNextSibling(old, start + 1, nextSibling), ns) } if (old.length > commonLength) removeNodes(old, start, old.length) if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) @@ -294,6 +308,7 @@ module.exports = function($window) { var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { + // both top down o = old[oldStart] v = vnodes[start] if (o == null) oldStart++ @@ -302,6 +317,7 @@ module.exports = function($window) { oldStart++, start++ if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { + // reversal: old top-down, new bottom-up v = vnodes[end] if (o == null) oldStart++ else if (v == null) end-- @@ -309,12 +325,13 @@ module.exports = function($window) { oldStart++ if (start < end--) insertNode(parent, toFragment(o), nextSibling) if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if(v.dom != null) nextSibling = v.dom + if (v.dom != null) nextSibling = v.dom } else break } } while (oldEnd >= oldStart && end >= start) { + // both bottom-up o = old[oldEnd] v = vnodes[end] if (o == null) oldEnd-- @@ -324,24 +341,31 @@ module.exports = function($window) { if (v.dom != null) nextSibling = v.dom oldEnd--, end-- } else { - if (!map) map = getKeyMap(old, oldEnd) + // old map-based, new bottom-up + if (map == null) { + // the last node can be left out of the map because it will be caught by the + // bottom-up part of the diff loop. If we were to refactor this to use distinct + // loops, we'd have to pass `oldEnd + 1` (or change `start < end` to `<=` in getKeyMap). + map = getKeyMap(old, oldStart, oldEnd) + } if (v != null) { var oldIndex = map[v.key] - if (oldIndex != null) { + if (oldIndex == null) { + createNode(parent, v, hooks, ns, nextSibling) + if (v.dom != null) nextSibling = v.dom + } else { o = old[oldIndex] insertNode(parent, toFragment(o), nextSibling) if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) o.skip = true if (v.dom != null) nextSibling = v.dom - } else { - createNode(parent, v, hooks, ns, nextSibling) - if (v.dom != null) nextSibling = v.dom } } end-- } if (end < start) break } + // deal with the leftovers. createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) removeNodes(old, oldStart, oldEnd + 1) } @@ -443,13 +467,13 @@ module.exports = function($window) { vnode.domSize = old.domSize } } - function getKeyMap(vnodes, end) { - var map = {}, i = 0 - for (var i = 0; i < end; i++) { - var vnode = vnodes[i] + function getKeyMap(vnodes, start, end) { + var map = {} + for (; start < end; start++) { + var vnode = vnodes[start] if (vnode != null) { var key = vnode.key - if (key != null) map[key] = i + if (key != null) map[key] = start } } return map From 44e165a357050cdfd1a7a278fc3af44839cdf4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 23 Apr 2018 11:37:24 +0200 Subject: [PATCH 190/301] [render/render] Misc comment fixes --- render/render.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/render/render.js b/render/render.js index 54ed3cb2..b9b6411a 100644 --- a/render/render.js +++ b/render/render.js @@ -187,10 +187,8 @@ module.exports = function($window) { // // The updateNodes() function: // - deals with trivial cases - // - determines whether the lists are keyed or unkeyed - // (Currently we look for the first pair of non-null nodes and deem the lists unkeyed - // if both nodes are unkeyed. TODO (v2) We may later take advantage of the fact that - // mixed diff is not supported and settle on the keyedness of the first vnode we find) + // - determines whether the lists are keyed or unkeyed based on the first non-null node + // of each list. // - diffs them and patches the DOM if needed (that's the brunt of the code) // - manages the leftovers: after diffing, are there: // - old nodes left to remove? @@ -265,7 +263,7 @@ module.exports = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length) else { - // default to keyed because, when either list isfull of null nodes, it has fewer branches + // default to keyed because, when either list is full of null nodes, it has fewer branches var start = 0, oldStart = 0, isOldKeyed = true, isKeyed = true for (; oldStart < old.length; oldStart++) { if (old[oldStart] != null) { @@ -288,9 +286,8 @@ module.exports = function($window) { // Don't index past the end of either list (causes deopts). var commonLength = old.length < vnodes.length ? old.length : vnodes.length // Rewind if necessary to the first non-null index on either side. - // We could also either create or remove nodes when start !== oldStart - // but that would be optimizing for sparse lists which are more rare - // than dense ones. + // We could alternatively either explicitly create or remove nodes when `start !== oldStart` + // but that would be optimizing for sparse lists which are more rare than dense ones. start = start < oldStart ? start : oldStart for (; start < commonLength; start++) { o = old[start] @@ -308,7 +305,7 @@ module.exports = function($window) { var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { - // both top down + // both top-down o = old[oldStart] v = vnodes[start] if (o == null) oldStart++ From 117fac91a79a85c1b8261d7c27a4944d26fd50a1 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 23 Apr 2018 11:54:15 +0000 Subject: [PATCH 191/301] Bundled output for commit 44e165a357050cdfd1a7a278fc3af44839cdf4fe [skip ci] --- README.md | 2 +- mithril.js | 177 ++++++++++++++++++++++++++++--------------------- mithril.min.js | 90 ++++++++++++------------- 3 files changed, 148 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index 5b67f110..296c4c32 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.34 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.30 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 769801aa..11b40899 100644 --- a/mithril.js +++ b/mithril.js @@ -452,18 +452,17 @@ var coreRenderer = function($window) { vnode.state = {} if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks) switch (tag) { - case "#": return createText(parent, vnode, nextSibling) - case "<": return createHTML(parent, vnode, ns, nextSibling) - case "[": return createFragment(parent, vnode, hooks, ns, nextSibling) - default: return createElement(parent, vnode, hooks, ns, nextSibling) + case "#": createText(parent, vnode, nextSibling); break + case "<": createHTML(parent, vnode, ns, nextSibling); break + case "[": createFragment(parent, vnode, hooks, ns, nextSibling); break + default: createElement(parent, vnode, hooks, ns, nextSibling) } } - else return createComponent(parent, vnode, hooks, ns, nextSibling) + else createComponent(parent, vnode, hooks, ns, nextSibling) } function createText(parent, vnode, nextSibling) { vnode.dom = $doc.createTextNode(vnode.children) insertNode(parent, vnode.dom, nextSibling) - return vnode.dom } var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"} function createHTML(parent, vnode, ns, nextSibling) { @@ -488,7 +487,6 @@ var coreRenderer = function($window) { fragment.appendChild(child) } insertNode(parent, fragment, nextSibling) - return fragment } function createFragment(parent, vnode, hooks, ns, nextSibling) { var fragment = $doc.createDocumentFragment() @@ -499,7 +497,6 @@ var coreRenderer = function($window) { vnode.dom = fragment.firstChild vnode.domSize = fragment.childNodes.length insertNode(parent, fragment, nextSibling) - return fragment } function createElement(parent, vnode, hooks, ns, nextSibling) { var tag = vnode.tag @@ -528,7 +525,6 @@ var coreRenderer = function($window) { setLateAttrs(vnode) } } - return element } function initComponent(vnode, hooks) { var sentinel @@ -553,15 +549,12 @@ var coreRenderer = function($window) { function createComponent(parent, vnode, hooks, ns, nextSibling) { initComponent(vnode, hooks) if (vnode.instance != null) { - var element = createNode(parent, vnode.instance, hooks, ns, nextSibling) + createNode(parent, vnode.instance, hooks, ns, nextSibling) vnode.dom = vnode.instance.dom vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0 - insertNode(parent, element, nextSibling) - return element } else { vnode.domSize = 0 - return $emptyFragment } } //update @@ -588,10 +581,8 @@ var coreRenderer = function($window) { // // The updateNodes() function: // - deals with trivial cases - // - determines whether the lists are keyed or unkeyed - // (Currently we look for the first pair of non-null nodes and deem the lists unkeyed - // if both nodes are unkeyed. TODO (v2) We may later take advantage of the fact that - // mixed diff is not supported and settle on the keyedness of the first vnode we find) + // - determines whether the lists are keyed or unkeyed based on the first non-null node + // of each list. // - diffs them and patches the DOM if needed (that's the brunt of the code) // - manages the leftovers: after diffing, are there: // - old nodes left to remove? @@ -602,13 +593,14 @@ var coreRenderer = function($window) { // are visited in the fourth part of the diff and in the `removeNodes` loop. // ## Diffing // - // There's first a simple diff for unkeyed lists of equal length. + // If one list is keyed and the other is unkeyed, the old is removed, and the new one is + // inserted (since the keys are guaranteed to differ). // - // Then comes the main diff algorithm that is split in four parts (simplifying a bit). + // Then comes the unkeyed diff algo, and at last0, the keyed diff algorithm that is split + // in four parts (simplifying a bit). // // The first part goes through both lists top-down as long as the nodes at each level have - // the same key2. This is always true for unkeyed lists that are entirely processed by this - // step. + // the same key2. // // The second part deals with lists reversals, and traverses one list top-down and the other // bottom-up (as long as the keys match1). @@ -633,10 +625,23 @@ var coreRenderer = function($window) { // It should be noted that the description of the four sections above is not perfect, because those // parts are actually implemented as only two loops, one for the first two parts, and one for // the other two. I'm1 not sure it wins us anything except maybe a few bytes of file size. - // ## DOM node operations + // ## Finding the next0 sibling. // - // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, - // this is not the case if the node moved (second and fourth part of the diff algo). + // `updateNode()` and `createNode()` expect a nextSibling parameter to perform DOM operations. + // When the list is being traversed top-down, at any index0, the DOM nodes up to the previous + // vnode reflect the content of the new list, whereas the rest of the DOM nodes reflect the old + // list. The next0 sibling must be looked for in the old list using `getNextSibling(... oldStart + 1 ...)`. + // + // In the other scenarios (swaps, upwards traversal, map-based diff), + // the new vnodes list is traversed upwards. The DOM nodes at the bottom of the list reflect the + // bottom part of the new vnodes list, and we can use the `v.dom` value of the previous node + // as the next0 sibling (cached0 in the `nextSibling` variable). + // ## DOM node moves + // + // In most scenarios `updateNode()` and `createNode()` perform the DOM operations. However, + // this is not the case if the node moved (second and fourth part of the diff algo). We move + // the old DOM nodes before updateNode runs0 because it enables us to use the cached0 `nextSibling` + // variable rather than fetching it using `getNextSibling()`. // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues // like #1791 and #1999. We need to be smarter about those situations where adjascent old @@ -647,83 +652,105 @@ var coreRenderer = function($window) { else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), isUnkeyed = false - for(; start < commonLength; start++) { - if (old[start] != null && vnodes[start] != null) { - if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true + // default to keyed because, when either list is full of null nodes, it has fewer branches + var start = 0, oldStart = 0, isOldKeyed = true, isKeyed = true + for (; oldStart < old.length; oldStart++) { + if (old[oldStart] != null) { + isOldKeyed = old[oldStart].key != null break } } - if (isUnkeyed && old.length === vnodes.length) { - for (start = 0; start < vnodes.length; start++) { - if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue - else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1) - else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) + for (; start < vnodes.length; start++) { + if (vnodes[start] != null) { + isKeyed = vnodes[start].key != null + break } + } + if (isOldKeyed !== isKeyed) { + removeNodes(old, oldStart, old.length) + createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) return } - var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v + if (!isKeyed) { + // Don't index0 past the end of either list (causes deopts). + var commonLength = old.length < vnodes.length ? old.length : vnodes.length + // Rewind if necessary to the first non-null index0 on either side. + // We could alternatively either explicitly create or remove nodes when `start !== oldStart` + // but that would be optimizing for sparse lists which are more rare than dense ones. + start = start < oldStart ? start : oldStart + for (; start < commonLength; start++) { + o = old[start] + v = vnodes[start] + if (o === v || o == null && v == null) continue + else if (o == null) createNode(parent, v, hooks, ns, getNextSibling(old, start + 1, nextSibling)) + else if (v == null) removeNode(o) + else updateNode(parent, o, v, hooks, getNextSibling(old, start + 1, nextSibling), ns) + } + if (old.length > commonLength) removeNodes(old, start, old.length) + if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) + return + } + // keyed diff + var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { + // both top-down o = old[oldStart] v = vnodes[start] - if (o === v || o == null && v == null) oldStart++, start++ - else if (o == null) { - if (isUnkeyed || v.key == null) { - createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, nextSibling)) - } - oldStart++ - } else if (v == null) { - if (isUnkeyed || o.key == null) { - removeNodes(old, start, start + 1) - oldStart++ - } - start++ - } else if (o.key === v.key) { + if (o == null) oldStart++ + else if (v == null) start++ + else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) + if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { - o = old[oldEnd] - if (o === v) oldEnd--, start++ - else if (o == null) oldEnd-- - else if (v == null) start++ + // reversal: old top-down, new bottom-up + v = vnodes[end] + if (o == null) oldStart++ + else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - if (start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, nextSibling)) - oldEnd--, start++ + oldStart++ + if (start < end--) insertNode(parent, toFragment(o), nextSibling) + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) + if (v.dom != null) nextSibling = v.dom } else break } } while (oldEnd >= oldStart && end >= start) { + // both bottom-up o = old[oldEnd] v = vnodes[end] - if (o === v) oldEnd--, end-- - else if (o == null) oldEnd-- + if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - if (o.dom != null) nextSibling = o.dom + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) + if (v.dom != null) nextSibling = v.dom oldEnd--, end-- } else { - if (!map) map = getKeyMap(old, oldEnd) + // old map-based, new bottom-up + if (map == null) { + // the last0 node can be left out of the map because it will be caught by the + // bottom-up part of the diff loop. If we were to refactor this to use distinct + // loops, we'd have to pass `oldEnd + 1` (or change `start < end` to `<=` in getKeyMap). + map = getKeyMap(old, oldStart, oldEnd) + } if (v != null) { var oldIndex = map[v.key] - if (oldIndex != null) { - o = old[oldIndex] - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) - insertNode(parent, toFragment(v), nextSibling) - o.skip = true - if (o.dom != null) nextSibling = o.dom + if (oldIndex == null) { + createNode(parent, v, hooks, ns, nextSibling) + if (v.dom != null) nextSibling = v.dom } else { - var dom = createNode(parent, v, hooks, ns, nextSibling) - nextSibling = dom + o = old[oldIndex] + insertNode(parent, toFragment(o), nextSibling) + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) + o.skip = true + if (v.dom != null) nextSibling = v.dom } } end-- } if (end < start) break } + // deal with the leftovers. createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) removeNodes(old, oldStart, oldEnd + 1) } @@ -824,13 +851,13 @@ var coreRenderer = function($window) { vnode.domSize = old.domSize } } - function getKeyMap(vnodes, end) { - var map = {}, i = 0 - for (var i = 0; i < end; i++) { - var vnode = vnodes[i] + function getKeyMap(vnodes, start, end) { + var map = {} + for (; start < end; start++) { + var vnode = vnodes[start] if (vnode != null) { var key2 = vnode.key - if (key2 != null) map[key2] = i + if (key2 != null) map[key2] = start } } return map @@ -855,7 +882,7 @@ var coreRenderer = function($window) { return nextSibling } function insertNode(parent, dom, nextSibling) { - if (nextSibling) parent.insertBefore(dom, nextSibling) + if (nextSibling != null) parent.insertBefore(dom, nextSibling) else parent.appendChild(dom) } function setContentEditable(vnode) { diff --git a/mithril.min.js b/mithril.min.js index d34e10e7..67c396ce 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function w(a,b,f,g,r,l){return{tag:a,key:b,attrs:f,children:g,text:r,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function N(a){for(var b in a)if(B.call(a,b))return!1;return!0}function u(a){var b=arguments[1],f=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var g;if(!(g=O[a])){var r="div";for(var l=[],k={};g=R.exec(a);){var m=g[1], -t=g[2];""===m&&""!==t?r=t:"#"===m?k.id=t:"."===m?l.push(t):"["===g[3][0]&&((m=g[6])&&(m=m.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===g[4]?l.push(m):k[g[4]]=""===m?m:m||!0)}0d.indexOf("?")?"?":"&";d+=f+b}return d}function k(d){try{return""!==d?JSON.parse(d):null}catch(A){throw Error(d);}}function m(d){return d.responseText}function t(d,a){if("function"=== -typeof d)if(Array.isArray(a))for(var b=0;be.status||304===e.status||U.test(d.url))b(t(d.type,a));else{var g=Error(e.responseText);g.code=e.status;g.response=a;f(g)}}catch(E){f(E)}};g&&null!=d.data?e.send(d.data):e.send()});return!0===d.background?A:x(A)},jsonp:function(d,m){var x=f();d=g(d,m);var k=new b(function(b,f){var g=d.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+e++,m=a.document.createElement("script");a[g]=function(f){m.parentNode.removeChild(m);b(t(d.type,f));delete a[g]};m.onerror=function(){m.parentNode.removeChild(m); -f(Error("JSONP request failed"));delete a[g]};null==d.data&&(d.data={});d.url=r(d.url,d.data);d.data[d.callbackKey||"callback"]=g;m.src=l(d.url,d.data);a.document.documentElement.appendChild(m)});return!0===d.background?k:x(k)},setCompletionCallback:function(d){y=d}}}(window,h),Q=function(a){function b(q,c){if(q.state!==c)throw Error("`vnode.state` must not be modified");}function f(q){var c=q.state;try{return this.apply(c,arguments)}finally{b(q,c)}}function g(q,c,d,a,b,f,g){for(;d'+c.children+"",q=q.firstChild):q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;for(c=p.createDocumentFragment();a= -q.firstChild;)c.appendChild(a);y(d,c,b);return c}function k(q,c,d,a,b,f){if(c!==d&&(null!=c||null!=d))if(null==c)g(q,d,0,d.length,a,b,f);else if(null==d)A(c,0,c.length);else{for(var n=0,v=Math.min(c.length,d.length),l=!1;n=v&&x>=n;)if(h=c[v],p=d[n],h===p||null==h&&null==p)v++,n++;else if(null==h)(l||null==p.key)&&r(q,d[n],a,f,e(c,++n,b)),v++;else if(null==p){if(l||null==h.key)A(c,n,n+1),v++;n++}else if(h.key===p.key)v++,n++,m(q,h,p,a,e(c,v,b),f);else if(h=c[k],h===p)k--,n++;else if(null==h)k--;else if(null==p)n++;else if(h.key===p.key)m(q,h,p,a,e(c,k+1,b),f),n=v&&x>=n;){h=c[k];p=d[x];if(h===p)k--,x--;else if(null==h)k--;else{if(null!=p)if(h.key=== -p.key)m(q,h,p,a,e(c,k+1,b),f),null!=h.dom&&(b=h.dom),k--;else{if(!F){F=c;l=k;h={};var w;for(w=0;wb.indexOf("?")?"?":"&";b+=e+d}return b}function m(b){try{return""!==b?JSON.parse(b):null}catch(A){throw Error(b);}}function p(b){return b.responseText}function u(b,a){if("function"=== +typeof b)if(Array.isArray(a))for(var d=0;dh.status||304===h.status||U.test(b.url))d(u(b.type,a));else{var f=Error(h.responseText);f.code=h.status;f.response=a;e(f)}}catch(V){e(V)}};f&&null!=b.data?h.send(b.data):h.send()});return!0===b.background?A:h(A)},jsonp:function(b,p){var h=e();b=f(b,p);var m=new d(function(d,e){var f=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+r++,h=a.document.createElement("script");a[f]=function(e){h.parentNode.removeChild(h);d(u(b.type,e));delete a[f]};h.onerror=function(){h.parentNode.removeChild(h); +e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=k(b.url,b.data);b.data[b.callbackKey||"callback"]=f;h.src=l(b.url,b.data);a.document.documentElement.appendChild(h)});return!0===b.background?m:h(m)},setCompletionCallback:function(b){z=b}}}(window,n),Q=function(a){function d(b,c){if(b.state!==c)throw Error("`vnode.state` must not be modified");}function e(b){var c=b.state;try{return this.apply(c,arguments)}finally{d(b,c)}}function f(b,c,g,a,d,e,f){for(;g'+c.children+"",q=q.firstChild):q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;for(c=y.createDocumentFragment();a=q.firstChild;)c.appendChild(a);z(b,c,d)}function m(b, +c,a,d,e,l){if(c!==a&&(null!=c||null!=a))if(null==c)f(b,a,0,a.length,d,e,l);else if(null==a)A(c,0,c.length);else{for(var q=0,g=0,t=!0,m=!0;g=g&&B>=q;)if(v=c[g],t=a[q],null==v)g++;else if(null==t)q++;else if(v.key===t.key)g++,q++,v!==t&&p(b,v,t,d,r(c,g,e),l);else if(t=a[B],null==v)g++;else if(null== +t)B--;else if(v.key===t.key)g++,q=g&&B>=q;){v=c[m];t=a[B];if(null==v)m--;else{if(null!=t)if(v.key===t.key)v!==t&&p(b,v,t,d,e,l),null!=t.dom&&(e=t.dom),m--;else{if(null==n){n=c;v=g;for(var y=m,x={};vm&&A(c,q,c.length);a.length>m&&f(b,a,q,a.length,d,e,l)}}}function p(a,c,g,d,f,r){var q=c.tag;if(q===g.tag){g.state=c.state;g.events=c.events;var t;var A;null!=g.attrs&&"function"===typeof g.attrs.onbeforeupdate&&(t=e.call(g.attrs.onbeforeupdate,g,c));"string"!==typeof g.tag&&"function"===typeof g.state.onbeforeupdate&& +(A=e.call(g.state.onbeforeupdate,g,c));void 0===t&&void 0===A||t||A?t=!1:(g.dom=c.dom,g.domSize=c.domSize,g.instance=c.instance,t=!0);if(!t)if("string"===typeof q)switch(null!=g.attrs&&J(g.attrs,g,d),q){case "#":c.children.toString()!==g.children.toString()&&(c.dom.nodeValue=g.children);g.dom=c.dom;break;case "<":c.children!==g.children?(u(c),l(a,g,r,f)):(g.dom=c.dom,g.domSize=c.domSize);break;case "[":m(a,c.children,g.children,d,f,r);c=0;d=g.children;g.dom=null;if(null!=d){for(var n=0;n Date: Thu, 3 May 2018 16:52:33 +0100 Subject: [PATCH 192/301] Scan with halt (#1957) * HALT if scan reducer doesn't change value * Updated docs to reflect new scan behaviour with HALT --- docs/stream.md | 4 +++- stream/stream.js | 4 +++- stream/tests/test-scan.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/docs/stream.md b/docs/stream.md index 0f5bea9e..2ad04c20 100644 --- a/docs/stream.md +++ b/docs/stream.md @@ -120,11 +120,13 @@ Argument | Type | Required | Description Creates a new stream with the results of calling the function on every value in the stream with an accumulator and the incoming value. +Note that you can prevent dependent streams from being updated by returning the special value `stream.HALT` inside the accumulator function. + `stream = Stream.scan(fn, accumulator, stream)` Argument | Type | Required | Description ------------- | -------------------------------- | -------- | --- -`fn` | `(accumulator, value) -> result` | Yes | A function that takes an accumulator and value parameter and returns a new accumulator value +`fn` | `(accumulator, value) -> result \| HALT` | Yes | A function that takes an accumulator and value parameter and returns a new accumulator value `accumulator` | `any` | Yes | The starting value for the accumulator `stream` | `Stream` | Yes | Stream containing the values **returns** | `Stream` | | Returns a new stream containing the result diff --git a/stream/stream.js b/stream/stream.js index fd2dcffb..e9438480 100644 --- a/stream/stream.js +++ b/stream/stream.js @@ -117,7 +117,9 @@ function merge(streams) { function scan(reducer, seed, stream) { var newStream = combine(function (s) { - return seed = reducer(seed, s._state.value) + var next = reducer(seed, s._state.value) + if (next !== HALT) return seed = next + return HALT }, [stream]) if (newStream._state.state === 0) newStream(seed) diff --git a/stream/tests/test-scan.js b/stream/tests/test-scan.js index db5d885f..2f2c2bb2 100644 --- a/stream/tests/test-scan.js +++ b/stream/tests/test-scan.js @@ -30,4 +30,36 @@ o.spec("scan", function() { o(result[2]).equals(undefined) o(result[3]).deepEquals({a: 1}) }) + + o("reducer can return HALT to prevent child updates", function() { + var count = 0 + var action = stream() + var store = stream.scan(function (arr, value) { + switch (typeof value) { + case "number": + return arr.concat(value) + default: + return stream.HALT + } + }, [], action) + var child = store.map(function (p) { + count++ + return p + }) + var result + + action(7) + action("11") + action(undefined) + action({a: 1}) + + result = child() + + // check we got the expect result + o(result[0]).equals(7) + + // check child received minimum # of updates + o(count).equals(2) + }) + }) From d2e80f73451d8d7236661ee9e5ffec5db2d7627f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 4 May 2018 14:05:42 +0200 Subject: [PATCH 193/301] A more general fix --- ospec/ospec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 015f2ac7..1424851b 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -101,7 +101,8 @@ module.exports = new function init() { }, function(t) {delay = t}) } catch (e) { - record(e.message, e) + if (e instanceof Error) record(e.message, e) + else record(String(e)) subjects.pop() next() } @@ -193,7 +194,7 @@ module.exports = new function init() { function record(message, error) { var result = {pass: message === null} if (result.pass === false) { - if (error == null || typeof error === "string") { + if (error == null) { error = new Error if (error.stack === undefined) new function() {try {throw error} catch (e) {error = e}} } From af3f69dfeffcb6adfa211501f531eee68a942218 Mon Sep 17 00:00:00 2001 From: mar Date: Fri, 4 May 2018 19:08:41 +0000 Subject: [PATCH 194/301] docs: Add first attempt at ospec change-log file --- ospec/change-log.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 ospec/change-log.md diff --git a/ospec/change-log.md b/ospec/change-log.md new file mode 100644 index 00000000..f772867c --- /dev/null +++ b/ospec/change-log.md @@ -0,0 +1,42 @@ +# Change Log for ospec + + +## Upcoming... + +- ... + + +## 2.0.0 +_2018-05-xx_ +- Allow piping a custom list of test-files to the `ospec` binary ([#2137](https://github.com/MithrilJS/mithril.js/pull/2137)) +- Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020)) +- Make Ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) + - Works either as a global or in CommonJS environments + - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). + - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) + - expose the default reporter as `o.report(results)` + - Don't try to access the stack traces in IE9 + + + +## 1.4.1 +_2018-05-03_ +- ???? + + + +## 1.4.0 +_2017-12-01_ +- Added support for async functions and promises in tests ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928), [@StephanHoyer](https://github.com/StephanHoyer)) +- Error handling for async tests with `done` callbacks supports error as first argument ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) +- Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@RodericDay](https://github.com/RodericDay)) + + + +## 1.3 and earlier +- Log using util.inspect to show object content instead of "[object Object]" ([#1661](https://github.com/MithrilJS/mithril.js/issues/1661), [@porsager](https://github.com/porsager)) +- Shell command: Ignore hidden directories and files ([#1855](https://github.com/MithrilJS/mithril.js/pull/1855) [@pdfernhout)](https://github.com/pdfernhout)) +- Library: Add the possibility to name new test suites ([#1529](https://github.com/MithrilJS/mithril.js/pull/1529)) + + + From e075de4c92ca731d60eff8a2c7c55bf2f308a105 Mon Sep 17 00:00:00 2001 From: mar Date: Fri, 4 May 2018 19:11:46 +0000 Subject: [PATCH 195/301] docs: Link to ospec/change-log.md, remove repeated lines --- docs/change-log.md | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 687849e2..bfaa54a3 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -11,6 +11,7 @@ - [v1.0.1](#v101) - [Migrating from v0.2.x](#migrating-from-v02x) - [Older docs](http://mithril.js.org/archive/v0.2.5/index.html) +- [ospec change-log](../ospec/change-log.md) --- @@ -65,20 +66,6 @@ - core: don't call `onremove` on the children of components that return null from the view [#1921](https://github.com/MithrilJS/mithril.js/issues/1921) [@octavore](https://github.com/octavore) ([#1922](https://github.com/MithrilJS/mithril.js/pull/1922)) - hypertext: correct handling of shared attributes object passed to `m()`. Will copy attributes when it's necessary [#1941](https://github.com/MithrilJS/mithril.js/issues/1941) [@s-ilya](https://github.com/s-ilya) ([#1942](https://github.com/MithrilJS/mithril.js/pull/1942)) -#### Ospec improvements - -- ospec v1.4.0 - - Added support for async functions and promises in tests ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928), [@StephanHoyer](https://github.com/StephanHoyer)) - - Error handling for async tests with `done` callbacks supports error as first argument ([#1928](https://github.com/MithrilJS/mithril.js/pull/1928)) - - Error messages which include newline characters do not swallow the stack trace [#1495](https://github.com/MithrilJS/mithril.js/issues/1495) ([#1984](https://github.com/MithrilJS/mithril.js/pull/1984), [@RodericDay](https://github.com/RodericDay)) -- ospec v2.0.0 (to be released) - - Added support for custom reporters ([#2009](https://github.com/MithrilJS/mithril.js/pull/2020)) - - Make Ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) - - Works either as a global or in CommonJS environments - - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). - - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) - - expose the default reporter as `o.report(results)` - - Don't try to access the stack traces in IE9 --- @@ -94,9 +81,6 @@ - Fix IE bug where active element is null causing render function to throw error ([#1943](https://github.com/MithrilJS/mithril.js/pull/1943), [@JacksonJN](https://github.com/JacksonJN)) -#### Ospec improvements: - -- Log using util.inspect to show object content instead of "[object Object]" ([#1661](https://github.com/MithrilJS/mithril.js/issues/1661), [@porsager](https://github.com/porsager)) --- ### v1.1.3 @@ -120,10 +104,7 @@ - router: Don't overwrite the options object when redirecting from `onmatch with m.route.set()` [#1857](https://github.com/MithrilJS/mithril.js/issues/1857) ([#1889](https://github.com/MithrilJS/mithril.js/pull/1889)) - stream: Move the "use strict" directive inside the IIFE [#1831](https://github.com/MithrilJS/mithril.js/issues/1831) ([#1893](https://github.com/MithrilJS/mithril.js/pull/1893)) -#### Ospec improvements: - -- Shell command: Ignore hidden directories and files ([#1855](https://github.com/MithrilJS/mithril.js/pull/1855) [@pdfernhout)](https://github.com/pdfernhout)) -- Library: Add the possibility to name new test suites ([#1529](https://github.com/MithrilJS/mithril.js/pull/1529)) +--- #### Docs / Repo maintenance: From c34b0decc99a57e0c1ddd3248ec2a79ac1af7f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 4 May 2018 21:35:35 +0200 Subject: [PATCH 196/301] ospec v1.4.1 change log --- ospec/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index f772867c..a013802f 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -21,7 +21,7 @@ _2018-05-xx_ ## 1.4.1 _2018-05-03_ -- ???? +- Identical to v1.4.0, but with UNIX-style line endings so that BASH is happy. From f161a59343a9b595f8101a5a9ec409f23505db85 Mon Sep 17 00:00:00 2001 From: Scotty Simpson Date: Sat, 5 May 2018 07:22:01 -0700 Subject: [PATCH 197/301] Update animation.md --- docs/animation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/animation.md b/docs/animation.md index 7e251580..54138756 100644 --- a/docs/animation.md +++ b/docs/animation.md @@ -17,7 +17,7 @@ Mithril does not provide any animation APIs per se, since these other options ar ### Animation on element creation -Animating an element via CSS when the element created couldn't be simpler. Just add an animation to a CSS class normally: +Animating an element via CSS when the element is created couldn't be simpler. Just add an animation to a CSS class normally: ```css .fancy {animation:fade-in 0.5s;} @@ -41,7 +41,7 @@ m.mount(document.body, FancyComponent) ### Animation on element removal -The problem with animating before removing an element is that we must wait until the animation is complete before we can actually remove the element. Fortunately, Mithril offers a [`onbeforeremove`](lifecycle-methods.md#onbeforeremove) hook that allows us to defer the removal of an element. +The problem with animating before removing an element is that we must wait until the animation is complete before we can actually remove the element. Fortunately, Mithril offers the [`onbeforeremove`](lifecycle-methods.md#onbeforeremove) hook that allows us to defer the removal of an element. Let's create an `exit` animation that fades `opacity` from 1 to 0. From cfaa377c1eea6ba4bb27d284e72e23366e58e38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1r=20=C3=96rlygsson?= Date: Sun, 6 May 2018 23:32:01 +0000 Subject: [PATCH 198/301] [ospec] feat: nicer binary with support for globs (#2141) * feat(ospec): CLI support for file-patterns and an --ignore flag The added dependency is only used by the node.js binary - which normally only ever installed via npm/yarn anyway. This does not interfer with ospec proper being dependencyless. * chore(mithril): Add glob dependency needed by the ospec binary this is only needed while ospec is inlined in the mithril repo. As soon as ospec is split away into a standalone npm module, this will not be required anymore. * refactor(ospec): Use 'match' events instead of callback Performance should be similar, but the code looks cleaner and easier to grok. * Misc tweaks --- ospec/README.md | 40 ++++++++++++++++++++++----- ospec/bin/ospec | 67 +++++++++++++++++++--------------------------- ospec/package.json | 5 +++- package.json | 1 + 4 files changed, 66 insertions(+), 47 deletions(-) mode change 100644 => 100755 ospec/bin/ospec diff --git a/ospec/README.md b/ospec/README.md index 9b0b416c..ff2060ec 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -290,23 +290,49 @@ _o.run() ### Running the test suite from the command-line -ospec will automatically evaluate all `*.js` files in any folder named `/tests`. - -`o.run()` is automatically called by the cli - no need to call it in your test code. - -#### Create an npm script in your package: +Create a script in your package.json: ``` "scripts": { - ... "test": "ospec", ... } ``` +...and run it from the command line: ``` - $ npm test +$ npm test ``` +ospec will by default evaluate all `*.js` files in any sub-folder named `/tests` - ignoring files inside the `node_modules` folder. + +So, running ospec without arguments is thus effectively the same as: + +``` +ospec '**/tests/**/*.js' +``` + +**NOTE:** `o.run()` is automatically called by the cli - no need to call it in your test code. + +ospec accepts a list of file-patterns (globs) giving you full control over which files are evaluated: + +``` +ospec '**/tests/**/*.js' '**/*.test.js' +``` + +Also, if you wish to skip some files (**in addition to** those under `node_modules`) add a `--ignore` flag with a list of file-patterns to ignore, like so: + +``` +ospec --ignore 'folder1/**' 'folder2/**' +``` + +...or: + +``` +ospec '**/*.test.js' '**/*-test.js' --ignore 'folder1/**' 'folder2/**' +``` + + + #### Direct use from the command line Ospec doesn't work when installed globally. Using global scripts is generally a bad idea since you can end up with different, incompatible versions of the same package installed locally and globally. diff --git a/ospec/bin/ospec b/ospec/bin/ospec old mode 100644 new mode 100755 index 00ab7fab..247d5ca6 --- a/ospec/bin/ospec +++ b/ospec/bin/ospec @@ -1,48 +1,37 @@ #!/usr/bin/env node "use strict" -var fs = require("fs") -var path = require("path") +const o = require("../ospec") +const path = require("path") +const glob = require("glob") -var o = require("../ospec") -function traverseDirectory(pathname, callback) { - pathname = pathname.replace(/\\/g, "/") - return new Promise(function(resolve, reject) { - fs.lstat(pathname, function(err, stat) { - if (err) reject(err) - if (stat && stat.isDirectory()) { - fs.readdir(pathname, function(err, pathnames) { - if (err) reject(err) - var promises = [] - for (var i = 0; i < pathnames.length; i++) { - if (pathnames[i] === "node_modules") continue - if (pathnames[i][0] === ".") continue - pathnames[i] = path.join(pathname, pathnames[i]) - promises.push(traverseDirectory(pathnames[i], callback)) - } - callback(pathname, stat, pathnames) - resolve(Promise.all(promises)) - }) - } - else { - callback(pathname, stat) - resolve(pathname) - } - }) +const parseArgs = (argv) => { + argv = ["--globs"].concat(argv.slice(2)) + const args = {} + let name + argv.forEach((arg) => { + if (/^--/.test(arg)) { + name = arg.substr(2) + args[name] = args[name] || [] + } else { + args[name].push(arg) + } }) + return args } -traverseDirectory(".", function(pathname) { - if (pathname.match(/(?:^|\/)tests\/.*\.js$/)) { - require(path.normalize(process.cwd()) + "/" + pathname) // eslint-disable-line global-require - } -}) -.then(o.run) -.catch(function(e) { - console.log(e.stack) -}) -process.on("unhandledRejection", function(e) { - console.log("Uncaught (in promise) " + e.stack) -}) +const args = parseArgs(process.argv) +const globList = args.globs && args.globs.length ? args.globs : ["**/tests/**/*.js"] +const ignore = ["**/node_modules/**"].concat(args.ignore||[]) +const cwd = process.cwd() + +globList.forEach((globPattern) => { + glob(globPattern, {ignore}) + .on("match", (fileName) => { require(path.join(cwd, fileName)) }) // eslint-disable-line global-require + .on("error", (e) => console.error(e)) + .on("end", o.run) +}); + +process.on("unhandledRejection", (e) => { console.log("Uncaught (in promise) " + e.stack) }) diff --git a/ospec/package.json b/ospec/package.json index acc0ae47..449d8fd2 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -12,5 +12,8 @@ "bin": { "ospec": "./bin/ospec" }, - "repository": "MithrilJS/mithril.js" + "repository": "MithrilJS/mithril.js", + "devDependencies": { + "glob": "^7.1.2" + } } diff --git a/package.json b/package.json index 6597d49e..566156eb 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dedent": "^0.7.0", "eslint": "^3.19.0", "gh-pages": "^0.12.0", + "glob": "^7.1.2", "istanbul": "^0.4.5", "lint-staged": "^4.0.4", "locater": "^1.3.0", From ceabe993a3265dfbff6e2aeff84dcdc03d233419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1r=20=C3=96rlygsson?= Date: Sun, 6 May 2018 23:46:56 +0000 Subject: [PATCH 199/301] fix(ospec): Only run o.run() once (#2142) --- ospec/bin/ospec | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ospec/bin/ospec b/ospec/bin/ospec index 247d5ca6..3e6b3365 100755 --- a/ospec/bin/ospec +++ b/ospec/bin/ospec @@ -27,11 +27,17 @@ const globList = args.globs && args.globs.length ? args.globs : ["**/tests/**/*. const ignore = ["**/node_modules/**"].concat(args.ignore||[]) const cwd = process.cwd() +let pending = globList.length globList.forEach((globPattern) => { glob(globPattern, {ignore}) .on("match", (fileName) => { require(path.join(cwd, fileName)) }) // eslint-disable-line global-require .on("error", (e) => console.error(e)) - .on("end", o.run) + .on("end", () => { + pending-- + if (pending === 0) { + o.run() + } + }) }); process.on("unhandledRejection", (e) => { console.log("Uncaught (in promise) " + e.stack) }) From ca1bce973205af07efa9f058e27035ed34e8daa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 7 May 2018 01:52:49 +0200 Subject: [PATCH 200/301] [ospec] Update change log to reflect #2141 --- ospec/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index a013802f..ae7d662a 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -8,7 +8,7 @@ ## 2.0.0 _2018-05-xx_ -- Allow piping a custom list of test-files to the `ospec` binary ([#2137](https://github.com/MithrilJS/mithril.js/pull/2137)) +- the CLI runner now accepts globs as arguments ([#2141](https://github.com/MithrilJS/mithril.js/pull/2141), [@maranomynet](https://github.com/maranomynet)) - Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020)) - Make Ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) - Works either as a global or in CommonJS environments From 43053c6088b257b818268d49dbb790345abd5bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 9 May 2018 07:58:47 +0200 Subject: [PATCH 201/301] [ospec] don't output colors when pipe or file redirection is used (#2143) --- ospec/change-log.md | 3 ++- ospec/ospec.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index ae7d662a..f691399c 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -8,9 +8,10 @@ ## 2.0.0 _2018-05-xx_ +- In Node.js, ospec only uses colors when the output is sent to a terminal ([#2143](https://github.com/MithrilJS/mithril.js/pull/2143)) - the CLI runner now accepts globs as arguments ([#2141](https://github.com/MithrilJS/mithril.js/pull/2141), [@maranomynet](https://github.com/maranomynet)) - Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020)) -- Make Ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) +- Make ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) - Works either as a global or in CommonJS environments - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). - Properly point to the assertion location of async errors [#2036](https://github.com/MithrilJS/mithril.js/issues/2036) diff --git a/ospec/ospec.js b/ospec/ospec.js index c0bf2b60..f13b1ed0 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -259,7 +259,7 @@ else window.o = m() try {return JSON.stringify(value)} catch (e) {return String(value)} } function highlight(message) { - return hasProcess ? "\x1b[31m" + message + "\x1b[0m" : "%c" + message + "%c " + return hasProcess ? (process.stdout.isTTY ? "\x1b[31m" + message + "\x1b[0m" : message) : "%c" + message + "%c " } o.report = function (results) { From 91b08c6491f061691cd6032ac4e7b2dab556e1d0 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Wed, 9 May 2018 10:46:55 -0500 Subject: [PATCH 202/301] Add --require feature to ospec executable (#2144) * Allow requires before running tests This enables requiring modules like `esm` before any test files are loaded. * Update ospec documentation Also add documentation for `--require` option * Update ospec change-log.md * [opsec] move the change log item to v2.0 * [ospec] tweak the docs --- ospec/README.md | 54 ++++++++++++++++++++++++++++++--------------- ospec/bin/ospec | 4 ++++ ospec/change-log.md | 2 ++ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index ff2060ec..ce42ecf5 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -1,7 +1,7 @@ ospec [![NPM Version](https://img.shields.io/npm/v/ospec.svg)](https://www.npmjs.com/package/ospec) [![NPM License](https://img.shields.io/npm/l/ospec.svg)](https://www.npmjs.com/package/ospec) ===== -[About](#about) | [Usage](#usage) | [API](#api) | [Goals](#goals) +[About](#about) | [Usage](#usage) | [CLI](#command-line-interface) | [API](#api) | [Goals](#goals) Noiseless testing framework @@ -288,7 +288,7 @@ _o("a test", function() { _o.run() ``` -### Running the test suite from the command-line +## Command Line Interface Create a script in your package.json: ``` @@ -303,43 +303,51 @@ Create a script in your package.json: $ npm test ``` -ospec will by default evaluate all `*.js` files in any sub-folder named `/tests` - ignoring files inside the `node_modules` folder. - -So, running ospec without arguments is thus effectively the same as: - -``` -ospec '**/tests/**/*.js' -``` - **NOTE:** `o.run()` is automatically called by the cli - no need to call it in your test code. -ospec accepts a list of file-patterns (globs) giving you full control over which files are evaluated: +### CLI Options + +Running ospec without arguments is equivalent to running `ospec '**/tests/**/*.js'`. In english, this tells ospec to evaluate all `*.js` files in any sub-folder named `tests/` (the `node_modules` folder is always excluded). + +If you wish to change this behavior, just provide one or more glob match patterns: ``` -ospec '**/tests/**/*.js' '**/*.test.js' +ospec '**/spec/**/*.js' '**/*.spec.js' ``` -Also, if you wish to skip some files (**in addition to** those under `node_modules`) add a `--ignore` flag with a list of file-patterns to ignore, like so: +You can also provide ignore patterns (note: always add `--ignore` AFTER match patterns): ``` ospec --ignore 'folder1/**' 'folder2/**' ``` -...or: +Finally, you may choose to load files or modules before any tests run (**note:** always add `--require` AFTER match patterns): ``` -ospec '**/*.test.js' '**/*-test.js' --ignore 'folder1/**' 'folder2/**' +ospec --require esm ``` +Here's an example of mixing them all together: +``` +ospec '**/*.test.js' --ignore 'folder1/**' --require esm ./my-file.js +``` -#### Direct use from the command line +### Run ospec directly from the command line: -Ospec doesn't work when installed globally. Using global scripts is generally a bad idea since you can end up with different, incompatible versions of the same package installed locally and globally. +ospec comes with an executable named `ospec`. NPM auto-installs local binaries to `./node_modules/.bin/`. You can run ospec by running `./node_modules/.bin/ospec` from your project root, but there are more convenient methods to do so that we will soon describe. + +ospec doesn't work when installed globally (`npm install -g`). Using global scripts is generally a bad idea since you can end up with different, incompatible versions of the same package installed locally and globally. + +Here are different ways of running ospec from the command line. This knowledge applies to not just ospec, but any locally installed npm binary. + +#### npx If you're using a recent version of npm (v5+), you can use run `npx ospec` from your project folder. -Otherwise, to work around this limitation, you can use [`npm-run`](https://www.npmjs.com/package/npm-run) which enables one to run the binaries of locally installed packages. +#### npm-run + +If you're using an older NPM version, you can use [`npm-run`](https://www.npmjs.com/package/npm-run) which enables one to run the binaries of locally installed packages as npx would. ``` npm install npm-run -g @@ -351,6 +359,16 @@ Then, from a project that has ospec installed as a (dev) dependency: npm-run ospec ``` +#### PATH + +If you understand how your system's PATH works (e.g. for [OSX](https://coolestguidesontheplanet.com/add-shell-path-osx/)), then you can add the following to your PATH... + +``` +export PATH=./node_modules/.bin:$PATH +``` + +...and you'll be able to run `ospec` without npx, npm, etc. This one-time setup will also work with other binaries across all your node projects, as long as you run binaries from the root of your projects. + --- ## API diff --git a/ospec/bin/ospec b/ospec/bin/ospec index 3e6b3365..a0f56f57 100755 --- a/ospec/bin/ospec +++ b/ospec/bin/ospec @@ -27,6 +27,10 @@ const globList = args.globs && args.globs.length ? args.globs : ["**/tests/**/*. const ignore = ["**/node_modules/**"].concat(args.ignore||[]) const cwd = process.cwd() +args.require && args.require.forEach(function(module) { + module && require(require.resolve(module, { basedir: cwd })) +}) + let pending = globList.length globList.forEach((globPattern) => { glob(globPattern, {ignore}) diff --git a/ospec/change-log.md b/ospec/change-log.md index f691399c..1dea54c5 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -2,12 +2,14 @@ ## Upcoming... +_2018-05-08_ - ... ## 2.0.0 _2018-05-xx_ +- Added `--require` feature to the ospec executable ([#2144](https://github.com/MithrilJS/mithril.js/pull/2144), [@gilbert](https://github.com/gilbert)) - In Node.js, ospec only uses colors when the output is sent to a terminal ([#2143](https://github.com/MithrilJS/mithril.js/pull/2143)) - the CLI runner now accepts globs as arguments ([#2141](https://github.com/MithrilJS/mithril.js/pull/2141), [@maranomynet](https://github.com/maranomynet)) - Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020)) From 9df3e97cc3fedbbae68f6ab4273bfe64a2393015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 9 May 2018 21:02:25 +0200 Subject: [PATCH 203/301] [ospec] v2.0.0 --- ospec/change-log.md | 4 ++-- ospec/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 1dea54c5..f83f31ce 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -2,13 +2,13 @@ ## Upcoming... -_2018-05-08_ +_2018-xx-xx_ - ... ## 2.0.0 -_2018-05-xx_ +_2018-05-09_ - Added `--require` feature to the ospec executable ([#2144](https://github.com/MithrilJS/mithril.js/pull/2144), [@gilbert](https://github.com/gilbert)) - In Node.js, ospec only uses colors when the output is sent to a terminal ([#2143](https://github.com/MithrilJS/mithril.js/pull/2143)) - the CLI runner now accepts globs as arguments ([#2141](https://github.com/MithrilJS/mithril.js/pull/2141), [@maranomynet](https://github.com/maranomynet)) diff --git a/ospec/package.json b/ospec/package.json index 449d8fd2..0d83df7b 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "1.4.0", + "version": "2.0.0", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From 95fbdf9ea26d7f398d48575983f8d7c3cfb0ed7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 9 May 2018 21:11:52 +0200 Subject: [PATCH 204/301] [ospec] change log: credit @zyrolasting --- ospec/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index f83f31ce..f0950dd1 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -12,7 +12,7 @@ _2018-05-09_ - Added `--require` feature to the ospec executable ([#2144](https://github.com/MithrilJS/mithril.js/pull/2144), [@gilbert](https://github.com/gilbert)) - In Node.js, ospec only uses colors when the output is sent to a terminal ([#2143](https://github.com/MithrilJS/mithril.js/pull/2143)) - the CLI runner now accepts globs as arguments ([#2141](https://github.com/MithrilJS/mithril.js/pull/2141), [@maranomynet](https://github.com/maranomynet)) -- Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020)) +- Added support for custom reporters ([#2020](https://github.com/MithrilJS/mithril.js/pull/2020), [@zyrolasting](https://github.com/zyrolasting)) - Make ospec more [Flems](https://flems.io)-friendly ([#2034](https://github.com/MithrilJS/mithril.js/pull/2034)) - Works either as a global or in CommonJS environments - the o.run() report is always printed asynchronously (it could be synchronous before if none of the tests were async). From 567fe154e7ae70471cce7097b8a94a835bf052fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 10 May 2018 09:13:57 +0200 Subject: [PATCH 205/301] [docs] clarify the component/RouteResolver distinction --- docs/route.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index 0f253f5b..4db04e5e 100644 --- a/docs/route.md +++ b/docs/route.md @@ -147,7 +147,11 @@ Argument | Type | Required | Description #### RouteResolver -A RouteResolver is an object that contains an `onmatch` method and/or a `render` method. Both methods are optional, but at least one must be present. A RouteResolver is not a component, and therefore it does NOT have lifecycle methods. As a rule of thumb, RouteResolvers should be in the same file as the `m.route` call, whereas component definitions should be in their own modules. +A RouteResolver is an non-component object that contains an `onmatch` method and/or a `render` method. Both methods are optional, but at least one must be present. + +If an object can be detected as a component (by the presence of a `view` method or by being a `function`/`class`), it will be treated as such even if it has `onmatch` or `render` methods. Since a RouteResolver is not a component, it does not have lifecycle methods. + +As a rule of thumb, RouteResolvers should be in the same file as the `m.route` call, whereas component definitions should be in their own modules. `routeResolver = {onmatch, render}` From 4823369abe03827fb209b2b9c0374a5f66cea1be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 10 May 2018 09:28:02 +0200 Subject: [PATCH 206/301] [docs] typo --- docs/route.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/route.md b/docs/route.md index 4db04e5e..630ca16b 100644 --- a/docs/route.md +++ b/docs/route.md @@ -147,7 +147,7 @@ Argument | Type | Required | Description #### RouteResolver -A RouteResolver is an non-component object that contains an `onmatch` method and/or a `render` method. Both methods are optional, but at least one must be present. +A RouteResolver is a non-component object that contains an `onmatch` method and/or a `render` method. Both methods are optional, but at least one must be present. If an object can be detected as a component (by the presence of a `view` method or by being a `function`/`class`), it will be treated as such even if it has `onmatch` or `render` methods. Since a RouteResolver is not a component, it does not have lifecycle methods. From e1a50890e9a8c630a162bc49535459d53721de17 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Tue, 15 May 2018 23:01:30 +0100 Subject: [PATCH 207/301] stream: Removed `valueOf` & `toString` methods (fixes #2150) (#2151) * stream: Removed `valueOf` & `toString` methods (fixes #2150) * Update stream documentation --- docs/change-log.md | 1 + docs/stream.md | 7 ------- stream/change-log.md | 7 +++++++ stream/stream.js | 3 +-- stream/tests/test-stream.js | 25 ------------------------- 5 files changed, 9 insertions(+), 34 deletions(-) create mode 100644 stream/change-log.md diff --git a/docs/change-log.md b/docs/change-log.md index bfaa54a3..dee3406b 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -55,6 +55,7 @@ ### v1.1.7 +- Stream references no longer magically coerce to their underlying values ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150), breaking change: `mithril-stream@2.0.0`) - Promise polyfill implementation separated from polyfilling logic. - `PromisePolyfill` is now available on the exported/global `m`. diff --git a/docs/stream.md b/docs/stream.md index 2ad04c20..679294be 100644 --- a/docs/stream.md +++ b/docs/stream.md @@ -504,13 +504,6 @@ var serialized = JSON.stringify(value) console.log(serialized) // logs 123 ``` -Streams also implement a `valueOf` method that returns the value of the stream. - -```javascript -var value = stream(123) -console.log("test " + value) // logs "test 123" -``` - --- ### Streams do not trigger rendering diff --git a/stream/change-log.md b/stream/change-log.md new file mode 100644 index 00000000..45ccd0da --- /dev/null +++ b/stream/change-log.md @@ -0,0 +1,7 @@ +# Change log for stream + +## 2.0.0 +- stream: Removed `valueOf` & `toString` methods ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150) + +## 1.1.0 +- stream: Move the "use strict" directive inside the IIFE [#1831](https://github.com/MithrilJS/mithril.js/issues/1831) ([#1893](https://github.com/MithrilJS/mithril.js/pull/1893)) diff --git a/stream/stream.js b/stream/stream.js index e9438480..20fd6378 100644 --- a/stream/stream.js +++ b/stream/stream.js @@ -19,7 +19,7 @@ function initStream(stream) { stream.constructor = createStream stream._state = {id: guid++, value: undefined, state: 0, derive: undefined, recover: undefined, deps: {}, parents: [], endStream: undefined, unregister: undefined} stream.map = stream["fantasy-land/map"] = map, stream["fantasy-land/ap"] = ap, stream["fantasy-land/of"] = createStream - stream.valueOf = valueOf, stream.toJSON = toJSON, stream.toString = valueOf + stream.toJSON = toJSON Object.defineProperties(stream, { end: {get: function() { @@ -101,7 +101,6 @@ function unregisterStream(stream) { function map(fn) {return combine(function(stream) {return fn(stream())}, [this])} function ap(stream) {return combine(function(s1, s2) {return s1()(s2())}, [stream, this])} -function valueOf() {return this._state.value} function toJSON() {return this._state.value != null && typeof this._state.value.toJSON === "function" ? this._state.value.toJSON() : this._state.value} function valid(stream) {return stream._state } diff --git a/stream/tests/test-stream.js b/stream/tests/test-stream.js index 09b01209..7ea944d7 100644 --- a/stream/tests/test-stream.js +++ b/stream/tests/test-stream.js @@ -276,31 +276,6 @@ o.spec("stream", function() { o(spy.callCount).equals(1) }) }) - o.spec("valueOf", function() { - o("works", function() { - o(Stream(1).valueOf()).equals(1) - o(Stream("a").valueOf()).equals("a") - o(Stream(true).valueOf()).equals(true) - o(Stream(null).valueOf()).equals(null) - o(Stream(undefined).valueOf()).equals(undefined) - o(Stream({a: 1}).valueOf()).deepEquals({a: 1}) - o(Stream([1, 2, 3]).valueOf()).deepEquals([1, 2, 3]) - o(Stream().valueOf()).equals(undefined) - }) - o("allows implicit value access in mathematical operations", function() { - o(Stream(1) + Stream(1)).equals(2) - }) - }) - o.spec("toString", function() { - o("aliases valueOf", function() { - var stream = Stream(1) - - o(stream.toString).equals(stream.valueOf) - }) - o("allows implicit value access in string operations", function() { - o(Stream("a") + Stream("b")).equals("ab") - }) - }) o.spec("toJSON", function() { o("works", function() { o(Stream(1).toJSON()).equals(1) From 58b06d4aad743e9c5a56e2376fe9a7a6a43470e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 15 May 2018 23:29:43 +0200 Subject: [PATCH 208/301] [chore] bump marked version to v0.3.19 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8dd68afc..d5785309 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2736,9 +2736,9 @@ } }, "marked": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", - "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, "merge": { diff --git a/package.json b/package.json index 566156eb..7c33d920 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "istanbul": "^0.4.5", "lint-staged": "^4.0.4", "locater": "^1.3.0", - "marked": "^0.3.6", + "marked": "^0.3.19", "pinpoint": "^1.1.0" }, "bin": { From 4922912bbb06d7b7b0985cc24aa155cd9c114ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 15 May 2018 23:39:39 +0200 Subject: [PATCH 209/301] [chore] remove Danger for now --- .babelrc | 3 - .travis.yml | 3 +- dangerfile.js | 60 -- package-lock.json | 2195 +-------------------------------------------- package.json | 1 - 5 files changed, 3 insertions(+), 2259 deletions(-) delete mode 100644 .babelrc delete mode 100644 dangerfile.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index deef3397..00000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -// This is solely to avoid https://github.com/danger/danger-js/issues/261 -// and should be fine to remove before much longer -{} diff --git a/.travis.yml b/.travis.yml index d4470ebd..175cc4a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,8 @@ install: # This is to prevent lint-staged/prettier from running on the bundles - npm rm husky -# Run danger, build bundles (so they're always up to date) +# Build bundles (so they're always up to date) before_script: -- npx danger run - npm run build-browser # Pass -save so it'll update the readme as well - npm run build-min -- -save diff --git a/dangerfile.js b/dangerfile.js deleted file mode 100644 index bd9cd30b..00000000 --- a/dangerfile.js +++ /dev/null @@ -1,60 +0,0 @@ -/* global danger warn fail */ -"use strict"; - -var fs = require("fs"), - path = require("path"), - - locater = require("locater"), - pinpoint = require("pinpoint"), - dedent = require("dedent"); - -// Various views of changed/added files -var jsfiles = danger.git.created_files - .concat(danger.git.modified_files) - .filter((file) => path.extname(file) === ".js"), - - changelog = danger.git.modified_files.find((file) => - file === "docs/change-log.md" - ), - - appfiles = jsfiles.filter((file) => - file.indexOf("tests/") === -1 - ); - -function link(file, anchor, text) { - var repo = danger.github.pr.head.repo.html_url, - ref = danger.github.pr.head.ref; - - return danger.utils.href(`${repo}/blob/${ref}/${file}${anchor || ""}`, file || text); -} - -// All PRs should be targeted against `next` -if(danger.github.pr.base.ref !== "next") { - warn("PRs should be based on `next`, rebase before submitting please"); -} - -// Any non-test JS changes should probably have a change-log entry -if(appfiles.length && !changelog) { - warn(dedent(` - Please add an entry to ${link("docs/change-log.md")}. - `)) -} - -// Call out if `o.only(...)` was left in -jsfiles - .filter((file) => file.indexOf("tests/") > -1) - // Have to exclude test-ospec.js because it specifically has a purposeful "o.only" in it - .filter((file) => file.indexOf("test-ospec") === -1) - .forEach((file) => { - var code = fs.readFileSync(file, "utf8"), - locs = locater.find("o.only", code); - - locs.forEach((loc) => - fail(dedent(` - Please remove the \`o.only\` from ${link(file, `#L${loc.line}`)}. -
-				${pinpoint(code, {line: loc.line, column : loc.cursor})}
-				
- `)) - ) - }); diff --git a/package-lock.json b/package-lock.json index d5785309..3ef8718d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,33 +10,12 @@ "integrity": "sha1-RdW5NXMXtsxVU9/ZmTGEOuCw5To=", "dev": true }, - "abab": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", - "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", - "dev": true - }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "dev": true, - "requires": { - "acorn": "4.0.13" - } - }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", @@ -54,16 +33,6 @@ } } }, - "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "dev": true, - "requires": { - "extend": "3.0.1", - "semver": "5.0.3" - } - }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", @@ -115,16 +84,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "anymatch": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", - "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", - "dev": true, - "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11" - } - }, "app-root-path": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", @@ -140,27 +99,6 @@ "sprintf-js": "1.0.3" } }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "1.1.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -176,30 +114,12 @@ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, "async": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/async/-/async-2.1.2.tgz", @@ -209,24 +129,6 @@ "lodash": "4.17.4" } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true - }, "babel-code-frame": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", @@ -238,221 +140,12 @@ "js-tokens": "3.0.2" } }, - "babel-core": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", - "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", - "dev": true, - "requires": { - "babel-code-frame": "6.22.0", - "babel-generator": "6.25.0", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.24.1", - "babel-runtime": "6.23.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "convert-source-map": "1.5.0", - "debug": "2.6.8", - "json5": "0.5.1", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.7", - "slash": "1.0.0", - "source-map": "0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true - } - } - }, - "babel-generator": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", - "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", - "dev": true, - "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.23.0", - "babel-types": "6.25.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.6", - "trim-right": "1.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true - } - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "babel-template": "6.25.0" - } - }, - "babel-jest": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", - "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-plugin-istanbul": "4.1.4", - "babel-preset-jest": "20.0.3" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0" - } - }, - "babel-plugin-istanbul": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", - "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", - "dev": true, - "requires": { - "find-up": "2.1.0", - "istanbul-lib-instrument": "1.7.4", - "test-exclude": "4.1.1" - } - }, - "babel-plugin-jest-hoist": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz", - "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=", - "dev": true - }, - "babel-polyfill": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", - "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "core-js": "2.4.1", - "regenerator-runtime": "0.10.5" - } - }, - "babel-preset-jest": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", - "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "20.0.3" - } - }, - "babel-register": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", - "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-runtime": "6.23.0", - "core-js": "2.4.1", - "home-or-tmp": "2.0.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "source-map-support": "0.4.15" - } - }, - "babel-runtime": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", - "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", - "dev": true, - "requires": { - "core-js": "2.4.1", - "regenerator-runtime": "0.10.5" - } - }, - "babel-template": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", - "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "lodash": "4.17.4" - } - }, - "babel-traverse": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", - "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", - "dev": true, - "requires": { - "babel-code-frame": "6.22.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.23.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "debug": "2.6.8", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" - } - }, - "babel-types": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", - "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", - "dev": true, - "requires": { - "babel-runtime": "6.23.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" - } - }, - "babylon": { - "version": "6.17.4", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", - "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", - "dev": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, "benchmark": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", @@ -463,15 +156,6 @@ "platform": "1.3.4" } }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -482,49 +166,6 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" - } - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "bser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", - "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", - "dev": true, - "requires": { - "node-int64": "0.4.0" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -540,18 +181,6 @@ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -613,17 +242,6 @@ "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", "dev": true }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - } - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -645,30 +263,6 @@ "weak-map": "1.0.0" } }, - "color-convert": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", @@ -692,24 +286,6 @@ "typedarray": "0.0.6" } }, - "content-type-parser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", - "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", - "dev": true - }, - "convert-source-map": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", - "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", - "dev": true - }, - "core-js": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", - "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -751,30 +327,6 @@ "which": "1.2.14" } }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "cssom": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", - "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", - "dev": true - }, - "cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", - "dev": true, - "requires": { - "cssom": "0.3.2" - } - }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", @@ -784,81 +336,6 @@ "es5-ext": "0.10.24" } }, - "danger": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/danger/-/danger-1.2.0.tgz", - "integrity": "sha512-uFZb/QIGMnuHgireqI1Nu0pLoYGOtCj7E5DD8wUkNyRq0LjDiz3P2M5SMjbgparl8BG+suqmWc+fo3VksSJJnw==", - "dev": true, - "requires": { - "babel-polyfill": "6.23.0", - "chalk": "2.1.0", - "commander": "2.11.0", - "debug": "2.6.8", - "github": "9.2.0", - "jest-config": "20.0.4", - "jest-environment-node": "20.0.3", - "jest-runtime": "20.0.4", - "jsome": "2.3.26", - "jsonpointer": "4.0.1", - "lodash.find": "4.6.0", - "lodash.includes": "4.3.0", - "lodash.isobject": "2.4.1", - "lodash.keys": "4.2.0", - "node-fetch": "1.7.1", - "parse-diff": "0.4.0", - "parse-link-header": "1.0.1", - "rfc6902": "1.3.0", - "voca": "1.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } - }, - "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.2.1" - } - }, - "supports-color": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", - "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", - "dev": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "date-fns": { "version": "1.28.5", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.28.5.tgz", @@ -878,7 +355,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "dev": true, + "optional": true }, "dedent": { "version": "0.7.0", @@ -907,27 +385,6 @@ "rimraf": "2.6.1" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } - }, - "diff": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", - "integrity": "sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg==", - "dev": true - }, "doctrine": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", @@ -938,40 +395,12 @@ "isarray": "1.0.0" } }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, "elegant-spinner": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", "dev": true }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "0.4.13" - } - }, - "errno": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", - "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "dev": true, - "requires": { - "prr": "0.0.0" - } - }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -1222,75 +651,18 @@ "es5-ext": "0.10.24" } }, - "exec-sh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", - "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", - "dev": true, - "requires": { - "merge": "1.2.0" - } - }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "0.1.1" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "2.2.3" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } - }, - "extsprintf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", - "dev": true - }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "2.0.0" - } - }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -1311,34 +683,6 @@ "object-assign": "4.1.1" } }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - } - }, "flat-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", @@ -1351,48 +695,6 @@ "write": "0.2.1" } }, - "follow-redirects": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", - "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", - "dev": true, - "requires": { - "debug": "2.6.8", - "stream-consume": "0.1.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1414,35 +716,12 @@ "is-property": "1.0.2" } }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true - }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "gh-pages": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-0.12.0.tgz", @@ -1488,18 +767,6 @@ } } }, - "github": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/github/-/github-9.2.0.tgz", - "integrity": "sha1-iohtxA3WNjZwfcr5nfPfJsWfFvw=", - "dev": true, - "requires": { - "follow-redirects": "0.0.7", - "https-proxy-agent": "1.0.0", - "mime": "1.3.6", - "netrc": "0.1.4" - } - }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -1514,25 +781,6 @@ "path-is-absolute": "1.0.1" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "2.0.1" - } - }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -1594,22 +842,6 @@ } } }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -1619,83 +851,6 @@ "ansi-regex": "2.1.1" } }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", - "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", - "dev": true, - "requires": { - "whatwg-encoding": "1.0.1" - } - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.1" - } - }, - "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dev": true, - "requires": { - "agent-base": "2.1.1", - "debug": "2.6.8", - "extend": "3.0.1" - } - }, - "iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", - "dev": true - }, "ignore": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", @@ -1760,21 +915,6 @@ "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", "dev": true }, - "invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "requires": { - "loose-envify": "1.3.1" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1787,42 +927,6 @@ "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", @@ -1841,15 +945,6 @@ "number-is-nan": "1.0.1" } }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "1.0.0" - } - }, "is-my-json-valid": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", @@ -1862,15 +957,6 @@ "xtend": "4.0.1" } }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } - }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -1895,18 +981,6 @@ "path-is-inside": "1.0.2" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -1934,18 +1008,6 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1958,21 +1020,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", @@ -2045,243 +1092,6 @@ } } }, - "istanbul-lib-coverage": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", - "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.4.tgz", - "integrity": "sha1-6f2SDkdn89Ge3HZeLWs/XMvQ7qg=", - "dev": true, - "requires": { - "babel-generator": "6.25.0", - "babel-template": "6.25.0", - "babel-traverse": "6.25.0", - "babel-types": "6.25.0", - "babylon": "6.17.4", - "istanbul-lib-coverage": "1.1.1", - "semver": "5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - } - } - }, - "jest-config": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", - "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "glob": "7.1.2", - "jest-environment-jsdom": "20.0.3", - "jest-environment-node": "20.0.3", - "jest-jasmine2": "20.0.4", - "jest-matcher-utils": "20.0.3", - "jest-regex-util": "20.0.3", - "jest-resolve": "20.0.4", - "jest-validate": "20.0.3", - "pretty-format": "20.0.3" - } - }, - "jest-diff": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", - "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "diff": "3.3.0", - "jest-matcher-utils": "20.0.3", - "pretty-format": "20.0.3" - } - }, - "jest-docblock": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz", - "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI=", - "dev": true - }, - "jest-environment-jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", - "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", - "dev": true, - "requires": { - "jest-mock": "20.0.3", - "jest-util": "20.0.3", - "jsdom": "9.12.0" - } - }, - "jest-environment-node": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", - "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", - "dev": true, - "requires": { - "jest-mock": "20.0.3", - "jest-util": "20.0.3" - } - }, - "jest-haste-map": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.4.tgz", - "integrity": "sha1-ZT61XIic48Ah97lGk/IKQVm63wM=", - "dev": true, - "requires": { - "fb-watchman": "2.0.0", - "graceful-fs": "4.1.11", - "jest-docblock": "20.0.3", - "micromatch": "2.3.11", - "sane": "1.6.0", - "worker-farm": "1.4.1" - } - }, - "jest-jasmine2": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", - "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "graceful-fs": "4.1.11", - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-matchers": "20.0.3", - "jest-message-util": "20.0.3", - "jest-snapshot": "20.0.3", - "once": "1.4.0", - "p-map": "1.1.1" - } - }, - "jest-matcher-utils": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", - "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "pretty-format": "20.0.3" - } - }, - "jest-matchers": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", - "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", - "dev": true, - "requires": { - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-message-util": "20.0.3", - "jest-regex-util": "20.0.3" - } - }, - "jest-message-util": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", - "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "micromatch": "2.3.11", - "slash": "1.0.0" - } - }, - "jest-mock": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz", - "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk=", - "dev": true - }, - "jest-regex-util": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz", - "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I=", - "dev": true - }, - "jest-resolve": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", - "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", - "dev": true, - "requires": { - "browser-resolve": "1.11.2", - "is-builtin-module": "1.0.0", - "resolve": "1.3.3" - } - }, - "jest-runtime": { - "version": "20.0.4", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", - "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", - "dev": true, - "requires": { - "babel-core": "6.25.0", - "babel-jest": "20.0.3", - "babel-plugin-istanbul": "4.1.4", - "chalk": "1.1.3", - "convert-source-map": "1.5.0", - "graceful-fs": "4.1.11", - "jest-config": "20.0.4", - "jest-haste-map": "20.0.4", - "jest-regex-util": "20.0.3", - "jest-resolve": "20.0.4", - "jest-util": "20.0.3", - "json-stable-stringify": "1.0.1", - "micromatch": "2.3.11", - "strip-bom": "3.0.0", - "yargs": "7.1.0" - } - }, - "jest-snapshot": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", - "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "jest-diff": "20.0.3", - "jest-matcher-utils": "20.0.3", - "jest-util": "20.0.3", - "natural-compare": "1.4.0", - "pretty-format": "20.0.3" - } - }, - "jest-util": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", - "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "graceful-fs": "4.1.11", - "jest-message-util": "20.0.3", - "jest-mock": "20.0.3", - "jest-validate": "20.0.3", - "leven": "2.1.0", - "mkdirp": "0.5.1" - } - }, - "jest-validate": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", - "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "jest-matcher-utils": "20.0.3", - "leven": "2.1.0", - "pretty-format": "20.0.3" - } - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -2306,97 +1116,6 @@ } } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", - "dev": true, - "requires": { - "abab": "1.0.3", - "acorn": "4.0.13", - "acorn-globals": "3.1.0", - "array-equal": "1.0.0", - "content-type-parser": "1.0.1", - "cssom": "0.3.2", - "cssstyle": "0.2.37", - "escodegen": "1.8.1", - "html-encoding-sniffer": "1.0.1", - "nwmatcher": "1.4.1", - "parse5": "1.5.1", - "request": "2.81.0", - "sax": "1.2.4", - "symbol-tree": "3.2.2", - "tough-cookie": "2.3.2", - "webidl-conversions": "4.0.1", - "whatwg-encoding": "1.0.1", - "whatwg-url": "4.8.0", - "xml-name-validator": "2.0.1" - } - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "jsome": { - "version": "2.3.26", - "resolved": "https://registry.npmjs.org/jsome/-/jsome-2.3.26.tgz", - "integrity": "sha1-jLRDiSTSyd1SlMkK3wPzVBT7PKk=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "json-stringify-safe": "5.0.1", - "yargs": "4.8.1" - }, - "dependencies": { - "yargs": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", - "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "dev": true, - "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "lodash.assign": "4.2.0", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "window-size": "0.2.0", - "y18n": "3.2.1", - "yargs-parser": "2.4.1" - } - }, - "yargs-parser": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", - "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "dev": true, - "requires": { - "camelcase": "3.0.0", - "lodash.assign": "4.2.0" - } - } - } - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", @@ -2406,18 +1125,6 @@ "jsonify": "0.0.0" } }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -2430,26 +1137,6 @@ "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", "dev": true }, - "jsprim": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", - "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -2466,21 +1153,6 @@ "dev": true, "optional": true }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "1.0.0" - } - }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "dev": true - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2591,40 +1263,6 @@ "figures": "1.7.0" } }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "0.2.1" - } - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - } - }, "locater": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/locater/-/locater-1.3.0.tgz", @@ -2637,51 +1275,12 @@ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true - }, "lodash.chunk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=", "dev": true }, - "lodash.find": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", - "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", - "dev": true - }, - "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "2.4.1" - } - }, - "lodash.keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz", - "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=", - "dev": true - }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", @@ -2707,15 +1306,6 @@ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "3.0.2" - } - }, "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", @@ -2726,69 +1316,18 @@ "yallist": "2.1.2" } }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.4" - } - }, "marked": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, - "merge": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", - "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", - "dev": true - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.3" - } - }, "mime": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", "dev": true }, - "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, "mimeparse": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/mimeparse/-/mimeparse-0.1.4.tgz", @@ -2837,28 +1376,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "netrc": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz", - "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=", - "dev": true - }, - "node-fetch": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", - "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", - "dev": true, - "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -2868,27 +1385,6 @@ "abbrev": "1.0.9" } }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.0.3", - "validate-npm-package-license": "3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "1.0.2" - } - }, "npm-path": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.3.tgz", @@ -2924,34 +1420,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "nwmatcher": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", - "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3017,66 +1491,18 @@ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "p-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", - "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", - "dev": true - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "1.1.0" - } - }, "p-map": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", "integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=", "dev": true }, - "parse-diff": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/parse-diff/-/parse-diff-0.4.0.tgz", - "integrity": "sha1-nONbzOj8C3xY9G1xETOU/AtJgt0=", - "dev": true - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" - } - }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -3086,27 +1512,6 @@ "error-ex": "1.3.1" } }, - "parse-link-header": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", - "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", - "dev": true, - "requires": { - "xtend": "4.0.1" - } - }, - "parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3131,23 +1536,6 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true - }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -3193,39 +1581,6 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "pretty-format": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", - "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1", - "ansi-styles": "3.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", - "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } - } - } - }, - "private": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", - "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", - "dev": true - }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -3238,24 +1593,12 @@ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, - "prr": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", - "dev": true - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, "q": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", @@ -3284,95 +1627,6 @@ } } }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "dev": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "1.1.5" - } - } - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } - } - } - }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", @@ -3408,34 +1662,6 @@ "resolve": "1.3.3" } }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true - }, - "regex-cache": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", - "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", - "dev": true, - "requires": { - "is-equal-shallow": "0.1.3", - "is-primitive": "2.0.0" - } - }, - "remove-trailing-separator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", - "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -3451,54 +1677,12 @@ "is-finite": "1.0.2" } }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, "require-from-string": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", "dev": true }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -3534,12 +1718,6 @@ "onetime": "1.1.0" } }, - "rfc6902": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfc6902/-/rfc6902-1.3.0.tgz", - "integrity": "sha1-hbLGnELc8RYIJDe5gpqWJEa0xKU=", - "dev": true - }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -3589,65 +1767,6 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, - "sane": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", - "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", - "dev": true, - "requires": { - "anymatch": "1.3.0", - "exec-sh": "0.2.0", - "fb-watchman": "1.9.2", - "minimatch": "3.0.4", - "minimist": "1.2.0", - "walker": "1.0.7", - "watch": "0.10.0" - }, - "dependencies": { - "bser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", - "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", - "dev": true, - "requires": { - "node-int64": "0.4.0" - } - }, - "fb-watchman": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", - "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", - "dev": true, - "requires": { - "bser": "1.0.2" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -3680,27 +1799,12 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, "slice-ansi": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", @@ -3711,86 +1815,18 @@ "amdefine": "1.0.1" } }, - "source-map-support": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", - "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", - "dev": true, - "requires": { - "source-map": "0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true - } - } - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "dev": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "staged-git-files": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-0.0.4.tgz", "integrity": "sha1-15fhtVHKemOd7AI33G60u5vhfTU=", "dev": true }, - "stream-consume": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", - "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", - "dev": true - }, "stream-to-observable": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", @@ -3817,12 +1853,6 @@ "safe-buffer": "5.1.1" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -3862,12 +1892,6 @@ "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=", "dev": true }, - "symbol-tree": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", - "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", - "dev": true - }, "table": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", @@ -3915,19 +1939,6 @@ } } }, - "test-exclude": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", - "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", - "dev": true, - "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1" - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3940,61 +1951,12 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "dev": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -4105,91 +2067,12 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } - }, - "verror": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", - "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", - "dev": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "voca": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/voca/-/voca-1.3.0.tgz", - "integrity": "sha1-AnUayDm/DJLiz+iOScOTyU3VCsM=", - "dev": true - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.11" - } - }, - "watch": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", - "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", - "dev": true - }, "weak-map": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.0.tgz", "integrity": "sha1-tm5Wqd8L0lp2u/G1FNsSkIBhSjc=", "dev": true }, - "webidl-conversions": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz", - "integrity": "sha1-gBWherg+fhsxFjhIas6B2mziBqA=", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", - "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", - "dev": true, - "requires": { - "iconv-lite": "0.4.13" - } - }, - "whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", - "dev": true, - "requires": { - "tr46": "0.0.3", - "webidl-conversions": "3.0.1" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - } - } - }, "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", @@ -4199,44 +2082,12 @@ "isexe": "2.0.0" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "window-size": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", - "dev": true - }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, - "worker-farm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", - "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", - "dev": true, - "requires": { - "errno": "0.1.4", - "xtend": "4.0.1" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4252,59 +2103,17 @@ "mkdirp": "0.5.1" } }, - "xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", - "dev": true - }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true, - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "5.0.0" - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true, - "requires": { - "camelcase": "3.0.0" - } } } } diff --git a/package.json b/package.json index 7c33d920..1e0f79bb 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "devDependencies": { "@alrra/travis-scripts": "^3.0.1", "benchmark": "^2.1.4", - "danger": "^1.2.0", "dedent": "^0.7.0", "eslint": "^3.19.0", "gh-pages": "^0.12.0", From 6097cfb2e9146c63a3cad3816cd18511b37e7808 Mon Sep 17 00:00:00 2001 From: magikstm Date: Fri, 18 May 2018 14:48:56 -0400 Subject: [PATCH 210/301] Small optimization in render hyperscript.js (#2064) * Small optimization in render hyperscript.js * Remove temporary variable * Small optimization in render hyperscript.js Squashed commits: [5b103291] Small optimization in render hyperscript.js * Remove sloppy mode comment --- render/hyperscript.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/render/hyperscript.js b/render/hyperscript.js index 00c438c9..768dad8f 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -79,16 +79,11 @@ function execSelector(state, attrs, children) { } function hyperscript(selector) { - // Because sloppy mode sucks - var attrs = arguments[1], start = 2, children - if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") { throw Error("The selector must be either a string or a component."); } - if (typeof selector === "string") { - var cached = selectorCache[selector] || compileSelector(selector) - } + var attrs = arguments[1], start = 2, children if (attrs == null) { attrs = {} @@ -108,7 +103,7 @@ function hyperscript(selector) { var normalized = Vnode.normalizeChildren(children) if (typeof selector === "string") { - return execSelector(cached, attrs, normalized) + return execSelector(selectorCache[selector] || compileSelector(selector), attrs, normalized) } else { return Vnode(selector, attrs.key, attrs, normalized) } From 11940b427b6497d4350ad0781d7b5041edbc86bf Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Fri, 18 May 2018 18:50:40 +0000 Subject: [PATCH 211/301] Bundled output for commit 6097cfb2e9146c63a3cad3816cd18511b37e7808 [skip ci] --- README.md | 2 +- mithril.js | 12 +++---- mithril.min.js | 88 +++++++++++++++++++++++++------------------------- 3 files changed, 49 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 296c4c32..6ddbbb0a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.30 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.29 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 11b40899..8b354041 100644 --- a/mithril.js +++ b/mithril.js @@ -78,14 +78,10 @@ function execSelector(state, attrs, children) { return Vnode(state.tag, attrs.key, hasAttrs ? attrs : undefined, childList, text) } function hyperscript(selector) { - // Because sloppy mode sucks - var attrs = arguments[1], start = 2, children if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") { throw Error("The selector must be either a string or a component."); } - if (typeof selector === "string") { - var cached = selectorCache[selector] || compileSelector(selector) - } + var attrs = arguments[1], start = 2, children if (attrs == null) { attrs = {} } else if (typeof attrs !== "object" || attrs.tag != null || Array.isArray(attrs)) { @@ -101,7 +97,7 @@ function hyperscript(selector) { } var normalized = Vnode.normalizeChildren(children) if (typeof selector === "string") { - return execSelector(cached, attrs, normalized) + return execSelector(selectorCache[selector] || compileSelector(selector), attrs, normalized) } else { return Vnode(selector, attrs.key, attrs, normalized) } @@ -635,12 +631,12 @@ var coreRenderer = function($window) { // In the other scenarios (swaps, upwards traversal, map-based diff), // the new vnodes list is traversed upwards. The DOM nodes at the bottom of the list reflect the // bottom part of the new vnodes list, and we can use the `v.dom` value of the previous node - // as the next0 sibling (cached0 in the `nextSibling` variable). + // as the next0 sibling (cached in the `nextSibling` variable). // ## DOM node moves // // In most scenarios `updateNode()` and `createNode()` perform the DOM operations. However, // this is not the case if the node moved (second and fourth part of the diff algo). We move - // the old DOM nodes before updateNode runs0 because it enables us to use the cached0 `nextSibling` + // the old DOM nodes before updateNode runs0 because it enables us to use the cached `nextSibling` // variable rather than fetching it using `getNextSibling()`. // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues diff --git a/mithril.min.js b/mithril.min.js index 67c396ce..3c3b8979 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function x(a,d,e,f,k,l){return{tag:a,key:d,attrs:e,children:f,text:k,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function M(a){for(var d in a)if(C.call(a,d))return!1;return!0}function w(a){var d=arguments[1],e=2;if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a){var f;if(!(f=N[a])){var k="div";for(var l=[],m={};f=R.exec(a);){var p=f[1], -u=f[2];""===p&&""!==u?k=u:"#"===p?m.id=u:"."===p?l.push(u):"["===f[3][0]&&((p=f[6])&&(p=p.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===f[4]?l.push(p):m[f[4]]=""===p?p:p||!0)}0b.indexOf("?")?"?":"&";b+=e+d}return b}function m(b){try{return""!==b?JSON.parse(b):null}catch(A){throw Error(b);}}function p(b){return b.responseText}function u(b,a){if("function"=== -typeof b)if(Array.isArray(a))for(var d=0;dh.status||304===h.status||U.test(b.url))d(u(b.type,a));else{var f=Error(h.responseText);f.code=h.status;f.response=a;e(f)}}catch(V){e(V)}};f&&null!=b.data?h.send(b.data):h.send()});return!0===b.background?A:h(A)},jsonp:function(b,p){var h=e();b=f(b,p);var m=new d(function(d,e){var f=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+r++,h=a.document.createElement("script");a[f]=function(e){h.parentNode.removeChild(h);d(u(b.type,e));delete a[f]};h.onerror=function(){h.parentNode.removeChild(h); -e(Error("JSONP request failed"));delete a[f]};null==b.data&&(b.data={});b.url=k(b.url,b.data);b.data[b.callbackKey||"callback"]=f;h.src=l(b.url,b.data);a.document.documentElement.appendChild(h)});return!0===b.background?m:h(m)},setCompletionCallback:function(b){z=b}}}(window,n),Q=function(a){function d(b,c){if(b.state!==c)throw Error("`vnode.state` must not be modified");}function e(b){var c=b.state;try{return this.apply(c,arguments)}finally{d(b,c)}}function f(b,c,g,a,d,e,f){for(;g'+c.children+"",q=q.firstChild):q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;for(c=y.createDocumentFragment();a=q.firstChild;)c.appendChild(a);z(b,c,d)}function m(b, -c,a,d,e,l){if(c!==a&&(null!=c||null!=a))if(null==c)f(b,a,0,a.length,d,e,l);else if(null==a)A(c,0,c.length);else{for(var q=0,g=0,t=!0,m=!0;g=g&&B>=q;)if(v=c[g],t=a[q],null==v)g++;else if(null==t)q++;else if(v.key===t.key)g++,q++,v!==t&&p(b,v,t,d,r(c,g,e),l);else if(t=a[B],null==v)g++;else if(null== -t)B--;else if(v.key===t.key)g++,q=g&&B>=q;){v=c[m];t=a[B];if(null==v)m--;else{if(null!=t)if(v.key===t.key)v!==t&&p(b,v,t,d,e,l),null!=t.dom&&(e=t.dom),m--;else{if(null==n){n=c;v=g;for(var y=m,x={};vm&&A(c,q,c.length);a.length>m&&f(b,a,q,a.length,d,e,l)}}}function p(a,c,g,d,f,r){var q=c.tag;if(q===g.tag){g.state=c.state;g.events=c.events;var t;var A;null!=g.attrs&&"function"===typeof g.attrs.onbeforeupdate&&(t=e.call(g.attrs.onbeforeupdate,g,c));"string"!==typeof g.tag&&"function"===typeof g.state.onbeforeupdate&& -(A=e.call(g.state.onbeforeupdate,g,c));void 0===t&&void 0===A||t||A?t=!1:(g.dom=c.dom,g.domSize=c.domSize,g.instance=c.instance,t=!0);if(!t)if("string"===typeof q)switch(null!=g.attrs&&J(g.attrs,g,d),q){case "#":c.children.toString()!==g.children.toString()&&(c.dom.nodeValue=g.children);g.dom=c.dom;break;case "<":c.children!==g.children?(u(c),l(a,g,r,f)):(g.dom=c.dom,g.domSize=c.domSize);break;case "[":m(a,c.children,g.children,d,f,r);c=0;d=g.children;g.dom=null;if(null!=d){for(var n=0;nb.indexOf("?")?"?":"&";b+=f+d}return b}function h(b){try{return""!==b?JSON.parse(b):null}catch(A){throw Error(b);}}function p(b){return b.responseText}function r(b,a){if("function"=== +typeof b)if(Array.isArray(a))for(var d=0;dk.status||304===k.status||U.test(b.url))d(r(b.type,a));else{var e=Error(k.responseText);e.code=k.status;e.response=a;f(e)}}catch(V){f(V)}};e&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?A:k(A)},jsonp:function(b,p){var k=e();b=f(b,p);var h=new d(function(d,f){var e=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,k=a.document.createElement("script");a[e]=function(f){k.parentNode.removeChild(k);d(r(b.type,f));delete a[e]};k.onerror=function(){k.parentNode.removeChild(k); +f(Error("JSONP request failed"));delete a[e]};null==b.data&&(b.data={});b.url=u(b.url,b.data);b.data[b.callbackKey||"callback"]=e;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?h:k(h)},setCompletionCallback:function(b){y=b}}}(window,m),Q=function(a){function d(b,c){if(b.state!==c)throw Error("`vnode.state` must not be modified");}function e(b){var c=b.state;try{return this.apply(c,arguments)}finally{d(b,c)}}function f(b,c,g,a,d,f,e){for(;g'+c.children+"",n=n.firstChild):n.innerHTML=c.children;c.dom=n.firstChild;c.domSize=n.childNodes.length;for(c=z.createDocumentFragment();a=n.firstChild;)c.appendChild(a);y(b,c,d)}function h(b, +c,a,d,e,h){if(c!==a&&(null!=c||null!=a))if(null==c)f(b,a,0,a.length,d,e,h);else if(null==a)A(c,0,c.length);else{for(var n=0,g=0,q=!0,l=!0;g=g&&B>=n;)if(v=c[g],q=a[n],null==v)g++;else if(null==q)n++;else if(v.key===q.key)g++,n++,v!==q&&p(b,v,q,d,t(c,g,e),h);else if(q=a[B],null==v)g++;else if(null== +q)B--;else if(v.key===q.key)g++,n=g&&B>=n;){v=c[l];q=a[B];if(null==v)l--;else{if(null!=q)if(v.key===q.key)v!==q&&p(b,v,q,d,e,h),null!=q.dom&&(e=q.dom),l--;else{if(null==m){m=c;v=g;for(var z=l,x={};vl&&A(c,n,c.length);a.length>l&&f(b,a,n,a.length,d,e,h)}}}function p(a,c,g,d,f,t){var n=c.tag;if(n===g.tag){g.state=c.state;g.events=c.events;var q;var A;null!=g.attrs&&"function"===typeof g.attrs.onbeforeupdate&&(q=e.call(g.attrs.onbeforeupdate,g,c));"string"!==typeof g.tag&&"function"===typeof g.state.onbeforeupdate&& +(A=e.call(g.state.onbeforeupdate,g,c));void 0===q&&void 0===A||q||A?q=!1:(g.dom=c.dom,g.domSize=c.domSize,g.instance=c.instance,q=!0);if(!q)if("string"===typeof n)switch(null!=g.attrs&&J(g.attrs,g,d),n){case "#":c.children.toString()!==g.children.toString()&&(c.dom.nodeValue=g.children);g.dom=c.dom;break;case "<":c.children!==g.children?(r(c),l(a,g,t,f)):(g.dom=c.dom,g.domSize=c.domSize);break;case "[":h(a,c.children,g.children,d,f,t);c=0;d=g.children;g.dom=null;if(null!=d){for(var m=0;m Date: Tue, 22 May 2018 16:19:54 +0000 Subject: [PATCH 212/301] [ospec] Make the default reporting nicer looking (#2147) * feat(ospec): Add spacing before report results ...sometimes tested code emits console.log() messages which then blend in with ospec's report * feat(ospec): Reword and prettify the report messages * feat(ospec): Make console.errors more compact, yet more readable * docs(ospec): Update change-log.md * fix(ospec): Fix grammar when number of assertions is 1 * feat(ospec): Make "all passed" message bright green * refactor(ospec): define `cStyle()` helper for browser styling * feat(ospec): Use en-dashes for the horizontal divider * feat(ospec): Revert stacktrace coloring, make context bright red ...and add extra newline above each error - for readability in commandline (node.js) mode * feat(ospec): Improve the only-test-passed message "1 assertion passed" --> "The 1 assertion passed" * docs: Update LOC count --- ospec/README.md | 2 +- ospec/change-log.md | 3 +-- ospec/ospec.js | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index ce42ecf5..38aae7b4 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -7,7 +7,7 @@ Noiseless testing framework ## About -- ~330 LOC including the CLI runner +- ~360 LOC including the CLI runner - terser and faster test code than with mocha, jasmine or tape - test code reads like bullet points - assertion code follows [SVO](https://en.wikipedia.org/wiki/Subject–verb–object) structure in present tense for terseness and readability diff --git a/ospec/change-log.md b/ospec/change-log.md index f0950dd1..bb7102a6 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -2,9 +2,8 @@ ## Upcoming... -_2018-xx-xx_ -- ... +- Improved wording, spacing and color-coding of report messages and errors ([#2147](https://github.com/MithrilJS/mithril.js/pull/2147), [@maranomynet](https://github.com/maranomynet)) ## 2.0.0 diff --git a/ospec/ospec.js b/ospec/ospec.js index f13b1ed0..5674b499 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -231,7 +231,7 @@ else window.o = m() function define(name, verb, compare) { Assert.prototype[name] = function assert(value) { if (compare(this.value, value)) record(null) - else record(serialize(this.value) + "\n" + verb + "\n" + serialize(value)) + else record(serialize(this.value) + "\n " + verb + "\n" + serialize(value)) return function(message) { var result = results[results.length - 1] result.message = message + "\n\n" + result.message @@ -258,8 +258,17 @@ else window.o = m() else if (typeof value === "function") return value.name || "" try {return JSON.stringify(value)} catch (e) {return String(value)} } - function highlight(message) { - return hasProcess ? (process.stdout.isTTY ? "\x1b[31m" + message + "\x1b[0m" : message) : "%c" + message + "%c " + var colorCodes = { + red: "31m", + red2: "31;1m", + green: "32;1m" + } + function highlight(message, color) { + var code = colorCodes[color] || colorCodes.red; + return hasProcess ? (process.stdout.isTTY ? "\x1b[" + code + message + "\x1b[0m" : message) : "%c" + message + "%c " + } + function cStyle(color, bold) { + return hasProcess||!color ? "" : "color:"+color+(bold ? ";font-weight:bold" : "") } o.report = function (results) { @@ -267,14 +276,28 @@ else window.o = m() for (var i = 0, r; r = results[i]; i++) { if (!r.pass) { var stackTrace = o.cleanStackTrace(r.error) - console.error(r.context + ":\n" + highlight(r.message) + (stackTrace ? "\n\n" + stackTrace + "\n\n" : ""), hasProcess ? "" : "color:red", hasProcess ? "" : "color:black") + console.error( + (hasProcess ? "\n" : "") + + highlight(r.context + ":", "red2") + "\n" + + highlight(r.message, "red") + + (stackTrace ? "\n" + stackTrace + "\n" : ""), + + cStyle("black", true), "", // reset to default + cStyle("red"), cStyle("black") + ) errCount++ } } + var pl = results.length === 1 ? "" : "s" + var resultSummary = (errCount === 0) ? + highlight((pl ? "All " : "The ") + results.length + " assertion" + pl + " passed", "green"): + highlight(errCount + " out of " + results.length + " assertion" + pl + " failed", "red2") + var runningTime = " in " + Math.round(Date.now() - start) + "ms" + console.log( - (name ? name + ": " : "") + - results.length + " assertions completed in " + Math.round(new Date - start) + "ms, " + - "of which " + results.filter(function(result){return result.error}).length + " failed" + (hasProcess ? "––––––\n" : "") + + (name ? name + ": " : "") + resultSummary + runningTime, + cStyle((errCount === 0 ? "green" : "red"), true), "" ) return errCount } From 010d8daae9719a034d768664ee3a0a4f451f2304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 21 May 2018 01:17:15 +0200 Subject: [PATCH 213/301] [ospec] pinpoint the o.only() call site --- ospec/change-log.md | 1 + ospec/ospec.js | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index bb7102a6..e037091c 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -3,6 +3,7 @@ ## Upcoming... +- Pinpoint the `o.only()` call site - Improved wording, spacing and color-coding of report messages and errors ([#2147](https://github.com/MithrilJS/mithril.js/pull/2147), [@maranomynet](https://github.com/maranomynet)) diff --git a/ospec/ospec.js b/ospec/ospec.js index 5674b499..526a088e 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -34,7 +34,12 @@ else window.o = m() ctx = parent } o.only = function(subject, predicate, silent) { - if (!silent) console.log(highlight("/!\\ WARNING /!\\ o.only() mode")) + if (!silent) { + console.log(highlight("/!\\ WARNING /!\\ o.only() mode")) + try {throw new Error} catch (e) { + console.log(this.cleanStackTrace(e) + "\n") + } + } o(subject, only = predicate) } o.spy = function(fn) { From 562d68098194d61668eb71fafd790a138eace0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 24 May 2018 18:32:37 +0200 Subject: [PATCH 214/301] [ospec/bin] Back to ES5 (and complimentary cleanup), fix #2160 --- ospec/bin/ospec | 41 ++++++++++++++++++----------------------- ospec/change-log.md | 7 ++++++- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ospec/bin/ospec b/ospec/bin/ospec index a0f56f57..5019f1d2 100755 --- a/ospec/bin/ospec +++ b/ospec/bin/ospec @@ -1,16 +1,16 @@ #!/usr/bin/env node "use strict" -const o = require("../ospec") -const path = require("path") -const glob = require("glob") +var o = require("../ospec") +var path = require("path") +var glob = require("glob") -const parseArgs = (argv) => { +function parseArgs(argv) { argv = ["--globs"].concat(argv.slice(2)) - const args = {} - let name - argv.forEach((arg) => { + var args = {} + var name + argv.forEach(function(arg) { if (/^--/.test(arg)) { name = arg.substr(2) args[name] = args[name] || [] @@ -22,26 +22,21 @@ const parseArgs = (argv) => { } -const args = parseArgs(process.argv) -const globList = args.globs && args.globs.length ? args.globs : ["**/tests/**/*.js"] -const ignore = ["**/node_modules/**"].concat(args.ignore||[]) -const cwd = process.cwd() +var args = parseArgs(process.argv) +var globList = args.globs && args.globs.length ? args.globs : ["**/tests/**/*.js"] +var ignore = ["**/node_modules/**"].concat(args.ignore||[]) +var cwd = process.cwd() args.require && args.require.forEach(function(module) { module && require(require.resolve(module, { basedir: cwd })) }) -let pending = globList.length -globList.forEach((globPattern) => { - glob(globPattern, {ignore}) - .on("match", (fileName) => { require(path.join(cwd, fileName)) }) // eslint-disable-line global-require - .on("error", (e) => console.error(e)) - .on("end", () => { - pending-- - if (pending === 0) { - o.run() - } - }) +var pending = globList.length +globList.forEach(function(globPattern) { + glob(globPattern, {ignore: ignore}) + .on("match", function(fileName) { require(path.join(cwd, fileName)) }) // eslint-disable-line global-require + .on("error", function(e) { console.error(e) }) + .on("end", function() { if (--pending === 0) o.run()}) }); -process.on("unhandledRejection", (e) => { console.log("Uncaught (in promise) " + e.stack) }) +process.on("unhandledRejection", function(e) { console.error("Uncaught (in promise) " + e.stack) }) diff --git a/ospec/change-log.md b/ospec/change-log.md index e037091c..5bd028e5 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -3,9 +3,14 @@ ## Upcoming... -- Pinpoint the `o.only()` call site +### Features +>>>>>>> [ospec/bin] Back to ES5 (and complimentary cleanup), fix #2160 +- Pinpoint the `o.only()` call site ([#2157](https://github.com/MithrilJS/mithril.js/pull/2157)) - Improved wording, spacing and color-coding of report messages and errors ([#2147](https://github.com/MithrilJS/mithril.js/pull/2147), [@maranomynet](https://github.com/maranomynet)) +### Bug fixes +- Convert the exectuable back to plain ES5 [#2160](https://github.com/MithrilJS/mithril.js/issues/2160) ([#2161](https://github.com/MithrilJS/mithril.js/pull/2161)) + ## 2.0.0 _2018-05-09_ From 4e35d0591c7c349478299dae66c183153d8fde90 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 24 May 2018 19:23:20 -0700 Subject: [PATCH 215/301] quick grammar fix (#2163) --- docs/simple-application.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/simple-application.md b/docs/simple-application.md index 9ca3a698..baa46d12 100644 --- a/docs/simple-application.md +++ b/docs/simple-application.md @@ -240,7 +240,7 @@ Now we can style the `UserList` component: The CSS above is written using a convention of keeping all styles for a rule in a single line, in alphabetical order. This convention is designed to take maximum advantage of screen real estate, and makes it easier to scan the CSS selectors (since they are always on the left side) and their logical grouping, and it enforces predictable and uniform placement of CSS rules for each selector. -Obviously you can use whatever spacing/indentation convention you prefer. The example above is just an illustration of a not-so-widespread convention that has strong rationales behind it, but deviate from the more widespread cosmetic-oriented spacing conventions. +Obviously you can use whatever spacing/indentation convention you prefer. The example above is just an illustration of a not-so-widespread convention that has strong rationales behind it, but deviates from the more widespread cosmetic-oriented spacing conventions. Reloading the browser window now should display some styled elements. From 2969b8323c7db90349b74644ce629512ffaf03f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 15:09:31 +0200 Subject: [PATCH 216/301] ospec v2.1.0 --- ospec/change-log.md | 2 ++ ospec/package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 5bd028e5..4b41f937 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -3,6 +3,8 @@ ## Upcoming... + +## 2.1.0 ### Features >>>>>>> [ospec/bin] Back to ES5 (and complimentary cleanup), fix #2160 - Pinpoint the `o.only()` call site ([#2157](https://github.com/MithrilJS/mithril.js/pull/2157)) diff --git a/ospec/package.json b/ospec/package.json index 0d83df7b..2f9113b5 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "2.0.0", + "version": "2.1.0", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From 64b1e47e66e772b813b005cd13a66084dd94adac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 16:18:31 +0200 Subject: [PATCH 217/301] Change log cleanup --- ospec/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 4b41f937..21a69058 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -5,8 +5,8 @@ ## 2.1.0 +_2018-05-25_ ### Features ->>>>>>> [ospec/bin] Back to ES5 (and complimentary cleanup), fix #2160 - Pinpoint the `o.only()` call site ([#2157](https://github.com/MithrilJS/mithril.js/pull/2157)) - Improved wording, spacing and color-coding of report messages and errors ([#2147](https://github.com/MithrilJS/mithril.js/pull/2147), [@maranomynet](https://github.com/maranomynet)) From 0f498e0aec23a2e638fa81b4e354627fd3656385 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Thu, 17 May 2018 00:05:54 -0500 Subject: [PATCH 218/301] Fix stack trace edge case --- ospec/ospec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 526a088e..8c55b39a 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -72,7 +72,7 @@ else window.o = m() } if (ospecFileName == null) return stack.join("\n") // skip ospec-related entries on the stack - while (stack[i].indexOf(ospecFileName) !== -1) i++ + while (stack[i] && stack[i].indexOf(ospecFileName) !== -1) i++ // now we're in user code return stack[i] } From 1579fe84301824cea1f0d2c86971cc0116146dd9 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Tue, 29 May 2018 10:53:16 +0100 Subject: [PATCH 219/301] Do not normalise component children on ingestion (#2155) * Do not normalise component children on ingestion * Don't normalise vnode children * Component hyperscript tests: children aren't normalised * test, not text * Update change log: #2155 & #2064 --- docs/change-log.md | 1 + render/hyperscript.js | 6 ++-- render/tests/index.html | 1 + render/tests/test-hyperscript.js | 25 +++++++++----- .../tests/test-normalizeComponentChildren.js | 34 +++++++++++++++++++ render/vnode.js | 7 ++-- 6 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 render/tests/test-normalizeComponentChildren.js diff --git a/docs/change-log.md b/docs/change-log.md index dee3406b..0ee241d9 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -19,6 +19,7 @@ #### Breaking changes +- API: Component vnode `children` are not normalized into vnodes on ingestion; normalization only happens if and when they are ingested by the view ([#2155](https://github.com/MithrilJS/mithril.js/pull/2155/) (thanks to [@magikstm](https://github.com/magikstm) for related optimization [#2064](https://github.com/MithrilJS/mithril.js/pull/2064))) - API: `m.redraw()` is always asynchronous ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: `m.mount()` will only render its own root when called, it will not trigger a `redraw()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Assigning to `vnode.state` (as in `vnode.state = ...`) is no longer supported. Instead, an error is thrown if `vnode.state` changes upon the invocation of a lifecycle hook. diff --git a/render/hyperscript.js b/render/hyperscript.js index 768dad8f..8573559c 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -100,12 +100,10 @@ function hyperscript(selector) { while (start < arguments.length) children.push(arguments[start++]) } - var normalized = Vnode.normalizeChildren(children) - if (typeof selector === "string") { - return execSelector(selectorCache[selector] || compileSelector(selector), attrs, normalized) + return execSelector(selectorCache[selector] || compileSelector(selector), attrs, Vnode.normalizeChildren(children)) } else { - return Vnode(selector, attrs.key, attrs, normalized) + return Vnode(selector, attrs.key, attrs, children) } } diff --git a/render/tests/index.html b/render/tests/index.html index eda51921..5c9fc0b7 100644 --- a/render/tests/index.html +++ b/render/tests/index.html @@ -21,6 +21,7 @@ + diff --git a/render/tests/test-hyperscript.js b/render/tests/test-hyperscript.js index f7c5f889..f221bef7 100644 --- a/render/tests/test-hyperscript.js +++ b/render/tests/test-hyperscript.js @@ -551,19 +551,29 @@ o.spec("hyperscript", function() { o.spec("components", function() { o("works with POJOs", function() { var component = { - view: function() { - return m("div") - } + view: function() {} } var vnode = m(component, {id: "a"}, "b") o(vnode.tag).equals(component) o(vnode.attrs.id).equals("a") o(vnode.children.length).equals(1) - o(vnode.children[0].tag).equals("#") - o(vnode.children[0].children).equals("b") + o(vnode.children[0]).equals("b") }) - o("works with functions", function() { + o("works with constructibles", function() { + var component = o.spy() + component.prototype.view = function() {} + + var vnode = m(component, {id: "a"}, "b") + + o(component.callCount).equals(0) + + o(vnode.tag).equals(component) + o(vnode.attrs.id).equals("a") + o(vnode.children.length).equals(1) + o(vnode.children[0]).equals("b") + }) + o("works with closures", function () { var component = o.spy() var vnode = m(component, {id: "a"}, "b") @@ -573,8 +583,7 @@ o.spec("hyperscript", function() { o(vnode.tag).equals(component) o(vnode.attrs.id).equals("a") o(vnode.children.length).equals(1) - o(vnode.children[0].tag).equals("#") - o(vnode.children[0].children).equals("b") + o(vnode.children[0]).equals("b") }) }) }) diff --git a/render/tests/test-normalizeComponentChildren.js b/render/tests/test-normalizeComponentChildren.js new file mode 100644 index 00000000..86f75ffe --- /dev/null +++ b/render/tests/test-normalizeComponentChildren.js @@ -0,0 +1,34 @@ +"use strict" + +var o = require("../../ospec/ospec") +var m = require("../../render/hyperscript") +var domMock = require("../../test-utils/domMock") +var vdom = require("../../render/render") + +o.spec("component children", function () { + var $window = domMock() + var root = $window.document.createElement("div") + var render = vdom($window).render + + o.spec("component children", function () { + var component = { + view: function (vnode) { + return vnode.children + } + } + + var vnode = m(component, "a") + + render(root, vnode) + + o("are not normalized on ingestion", function () { + o(vnode.children[0]).equals("a") + }) + + o("are normalized upon view interpolation", function () { + o(vnode.instance.children.length).equals(1) + o(vnode.instance.children[0].tag).equals("#") + o(vnode.instance.children[0].children).equals("a") + }) + }) +}) diff --git a/render/vnode.js b/render/vnode.js index 13ed393f..5873dca5 100644 --- a/render/vnode.js +++ b/render/vnode.js @@ -8,9 +8,10 @@ Vnode.normalize = function(node) { if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined) return node } -Vnode.normalizeChildren = function normalizeChildren(children) { - for (var i = 0; i < children.length; i++) { - children[i] = Vnode.normalize(children[i]) +Vnode.normalizeChildren = function normalizeChildren(input) { + var children = [] + for (var i = 0; i < input.length; i++) { + children[i] = Vnode.normalize(input[i]) } return children } From da0c5c9b9aca91f613c81729463f149fbf930292 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 29 May 2018 09:54:58 +0000 Subject: [PATCH 220/301] Bundled output for commit 1579fe84301824cea1f0d2c86971cc0116146dd9 [skip ci] --- mithril.js | 58 ++++++++++++++++----------------- mithril.min.js | 88 +++++++++++++++++++++++++------------------------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/mithril.js b/mithril.js index 8b354041..63f91953 100644 --- a/mithril.js +++ b/mithril.js @@ -8,9 +8,10 @@ Vnode.normalize = function(node) { if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined) return node } -Vnode.normalizeChildren = function normalizeChildren(children) { - for (var i = 0; i < children.length; i++) { - children[i] = Vnode.normalize(children[i]) +Vnode.normalizeChildren = function normalizeChildren(input) { + var children = [] + for (var i = 0; i < input.length; i++) { + children[i] = Vnode.normalize(input[i]) } return children } @@ -95,19 +96,18 @@ function hyperscript(selector) { children = [] while (start < arguments.length) children.push(arguments[start++]) } - var normalized = Vnode.normalizeChildren(children) if (typeof selector === "string") { - return execSelector(selectorCache[selector] || compileSelector(selector), attrs, normalized) + return execSelector(selectorCache[selector] || compileSelector(selector), attrs, Vnode.normalizeChildren(children)) } else { - return Vnode(selector, attrs.key, attrs, normalized) + return Vnode(selector, attrs.key, attrs, children) } } hyperscript.trust = function(html) { if (html == null) html = "" return Vnode("<", undefined, undefined, html, undefined, undefined) } -hyperscript.fragment = function(attrs1, children) { - return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children), undefined, undefined) +hyperscript.fragment = function(attrs1, children0) { + return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children0), undefined, undefined) } var m = hyperscript /** @constructor */ @@ -487,8 +487,8 @@ var coreRenderer = function($window) { function createFragment(parent, vnode, hooks, ns, nextSibling) { var fragment = $doc.createDocumentFragment() if (vnode.children != null) { - var children = vnode.children - createNodes(fragment, children, 0, children.length, hooks, null, ns) + var children1 = vnode.children + createNodes(fragment, children1, 0, children1.length, hooks, null, ns) } vnode.dom = fragment.firstChild vnode.domSize = fragment.childNodes.length @@ -516,8 +516,8 @@ var coreRenderer = function($window) { else vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)] } if (vnode.children != null) { - var children = vnode.children - createNodes(element, children, 0, children.length, hooks, null, ns) + var children1 = vnode.children + createNodes(element, children1, 0, children1.length, hooks, null, ns) setLateAttrs(vnode) } } @@ -790,11 +790,11 @@ var coreRenderer = function($window) { } function updateFragment(parent, old, vnode, hooks, nextSibling, ns) { updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns) - var domSize = 0, children = vnode.children + var domSize = 0, children1 = vnode.children vnode.dom = null - if (children != null) { - for (var i = 0; i < children.length; i++) { - var child = children[i] + if (children1 != null) { + for (var i = 0; i < children1.length; i++) { + var child = children1[i] if (child != null && child.dom != null) { if (vnode.dom == null) vnode.dom = child.dom domSize += child.domSize || 1 @@ -809,7 +809,7 @@ var coreRenderer = function($window) { if (vnode.tag === "textarea") { if (vnode.attrs == null) vnode.attrs = {} if (vnode.text != null) { - vnode.attrs.value = vnode.text //FIXME handle0 multiple children + vnode.attrs.value = vnode.text //FIXME handle0 multiple children1 vnode.text = undefined } } @@ -882,12 +882,12 @@ var coreRenderer = function($window) { else parent.appendChild(dom) } function setContentEditable(vnode) { - var children = vnode.children - if (children != null && children.length === 1 && children[0].tag === "<") { - var content = children[0].children + var children1 = vnode.children + if (children1 != null && children1.length === 1 && children1[0].tag === "<") { + var content = children1[0].children if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content } - else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") + else if (vnode.text != null || children1 != null && children1.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove function removeNodes(vnodes, start, end) { @@ -944,10 +944,10 @@ var coreRenderer = function($window) { if (typeof vnode.state.onremove === "function") callHook.call(vnode.state.onremove, vnode) if (vnode.instance != null) onremove(vnode.instance) } else { - var children = vnode.children - if (Array.isArray(children)) { - for (var i = 0; i < children.length; i++) { - var child = children[i] + var children1 = vnode.children + if (Array.isArray(children1)) { + for (var i = 0; i < children1.length; i++) { + var child = children1[i] if (child != null) onremove(child) } } @@ -972,19 +972,19 @@ var coreRenderer = function($window) { else if (key2 === "style") updateStyle(element, old, value) else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) { if (key2 === "value") { - var normalized0 = "" + value // eslint-disable-line no-implicit-coercion + var normalized = "" + value // eslint-disable-line no-implicit-coercion //setting input[value] to same value by typing on focused element moves cursor to end in Chrome - if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === normalized0 && vnode.dom === $doc.activeElement) return + if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return //setting select[value] to same value while having select open blinks select dropdown in Chrome if (vnode.tag === "select") { if (value === null) { if (vnode.dom.selectedIndex === -1 && vnode.dom === $doc.activeElement) return } else { - if (old !== null && vnode.dom.value === normalized0 && vnode.dom === $doc.activeElement) return + if (old !== null && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return } } //setting option[value] to same value while having select open blinks select dropdown in Chrome - if (vnode.tag === "option" && old != null && vnode.dom.value === normalized0) return + if (vnode.tag === "option" && old != null && vnode.dom.value === normalized) return } // If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error1 will occur. if (vnode.tag === "input" && key2 === "type") { diff --git a/mithril.min.js b/mithril.min.js index 3c3b8979..2ec17ce2 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,45 @@ -(function(){function x(a,d,e,f,u,l){return{tag:a,key:d,attrs:e,children:f,text:u,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function M(a){for(var d in a)if(C.call(a,d))return!1;return!0}function w(a){if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");var d=arguments[1],e=2;if(null==d)d={};else if("object"!==typeof d||null!=d.tag||Array.isArray(d))d={},e=1;if(arguments.length=== -e+1){var f=arguments[e];Array.isArray(f)||(f=[f])}else for(f=[];eb.indexOf("?")?"?":"&";b+=f+d}return b}function h(b){try{return""!==b?JSON.parse(b):null}catch(A){throw Error(b);}}function p(b){return b.responseText}function r(b,a){if("function"=== -typeof b)if(Array.isArray(a))for(var d=0;dk.status||304===k.status||U.test(b.url))d(r(b.type,a));else{var e=Error(k.responseText);e.code=k.status;e.response=a;f(e)}}catch(V){f(V)}};e&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?A:k(A)},jsonp:function(b,p){var k=e();b=f(b,p);var h=new d(function(d,f){var e=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,k=a.document.createElement("script");a[e]=function(f){k.parentNode.removeChild(k);d(r(b.type,f));delete a[e]};k.onerror=function(){k.parentNode.removeChild(k); -f(Error("JSONP request failed"));delete a[e]};null==b.data&&(b.data={});b.url=u(b.url,b.data);b.data[b.callbackKey||"callback"]=e;k.src=l(b.url,b.data);a.document.documentElement.appendChild(k)});return!0===b.background?h:k(h)},setCompletionCallback:function(b){y=b}}}(window,m),Q=function(a){function d(b,c){if(b.state!==c)throw Error("`vnode.state` must not be modified");}function e(b){var c=b.state;try{return this.apply(c,arguments)}finally{d(b,c)}}function f(b,c,g,a,d,f,e){for(;g'+c.children+"",n=n.firstChild):n.innerHTML=c.children;c.dom=n.firstChild;c.domSize=n.childNodes.length;for(c=z.createDocumentFragment();a=n.firstChild;)c.appendChild(a);y(b,c,d)}function h(b, -c,a,d,e,h){if(c!==a&&(null!=c||null!=a))if(null==c)f(b,a,0,a.length,d,e,h);else if(null==a)A(c,0,c.length);else{for(var n=0,g=0,q=!0,l=!0;g=g&&B>=n;)if(v=c[g],q=a[n],null==v)g++;else if(null==q)n++;else if(v.key===q.key)g++,n++,v!==q&&p(b,v,q,d,t(c,g,e),h);else if(q=a[B],null==v)g++;else if(null== -q)B--;else if(v.key===q.key)g++,n=g&&B>=n;){v=c[l];q=a[B];if(null==v)l--;else{if(null!=q)if(v.key===q.key)v!==q&&p(b,v,q,d,e,h),null!=q.dom&&(e=q.dom),l--;else{if(null==m){m=c;v=g;for(var z=l,x={};vl&&A(c,n,c.length);a.length>l&&f(b,a,n,a.length,d,e,h)}}}function p(a,c,g,d,f,t){var n=c.tag;if(n===g.tag){g.state=c.state;g.events=c.events;var q;var A;null!=g.attrs&&"function"===typeof g.attrs.onbeforeupdate&&(q=e.call(g.attrs.onbeforeupdate,g,c));"string"!==typeof g.tag&&"function"===typeof g.state.onbeforeupdate&& -(A=e.call(g.state.onbeforeupdate,g,c));void 0===q&&void 0===A||q||A?q=!1:(g.dom=c.dom,g.domSize=c.domSize,g.instance=c.instance,q=!0);if(!q)if("string"===typeof n)switch(null!=g.attrs&&J(g.attrs,g,d),n){case "#":c.children.toString()!==g.children.toString()&&(c.dom.nodeValue=g.children);g.dom=c.dom;break;case "<":c.children!==g.children?(r(c),l(a,g,t,f)):(g.dom=c.dom,g.domSize=c.domSize);break;case "[":h(a,c.children,g.children,d,f,t);c=0;d=g.children;g.dom=null;if(null!=d){for(var m=0;ma.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(A){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"=== +typeof a)if(Array.isArray(b))for(var d=0;dk.status||304===k.status||U.test(a.url))d(r(a.type,b));else{var g=Error(k.responseText);g.code=k.status;g.response=b;e(g)}}catch(V){e(V)}};g&&null!=a.data?k.send(a.data):k.send()});return!0===a.background?A:k(A)},jsonp:function(a,p){var k=e();a=g(a,p);var h=new d(function(d,e){var g=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,k=b.document.createElement("script");b[g]=function(e){k.parentNode.removeChild(k);d(r(a.type,e));delete b[g]};k.onerror=function(){k.parentNode.removeChild(k); +e(Error("JSONP request failed"));delete b[g]};null==a.data&&(a.data={});a.url=u(a.url,a.data);a.data[a.callbackKey||"callback"]=g;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?h:k(h)},setCompletionCallback:function(a){y=a}}}(window,m),Q=function(b){function d(a,c){if(a.state!==c)throw Error("`vnode.state` must not be modified");}function e(a){var c=a.state;try{return this.apply(c,arguments)}finally{d(a,c)}}function g(a,c,f,b,d,e,g){for(;f'+c.children+"",n=n.firstChild):n.innerHTML=c.children;c.dom=n.firstChild;c.domSize=n.childNodes.length;for(c=z.createDocumentFragment();f=n.firstChild;)c.appendChild(f);y(a,c,b)}function h(a, +c,b,d,e,h){if(c!==b&&(null!=c||null!=b))if(null==c)g(a,b,0,b.length,d,e,h);else if(null==b)A(c,0,c.length);else{for(var n=0,f=0,q=!0,l=!0;f=f&&B>=n;)if(v=c[f],q=b[n],null==v)f++;else if(null==q)n++;else if(v.key===q.key)f++,n++,v!==q&&p(a,v,q,d,t(c,f,e),h);else if(q=b[B],null==v)f++;else if(null== +q)B--;else if(v.key===q.key)f++,n=f&&B>=n;){v=c[l];q=b[B];if(null==v)l--;else{if(null!=q)if(v.key===q.key)v!==q&&p(a,v,q,d,e,h),null!=q.dom&&(e=q.dom),l--;else{if(null==m){m=c;v=f;for(var z=l,x={};vl&&A(c,n,c.length);b.length>l&&g(a,b,n,b.length,d,e,h)}}}function p(b,c,f,d,g,t){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var q;var A;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(q=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&& +(A=e.call(f.state.onbeforeupdate,f,c));void 0===q&&void 0===A||q||A?q=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,q=!0);if(!q)if("string"===typeof n)switch(null!=f.attrs&&J(f.attrs,f,d),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(r(c),l(b,f,t,g)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":h(b,c.children,f.children,d,g,t);c=0;d=f.children;f.dom=null;if(null!=d){for(var m=0;m Date: Thu, 24 May 2018 22:44:19 +0200 Subject: [PATCH 221/301] [ospec] give async timeouts a proper stack trace --- ospec/ospec.js | 51 ++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 8c55b39a..480e675e 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -17,7 +17,7 @@ else window.o = m() return new Assert(subject) } else if (results == null) { - ctx[unique(subject)] = predicate + ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error)) } else { throw new Error("Test definition shouldn't be nested. To group tests use `o.spec()`") } @@ -37,7 +37,7 @@ else window.o = m() if (!silent) { console.log(highlight("/!\\ WARNING /!\\ o.only() mode")) try {throw new Error} catch (e) { - console.log(this.cleanStackTrace(e) + "\n") + console.log(o.cleanStackTrace(e) + "\n") } } o(subject, only = predicate) @@ -79,7 +79,7 @@ else window.o = m() o.run = function(reporter) { results = [] start = new Date - test(spec, [], [], function() { + test(spec, [], [], new Task(function() { setTimeout(function () { if (typeof reporter === "function") reporter(results) else { @@ -87,38 +87,39 @@ else window.o = m() if (hasProcess && errCount !== 0) process.exit(1) } }) - }) + }, null)) function test(spec, pre, post, finalize) { pre = [].concat(pre, spec["__beforeEach"] || []) post = [].concat(spec["__afterEach"] || [], post) series([].concat(spec["__before"] || [], Object.keys(spec).map(function(key) { - return function(done, timeout) { + return new Task(function(done, timeout) { timeout(Infinity) - if (key.slice(0, 2) === "__") return done() - if (only !== null && spec[key] !== only && typeof only === typeof spec[key]) return done() - subjects.push(key) - var type = typeof spec[key] - if (type === "object") test(spec[key], pre, post, pop) - if (type === "function") series([].concat(pre, spec[key], post, pop)) + if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() - function pop() { + subjects.push(key) + var pop = new Task(function pop() { subjects.pop() done() - } - } + }, null) + + if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop)) + else test(spec[key], pre, post, pop) + + }, null) }), spec["__after"] || [], finalize)) } - function series(fns) { + function series(tasks) { var cursor = 0 next() function next() { - if (cursor === fns.length) return + if (cursor === tasks.length) return - var fn = fns[cursor++] + var task = tasks[cursor++] + var fn = task.fn var timeout = 0, delay = 200, s = new Date var isDone = false @@ -142,7 +143,7 @@ else window.o = m() function startTimer() { timeout = setTimeout(function() { timeout = undefined - record("async test timed out") + record("async test timed out", task.err) next() }, Math.min(delay, 2147483647)) } @@ -183,7 +184,7 @@ else window.o = m() function hook(name) { return function(predicate) { if (ctx[name]) throw new Error("This hook should be defined outside of a loop or inside a nested test group:\n" + predicate) - ctx[name] = predicate + ctx[name] = new Task(predicate, ensureStackTrace(new Error)) } } @@ -233,6 +234,7 @@ else window.o = m() } function Assert(value) {this.value = value} + function Task(fn, err) {this.fn = fn, this.err = err} function define(name, verb, compare) { Assert.prototype[name] = function assert(value) { if (compare(this.value, value)) record(null) @@ -246,10 +248,7 @@ else window.o = m() function record(message, error) { var result = {pass: message === null} if (result.pass === false) { - if (error == null) { - error = new Error - if (error.stack === undefined) new function() {try {throw error} catch (e) {error = e}} - } + if (error == null) error = ensureStackTrace(new Error) result.context = subjects.join(" > ") result.message = message result.error = error @@ -275,7 +274,11 @@ else window.o = m() function cStyle(color, bold) { return hasProcess||!color ? "" : "color:"+color+(bold ? ";font-weight:bold" : "") } - + function ensureStackTrace(error) { + // mandatory to get a stack in IE 10 and 11 (and maybe other envs?) + if (error.stack === undefined) try { throw error } catch(e) {return e} + else return error + } o.report = function (results) { var errCount = 0 for (var i = 0, r; r = results[i]; i++) { From 89b665fbf62bf854784f21b69c6d1232c2986718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 15:07:45 +0200 Subject: [PATCH 222/301] [ospec] revamp async testing finalization --- ospec/ospec.js | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 480e675e..6b7d72f1 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -5,12 +5,10 @@ if (typeof module !== "undefined") module["exports"] = m() else window.o = m() })(function init(name) { var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty + var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName if (name != null) spec[name] = ctx = {} - try {throw new Error} catch (e) { - var ospecFileName = e.stack && (/[\/\\](.*?):\d+:\d+/).test(e.stack) ? e.stack.match(/[\/\\](.*?):\d+:\d+/)[1] : null - } function o(subject, predicate) { if (predicate === undefined) { if (results == null) throw new Error("Assertions should not occur outside test definitions") @@ -72,8 +70,8 @@ else window.o = m() } if (ospecFileName == null) return stack.join("\n") // skip ospec-related entries on the stack - while (stack[i] && stack[i].indexOf(ospecFileName) !== -1) i++ - // now we're in user code + while (stack[i] != null && stack[i].indexOf(ospecFileName) !== -1) i++ + // now we're in user code (or past the stack end) return stack[i] } o.run = function(reporter) { @@ -81,6 +79,7 @@ else window.o = m() start = new Date test(spec, [], [], new Task(function() { setTimeout(function () { + timeoutStackName = getStackName({stack: o.cleanStackTrace(ensureStackTrace(new Error))}, /([\w \.]+?:\d+:\d+)/) if (typeof reporter === "function") reporter(results) else { var errCount = o.report(results) @@ -119,50 +118,54 @@ else window.o = m() if (cursor === tasks.length) return var task = tasks[cursor++] + var current = cursor var fn = task.fn var timeout = 0, delay = 200, s = new Date - var isDone = false + var arg + var isDone = false + // public API, may only be called once from use code (or after returned Promise resolution) function done(err) { + if (!isDone) isDone = true + else throw new Error("`" + arg + "()` should only be called once") + + if (timeout === undefined) console.warn("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms\n" + o.cleanStackTrace(task.err)) + finalizeAsync(err) + } + // for internal use only + function finalizeAsync(err) { if (err) { - if (err instanceof Error) record(err.message, err) - else record(String(err)) - subjects.pop() - next() + if (err instanceof Error) record(err.message, err, task.err) + else record(String(err), null, task.err) } if (timeout !== undefined) { timeout = clearTimeout(timeout) if (delay !== Infinity) record(null) - if (!isDone) next() - else throw new Error("`" + arg + "()` should only be called once") - isDone = true } - else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms") + if (current === cursor) next() } function startTimer() { timeout = setTimeout(function() { timeout = undefined - record("async test timed out", task.err) - next() + finalizeAsync("async test timed out") }, Math.min(delay, 2147483647)) } if (fn.length > 0) { var body = fn.toString() - var arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() + arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once") try { fn(done, function(t) {delay = t}) } catch (e) { - done(e) + finalizeAsync(e) } if (timeout === 0) { startTimer() } - } - else { + } else { var p = fn() if (p && p.then) { startTimer() @@ -245,14 +248,13 @@ else window.o = m() } } } - function record(message, error) { + function record(message, error, fallbackError) { var result = {pass: message === null} if (result.pass === false) { - if (error == null) error = ensureStackTrace(new Error) result.context = subjects.join(" > ") result.message = message - result.error = error - + result.error = error != null ? error : ensureStackTrace(new Error) + result.fallbackError = fallbackError } results.push(result) } @@ -279,11 +281,17 @@ else window.o = m() if (error.stack === undefined) try { throw error } catch(e) {return e} else return error } + function getStackName(e, exp) { + return e.stack && exp.test(e.stack) ? e.stack.match(exp)[1] : null + } + o.report = function (results) { var errCount = 0 for (var i = 0, r; r = results[i]; i++) { if (!r.pass) { var stackTrace = o.cleanStackTrace(r.error) + var couldHaveABetterStackTrace = !stackTrace || timeoutStackName != null && stackTrace.indexOf(timeoutStackName) !== -1 + if (couldHaveABetterStackTrace) stackTrace = r.fallbackError != null ? o.cleanStackTrace(r.fallbackError) : r.error.stack || "" console.error( (hasProcess ? "\n" : "") + highlight(r.context + ":", "red2") + "\n" + From b292f75bd852d015231d6072cedf720071a4b84a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 18:38:31 +0200 Subject: [PATCH 223/301] [ospec] don't count succesful async test termination as a test success --- ospec/ospec.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 6b7d72f1..60fe6d3f 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -138,10 +138,7 @@ else window.o = m() if (err instanceof Error) record(err.message, err, task.err) else record(String(err), null, task.err) } - if (timeout !== undefined) { - timeout = clearTimeout(timeout) - if (delay !== Infinity) record(null) - } + if (timeout !== undefined) timeout = clearTimeout(timeout) if (current === cursor) next() } From 64680425e74100b1358c8cba1268f734afe20392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 22:43:53 +0200 Subject: [PATCH 224/301] [ospec] Add o.timeout() to set a timeout for Promise-based async tests --- ospec/ospec.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 60fe6d3f..2b98c072 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -6,7 +6,7 @@ else window.o = m() })(function init(name) { var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName - + var globalTimeout = noTimeoutRightNow if (name != null) spec[name] = ctx = {} function o(subject, predicate) { @@ -74,6 +74,9 @@ else window.o = m() // now we're in user code (or past the stack end) return stack[i] } + o.timeout = function(n) { + globalTimeout(n) + } o.run = function(reporter) { results = [] start = new Date @@ -123,6 +126,8 @@ else window.o = m() var timeout = 0, delay = 200, s = new Date var arg + globalTimeout = setDelay + var isDone = false // public API, may only be called once from use code (or after returned Promise resolution) function done(err) { @@ -141,7 +146,6 @@ else window.o = m() if (timeout !== undefined) timeout = clearTimeout(timeout) if (current === cursor) next() } - function startTimer() { timeout = setTimeout(function() { timeout = undefined @@ -149,12 +153,14 @@ else window.o = m() }, Math.min(delay, 2147483647)) } + function setDelay (t) {delay = t} + if (fn.length > 0) { var body = fn.toString() arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once") try { - fn(done, function(t) {delay = t}) + fn(done, setDelay) } catch (e) { finalizeAsync(e) @@ -171,6 +177,7 @@ else window.o = m() nextTickish(next) } } + globalTimeout = noTimeoutRightNow } } } @@ -261,6 +268,9 @@ else window.o = m() else if (typeof value === "function") return value.name || "" try {return JSON.stringify(value)} catch (e) {return String(value)} } + function noTimeoutRightNow() { + throw new Error("o.timeout must be called snchronously from within a test definition or a hook") + } var colorCodes = { red: "31m", red2: "31;1m", From 8d78d493a7a730a7c9bd3928e3a10768778833d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 15:07:52 +0200 Subject: [PATCH 225/301] [ospec] tests for the done() callback --- ospec/tests/test-ospec.js | 225 ++++++++++++++++++++++++++++++++++---- 1 file changed, 203 insertions(+), 22 deletions(-) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 526671c6..753acdf8 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -180,41 +180,222 @@ o.spec("ospec", function() { }) o.spec("async callback", function() { var a = 0, b = 0 + o.after(function() { + o(a).equals(0) + o(b).equals(0) + }) + o.spec("", function(){ + o.before(function(done) { + callAsync(function() { + a = 1 + done() + }) + }) + o.after(function(done) { + callAsync(function() { + a = 0 + done() + }) + }) + + o.beforeEach(function(done) { + o(b).equals(0) + callAsync(function() { + b = 1 + done() + }) + }) + o.afterEach(function(done) { + callAsync(function() { + b = 0 + done() + }) + }) + + o("hooks work as intended the first time", function(done) { + callAsync(function() { + var spy = o.spy() + spy(a) + + o(a).equals(1) + o(b).equals(1) + + done() + }) + }) + o("hooks work as intended the second time", function(done) { + callAsync(function() { + var spy = o.spy() + spy(a) + + o(a).equals(1) + o(b).equals(1) + + done() + }) + }) + }) + }) + + o.spec("timeout", function () { + o("when using done()", function(done) { + var oo = o.new() + var err + // the success of this test is dependent on having the + // oo() call three linew below this one + try {throw new Error} catch(e) {err = e} + if (err.stack) { + var line = Number(err.stack.match(/:(\d+):/)[1]) + oo("", function(oodone, timeout) { + // oodone() keep this line for now + timeout(1) + }) + oo.run((function(results) { + o(results.length).equals(1) + o(results[0].pass).equals(false) + // todo test cleaned up results[0].error stack trace for the presence + // of the timeout stack entry + o(results[0].fallbackError instanceof Error).equals(true) + o(o.cleanStackTrace(results[0].fallbackError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) + + done() + })) + } else { + done() + } + }) + o("when using a thenable", function(done) { + var oo = o.new() + var err + // the success of this test is dependent on having the + // oo() call three linew below this one + try {throw new Error} catch(e) {err = e} + if (err.stack) { + var line = Number(err.stack.match(/:(\d+):/)[1]) + oo("", function() { + oo.timeout(1) + return {then: function(){}} + }) + oo.run((function(results) { + o(results.length).equals(1) + o(results[0].pass).equals(false) + o(results[0].fallbackError instanceof Error).equals(true) + o(o.cleanStackTrace(results[0].fallbackError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) + + done() + })) + } else { + done() + } + }) + }) + o.spec("o.timeout", function() { + o("throws when called out of test definitions", function(done) { + var oo = o.new() + var count = 0 + try { oo.timeout(1) } catch (e) { count++ } + oo.spec("a spec", function() { + try { oo.timeout(1) } catch (e) { count++ } + }) + oo("", function() { + oo.timeout(30) + return {then: function(f) {setTimeout(f)}} + }) + oo.run(function(){ + o(count).equals(2) - o.before(function(done) { - callAsync(function() { - a = 1 done() }) }) - o.after(function(done) { - callAsync(function() { - a = 0 + o("works", function(done) { + var oo = o.new() + var t = new Date + oo("", function() { + oo.timeout(10) + return {then: function() {}} + }) + oo.run(function(){ + o(new Date - t >= 10).equals(true) + o(200 > new Date - t).equals(true) + done() }) }) - - o.beforeEach(function(done) { - callAsync(function() { - b = 1 + }) + o.spec("calling done() twice throws", function () { + o("two successes", function(done) { + var oo = o.new() + var err = null + oo("foo", function(oodone) { + try { + oodone() + oodone() + } catch (e) { + err = e + } + o(err instanceof Error).equals(true) + o(err.message).equals("`oodone()` should only be called once") + }) + oo.run(function(results) { + o(results.length).equals(0) done() }) }) - o.afterEach(function(done) { - callAsync(function() { - b = 0 + o("a success followed by an error", function(done) { + var oo = o.new() + var err = null + oo("foo", function(oodone) { + try { + oodone() + oodone("error") + } catch (e) { + err = e + } + o(err instanceof Error).equals(true) + o(err.message).equals("`oodone()` should only be called once") + }) + oo.run(function(results) { + o(results.length).equals(0) done() }) }) - - o("async hooks", function(done) { - callAsync(function() { - var spy = o.spy() - spy(a) - - o(a).equals(b) - o(a).equals(1)("a and b should be initialized") - + o("two errors", function(done) { + var oo = o.new() + var err = null + oo("foo", function(oodone) { + try { + oodone("bar") + oodone("baz") + } catch (e) { + err = e + } + o(err instanceof Error).equals(true) + o(err.message).equals("`oodone()` should only be called once") + }) + oo.run(function(results) { + o(results.length).equals(1) + o(results[0].pass).equals(false) + o(results[0].message).equals("bar") + done() + }) + }) + o("an error followed by a success", function(done) { + var oo = o.new() + var err = null + oo("foo", function(oodone) { + try { + oodone("bar") + oodone() + } catch (e) { + err = e + } + o(err instanceof Error).equals(true) + o(err.message).equals("`oodone()` should only be called once") + }) + oo.run(function(results) { + o(results.length).equals(1) + o(results[0].pass).equals(false) + o(results[0].message).equals("bar") done() }) }) From f6e23da56cca4e1abf4784676deb360482f57682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 25 May 2018 23:48:06 +0200 Subject: [PATCH 226/301] [ospec] update change log --- ospec/change-log.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ospec/change-log.md b/ospec/change-log.md index 21a69058..d6b5e626 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -2,6 +2,14 @@ ## Upcoming... +_2018-xx-yy_ +### Features +- Give async timeout a stack trace that points to the problematic test ([#2154(https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- add `o.timeout()` for setting timeout in Promise-based tests ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) + +### Bug fixes +- Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Don't count `done()` calls as passing tests in the final tally [#2166](https://github.com/MithrilJS/mithril.js/issues/2166) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) ## 2.1.0 From e47353686667f5ecb81b2f8ef4144e0dd7f3ba08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 00:48:44 +0200 Subject: [PATCH 227/301] [ospec] cleanup o.only --- ospec/ospec.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 2b98c072..a8d7b306 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -32,12 +32,11 @@ else window.o = m() ctx = parent } o.only = function(subject, predicate, silent) { - if (!silent) { - console.log(highlight("/!\\ WARNING /!\\ o.only() mode")) - try {throw new Error} catch (e) { - console.log(o.cleanStackTrace(e) + "\n") - } - } + if (!silent) console.log( + highlight("/!\\ WARNING /!\\ o.only() mode") + "\n" + o.cleanStackTrace(ensureStackTrace(new Error)) + "\n", + cStyle("red"), "" + ) + o(subject, only = predicate) } o.spy = function(fn) { From 9c1f8d5f353edf5c2becbba4f542a7ee2f0a731e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 12:23:00 +0200 Subject: [PATCH 228/301] [ospec] cleanup in code and tests, better error messages --- ospec/ospec.js | 64 ++++++++++------ ospec/tests/test-ospec.js | 155 ++++++++++++++++++++------------------ 2 files changed, 119 insertions(+), 100 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index a8d7b306..eadb4150 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -7,17 +7,21 @@ else window.o = m() var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var globalTimeout = noTimeoutRightNow + var hooks = { + __before: true, + __beforeEach: true, + __after: true, + __afterEach: true + } if (name != null) spec[name] = ctx = {} function o(subject, predicate) { - if (predicate === undefined) { - if (results == null) throw new Error("Assertions should not occur outside test definitions") - return new Assert(subject) - } - else if (results == null) { + if (predicate === undefined) return new Assert(subject) + else { + subject = String(subject) + if (hasOwn.call(hooks, subject)) throw new Error("'" + subject + "' is a reserved test name") + if (subject.slice(0, 2) === "__") console.warn("test names starting with '__' are reserved for internal use\n" + o.cleanStackTrace(ensureStackTrace(new Error))) ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error)) - } else { - throw new Error("Test definition shouldn't be nested. To group tests use `o.spec()`") } } o.before = hook("__before") @@ -36,7 +40,6 @@ else window.o = m() highlight("/!\\ WARNING /!\\ o.only() mode") + "\n" + o.cleanStackTrace(ensureStackTrace(new Error)) + "\n", cStyle("red"), "" ) - o(subject, only = predicate) } o.spy = function(fn) { @@ -93,23 +96,25 @@ else window.o = m() function test(spec, pre, post, finalize) { pre = [].concat(pre, spec["__beforeEach"] || []) post = [].concat(spec["__afterEach"] || [], post) - series([].concat(spec["__before"] || [], Object.keys(spec).map(function(key) { - return new Task(function(done, timeout) { - timeout(Infinity) - if (key.slice(0, 2) === "__") return done() - if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() + series([].concat(spec["__before"] || [], Object.keys(spec).reduce(function(tasks, key) { + if (!hasOwn.call(hooks, key)) { + tasks.push(new Task(function(done, timeout) { + timeout(Infinity) + if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() - subjects.push(key) - var pop = new Task(function pop() { - subjects.pop() - done() - }, null) + subjects.push(key) + var pop = new Task(function pop() { + subjects.pop() + done() + }, null) - if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop)) - else test(spec[key], pre, post, pop) + if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop)) + else test(spec[key], pre, post, pop) - }, null) - }), spec["__after"] || [], finalize)) + }, null)) + } + return tasks + }, []), spec["__after"] || [], finalize)) } function series(tasks) { @@ -162,7 +167,8 @@ else window.o = m() fn(done, setDelay) } catch (e) { - finalizeAsync(e) + if (task.err != null) finalizeAsync(e) + else throw e } if (timeout === 0) { startTimer() @@ -239,8 +245,16 @@ else window.o = m() return false } - function Assert(value) {this.value = value} - function Task(fn, err) {this.fn = fn, this.err = err} + function isRunning() {return results != null} + function Assert(value) { + if (!isRunning()) throw new Error("Assertions should not occur outside test definitions") + this.value = value + } + function Task(fn, err) { + if (err != null && isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") + this.fn = fn + this.err = err + } function define(name, verb, compare) { Assert.prototype[name] = function assert(value) { if (compare(this.value, value)) record(null) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 753acdf8..2d949a8a 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -3,91 +3,96 @@ var callAsync = require("../../test-utils/callAsync") var o = require("../ospec") -new function(o) { - o = o.new() +o("o.only", function(done) { + var oo = o.new() - o.spec("ospec", function() { - o("skipped", function() { - o(true).equals(false) + oo.spec("ospec", function() { + oo("skipped", function() { + oo(true).equals(false) }) - o.only(".only()", function() { - o(2).equals(2) + oo.only(".only()", function() { + oo(2).equals(2) }, true) }) - o.run() -}(o) - -new function(o) { - var clone = o.new() - - clone.spec("clone", function() { - clone("fail", function() { - clone(true).equals(false) - }) - - clone("pass", function() { - clone(true).equals(true) - }) + oo.run(function(results){ + o(results.length).equals(1) + o(results[0].pass).equals(true) + done() }) +}) - // Predicate test passing on clone results - o.spec("reporting", function() { - o("reports per instance", function(done, timeout) { - timeout(100) // Waiting on clone +// Predicate test passing on clone results +o.spec("reporting", function() { + var oo + o.beforeEach(function(){ + oo = o.new() - clone.run(function(results) { - o(typeof results).equals("object") - o("length" in results).equals(true) - o(results.length).equals(2)("Two results") + oo.spec("clone", function() { + oo("fail", function() { + oo(true).equals(false) + }) - o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result") - o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result") - o(results[0].pass).equals(false)("Test meant to fail has failed") - o(results[1].pass).equals(true)("Test meant to pass has passed") - - done() + oo("pass", function() { + oo(true).equals(true) }) }) - o("o.report() returns the number of failures", function () { - var log = console.log, error = console.error - console.log = o.spy() - console.error = o.spy() + }) + o("reports per instance", function(done, timeout) { + timeout(100) // Waiting on clone - function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}} - try { - var errCount = o.report([{pass: true}, {pass: true}]) + oo.run(function(results) { + o(typeof results).equals("object") + o("length" in results).equals(true) + o(results.length).equals(2)("Two results") - o(errCount).equals(0) - o(console.log.callCount).equals(1) - o(console.error.callCount).equals(0) + o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result") + o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result") + o(results[0].pass).equals(false)("Test meant to fail has failed") + o(results[1].pass).equals(true)("Test meant to pass has passed") - errCount = o.report([ - {pass: false, error: makeError("hey"), message: "hey"} - ]) - - o(errCount).equals(1) - o(console.log.callCount).equals(2) - o(console.error.callCount).equals(1) - - errCount = o.report([ - {pass: false, error: makeError("hey"), message: "hey"}, - {pass: true}, - {pass: false, error: makeError("ho"), message: "ho"} - ]) - - o(errCount).equals(2) - o(console.log.callCount).equals(3) - o(console.error.callCount).equals(3) - } catch (e) { - o(1).equals(0)("Error while testing the reporter") - } - - console.log = log - console.error = error + done() }) }) -}(o) + o("o.report() returns the number of failures", function () { + var log = console.log, error = console.error + console.log = o.spy() + console.error = o.spy() + + function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}} + try { + var errCount = o.report([{pass: true}, {pass: true}]) + + o(errCount).equals(0) + o(console.log.callCount).equals(1) + o(console.error.callCount).equals(0) + + errCount = o.report([ + {pass: false, error: makeError("hey"), message: "hey"} + ]) + + o(errCount).equals(1) + o(console.log.callCount).equals(2) + o(console.error.callCount).equals(1) + + errCount = o.report([ + {pass: false, error: makeError("hey"), message: "hey"}, + {pass: true}, + {pass: false, error: makeError("ho"), message: "ho"} + ]) + + o(errCount).equals(2) + o(console.log.callCount).equals(3) + o(console.error.callCount).equals(3) + } catch (e) { + o(1).equals(0)("Error while testing the reporter") + } + + console.log = log + console.error = error + }) +}) + o.spec("ospec", function() { o.spec("sync", function() { @@ -197,7 +202,7 @@ o.spec("ospec", function() { done() }) }) - + o.beforeEach(function(done) { o(b).equals(0) callAsync(function() { @@ -211,15 +216,15 @@ o.spec("ospec", function() { done() }) }) - + o("hooks work as intended the first time", function(done) { callAsync(function() { var spy = o.spy() spy(a) - + o(a).equals(1) o(b).equals(1) - + done() }) }) @@ -227,10 +232,10 @@ o.spec("ospec", function() { callAsync(function() { var spy = o.spy() spy(a) - + o(a).equals(1) o(b).equals(1) - + done() }) }) From e342805bfbf161573479ffc8e9fcd315beac2108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 13:42:43 +0200 Subject: [PATCH 229/301] [ospec] Add o.defaultTimeout() --- ospec/ospec.js | 36 +++++++----- ospec/tests/test-ospec.js | 114 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 13 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index eadb4150..56003566 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -11,7 +11,8 @@ else window.o = m() __before: true, __beforeEach: true, __after: true, - __afterEach: true + __afterEach: true, + __defaultTimeout: true } if (name != null) spec[name] = ctx = {} @@ -28,6 +29,12 @@ else window.o = m() o.after = hook("__after") o.beforeEach = hook("__beforeEach") o.afterEach = hook("__afterEach") + o.defaultTimeout = function (t) { + if (isRunning()) throw new Error("o.defaultTimeout() can only be called before o.run()") + if (hasOwn.call(ctx, "__defaultTimeout")) throw new Error("A default timeout has already been defined in this context") + if (typeof t !== "number") throw new Error("o.defaultTimeout() expects a number as argument") + ctx.__defaultTimeout = t + } o.new = init o.spec = function(subject, predicate) { var parent = ctx @@ -91,9 +98,10 @@ else window.o = m() if (hasProcess && errCount !== 0) process.exit(1) } }) - }, null)) + }, null), 200 /*default timeout delay*/) - function test(spec, pre, post, finalize) { + function test(spec, pre, post, finalize, defaultDelay) { + if (hasOwn.call(spec, "__defaultTimeout")) defaultDelay = spec.__defaultTimeout pre = [].concat(pre, spec["__beforeEach"] || []) post = [].concat(spec["__afterEach"] || [], post) series([].concat(spec["__before"] || [], Object.keys(spec).reduce(function(tasks, key) { @@ -108,16 +116,16 @@ else window.o = m() done() }, null) - if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop)) - else test(spec[key], pre, post, pop) + if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop), defaultDelay) + else test(spec[key], pre, post, pop, defaultDelay) }, null)) } return tasks - }, []), spec["__after"] || [], finalize)) + }, []), spec["__after"] || [], finalize), defaultDelay) } - function series(tasks) { + function series(tasks, defaultDelay) { var cursor = 0 next() @@ -127,7 +135,7 @@ else window.o = m() var task = tasks[cursor++] var current = cursor var fn = task.fn - var timeout = 0, delay = 200, s = new Date + var timeout = 0, delay = defaultDelay, s = new Date var arg globalTimeout = setDelay @@ -137,7 +145,6 @@ else window.o = m() function done(err) { if (!isDone) isDone = true else throw new Error("`" + arg + "()` should only be called once") - if (timeout === undefined) console.warn("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms\n" + o.cleanStackTrace(task.err)) finalizeAsync(err) } @@ -153,12 +160,13 @@ else window.o = m() function startTimer() { timeout = setTimeout(function() { timeout = undefined - finalizeAsync("async test timed out") + finalizeAsync("async test timed out after " + delay + "ms") }, Math.min(delay, 2147483647)) } - - function setDelay (t) {delay = t} - + function setDelay (t) { + if (typeof t !== "number") throw new Error("timeout() and o.timeout() expect a number as argument") + delay = t + } if (fn.length > 0) { var body = fn.toString() arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() @@ -168,6 +176,7 @@ else window.o = m() } catch (e) { if (task.err != null) finalizeAsync(e) + // The errors of internal tasks (which don't have an Err) are ospec bugs and must be rethrown. else throw e } if (timeout === 0) { @@ -251,6 +260,7 @@ else window.o = m() this.value = value } function Task(fn, err) { + // Tasks defined internally don't have an `err`, and may be created at run-time. if (err != null && isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") this.fn = fn this.err = err diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 2d949a8a..f220d214 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -327,6 +327,120 @@ o.spec("ospec", function() { }) }) }) + o.spec("o.defaultTimeout", function() { + o("throws when called inside of test definitions", function(done) { + var err + var oo = o.new() + oo("", function() { + try { oo.defaultTimeout(5) } catch (e) {err = e} + return {then: function(f) {setTimeout(f)}} + }) + oo.run(function(){ + o(err instanceof Error).equals(true) + + done() + }) + }) + o("works", function(done) { + var oo = o.new() + var t + + oo.defaultTimeout(10) + oo.beforeEach(function () { + t = new Date + }) + oo.afterEach(function () { + var diff = new Date - t + o(diff >= 10).equals(true) + o(diff < 200).equals(true) + }) + + oo("", function() { + oo(true).equals(true) + + return {then: function() {}} + }) + + oo.run(function(results) { + o(results.length).equals(2) + o(results[0].pass).equals(true) + o(results[1].pass).equals(false) + done() + }) + }) + o("scoped when nested", function(done) { + var oo = o.new() + var t + + oo.defaultTimeout(10) + oo.beforeEach(function () { + t = new Date + }) + oo.afterEach(function () { + var diff = new Date - t + o(diff >= 10).equals(true) + o(diff < 200).equals(true) + }) + + oo.spec("nested 1", function () { + var t + + oo.defaultTimeout(30) + oo.beforeEach(function () { + t = new Date + }) + oo.afterEach(function () { + var diff = new Date - t + o(diff >= 30).equals(true) + o(diff < 200).equals(true) + }) + + oo("", function() { + oo(true).equals(true) + + return {then: function() {}} + }) + }) + + oo("", function() { + oo(true).equals(true) + + return {then: function() {}} + }) + + oo.spec("nested 2", function () { + oo.spec("deeply", function() { + var t + + oo.defaultTimeout(20) + oo.beforeEach(function () { + t = new Date + }) + oo.afterEach(function () { + var diff = new Date - t + o(diff >= 20).equals(true) + o(diff < 200).equals(true) + }) + + oo("", function() { + oo(true).equals(true) + + return {then: function() {}} + }) + }) + }) + oo.run(function(results) { + o(results.length).equals(6) + o(results[0].pass).equals(true) + o(results[1].pass).equals(false) + o(results[2].pass).equals(true) + o(results[3].pass).equals(false) + o(results[4].pass).equals(true) + o(results[5].pass).equals(false) + done() + }) + }) + }) o.spec("calling done() twice throws", function () { o("two successes", function(done) { var oo = o.new() From ad83d617e1d50ef37b36c21b3d342501d57283e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 14:15:58 +0200 Subject: [PATCH 230/301] [ospec] replace ES6 std lib call with ES5 equivalent --- ospec/tests/test-ospec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index f220d214..35d60e0a 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -527,7 +527,7 @@ o.spec("ospec", function() { } catch(error) { var trace = o.cleanStackTrace(error) o(trace).notEquals("break") - o(trace.includes("test-ospec.js")).equals(true) + o(trace.indexOf("test-ospec.js") !== -1).equals(true) } }) }) From 21a6a857efccfa055bba0e875f9364913acddd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 14:16:40 +0200 Subject: [PATCH 231/301] [ospec] update change log --- ospec/change-log.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index d6b5e626..1405523f 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -3,14 +3,19 @@ ## Upcoming... _2018-xx-yy_ + +### Breaking +- Better input checking to prevent misuses of the library. This may uncover bugs in your test suites. Since it is potentially a disruptive update this change triggers a semver major bump. ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) + ### Features -- Give async timeout a stack trace that points to the problematic test ([#2154(https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) -- add `o.timeout()` for setting timeout in Promise-based tests ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- add `o.timeout()` for setting the timeout delay in Promise-based tests ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- add `o.defaultTimeout()` for setting the the timeout delay for the current spec and its children ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ### Bug fixes -- Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) -- Don't count `done()` calls as passing tests in the final tally [#2166](https://github.com/MithrilJS/mithril.js/issues/2166) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) - +- Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Don't count `done()` calls as passing tests in the final tally [#2166](https://github.com/MithrilJS/mithril.js/issues/2166) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Don't try to report internal errors as assertion failures, throw them instead ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ## 2.1.0 _2018-05-25_ From 285d00742d186513f4483cedb2b5314b5eb5b20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 14:33:53 +0200 Subject: [PATCH 232/301] [ospec] Detect incomplete assertions --- ospec/ospec.js | 54 ++++++++++++++++++++++----------------- ospec/tests/test-ospec.js | 40 +++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 56003566..05a1ef95 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -7,6 +7,7 @@ else window.o = m() var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var globalTimeout = noTimeoutRightNow + var currentTestError = null var hooks = { __before: true, __beforeEach: true, @@ -17,8 +18,11 @@ else window.o = m() if (name != null) spec[name] = ctx = {} function o(subject, predicate) { - if (predicate === undefined) return new Assert(subject) - else { + if (predicate === undefined) { + if (!isRunning()) throw new Error("Assertions should not occur outside test definitions") + return new Assert(subject) + } else { + if (isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") subject = String(subject) if (hasOwn.call(hooks, subject)) throw new Error("'" + subject + "' is a reserved test name") if (subject.slice(0, 2) === "__") console.warn("test names starting with '__' are reserved for internal use\n" + o.cleanStackTrace(ensureStackTrace(new Error))) @@ -133,9 +137,10 @@ else window.o = m() if (cursor === tasks.length) return var task = tasks[cursor++] - var current = cursor var fn = task.fn + currentTestError = task.err var timeout = 0, delay = defaultDelay, s = new Date + var current = cursor var arg globalTimeout = setDelay @@ -150,9 +155,9 @@ else window.o = m() } // for internal use only function finalizeAsync(err) { - if (err) { - if (err instanceof Error) record(err.message, err, task.err) - else record(String(err), null, task.err) + if (err != null) { + if (err instanceof Error) fail(new Assert, err.message, err) + else fail(new Assert, String(err), null) } if (timeout !== undefined) timeout = clearTimeout(timeout) if (current === cursor) next() @@ -256,34 +261,32 @@ else window.o = m() function isRunning() {return results != null} function Assert(value) { - if (!isRunning()) throw new Error("Assertions should not occur outside test definitions") this.value = value + this.i = results.length + results.push({pass: null, context: "", message: "Incomplete assertion in the test definition starting at...", error: currentTestError, testError: currentTestError}) } function Task(fn, err) { - // Tasks defined internally don't have an `err`, and may be created at run-time. - if (err != null && isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") this.fn = fn this.err = err } function define(name, verb, compare) { Assert.prototype[name] = function assert(value) { - if (compare(this.value, value)) record(null) - else record(serialize(this.value) + "\n " + verb + "\n" + serialize(value)) + if (compare(this.value, value)) succeed(this) + else fail(this, serialize(this.value) + "\n " + verb + "\n" + serialize(value)) + var self = this return function(message) { - var result = results[results.length - 1] - result.message = message + "\n\n" + result.message + if (!self.pass) self.message = message + "\n\n" + self.message } } } - function record(message, error, fallbackError) { - var result = {pass: message === null} - if (result.pass === false) { - result.context = subjects.join(" > ") - result.message = message - result.error = error != null ? error : ensureStackTrace(new Error) - result.fallbackError = fallbackError - } - results.push(result) + function succeed(assertion) { + results[assertion.i].pass = true + } + function fail(assertion, message, error) { + results[assertion.i].pass = false + results[assertion.i].context = subjects.join(" > ") + results[assertion.i].message = message + results[assertion.i].error = error != null ? error : ensureStackTrace(new Error) } function serialize(value) { if (hasProcess) return require("util").inspect(value) @@ -318,10 +321,15 @@ else window.o = m() o.report = function (results) { var errCount = 0 for (var i = 0, r; r = results[i]; i++) { + if (r.pass == null) { + r.testError.stack = r.message + "\n" + o.cleanStackTrace(r.testError) + r.testError.message = r.message + throw r.testError + } if (!r.pass) { var stackTrace = o.cleanStackTrace(r.error) var couldHaveABetterStackTrace = !stackTrace || timeoutStackName != null && stackTrace.indexOf(timeoutStackName) !== -1 - if (couldHaveABetterStackTrace) stackTrace = r.fallbackError != null ? o.cleanStackTrace(r.fallbackError) : r.error.stack || "" + if (couldHaveABetterStackTrace) stackTrace = r.testError != null ? o.cleanStackTrace(r.testError) : r.error.stack || "" console.error( (hasProcess ? "\n" : "") + highlight(r.context + ":", "red2") + "\n" + diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 35d60e0a..b988898c 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -3,6 +3,37 @@ var callAsync = require("../../test-utils/callAsync") var o = require("../ospec") + +// this throws an async error that can't be caught in browsers +if (typeof process !== "undefined") { + o("incomplete assertion", function(done) { + var stackMatcher = /([\w\.\\\/\-]+):(\d+):/ + // /!\ this test relies on the `new Error` expression being six lines + // above the `oo("test", function(){...})` call. + var matches = (new Error).stack.match(stackMatcher) + if (matches != null) { + var name = matches[1] + var num = Number(matches[2]) + } + var oo = o.new() + oo("test", function() { + oo("incomplete") + }) + oo.run(function(results) { + o(results.length).equals(1) + o(results[0].message).equals("Incomplete assertion in the test definition starting at...") + o(results[0].pass).equals(null) + var stack = o.cleanStackTrace(results[0].testError) + var matches2 = stack && stack.match(stackMatcher) + if (matches != null && matches2 != null) { + o(matches[1]).equals(name) + o(Number(matches2[2])).equals(num + 6) + } + done() + }) + }) +} + o("o.only", function(done) { var oo = o.new() @@ -47,7 +78,6 @@ o.spec("reporting", function() { o(results.length).equals(2)("Two results") o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result") - o(!("error" in results[1]) && "pass" in results[1]).equals(true)("only pass key present in passing result") o(results[0].pass).equals(false)("Test meant to fail has failed") o(results[1].pass).equals(true)("Test meant to pass has passed") @@ -260,8 +290,8 @@ o.spec("ospec", function() { o(results[0].pass).equals(false) // todo test cleaned up results[0].error stack trace for the presence // of the timeout stack entry - o(results[0].fallbackError instanceof Error).equals(true) - o(o.cleanStackTrace(results[0].fallbackError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) + o(results[0].testError instanceof Error).equals(true) + o(o.cleanStackTrace(results[0].testError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) done() })) @@ -284,8 +314,8 @@ o.spec("ospec", function() { oo.run((function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) - o(results[0].fallbackError instanceof Error).equals(true) - o(o.cleanStackTrace(results[0].fallbackError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) + o(results[0].testError instanceof Error).equals(true) + o(o.cleanStackTrace(results[0].testError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) done() })) From 0574d193a0f0644cb13cce28b83066b44b480a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 26 May 2018 18:34:33 +0200 Subject: [PATCH 233/301] [ospec] better variable name --- ospec/ospec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 05a1ef95..fe3b6956 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -8,7 +8,7 @@ else window.o = m() var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var globalTimeout = noTimeoutRightNow var currentTestError = null - var hooks = { + var reservedNames = { __before: true, __beforeEach: true, __after: true, @@ -24,7 +24,7 @@ else window.o = m() } else { if (isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") subject = String(subject) - if (hasOwn.call(hooks, subject)) throw new Error("'" + subject + "' is a reserved test name") + if (hasOwn.call(reservedNames, subject)) throw new Error("'" + subject + "' is a reserved test name") if (subject.slice(0, 2) === "__") console.warn("test names starting with '__' are reserved for internal use\n" + o.cleanStackTrace(ensureStackTrace(new Error))) ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error)) } @@ -109,7 +109,7 @@ else window.o = m() pre = [].concat(pre, spec["__beforeEach"] || []) post = [].concat(spec["__afterEach"] || [], post) series([].concat(spec["__before"] || [], Object.keys(spec).reduce(function(tasks, key) { - if (!hasOwn.call(hooks, key)) { + if (!hasOwn.call(reservedNames, key)) { tasks.push(new Task(function(done, timeout) { timeout(Infinity) if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() From 33180370ead05e3f47d03e01aaef7a2786875a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 27 May 2018 10:29:06 +0200 Subject: [PATCH 234/301] [ospec] Change the reserved test name token from '__' to '\x01' --- ospec/ospec.js | 34 +++++++++++++--------------------- ospec/tests/test-ospec.js | 3 +++ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index fe3b6956..29e2835e 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -8,13 +8,6 @@ else window.o = m() var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var globalTimeout = noTimeoutRightNow var currentTestError = null - var reservedNames = { - __before: true, - __beforeEach: true, - __after: true, - __afterEach: true, - __defaultTimeout: true - } if (name != null) spec[name] = ctx = {} function o(subject, predicate) { @@ -24,20 +17,19 @@ else window.o = m() } else { if (isRunning()) throw new Error("Test definitions and hooks shouldn't be nested. To group tests use `o.spec()`") subject = String(subject) - if (hasOwn.call(reservedNames, subject)) throw new Error("'" + subject + "' is a reserved test name") - if (subject.slice(0, 2) === "__") console.warn("test names starting with '__' are reserved for internal use\n" + o.cleanStackTrace(ensureStackTrace(new Error))) + if (subject.charCodeAt(0) === 1) throw new Error("test names starting with '\\x01' are reserved for internal use") ctx[unique(subject)] = new Task(predicate, ensureStackTrace(new Error)) } } - o.before = hook("__before") - o.after = hook("__after") - o.beforeEach = hook("__beforeEach") - o.afterEach = hook("__afterEach") + o.before = hook("\x01before") + o.after = hook("\x01after") + o.beforeEach = hook("\x01beforeEach") + o.afterEach = hook("\x01afterEach") o.defaultTimeout = function (t) { if (isRunning()) throw new Error("o.defaultTimeout() can only be called before o.run()") - if (hasOwn.call(ctx, "__defaultTimeout")) throw new Error("A default timeout has already been defined in this context") + if (hasOwn.call(ctx, "\x01defaultTimeout")) throw new Error("A default timeout has already been defined in this context") if (typeof t !== "number") throw new Error("o.defaultTimeout() expects a number as argument") - ctx.__defaultTimeout = t + ctx["\x01defaultTimeout"] = t } o.new = init o.spec = function(subject, predicate) { @@ -105,11 +97,11 @@ else window.o = m() }, null), 200 /*default timeout delay*/) function test(spec, pre, post, finalize, defaultDelay) { - if (hasOwn.call(spec, "__defaultTimeout")) defaultDelay = spec.__defaultTimeout - pre = [].concat(pre, spec["__beforeEach"] || []) - post = [].concat(spec["__afterEach"] || [], post) - series([].concat(spec["__before"] || [], Object.keys(spec).reduce(function(tasks, key) { - if (!hasOwn.call(reservedNames, key)) { + if (hasOwn.call(spec, "\x01defaultTimeout")) defaultDelay = spec["\x01defaultTimeout"] + pre = [].concat(pre, spec["\x01beforeEach"] || []) + post = [].concat(spec["\x01afterEach"] || [], post) + series([].concat(spec["\x01before"] || [], Object.keys(spec).reduce(function(tasks, key) { + if (key.charCodeAt(0) !== 1) { tasks.push(new Task(function(done, timeout) { timeout(Infinity) if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() @@ -126,7 +118,7 @@ else window.o = m() }, null)) } return tasks - }, []), spec["__after"] || [], finalize), defaultDelay) + }, []), spec["\x01after"] || [], finalize), defaultDelay) } function series(tasks, defaultDelay) { diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index b988898c..9ff04725 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -127,6 +127,7 @@ o.spec("reporting", function() { o.spec("ospec", function() { o.spec("sync", function() { var a = 0, b = 0, illegalAssertionThrows = false + var reservedTestNameTrows = false o.before(function() {a = 1}) o.after(function() {a = 0}) @@ -135,6 +136,7 @@ o.spec("ospec", function() { o.afterEach(function() {b = 0}) try {o("illegal assertion")} catch (e) {illegalAssertionThrows = true} + try {o("\x01reserved test name", function(){})} catch (e) {reservedTestNameTrows = true} o("assertions", function() { var nestedTestDeclarationThrows = false @@ -142,6 +144,7 @@ o.spec("ospec", function() { o(illegalAssertionThrows).equals(true) o(nestedTestDeclarationThrows).equals(true) + o(reservedTestNameTrows).equals(true) var spy = o.spy() spy(a) From 8ebf036b8cac52c0c8d14015d628dd3c8598de23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 27 May 2018 22:30:01 +0200 Subject: [PATCH 235/301] [ospec] Improve the done() call checker --- ospec/change-log.md | 4 +++ ospec/ospec.js | 8 +++-- ospec/tests/test-ospec.js | 76 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 1405523f..b4cadc5c 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -6,6 +6,8 @@ _2018-xx-yy_ ### Breaking - Better input checking to prevent misuses of the library. This may uncover bugs in your test suites. Since it is potentially a disruptive update this change triggers a semver major bump. ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Change the reserved character for hooks and test suite meta-information from `"__"` to `"\x01"`. Tests whose name start with `"\0x01"` will be rejected ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Misues of the library will now throw errors, rather than report failures. ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) ### Features - Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) @@ -16,6 +18,8 @@ _2018-xx-yy_ - Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't count `done()` calls as passing tests in the final tally [#2166](https://github.com/MithrilJS/mithril.js/issues/2166) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't try to report internal errors as assertion failures, throw them instead ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Don't ignore, silently, tests whose name start with the test suite meta-information sequence (was `"__"` up to this version) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Fix the `done()` call detection logic [#2158](https://github.com/MithrilJS/mithril.js/issues/2158) and assorted fixes (accept non-English names, tolerate comments; [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ## 2.1.0 _2018-05-25_ diff --git a/ospec/ospec.js b/ospec/ospec.js index 29e2835e..ae8bc980 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -166,8 +166,12 @@ else window.o = m() } if (fn.length > 0) { var body = fn.toString() - arg = (body.match(/\(([\w$]+)/) || body.match(/([\w$]+)\s*=>/) || []).pop() - if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once") + arg = (body.match(/^(.+?)(?:\s|\/\*[\s\S]*?\*\/|\/\/.*?\n)*=>/) || body.match(/\((?:\s|\/\*[\s\S]*?\*\/|\/\/.*?\n)*(.+?)(?:\s|\/\*[\s\S]*?\*\/|\/\/.*?\n)*[,\)]/) || []).pop() + if (body.indexOf(arg) === body.lastIndexOf(arg)) { + var e = new Error + e.stack = "`" + arg + "()` should be called at least once\n" + o.cleanStackTrace(task.err) + throw e + } try { fn(done, setDelay) } diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 9ff04725..a3ef11a0 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -612,3 +612,79 @@ o.spec("ospec", function() { }) }) }) +o.spec("the done parser", function() { + o("accepts non-English names", function() { + var oo = o.new() + var threw = false + oo("test", function(完了) { + oo(true).equals(true) + 完了() + }) + try {oo.run(function(){})} catch(e) {threw = true} + o(threw).equals(false) + }) + o("tolerates comments", function() { + var oo = o.new() + var threw = false + oo("test", function(/*hey + */ /**/ //ho + done /*hey + */ /**/ //huuu + , timeout + ) { + timeout(5) + oo(true).equals(true) + done() + }) + try {oo.run(function(){})} catch(e) {threw = true} + o(threw).equals(false) + }) + /*eslint-disable no-eval*/ + try {eval("(()=>{})()"); o.spec("with ES6 arrow functions", function() { + function getCommentContent(f) { + f = f.toString() + return f.slice(f.indexOf("/*") + 2, f.lastIndexOf("*/")) + } + o("has no false positives 1", function(){ + var oo = o.new() + var threw = false + eval(getCommentContent(function(){/* + oo( + 'Async test parser mistakenly identified 1st token after a parens to be `done` reference', + done => { + oo(threw).equals(false) + done() + } + ) + */})) + try {oo.run(function(){})} catch(e) {threw = true} + o(threw).equals(false) + }) + o("has no false negatives", function(){ + var oo = o.new() + var threw = false + eval(getCommentContent(function(){/* + oo( + "Multiple references to the wrong thing doesn't fool the checker", + done => { + oo(threw).equals(false) + oo(threw).equals(false) + } + ) + */})) + try {oo.run(function(){})} catch(e) {threw = true} + o(threw).equals(true) + }) + o("isn't fooled by comments", function(){ + var oo = o.new() + var threw = false + oo( + "comments won't throw the parser off", + eval("done /*hey*/ /**/ => {oo(threw).equals(false);done()}") + ) + try {oo.run(function(){})} catch(e) {threw = true} + o(threw).equals(false) + }) + })} catch (e) {/*ES5 env, or no eval, ignore*/} + /*eslint-enable no-eval*/ +}) From 25975c5ce4313a1281b5466a3b090e9e46892001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 27 May 2018 23:09:51 +0200 Subject: [PATCH 236/301] [ospec] Restore the assertion success on async test finalization in time --- ospec/change-log.md | 1 - ospec/ospec.js | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index b4cadc5c..6171a587 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -16,7 +16,6 @@ _2018-xx-yy_ ### Bug fixes - Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) -- Don't count `done()` calls as passing tests in the final tally [#2166](https://github.com/MithrilJS/mithril.js/issues/2166) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't try to report internal errors as assertion failures, throw them instead ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't ignore, silently, tests whose name start with the test suite meta-information sequence (was `"__"` up to this version) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) - Fix the `done()` call detection logic [#2158](https://github.com/MithrilJS/mithril.js/issues/2158) and assorted fixes (accept non-English names, tolerate comments; [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) diff --git a/ospec/ospec.js b/ospec/ospec.js index ae8bc980..37b3f659 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -147,7 +147,9 @@ else window.o = m() } // for internal use only function finalizeAsync(err) { - if (err != null) { + if (err == null) { + if (task.err != null) succeed(new Assert) + } else { if (err instanceof Error) fail(new Assert, err.message, err) else fail(new Assert, String(err), null) } From aa0f9eae98f30bc8411185a9843ebcaf6e0bc585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 27 May 2018 23:21:31 +0200 Subject: [PATCH 237/301] [ospec] o.defaultTimeout => o.specTimeout, and documentation. The timeout parameter is deprecated but will still work for now --- ospec/README.md | 44 ++++++++++++++++++++++++++++++--------- ospec/ospec.js | 12 +++++------ ospec/tests/test-ospec.js | 18 +++++++++------- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 38aae7b4..83a2fed7 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -164,30 +164,54 @@ o("promise test", async function() { }) ``` -By default, asynchronous tests time out after 20ms. This can be changed on a per-test basis using the `timeout` argument: +#### Timeout delays + +By default, asynchronous tests time out after 200ms. You can change that default for the current test suite and +its children by using the `o.specTimeout(delay)` function. + +```javascript +o.spec("a spec that must timeout quickly", function(done, timeout) { + // wait 20ms before bailing out of the tests of this suite and + // its descendants + o.specTimeout(20) + o("some test", function(done) { + setTimeout(done, 10) // this will pass + }) + + o.spec("a child suite where the delay also applies", function () { + o("some test", function(done) { + setTimeout(done, 30) // this will time out. + }) + }) +}) +o.spec("a spec that uses the default delay", function() { + // ... +}) +``` + +This can also be changed on a per-test basis using the `o.timeout(delay)` function from within a test: ```javascript o("setTimeout calls callback", function(done, timeout) { - timeout(50) //wait 50ms before bailing out of the test + o.timeout(500) //wait 50ms before bailing out of the test - setTimeout(done, 30) + setTimeout(done, 300) }) ``` -Note that the `timeout` function call must be the first statement in its test. This currently does not work for promise tests. You can combine both methods to do this: +Note that the `o.timeout` function call must be the first statement in its test. It also works with Promise-returning tests: ```javascript -o("promise test", function(done, timeout) { - timeout(1000) - someOtherAsyncFunctionThatTakes900ms().then(done) +o("promise test", function() { + o.timeout(1000) + return someOtherAsyncFunctionThatTakes900ms() }) ``` ```javascript -o("promise test", async function(done, timeout) { - timeout(1000) +o("promise test", async function() { + o.timeout(1000) await someOtherAsyncFunctionThatTakes900ms() - done() }) ``` diff --git a/ospec/ospec.js b/ospec/ospec.js index 37b3f659..ea542f82 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -25,11 +25,11 @@ else window.o = m() o.after = hook("\x01after") o.beforeEach = hook("\x01beforeEach") o.afterEach = hook("\x01afterEach") - o.defaultTimeout = function (t) { - if (isRunning()) throw new Error("o.defaultTimeout() can only be called before o.run()") - if (hasOwn.call(ctx, "\x01defaultTimeout")) throw new Error("A default timeout has already been defined in this context") - if (typeof t !== "number") throw new Error("o.defaultTimeout() expects a number as argument") - ctx["\x01defaultTimeout"] = t + o.specTimeout = function (t) { + if (isRunning()) throw new Error("o.specTimeout() can only be called before o.run()") + if (hasOwn.call(ctx, "\x01specTimeout")) throw new Error("A default timeout has already been defined in this context") + if (typeof t !== "number") throw new Error("o.specTimeout() expects a number as argument") + ctx["\x01specTimeout"] = t } o.new = init o.spec = function(subject, predicate) { @@ -97,7 +97,7 @@ else window.o = m() }, null), 200 /*default timeout delay*/) function test(spec, pre, post, finalize, defaultDelay) { - if (hasOwn.call(spec, "\x01defaultTimeout")) defaultDelay = spec["\x01defaultTimeout"] + if (hasOwn.call(spec, "\x01specTimeout")) defaultDelay = spec["\x01specTimeout"] pre = [].concat(pre, spec["\x01beforeEach"] || []) post = [].concat(spec["\x01afterEach"] || [], post) series([].concat(spec["\x01before"] || [], Object.keys(spec).reduce(function(tasks, key) { diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index a3ef11a0..d4748545 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -360,12 +360,12 @@ o.spec("ospec", function() { }) }) }) - o.spec("o.defaultTimeout", function() { + o.spec("o.specTimeout", function() { o("throws when called inside of test definitions", function(done) { var err var oo = o.new() oo("", function() { - try { oo.defaultTimeout(5) } catch (e) {err = e} + try { oo.specTimeout(5) } catch (e) {err = e} return {then: function(f) {setTimeout(f)}} }) oo.run(function(){ @@ -378,7 +378,7 @@ o.spec("ospec", function() { var oo = o.new() var t - oo.defaultTimeout(10) + oo.specTimeout(10) oo.beforeEach(function () { t = new Date }) @@ -405,7 +405,7 @@ o.spec("ospec", function() { var oo = o.new() var t - oo.defaultTimeout(10) + oo.specTimeout(10) oo.beforeEach(function () { t = new Date }) @@ -418,7 +418,7 @@ o.spec("ospec", function() { oo.spec("nested 1", function () { var t - oo.defaultTimeout(30) + oo.specTimeout(30) oo.beforeEach(function () { t = new Date }) @@ -445,7 +445,7 @@ o.spec("ospec", function() { oo.spec("deeply", function() { var t - oo.defaultTimeout(20) + oo.specTimeout(20) oo.beforeEach(function () { t = new Date }) @@ -489,7 +489,8 @@ o.spec("ospec", function() { o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { - o(results.length).equals(0) + o(results.length).equals(1) + o(results[0].pass).equals(true) done() }) }) @@ -507,7 +508,8 @@ o.spec("ospec", function() { o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { - o(results.length).equals(0) + o(results.length).equals(1) + o(results[0].pass).equals(true) done() }) }) From 4a4377e553e119eba183043e3870720f42a8b1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 27 May 2018 23:40:25 +0200 Subject: [PATCH 238/301] [ospec] Make the specTimeout tests hopefully less flaky --- ospec/tests/test-ospec.js | 62 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index d4748545..d652ad90 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -401,38 +401,22 @@ o.spec("ospec", function() { done() }) }) - o("scoped when nested", function(done) { + o("The parent and sibling suites are not affected by the specTimeout", function(done) { var oo = o.new() var t - oo.specTimeout(10) + oo.specTimeout(50) oo.beforeEach(function () { t = new Date }) oo.afterEach(function () { var diff = new Date - t - o(diff >= 10).equals(true) - o(diff < 200).equals(true) + o(diff >= 50).equals(true) + o(diff < 80).equals(true) }) oo.spec("nested 1", function () { - var t - - oo.specTimeout(30) - oo.beforeEach(function () { - t = new Date - }) - oo.afterEach(function () { - var diff = new Date - t - o(diff >= 30).equals(true) - o(diff < 200).equals(true) - }) - - oo("", function() { - oo(true).equals(true) - - return {then: function() {}} - }) + oo.specTimeout(80) }) oo("", function() { @@ -440,19 +424,40 @@ o.spec("ospec", function() { return {then: function() {}} }) - oo.spec("nested 2", function () { + oo.specTimeout(80) + }) + oo.spec("nested 3", function () { + oo("", function() { + oo(true).equals(true) + + return {then: function() {}} + }) + }) + oo.run(function(results) { + o(results.length).equals(4) + o(results[0].pass).equals(true) + o(results[1].pass).equals(false) + o(results[2].pass).equals(true) + o(results[3].pass).equals(false) + done() + }) + }) + o("nested suites inherit the specTimeout", function(done) { + var oo = o.new() + + oo.specTimeout(50) + oo.spec("nested", function () { oo.spec("deeply", function() { var t - oo.specTimeout(20) oo.beforeEach(function () { t = new Date }) oo.afterEach(function () { var diff = new Date - t - o(diff >= 20).equals(true) - o(diff < 200).equals(true) + o(diff >= 50).equals(true) + o(diff < 80).equals(true) }) oo("", function() { @@ -463,17 +468,14 @@ o.spec("ospec", function() { }) }) oo.run(function(results) { - o(results.length).equals(6) + o(results.length).equals(2) o(results[0].pass).equals(true) o(results[1].pass).equals(false) - o(results[2].pass).equals(true) - o(results[3].pass).equals(false) - o(results[4].pass).equals(true) - o(results[5].pass).equals(false) done() }) }) }) + o.spec("calling done() twice throws", function () { o("two successes", function(done) { var oo = o.new() From d05bc9be4958b2d815b87c3388e304d2158ee024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 28 May 2018 00:05:46 +0200 Subject: [PATCH 239/301] [ospec] make it clear the timeout parameter is deprecated. --- ospec/change-log.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 6171a587..77186634 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -11,7 +11,7 @@ _2018-xx-yy_ ### Features - Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) -- add `o.timeout()` for setting the timeout delay in Promise-based tests ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- deprecate the `timeout` parameter in async tests in favour of `o.timeout()` for setting the timeout delay. The `timeout` parameter still works for v3, and will be removed in v4 ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - add `o.defaultTimeout()` for setting the the timeout delay for the current spec and its children ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ### Bug fixes From 0484758837c79fa637066a8bf3472fd931d2be33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 29 May 2018 22:38:32 +0200 Subject: [PATCH 240/301] [ospec] docs and change log tweaks --- ospec/README.md | 2 +- ospec/change-log.md | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 83a2fed7..2e2f55f1 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -193,7 +193,7 @@ This can also be changed on a per-test basis using the `o.timeout(delay)` functi ```javascript o("setTimeout calls callback", function(done, timeout) { - o.timeout(500) //wait 50ms before bailing out of the test + o.timeout(500) //wait 500ms before bailing out of the test setTimeout(done, 300) }) diff --git a/ospec/change-log.md b/ospec/change-log.md index 77186634..095a0743 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -5,9 +5,8 @@ _2018-xx-yy_ ### Breaking -- Better input checking to prevent misuses of the library. This may uncover bugs in your test suites. Since it is potentially a disruptive update this change triggers a semver major bump. ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) -- Change the reserved character for hooks and test suite meta-information from `"__"` to `"\x01"`. Tests whose name start with `"\0x01"` will be rejected ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) -- Misues of the library will now throw errors, rather than report failures. ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) +- Better input checking to prevent misuses of the library. Misues of the library will now throw errors, rather than report failures. This may uncover bugs in your test suites. Since it is potentially a disruptive update this change triggers a semver major bump. ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Change the reserved character for hooks and test suite meta-information from `"__"` to `"\x01"`. Tests whose name start with `"\0x01"` will be rejected ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ### Features - Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) @@ -17,8 +16,8 @@ _2018-xx-yy_ ### Bug fixes - Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't try to report internal errors as assertion failures, throw them instead ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) -- Don't ignore, silently, tests whose name start with the test suite meta-information sequence (was `"__"` up to this version) ([#2167(https://github.com/MithrilJS/mithril.js/pull/2167)) -- Fix the `done()` call detection logic [#2158](https://github.com/MithrilJS/mithril.js/issues/2158) and assorted fixes (accept non-English names, tolerate comments; [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Don't ignore, silently, tests whose name start with the test suite meta-information sequence (was `"__"` up to this version) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Fix the `done()` call detection logic [#2158](https://github.com/MithrilJS/mithril.js/issues/2158) and assorted fixes (accept non-English names, tolerate comments) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) ## 2.1.0 _2018-05-25_ From 315b9f13faa674357e1145e068ce456299de7848 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 29 May 2018 20:44:39 +0000 Subject: [PATCH 241/301] Bundled output for commit 0484758837c79fa637066a8bf3472fd931d2be33 [skip ci] --- package-lock.json | 668 +++++++++++++++++++++++----------------------- 1 file changed, 334 insertions(+), 334 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ef8718d..c112fc71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -39,8 +39,8 @@ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } }, "ajv-keywords": { @@ -55,9 +55,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -96,7 +96,7 @@ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "array-union": { @@ -105,7 +105,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -126,7 +126,7 @@ "integrity": "sha1-YSpKtF70KnDN6Aa62G7m2wR+g4U=", "dev": true, "requires": { - "lodash": "4.17.4" + "lodash": "^4.14.0" } }, "babel-code-frame": { @@ -135,9 +135,9 @@ "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" } }, "balanced-match": { @@ -152,8 +152,8 @@ "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", "dev": true, "requires": { - "lodash": "4.17.4", - "platform": "1.3.4" + "lodash": "^4.17.4", + "platform": "^1.3.3" } }, "brace-expansion": { @@ -162,7 +162,7 @@ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -172,7 +172,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -188,8 +188,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chalk": { @@ -198,11 +198,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "circular-json": { @@ -217,7 +217,7 @@ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { - "restore-cursor": "1.0.1" + "restore-cursor": "^1.0.1" } }, "cli-spinners": { @@ -233,7 +233,7 @@ "dev": true, "requires": { "slice-ansi": "0.0.4", - "string-width": "1.0.2" + "string-width": "^1.0.1" } }, "cli-width": { @@ -281,9 +281,9 @@ "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "core-util-is": { @@ -298,14 +298,14 @@ "integrity": "sha1-DeoPmATv37kp+7GxiOJVU+oFPTc=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "js-yaml": "3.9.0", - "minimist": "1.2.0", - "object-assign": "4.1.1", - "os-homedir": "1.0.2", - "parse-json": "2.2.0", - "pinkie-promise": "2.0.1", - "require-from-string": "1.2.1" + "graceful-fs": "^4.1.2", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.0.1", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "pinkie-promise": "^2.0.0", + "require-from-string": "^1.1.0" }, "dependencies": { "minimist": { @@ -322,9 +322,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.2.14" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "d": { @@ -333,7 +333,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.24" + "es5-ext": "^0.10.9" } }, "date-fns": { @@ -376,13 +376,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.1" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "doctrine": { @@ -391,8 +391,8 @@ "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, "elegant-spinner": { @@ -407,7 +407,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es5-ext": { @@ -416,8 +416,8 @@ "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", "dev": true, "requires": { - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" + "es6-iterator": "2", + "es6-symbol": "~3.1" } }, "es6-iterator": { @@ -426,9 +426,9 @@ "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-symbol": "^3.1" } }, "es6-map": { @@ -437,12 +437,12 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, "es6-set": { @@ -451,11 +451,11 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "event-emitter": "~0.3.5" } }, "es6-symbol": { @@ -464,8 +464,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" + "d": "1", + "es5-ext": "~0.10.14" } }, "es6-weak-map": { @@ -474,10 +474,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, "escape-string-regexp": { @@ -492,11 +492,11 @@ "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "esprima": "2.7.3", - "estraverse": "1.9.3", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.2.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" } }, "escope": { @@ -505,10 +505,10 @@ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" }, "dependencies": { "estraverse": { @@ -525,41 +525,41 @@ "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "dev": true, "requires": { - "babel-code-frame": "6.22.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.6.8", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.4.3", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.3", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.0", - "is-resolvable": "1.0.0", - "js-yaml": "3.9.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" }, "dependencies": { "estraverse": { @@ -576,8 +576,8 @@ "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", "dev": true, "requires": { - "acorn": "5.1.1", - "acorn-jsx": "3.0.1" + "acorn": "^5.0.1", + "acorn-jsx": "^3.0.0" }, "dependencies": { "acorn": { @@ -600,7 +600,7 @@ "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" }, "dependencies": { "estraverse": { @@ -617,8 +617,8 @@ "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", "dev": true, "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" + "estraverse": "^4.1.0", + "object-assign": "^4.0.1" }, "dependencies": { "estraverse": { @@ -647,8 +647,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" + "d": "1", + "es5-ext": "~0.10.14" } }, "exit-hook": { @@ -669,8 +669,8 @@ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-entry-cache": { @@ -679,8 +679,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.2.2", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "flat-cache": { @@ -689,10 +689,10 @@ "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", "dev": true, "requires": { - "circular-json": "0.3.1", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "fs.realpath": { @@ -713,7 +713,7 @@ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { - "is-property": "1.0.2" + "is-property": "^1.0.0" } }, "get-stream": { @@ -730,11 +730,11 @@ "requires": { "async": "2.1.2", "commander": "2.9.0", - "globby": "6.1.0", + "globby": "^6.1.0", "graceful-fs": "4.1.10", "q": "1.4.1", "q-io": "1.13.2", - "rimraf": "2.6.1" + "rimraf": "^2.5.4" }, "dependencies": { "commander": { @@ -743,7 +743,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "globby": { @@ -752,11 +752,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "1.0.2", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "graceful-fs": { @@ -773,12 +773,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "globals": { @@ -793,12 +793,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "graceful-fs": { @@ -819,10 +819,10 @@ "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "async": { @@ -837,7 +837,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -848,7 +848,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "ignore": { @@ -869,7 +869,7 @@ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "inflight": { @@ -878,8 +878,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -894,19 +894,19 @@ "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.1.0", - "figures": "1.7.0", - "lodash": "4.17.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" } }, "interpret": { @@ -933,7 +933,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -942,7 +942,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-my-json-valid": { @@ -951,10 +951,10 @@ "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", "dev": true, "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-path-cwd": { @@ -969,7 +969,7 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -978,7 +978,7 @@ "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-promise": { @@ -999,7 +999,7 @@ "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", "dev": true, "requires": { - "tryit": "1.0.3" + "tryit": "^1.0.1" } }, "is-stream": { @@ -1026,20 +1026,20 @@ "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "abbrev": "1.0.9", - "async": "1.5.2", - "escodegen": "1.8.1", - "esprima": "2.7.3", - "glob": "5.0.15", - "handlebars": "4.0.10", - "js-yaml": "3.9.0", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "once": "1.4.0", - "resolve": "1.1.7", - "supports-color": "3.2.3", - "which": "1.2.14", - "wordwrap": "1.0.0" + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" }, "dependencies": { "async": { @@ -1060,11 +1060,11 @@ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "resolve": { @@ -1079,7 +1079,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" }, "dependencies": { "has-flag": { @@ -1104,8 +1104,8 @@ "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", "dev": true, "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "dependencies": { "esprima": { @@ -1122,7 +1122,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "jsonify": { @@ -1143,7 +1143,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "^1.1.5" } }, "lazy-cache": { @@ -1159,8 +1159,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lint-staged": { @@ -1169,14 +1169,14 @@ "integrity": "sha1-nKaWizDfv+gTZbenY81PSZKJZVM=", "dev": true, "requires": { - "app-root-path": "2.0.1", - "cosmiconfig": "1.1.0", - "execa": "0.8.0", - "listr": "0.12.0", - "lodash.chunk": "4.2.0", - "minimatch": "3.0.4", - "npm-which": "3.0.1", - "p-map": "1.1.1", + "app-root-path": "^2.0.0", + "cosmiconfig": "^1.1.0", + "execa": "^0.8.0", + "listr": "^0.12.0", + "lodash.chunk": "^4.2.0", + "minimatch": "^3.0.0", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", "staged-git-files": "0.0.4" }, "dependencies": { @@ -1186,13 +1186,13 @@ "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } } } @@ -1203,22 +1203,22 @@ "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", "dev": true, "requires": { - "chalk": "1.1.3", - "cli-truncate": "0.2.1", - "figures": "1.7.0", - "indent-string": "2.1.0", - "is-promise": "2.1.0", - "is-stream": "1.1.0", - "listr-silent-renderer": "1.1.1", - "listr-update-renderer": "0.2.0", - "listr-verbose-renderer": "0.4.0", - "log-symbols": "1.0.2", - "log-update": "1.0.2", - "ora": "0.2.3", - "p-map": "1.1.1", - "rxjs": "5.4.2", - "stream-to-observable": "0.1.0", - "strip-ansi": "3.0.1" + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "figures": "^1.7.0", + "indent-string": "^2.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.2.0", + "listr-verbose-renderer": "^0.4.0", + "log-symbols": "^1.0.2", + "log-update": "^1.0.2", + "ora": "^0.2.3", + "p-map": "^1.1.1", + "rxjs": "^5.0.0-beta.11", + "stream-to-observable": "^0.1.0", + "strip-ansi": "^3.0.1" } }, "listr-silent-renderer": { @@ -1233,14 +1233,14 @@ "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", "dev": true, "requires": { - "chalk": "1.1.3", - "cli-truncate": "0.2.1", - "elegant-spinner": "1.0.1", - "figures": "1.7.0", - "indent-string": "3.1.0", - "log-symbols": "1.0.2", - "log-update": "1.0.2", - "strip-ansi": "3.0.1" + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^1.0.2", + "strip-ansi": "^3.0.1" }, "dependencies": { "indent-string": { @@ -1257,10 +1257,10 @@ "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", "dev": true, "requires": { - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "date-fns": "1.28.5", - "figures": "1.7.0" + "chalk": "^1.1.3", + "cli-cursor": "^1.0.2", + "date-fns": "^1.27.2", + "figures": "^1.7.0" } }, "locater": { @@ -1287,7 +1287,7 @@ "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", "dev": true, "requires": { - "chalk": "1.1.3" + "chalk": "^1.0.0" } }, "log-update": { @@ -1296,8 +1296,8 @@ "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "cli-cursor": "1.0.2" + "ansi-escapes": "^1.0.0", + "cli-cursor": "^1.0.2" } }, "longest": { @@ -1312,8 +1312,8 @@ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "marked": { @@ -1340,7 +1340,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1382,7 +1382,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } }, "npm-path": { @@ -1391,7 +1391,7 @@ "integrity": "sha1-Fc/04ciaONp39W9gVbJPl137K74=", "dev": true, "requires": { - "which": "1.2.14" + "which": "^1.2.10" } }, "npm-run-path": { @@ -1400,7 +1400,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "npm-which": { @@ -1409,9 +1409,9 @@ "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", "dev": true, "requires": { - "commander": "2.11.0", - "npm-path": "2.0.3", - "which": "1.2.14" + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" } }, "number-is-nan": { @@ -1432,7 +1432,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -1447,8 +1447,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "wordwrap": { @@ -1465,12 +1465,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "ora": { @@ -1479,10 +1479,10 @@ "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", "dev": true, "requires": { - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-spinners": "0.1.2", - "object-assign": "4.1.1" + "chalk": "^1.1.1", + "cli-cursor": "^1.0.2", + "cli-spinners": "^0.1.2", + "object-assign": "^4.0.1" } }, "os-homedir": { @@ -1509,7 +1509,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "path-is-absolute": { @@ -1554,7 +1554,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pinpoint": { @@ -1611,12 +1611,12 @@ "integrity": "sha1-7qEw1IHdteGqG8WmaFX3OR0G8AM=", "dev": true, "requires": { - "collections": "0.2.2", - "mime": "1.3.6", - "mimeparse": "0.1.4", - "q": "1.4.1", - "qs": "1.2.2", - "url2": "0.0.0" + "collections": "^0.2.0", + "mime": "^1.2.11", + "mimeparse": "^0.1.4", + "q": "^1.0.1", + "qs": "^1.2.1", + "url2": "^0.0.0" }, "dependencies": { "qs": { @@ -1633,13 +1633,13 @@ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "readline2": { @@ -1648,8 +1648,8 @@ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", "mute-stream": "0.0.5" } }, @@ -1659,7 +1659,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.3.3" + "resolve": "^1.1.6" } }, "repeat-string": { @@ -1674,7 +1674,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "require-from-string": { @@ -1689,8 +1689,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve": { @@ -1699,7 +1699,7 @@ "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-from": { @@ -1714,8 +1714,8 @@ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" } }, "right-align": { @@ -1725,7 +1725,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -1734,7 +1734,7 @@ "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-async": { @@ -1743,7 +1743,7 @@ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.3.0" } }, "rx-lite": { @@ -1758,7 +1758,7 @@ "integrity": "sha1-KjI2/L8D31e64G/Wly/ZnlwI/Pc=", "dev": true, "requires": { - "symbol-observable": "1.0.4" + "symbol-observable": "^1.0.1" } }, "safe-buffer": { @@ -1773,7 +1773,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -1788,9 +1788,9 @@ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", "dev": true, "requires": { - "glob": "7.1.2", - "interpret": "1.0.3", - "rechoir": "0.6.2" + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" } }, "signal-exit": { @@ -1812,7 +1812,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "sprintf-js": { @@ -1839,9 +1839,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -1850,7 +1850,7 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1859,7 +1859,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -1898,12 +1898,12 @@ "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", "slice-ansi": "0.0.4", - "string-width": "2.1.1" + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -1924,8 +1924,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { @@ -1934,7 +1934,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -1963,7 +1963,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "typedarray": { @@ -1979,9 +1979,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.6", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "camelcase": { @@ -1998,8 +1998,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" } }, @@ -2031,9 +2031,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } @@ -2058,7 +2058,7 @@ "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } }, "util-deprecate": { @@ -2079,7 +2079,7 @@ "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "wordwrap": { @@ -2100,7 +2100,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "xtend": { From 24875832e90ba67e23d528915141b544c16f34ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 29 May 2018 23:02:23 +0200 Subject: [PATCH 242/301] [ospec] Document changes made to the result objects. --- ospec/README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 2e2f55f1..4b71e74f 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -559,15 +559,23 @@ o.run(function(results) { --- -### Boolean result.pass +### Boolean|Null result.pass -True if the test passed. **No other keys will exist on the result if this value is true.** +- `true` if the assertion passed. +- `false` if the assertion failed. +- `null` if the assertion was incomplete (`o("partial assertion) // and that's it`). --- ### Error result.error -The `Error` object explaining the reason behind a failure. +The `Error` object explaining the reason behind a failure. If the assertion failed, the stack will point to the actuall error. If the assertion did pass or was incomplete, this field is identical to `result.testError`. + +--- + +### Error result.testError + +An `Error` object whose stack points to the test definition that wraps the assertion. Useful as a fallback because in some async cases the main may not point to test code. --- @@ -595,7 +603,7 @@ o.spec("message", function() { ### String result.context -A `>`-separated string showing the structure of the test specification. +In case of failure, a `>`-separated string showing the structure of the test specification. In the below example, `result.context` would be `testing > rocks`. ```javascript From 95ec3d28aa866a75050983c62aa1b2186a59150a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 18 May 2018 21:12:52 +0200 Subject: [PATCH 243/301] test for the LIS-based diff --- render/tests/test-updateNodes.js | 151 ++++++++++++++++++++++- render/tests/test-updateNodesFuzzer.js | 159 +++++++++++++++++++++++++ 2 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 render/tests/test-updateNodesFuzzer.js diff --git a/render/tests/test-updateNodes.js b/render/tests/test-updateNodes.js index 85a5ffd3..d464eda9 100644 --- a/render/tests/test-updateNodes.js +++ b/render/tests/test-updateNodes.js @@ -134,17 +134,17 @@ o.spec("updateNodes", function() { o("reverses els w/ odd count", function() { var vnodes = [{tag: "a", key: 1}, {tag: "b", key: 2}, {tag: "i", key: 3}] var updated = [{tag: "i", key: 3}, {tag: "b", key: 2}, {tag: "a", key: 1}] - + var expectedTags = updated.map(function(vn) {return vn.tag}) render(root, vnodes) render(root, updated) + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + o(root.childNodes.length).equals(3) o(updated[0].dom.nodeName).equals("I") - o(updated[0].dom).equals(root.childNodes[0]) o(updated[1].dom.nodeName).equals("B") - o(updated[1].dom).equals(root.childNodes[1]) o(updated[2].dom.nodeName).equals("A") - o(updated[2].dom).equals(root.childNodes[2]) + o(tagNames).deepEquals(expectedTags) }) o("creates el at start", function() { var vnodes = [{tag: "a", key: 1}] @@ -1100,6 +1100,149 @@ o.spec("updateNodes", function() { o([].map.call(root.childNodes, function(el) {return el.nodeName})).deepEquals(["DIV", "DIV", "P"]) }) + o("minimizes DOM operations when scrambling a keyed lists", function() { + var vnodes = [{tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}, {tag: "d", key: "d"}] + var updated = [{tag: "b", key: "b"}, {tag: "a", key: "a"}, {tag: "d", key: "d"}, {tag: "c", key: "c"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(2) + o(tagNames).deepEquals(expectedTagNames) + }) + o("minimizes DOM operations when reversing a keyed lists with an odd number of items", function() { + var vnodes = [{tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}, {tag: "d", key: "d"}] + var updated = [{tag: "d", key: "d"}, {tag: "c", key: "c"}, {tag: "b", key: "b"}, {tag: "a", key: "a"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(3) + o(tagNames).deepEquals(expectedTagNames) + }) + o("minimizes DOM operations when reversing a keyed lists with an even number of items", function() { + var vnodes = [{tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}] + var updated = [{tag: "c", key: "c"}, {tag: "b", key: "b"}, {tag: "a", key: "a"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(2) + o(tagNames).deepEquals(expectedTagNames) + }) + o("minimizes DOM operations when scrambling a keyed lists with prefixes and suffixes", function() { + var vnodes = [{tag: "i", key: "i"}, {tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}, {tag: "d", key: "d"}, {tag: "j", key: "j"}] + var updated = [{tag: "i", key: "i"}, {tag: "b", key: "b"}, {tag: "a", key: "a"}, {tag: "d", key: "d"}, {tag: "c", key: "c"}, {tag: "j", key: "j"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(2) + o(tagNames).deepEquals(expectedTagNames) + }) + o("minimizes DOM operations when reversing a keyed lists with an odd number of items with prefixes and suffixes", function() { + var vnodes = [{tag: "i", key: "i"}, {tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}, {tag: "d", key: "d"}, {tag: "j", key: "j"}] + var updated = [{tag: "i", key: "i"}, {tag: "d", key: "d"}, {tag: "c", key: "c"}, {tag: "b", key: "b"}, {tag: "a", key: "a"}, {tag: "j", key: "j"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(3) + o(tagNames).deepEquals(expectedTagNames) + }) + o("minimizes DOM operations when reversing a keyed lists with an even number of items with prefixes and suffixes", function() { + var vnodes = [{tag: "i", key: "i"}, {tag: "a", key: "a"}, {tag: "b", key: "b"}, {tag: "c", key: "c"}, {tag: "j", key: "j"}] + var updated = [{tag: "i", key: "i"}, {tag: "c", key: "c"}, {tag: "b", key: "b"}, {tag: "a", key: "a"}, {tag: "j", key: "j"}] + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(2) + o(tagNames).deepEquals(expectedTagNames) + }) + o("scrambling sample 1", function() { + function vnodify(str) { + return str.split(",").map(function(k) {return {tag: k, key: k}}) + } + var vnodes = vnodify("k0,k1,k2,k3,k4,k5,k6,k7,k8,k9") + var updated = vnodify("k4,k1,k2,k9,k0,k3,k6,k5,k8,k7") + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(5) + o(tagNames).deepEquals(expectedTagNames) + }) + o("scrambling sample 2", function() { + function vnodify(str) { + return str.split(",").map(function(k) {return {tag: k, key: k}}) + } + var vnodes = vnodify("k0,k1,k2,k3,k4,k5,k6,k7,k8,k9") + var updated = vnodify("b,d,k1,k0,k2,k3,k4,a,c,k5,k6,k7,k8,k9") + var expectedTagNames = updated.map(function(vn) {return vn.tag}) + + render(root, vnodes) + + root.appendChild = o.spy(root.appendChild) + root.insertBefore = o.spy(root.insertBefore) + + render(root, updated) + + var tagNames = [].map.call(root.childNodes, function(n) {return n.nodeName.toLowerCase()}) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(5) + o(tagNames).deepEquals(expectedTagNames) + }) + components.forEach(function(cmp){ o.spec(cmp.kind, function(){ var createComponent = cmp.create diff --git a/render/tests/test-updateNodesFuzzer.js b/render/tests/test-updateNodesFuzzer.js new file mode 100644 index 00000000..db5cafa7 --- /dev/null +++ b/render/tests/test-updateNodesFuzzer.js @@ -0,0 +1,159 @@ +"use strict" + +var o = require("../../ospec/ospec") +var domMock = require("../../test-utils/domMock") +var vdom = require("../../render/render") + +// pilfered and adapted from https://github.com/domvm/domvm/blob/7aaec609e4c625b9acf9a22d035d6252a5ca654f/test/src/flat-list-keyed-fuzz.js +o.spec("updateNodes keyed list Fuzzer", function() { + var i = 0, $window, root, render + o.beforeEach(function() { + $window = domMock() + root = $window.document.createElement("div") + render = vdom($window).render + }) + + + void [ + {delMax: 0, movMax: 50, insMax: 9}, + {delMax: 3, movMax: 5, insMax: 5}, + {delMax: 7, movMax: 15, insMax: 0}, + {delMax: 5, movMax: 100, insMax: 3}, + {delMax: 5, movMax: 0, insMax: 3}, + ].forEach(function(c) { + var tests = 250 + + while (tests--) { + var test = fuzzTest(c.delMax, c.movMax, c.insMax) + o(i++ + ": " + test.list.join() + " -> " + test.updated.join(), function() { + render(root, test.list.map(function(x){return {tag: x, key: x}})) + addSpies(root) + render(root, test.updated.map(function(x){return {tag: x, key: x}})) + + if (root.appendChild.callCount + root.insertBefore.callCount !== test.expected.creations + test.expected.moves) console.log(test, {aC: root.appendChild.callCount, iB: root.insertBefore.callCount}, [].map.call(root.childNodes, function(n){return n.nodeName.toLowerCase()})) + + o(root.appendChild.callCount + root.insertBefore.callCount).equals(test.expected.creations + test.expected.moves)("moves") + o(root.removeChild.callCount).equals(test.expected.deletions)("deletions") + o([].map.call(root.childNodes, function(n){return n.nodeName.toLowerCase()})).deepEquals(test.updated) + }) + } + }) +}) + +// https://en.wikipedia.org/wiki/Longest_increasing_subsequence +// impl borrowed from https://github.com/ivijs/ivi +function longestIncreasingSubsequence(a) { + var p = a.slice() + var result = [] + result.push(0) + var u + var v + + for (var i = 0, il = a.length; i < il; ++i) { + var j = result[result.length - 1] + if (a[j] < a[i]) { + p[i] = j + result.push(i) + continue + } + + u = 0 + v = result.length - 1 + + while (u < v) { + /*eslint-disable no-bitwise*/ + var c = ((u + v) / 2) | 0 + /*eslint-enable no-bitwise*/ + if (a[result[c]] < a[i]) { + u = c + 1 + } else { + v = c + } + } + + if (a[i] < a[result[u]]) { + if (u > 0) { + p[i] = result[u - 1] + } + result[u] = i + } + } + + u = result.length + v = result[u - 1] + + while (u-- > 0) { + result[u] = v + v = p[v] + } + + return result +} + +function rand(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min +} + +function ins(arr, qty) { + var p = ["a","b","c","d","e","f","g","h","i"] + + while (qty-- > 0) + arr.splice(rand(0, arr.length - 1), 0, p.shift()) +} + +function del(arr, qty) { + while (qty-- > 0) + arr.splice(rand(0, arr.length - 1), 1) +} + +function mov(arr, qty) { + while (qty-- > 0) { + var from = rand(0, arr.length - 1) + var to = rand(0, arr.length - 1) + + arr.splice(to, 0, arr.splice(from, 1)[0]) + } +} + +function fuzzTest(delMax, movMax, insMax) { + var list = ["k0","k1","k2","k3","k4","k5","k6","k7","k8","k9"] + var copy = list.slice() + + var delCount = rand(0, delMax), + movCount = rand(0, movMax), + insCount = rand(0, insMax) + + del(copy, delCount) + mov(copy, movCount) + + var expected = { + creations: insCount, + deletions: delCount, + moves: 0 + } + + if (movCount > 0) { + var newPos = copy.map(function(v) { + return list.indexOf(v) + }).filter(function(i) { + return i != -1 + }) + var lis = longestIncreasingSubsequence(newPos) + expected.moves = copy.length - lis.length + } + + ins(copy, insCount) + + return { + expected: expected, + list: list, + updated: copy + } +} + +function addSpies(node) { + node.appendChild = o.spy(node.appendChild) + node.insertBefore = o.spy(node.insertBefore) + node.removeChild = o.spy(node.removeChild) +} + From 2cfc68359d50786bc385ab26dd338e4194214797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sun, 22 Apr 2018 11:09:57 +0200 Subject: [PATCH 244/301] [render/render] Introduce longest increasing subsequence-based node moves in keyed diff, fix #1791, fix #2026 --- render/render.js | 222 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 157 insertions(+), 65 deletions(-) diff --git a/render/render.js b/render/render.js index b9b6411a..30d6db0c 100644 --- a/render/render.js +++ b/render/render.js @@ -260,11 +260,10 @@ module.exports = function($window) { function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { if (old === vnodes || old == null && vnodes == null) return - else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length) + else if (old == null || old.length === 0) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) + else if (vnodes == null || vnodes.length === 0) removeNodes(old, 0, old.length) else { - // default to keyed because, when either list is full of null nodes, it has fewer branches - var start = 0, oldStart = 0, isOldKeyed = true, isKeyed = true + var start = 0, oldStart = 0, isOldKeyed = null, isKeyed = null for (; oldStart < old.length; oldStart++) { if (old[oldStart] != null) { isOldKeyed = old[oldStart].key != null @@ -277,12 +276,11 @@ module.exports = function($window) { break } } + if (isKeyed === null && isOldKeyed == null) return // both lists are full of nulls if (isOldKeyed !== isKeyed) { removeNodes(old, oldStart, old.length) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) - return - } - if (!isKeyed) { + } else if (!isKeyed) { // Don't index past the end of either list (causes deopts). var commonLength = old.length < vnodes.length ? old.length : vnodes.length // Rewind if necessary to the first non-null index on either side. @@ -299,72 +297,120 @@ module.exports = function($window) { } if (old.length > commonLength) removeNodes(old, start, old.length) if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) - return - } - // keyed diff - var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v + } else { + // keyed diff + var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling - while (oldEnd >= oldStart && end >= start) { - // both top-down - o = old[oldStart] - v = vnodes[start] - if (o == null) oldStart++ - else if (v == null) start++ - else if (o.key === v.key) { - oldStart++, start++ - if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) - } else { - // reversal: old top-down, new bottom-up - v = vnodes[end] - if (o == null) oldStart++ - else if (v == null) end-- - else if (o.key === v.key) { - oldStart++ - if (start < end--) insertNode(parent, toFragment(o), nextSibling) - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if (v.dom != null) nextSibling = v.dom + while (oldEnd >= oldStart && end >= start) { + oe = old[oldEnd] + ve = vnodes[end] + if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (oe.key === ve.key) { + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldEnd--, end-- + } else { + break } - else break } - } - while (oldEnd >= oldStart && end >= start) { - // both bottom-up - o = old[oldEnd] - v = vnodes[end] - if (o == null) oldEnd-- - else if (v == null) end-- - else if (o.key === v.key) { - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if (v.dom != null) nextSibling = v.dom - oldEnd--, end-- - } else { - // old map-based, new bottom-up - if (map == null) { - // the last node can be left out of the map because it will be caught by the - // bottom-up part of the diff loop. If we were to refactor this to use distinct - // loops, we'd have to pass `oldEnd + 1` (or change `start < end` to `<=` in getKeyMap). - map = getKeyMap(old, oldStart, oldEnd) + while (oldEnd >= oldStart && end >= start) { + o = old[oldStart] + v = vnodes[start] + if (o == null) oldStart++ + else if (v == null) start++ + else if (o.key === v.key) { + oldStart++, start++ + if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) + } else { + break } - if (v != null) { - var oldIndex = map[v.key] - if (oldIndex == null) { - createNode(parent, v, hooks, ns, nextSibling) - if (v.dom != null) nextSibling = v.dom - } else { - o = old[oldIndex] - insertNode(parent, toFragment(o), nextSibling) - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - o.skip = true - if (v.dom != null) nextSibling = v.dom + } + + //swaps and list reversals + while (oldEnd >= oldStart && end >= start) { + o = old[oldStart] + v = vnodes[start] + if (o == null) oldStart++ + else if (v == null) start++ + else if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (start === end) break + else { + if (o.key !== ve.key || oe.key !== v.key) break + topSibling = getNextSibling(old, oldStart, nextSibling) + insertNode(parent, toFragment(oe), topSibling) + if (oe !== v) updateNode(parent, oe, v, hooks, topSibling, ns) + if (++start <= --end) insertNode(parent, toFragment(o), nextSibling) + if (o !== ve) updateNode(parent, o, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldStart++; oldEnd-- + } + oe = old[oldEnd] + ve = vnodes[end] + } + while (oldEnd >= oldStart && end >= start) { + if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (oe.key === ve.key) { + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldEnd--, end-- + } else { + break + } + oe = old[oldEnd] + ve = vnodes[end] + } + if (start > end) removeNodes(old, oldStart, oldEnd + 1) + else if (oldStart > oldEnd) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) + else { + // inspired by ivi + var originalNextSibling = nextSibling, vnodesLength = end - start + 1, map, i, lis + var oldIndices = new Array(end - start + 1) + for (i = 0; i < vnodesLength; i++) oldIndices[i] = -1 + var pos = 2147483647, matched = false + + for (i = end; i >= start; i--) { + if (map == null) map = getKeyMap(old, oldStart, oldEnd + 1) + v = vnodes[i] + if (v != null) { + var oldIndex = map[v.key] + if (oldIndex != null) { + pos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered + oldIndices[i-start] = oldIndex + o = old[oldIndex] + o.skip = true + if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) + if (v.dom != null) nextSibling = v.dom + matched = true + } + } + } + nextSibling = originalNextSibling + removeNodes(old, oldStart, oldEnd + 1) + if (!matched) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) + else { + if (pos === -1) { + lis = makeLis(oldIndices) + var lisi = lis.length - 1 + for (i = end; i >= start; i--) { + if (oldIndices[i-start] === -1) createNode(parent, vnodes[i], hooks, ns, nextSibling) + else { + if (lis[lisi] === i - start) lisi-- + else insertNode(parent, toFragment(vnodes[i]), nextSibling) + } + if (vnodes[i].dom != null) nextSibling = vnodes[i].dom + } + } else { + for (i = end; i >= start; i--) { + if (oldIndices[i-start] === -1) createNode(parent, vnodes[i], hooks, ns, nextSibling) + if (vnodes[i].dom != null) nextSibling = vnodes[i].dom + } } } - end-- } - if (end < start) break } - // deal with the leftovers. - createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, oldEnd + 1) } } function updateNode(parent, old, vnode, hooks, nextSibling, ns) { @@ -475,6 +521,52 @@ module.exports = function($window) { } return map } + // Lifted from ivi https://github.com/ivijs/ivi/ + function makeLis(a) { + var p = a.slice() + var result = [] + result.push(0) + var u + var v + for (var i = 0, il = a.length; i < il; ++i) { + if (a[i] === -1) { + continue + } + var j = result[result.length - 1] + if (a[j] < a[i]) { + p[i] = j + result.push(i) + continue + } + u = 0 + v = result.length - 1 + while (u < v) { + /*eslint-disable no-bitwise*/ + var c = ((u + v) / 2) | 0 + /*eslint-enable no-bitwise*/ + if (a[result[c]] < a[i]) { + u = c + 1 + } + else { + v = c + } + } + if (a[i] < a[result[u]]) { + if (u > 0) { + p[i] = result[u - 1] + } + result[u] = i + } + } + u = result.length + v = result[u - 1] + while (u-- > 0) { + result[u] = v + v = p[v] + } + return result + } + function toFragment(vnode) { var count = vnode.domSize if (count != null || vnode.dom == null) { From e3b240032acc095770792b34fdff5954d11cf282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 21 May 2018 01:13:28 +0200 Subject: [PATCH 245/301] [domMock] don't call public methods from DOM API methods (it messes up spying) --- test-utils/domMock.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-utils/domMock.js b/test-utils/domMock.js index e5c1f68c..c45b34e9 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -71,7 +71,7 @@ module.exports = function(options) { var index = this.childNodes.indexOf(child) if (index > -1) this.childNodes.splice(index, 1) if (child.nodeType === 11) { - while (child.firstChild != null) this.appendChild(child.firstChild) + while (child.firstChild != null) appendChild.call(this, child.firstChild) child.childNodes = [] } else { @@ -99,7 +99,7 @@ module.exports = function(options) { var index = this.childNodes.indexOf(child) if (reference !== null && refIndex < 0) throw new TypeError("Invalid argument") if (index > -1) this.childNodes.splice(index, 1) - if (reference === null) this.appendChild(child) + if (reference === null) appendChild.call(this, child) else { if (index !== -1 && refIndex > index) refIndex-- if (child.nodeType === 11) { @@ -276,7 +276,7 @@ module.exports = function(options) { }, set textContent(value) { this.childNodes = [] - if (value !== "") this.appendChild($window.document.createTextNode(value)) + if (value !== "") appendChild.call(this, $window.document.createTextNode(value)) }, set innerHTML(value) { var voidElements = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"] @@ -286,7 +286,7 @@ module.exports = function(options) { var value = match[1] root = $window.document.createElementNS("http://www.w3.org/2000/svg", "svg") ns = "http://www.w3.org/2000/svg" - this.appendChild(root) + appendChild.call(this, root) } else { root = this } From 144ce681924b688f633455b0ad2eb2f87b7af677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Mon, 21 May 2018 01:28:09 +0200 Subject: [PATCH 246/301] [render/render] get rid of vnode.skip --- render/render.js | 13 +++++-------- render/vnode.js | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/render/render.js b/render/render.js index 30d6db0c..009aa99e 100644 --- a/render/render.js +++ b/render/render.js @@ -221,13 +221,13 @@ module.exports = function($window) { // The fourth section does keyed diff for the situations not covered by the other three. It // builds a {key: oldIndex} dictionary and uses it to find old nodes that match the keys of // new ones. - // The nodes from the `old` array that have a match in the new `vnodes` one are marked as - // `vnode.skip: true`. + // The nodes from the `old` array that have a match in the new `vnodes` one are removed from + // the old list (set to `null`). // // If there are still nodes in the new `vnodes` array that haven't been matched to old ones, // they are created. // The range of old nodes that wasn't covered by the first three sections is passed to - // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. + // `removeNodes()`. The nodes that remain in the list are removed from the DOM. // // It should be noted that the description of the four sections above is not perfect, because those // parts are actually implemented as only two loops, one for the first two parts, and one for @@ -380,7 +380,7 @@ module.exports = function($window) { pos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered oldIndices[i-start] = oldIndex o = old[oldIndex] - o.skip = true + old[oldIndex] = null if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) if (v.dom != null) nextSibling = v.dom matched = true @@ -605,10 +605,7 @@ module.exports = function($window) { function removeNodes(vnodes, start, end) { for (var i = start; i < end; i++) { var vnode = vnodes[i] - if (vnode != null) { - if (vnode.skip) vnode.skip = false - else removeNode(vnode) - } + if (vnode != null) removeNode(vnode) } } function removeNode(vnode) { diff --git a/render/vnode.js b/render/vnode.js index 5873dca5..98acdd41 100644 --- a/render/vnode.js +++ b/render/vnode.js @@ -1,7 +1,7 @@ "use strict" function Vnode(tag, key, attrs, children, text, dom) { - return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined, skip: false} + return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined} } Vnode.normalize = function(node) { if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) From 285cb5382f3b3ebaf9aa7685e8bc66ffc6d702ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 22 May 2018 18:30:55 +0200 Subject: [PATCH 247/301] [render] cleanup and comments --- docs/change-log.md | 3 +- render/render.js | 119 +++++++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index 0ee241d9..b38fdb03 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -33,7 +33,8 @@ - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) - Mocks: add limited support for the DOMParser API ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) - API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) -- Internals: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122)) +- render/core: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122)) +- render/core: revamp the core diff engine, and introduce a longest-increasing-subsequence-based logic to minimize DOM operations when re-ordering keyed nodes. #### Bug fixes diff --git a/render/render.js b/render/render.js index 009aa99e..41fd6100 100644 --- a/render/render.js +++ b/render/render.js @@ -200,39 +200,47 @@ module.exports = function($window) { // ## Diffing // - // If one list is keyed and the other is unkeyed, the old is removed, and the new one is - // inserted (since the keys are guaranteed to differ). + // Reading https://github.com/localvoid/ivi/blob/ddc09d06abaef45248e6133f7040d00d3c6be853/packages/ivi/src/vdom/implementation.ts#L617-L837 + // may be good for context on longest increasing subsequence-based logic for moving nodes. // - // Then comes the unkeyed diff algo, and at last, the keyed diff algorithm that is split - // in four parts (simplifying a bit). + // In order to diff keyed lists, one has to // - // The first part goes through both lists top-down as long as the nodes at each level have - // the same key. + // 1) match nodes in both lists, per key, and update them accordingly + // 2) create the nodes present in the new list, but absent in the old one + // 3) remove the nodes present in the old list, but absent in the new one + // 4) figure out what nodes in 1) to move in order to minimize the DOM operations. // - // The second part deals with lists reversals, and traverses one list top-down and the other - // bottom-up (as long as the keys match). + // To achieve 1) one can create a dictionary of keys => index (for the old list), then iterate + // over the new list and for each new vnode, find the corresponding vnode in the old list using + // the map. + // 2) is achieved in the same step: if a new node has no corresponding entry in the map, it is new + // and must be created. + // For the removals, we actually remove the nodes that have been updated from the old list. + // The nodes that remain in that list after 1) and 2) have been performed can be safely removed. + // The fourth step is a bit more complex and relies on the longest increasing subsequence (LIS) + // algorithm. // - // The third part goes through both lists bottom up as long as the keys match. + // the longest increasing subsequence is the list of nodes that can remain in place. Imagine going + // from `1,2,3,4,5` to `4,5,1,2,3` where the numbers are not necessarily the keys, but the indices + // corresponding to the keyed nodes in the old list (keyed nodes `e,d,c,b,a` => `b,a,e,d,c` would + // match the above lists, for example). // - // The first and third sections allow us to deal efficiently with situations where one or - // more contiguous nodes were either inserted into, removed from or re-ordered in an otherwise - // sorted list. They may reduce the number of nodes to be processed in the fourth section. + // In there are two increasing subsequences: `4,5` and `1,2,3`, the latter being the longest. We + // can update those nodes without moving them, and only call `insertNode` on `4` and `5`. // - // The fourth section does keyed diff for the situations not covered by the other three. It - // builds a {key: oldIndex} dictionary and uses it to find old nodes that match the keys of - // new ones. - // The nodes from the `old` array that have a match in the new `vnodes` one are removed from - // the old list (set to `null`). + // @localvoid adapted the algo to also support node deletions and insertions (the `lis` is actually + // the longest increasing subsequence *of old nodes still present in the new list*). // - // If there are still nodes in the new `vnodes` array that haven't been matched to old ones, - // they are created. - // The range of old nodes that wasn't covered by the first three sections is passed to - // `removeNodes()`. The nodes that remain in the list are removed from the DOM. + // It is a general algorithm that is fireproof in all circumstances, but it requires the allocation + // and the construction of a `key => oldIndex` map, and three arrays (one with `newIndex => oldIndex`, + // the `LIS` and a temporary one to create the LIS). + // + // So we cheat where we can: if the tails of the lists are identical, they are guaranteed to be part of + // the LIS and can be updated without moving them. + // + // If two nodes are swapped, they are guaranteed not to be part of the LIS, and must be moved (with + // the exception of the last node if the list is fully reversed). // - // It should be noted that the description of the four sections above is not perfect, because those - // parts are actually implemented as only two loops, one for the first two parts, and one for - // the other two. I'm not sure it wins us anything except maybe a few bytes of file size. - // ## Finding the next sibling. // // `updateNode()` and `createNode()` expect a nextSibling parameter to perform DOM operations. @@ -301,6 +309,7 @@ module.exports = function($window) { // keyed diff var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling + // bottom-up while (oldEnd >= oldStart && end >= start) { oe = old[oldEnd] ve = vnodes[end] @@ -314,6 +323,7 @@ module.exports = function($window) { break } } + // top-down while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] @@ -326,11 +336,8 @@ module.exports = function($window) { break } } - - //swaps and list reversals + // swaps and list reversals while (oldEnd >= oldStart && end >= start) { - o = old[oldStart] - v = vnodes[start] if (o == null) oldStart++ else if (v == null) start++ else if (oe == null) oldEnd-- @@ -348,7 +355,10 @@ module.exports = function($window) { } oe = old[oldEnd] ve = vnodes[end] + o = old[oldStart] + v = vnodes[start] } + // bottom up once again while (oldEnd >= oldStart && end >= start) { if (oe == null) oldEnd-- else if (ve == null) end-- @@ -365,47 +375,48 @@ module.exports = function($window) { if (start > end) removeNodes(old, oldStart, oldEnd + 1) else if (oldStart > oldEnd) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) else { - // inspired by ivi - var originalNextSibling = nextSibling, vnodesLength = end - start + 1, map, i, lis - var oldIndices = new Array(end - start + 1) + // inspired by ivi https://github.com/ivijs/ivi/ by Boris Kaul + var originalNextSibling = nextSibling, vnodesLength = end - start + 1, oldIndices = new Array(vnodesLength), li=0, i=0, pos = 2147483647, matched = 0, map, lisIndices for (i = 0; i < vnodesLength; i++) oldIndices[i] = -1 - var pos = 2147483647, matched = false - for (i = end; i >= start; i--) { if (map == null) map = getKeyMap(old, oldStart, oldEnd + 1) - v = vnodes[i] - if (v != null) { - var oldIndex = map[v.key] + ve = vnodes[i] + if (ve != null) { + var oldIndex = map[ve.key] if (oldIndex != null) { pos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered oldIndices[i-start] = oldIndex - o = old[oldIndex] + oe = old[oldIndex] old[oldIndex] = null - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if (v.dom != null) nextSibling = v.dom - matched = true + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + matched++ } } } nextSibling = originalNextSibling - removeNodes(old, oldStart, oldEnd + 1) - if (!matched) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) + if (matched !== oldEnd - oldStart + 1) removeNodes(old, oldStart, oldEnd + 1) + if (matched === 0) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) else { if (pos === -1) { - lis = makeLis(oldIndices) - var lisi = lis.length - 1 + // the indices of the indices of the items that are part of the + // longest increasing subsequence in the oldIndices list + lisIndices = makeLisIndices(oldIndices) + li = lisIndices.length - 1 for (i = end; i >= start; i--) { - if (oldIndices[i-start] === -1) createNode(parent, vnodes[i], hooks, ns, nextSibling) + v = vnodes[i] + if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling) else { - if (lis[lisi] === i - start) lisi-- - else insertNode(parent, toFragment(vnodes[i]), nextSibling) + if (lisIndices[li] === i - start) li-- + else insertNode(parent, toFragment(v), nextSibling) } - if (vnodes[i].dom != null) nextSibling = vnodes[i].dom + if (v.dom != null) nextSibling = vnodes[i].dom } } else { for (i = end; i >= start; i--) { - if (oldIndices[i-start] === -1) createNode(parent, vnodes[i], hooks, ns, nextSibling) - if (vnodes[i].dom != null) nextSibling = vnodes[i].dom + v = vnodes[i] + if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling) + if (v.dom != null) nextSibling = vnodes[i].dom } } } @@ -522,7 +533,11 @@ module.exports = function($window) { return map } // Lifted from ivi https://github.com/ivijs/ivi/ - function makeLis(a) { + // takes a list of unique numbers (-1 is special and can + // occur multiple times) and returns an array with the indices + // of the items that are part of the longest increasing + // subsequece + function makeLisIndices(a) { var p = a.slice() var result = [] result.push(0) From 277f35fb3a5f762244bb49d1778c196e2852c8bf Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Tue, 29 May 2018 21:52:06 +0000 Subject: [PATCH 248/301] Bundled output for commit 285cb5382f3b3ebaf9aa7685e8bc66ffc6d702ae [skip ci] --- README.md | 2 +- mithril.js | 302 +++++++++++++++++++++++++++++++++---------------- mithril.min.js | 92 +++++++-------- 3 files changed, 251 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index 6ddbbb0a..a7347635 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.29 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.71 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 63f91953..7478e740 100644 --- a/mithril.js +++ b/mithril.js @@ -1,7 +1,7 @@ ;(function() { "use strict" function Vnode(tag, key, attrs0, children, text, dom) { - return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined, skip: false} + return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined} } Vnode.normalize = function(node) { if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) @@ -589,38 +589,47 @@ var coreRenderer = function($window) { // are visited in the fourth part of the diff and in the `removeNodes` loop. // ## Diffing // - // If one list is keyed and the other is unkeyed, the old is removed, and the new one is - // inserted (since the keys are guaranteed to differ). + // Reading https://github.com/localvoid/ivi/blob/ddc09d06abaef45248e6133f7040d00d3c6be853/packages/ivi/src/vdom/implementation.ts#L617-L837 + // may be good for context on longest increasing subsequence-based logic for moving nodes. // - // Then comes the unkeyed diff algo, and at last0, the keyed diff algorithm that is split - // in four parts (simplifying a bit). + // In order to diff keyed lists, one has to // - // The first part goes through both lists top-down as long as the nodes at each level have - // the same key2. + // 1) match1 nodes in both lists, per key2, and update them accordingly + // 2) create the nodes present in the new list, but absent in the old one + // 3) remove the nodes present in the old list, but absent in the new one + // 4) figure out what nodes in 1) to move in order to minimize the DOM operations. // - // The second part deals with lists reversals, and traverses one list top-down and the other - // bottom-up (as long as the keys match1). + // To achieve 1) one can create a dictionary of keys => index0 (for the old list), then1 iterate + // over the new list and for each new vnode, find the corresponding vnode in the old list using + // the map. + // 2) is achieved in the same step: if a new node has no corresponding entry in the map, it is new + // and must be created. + // For the removals, we actually remove the nodes that have been updated from the old list. + // The nodes that remain in that list after 1) and 2) have been performed can be safely removed. + // The fourth step is a bit more complex and relies on the longest increasing subsequence (LIS) + // algorithm. // - // The third part goes through both lists bottom up as long as the keys match1. + // the longest increasing subsequence is the list of nodes that can remain in place. Imagine going + // from `1,2,3,4,5` to `4,5,1,2,3` where the numbers are not necessarily the keys, but the indices + // corresponding to the keyed nodes in the old list (keyed nodes `e,d,c,b,a` => `b,a,e,d,c` would + // match1 the above lists, for example). // - // The first and third sections allow us to deal efficiently with situations where one or - // more contiguous nodes were either inserted into, removed from or re-ordered in an otherwise - // sorted list. They may reduce the number of nodes to be processed in the fourth section. + // In there are two increasing subsequences: `4,5` and `1,2,3`, the latter being the longest. We + // can update those nodes without moving them, and only call `insertNode` on `4` and `5`. // - // The fourth section does keyed diff for the situations not covered by the other three. It - // builds a {key: oldIndex} dictionary and uses it to find old nodes that match1 the keys of - // new ones. - // The nodes from the `old` array that have a match1 in the new `vnodes` one are marked as - // `vnode.skip: true`. + // @localvoid adapted the algo to also support node deletions and insertions (the `lis` is actually + // the longest increasing subsequence *of old nodes still present in the new list*). // - // If there are still nodes in the new `vnodes` array that haven't been matched to old ones, - // they are created. - // The range of old nodes that wasn't covered by the first three sections is passed to - // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. + // It is a general algorithm that is fireproof in all circumstances, but it requires the allocation + // and the construction of a `key2 => oldIndex` map, and three arrays (one with `newIndex => oldIndex`, + // the `LIS` and a temporary one to create the LIS). + // + // So we cheat where we can: if the tails of the lists are identical, they are guaranteed to be part of + // the LIS and can be updated without moving them. + // + // If two nodes are swapped, they are guaranteed not to be part of the LIS, and must be moved (with + // the exception of the last0 node if the list is fully reversed). // - // It should be noted that the description of the four sections above is not perfect, because those - // parts are actually implemented as only two loops, one for the first two parts, and one for - // the other two. I'm1 not sure it wins us anything except maybe a few bytes of file size. // ## Finding the next0 sibling. // // `updateNode()` and `createNode()` expect a nextSibling parameter to perform DOM operations. @@ -645,11 +654,10 @@ var coreRenderer = function($window) { // three of the diff algo. function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { if (old === vnodes || old == null && vnodes == null) return - else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length) + else if (old == null || old.length === 0) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) + else if (vnodes == null || vnodes.length === 0) removeNodes(old, 0, old.length) else { - // default to keyed because, when either list is full of null nodes, it has fewer branches - var start = 0, oldStart = 0, isOldKeyed = true, isKeyed = true + var start = 0, oldStart = 0, isOldKeyed = null, isKeyed = null for (; oldStart < old.length; oldStart++) { if (old[oldStart] != null) { isOldKeyed = old[oldStart].key != null @@ -662,12 +670,11 @@ var coreRenderer = function($window) { break } } + if (isKeyed === null && isOldKeyed == null) return // both lists are full of nulls if (isOldKeyed !== isKeyed) { removeNodes(old, oldStart, old.length) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) - return - } - if (!isKeyed) { + } else if (!isKeyed) { // Don't index0 past the end of either list (causes deopts). var commonLength = old.length < vnodes.length ? old.length : vnodes.length // Rewind if necessary to the first non-null index0 on either side. @@ -684,71 +691,122 @@ var coreRenderer = function($window) { } if (old.length > commonLength) removeNodes(old, start, old.length) if (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns) - return - } - // keyed diff - var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v - while (oldEnd >= oldStart && end >= start) { - // both top-down - o = old[oldStart] - v = vnodes[start] - if (o == null) oldStart++ - else if (v == null) start++ - else if (o.key === v.key) { - oldStart++, start++ - if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) - } else { - // reversal: old top-down, new bottom-up - v = vnodes[end] - if (o == null) oldStart++ - else if (v == null) end-- - else if (o.key === v.key) { - oldStart++ - if (start < end--) insertNode(parent, toFragment(o), nextSibling) - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if (v.dom != null) nextSibling = v.dom + } else { + // keyed diff + var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling + // bottom-up + while (oldEnd >= oldStart && end >= start) { + oe = old[oldEnd] + ve = vnodes[end] + if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (oe.key === ve.key) { + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldEnd--, end-- + } else { + break } - else break } - } - while (oldEnd >= oldStart && end >= start) { - // both bottom-up - o = old[oldEnd] - v = vnodes[end] - if (o == null) oldEnd-- - else if (v == null) end-- - else if (o.key === v.key) { - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - if (v.dom != null) nextSibling = v.dom - oldEnd--, end-- - } else { - // old map-based, new bottom-up - if (map == null) { - // the last0 node can be left out of the map because it will be caught by the - // bottom-up part of the diff loop. If we were to refactor this to use distinct - // loops, we'd have to pass `oldEnd + 1` (or change `start < end` to `<=` in getKeyMap). - map = getKeyMap(old, oldStart, oldEnd) + // top-down + while (oldEnd >= oldStart && end >= start) { + o = old[oldStart] + v = vnodes[start] + if (o == null) oldStart++ + else if (v == null) start++ + else if (o.key === v.key) { + oldStart++, start++ + if (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) + } else { + break } - if (v != null) { - var oldIndex = map[v.key] - if (oldIndex == null) { - createNode(parent, v, hooks, ns, nextSibling) - if (v.dom != null) nextSibling = v.dom - } else { - o = old[oldIndex] - insertNode(parent, toFragment(o), nextSibling) - if (o !== v) updateNode(parent, o, v, hooks, nextSibling, ns) - o.skip = true - if (v.dom != null) nextSibling = v.dom + } + // swaps and list reversals + while (oldEnd >= oldStart && end >= start) { + if (o == null) oldStart++ + else if (v == null) start++ + else if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (start === end) break + else { + if (o.key !== ve.key || oe.key !== v.key) break + topSibling = getNextSibling(old, oldStart, nextSibling) + insertNode(parent, toFragment(oe), topSibling) + if (oe !== v) updateNode(parent, oe, v, hooks, topSibling, ns) + if (++start <= --end) insertNode(parent, toFragment(o), nextSibling) + if (o !== ve) updateNode(parent, o, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldStart++; oldEnd-- + } + oe = old[oldEnd] + ve = vnodes[end] + o = old[oldStart] + v = vnodes[start] + } + // bottom up once again + while (oldEnd >= oldStart && end >= start) { + if (oe == null) oldEnd-- + else if (ve == null) end-- + else if (oe.key === ve.key) { + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + oldEnd--, end-- + } else { + break + } + oe = old[oldEnd] + ve = vnodes[end] + } + if (start > end) removeNodes(old, oldStart, oldEnd + 1) + else if (oldStart > oldEnd) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) + else { + // inspired by ivi https://github.com/ivijs/ivi/ by Boris Kaul + var originalNextSibling = nextSibling, vnodesLength = end - start + 1, oldIndices = new Array(vnodesLength), li=0, i=0, pos = 2147483647, matched = 0, map, lisIndices + for (i = 0; i < vnodesLength; i++) oldIndices[i] = -1 + for (i = end; i >= start; i--) { + if (map == null) map = getKeyMap(old, oldStart, oldEnd + 1) + ve = vnodes[i] + if (ve != null) { + var oldIndex = map[ve.key] + if (oldIndex != null) { + pos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered + oldIndices[i-start] = oldIndex + oe = old[oldIndex] + old[oldIndex] = null + if (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns) + if (ve.dom != null) nextSibling = ve.dom + matched++ + } + } + } + nextSibling = originalNextSibling + if (matched !== oldEnd - oldStart + 1) removeNodes(old, oldStart, oldEnd + 1) + if (matched === 0) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) + else { + if (pos === -1) { + // the indices of the indices of the items that are part of the + // longest increasing subsequence in the oldIndices list + lisIndices = makeLisIndices(oldIndices) + li = lisIndices.length - 1 + for (i = end; i >= start; i--) { + v = vnodes[i] + if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling) + else { + if (lisIndices[li] === i - start) li-- + else insertNode(parent, toFragment(v), nextSibling) + } + if (v.dom != null) nextSibling = vnodes[i].dom + } + } else { + for (i = end; i >= start; i--) { + v = vnodes[i] + if (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling) + if (v.dom != null) nextSibling = vnodes[i].dom + } } } - end-- } - if (end < start) break } - // deal with the leftovers. - createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, oldEnd + 1) } } function updateNode(parent, old, vnode, hooks, nextSibling, ns) { @@ -858,6 +916,55 @@ var coreRenderer = function($window) { } return map } + // Lifted from ivi https://github.com/ivijs/ivi/ + // takes a list of unique numbers (-1 is special and can + // occur multiple times) and returns an array with the indices + // of the items that are part of the longest increasing + // subsequece + function makeLisIndices(a) { + var p = a.slice() + var result = [] + result.push(0) + var u + var v + for (var i = 0, il = a.length; i < il; ++i) { + if (a[i] === -1) { + continue + } + var j = result[result.length - 1] + if (a[j] < a[i]) { + p[i] = j + result.push(i) + continue + } + u = 0 + v = result.length - 1 + while (u < v) { + /*eslint-disable no-bitwise*/ + var c = ((u + v) / 2) | 0 + /*eslint-enable no-bitwise*/ + if (a[result[c]] < a[i]) { + u = c + 1 + } + else { + v = c + } + } + if (a[i] < a[result[u]]) { + if (u > 0) { + p[i] = result[u - 1] + } + result[u] = i + } + } + u = result.length + v = result[u - 1] + while (u-- > 0) { + result[u] = v + v = p[v] + } + return result + } function toFragment(vnode) { var count0 = vnode.domSize if (count0 != null || vnode.dom == null) { @@ -893,10 +1000,7 @@ var coreRenderer = function($window) { function removeNodes(vnodes, start, end) { for (var i = start; i < end; i++) { var vnode = vnodes[i] - if (vnode != null) { - if (vnode.skip) vnode.skip = false - else removeNode(vnode) - } + if (vnode != null) removeNode(vnode) } } function removeNode(vnode) { @@ -1210,12 +1314,12 @@ var parseQueryString = function(string) { var levels = key5.split(/\]\[?|\[/) var cursor = data0 if (key5.indexOf("[") > -1) levels.pop() - for (var j = 0; j < levels.length; j++) { - var level = levels[j], nextLevel = levels[j + 1] + for (var j0 = 0; j0 < levels.length; j0++) { + var level = levels[j0], nextLevel = levels[j0 + 1] var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel, 10)) - var isValue = j === levels.length - 1 + var isValue = j0 === levels.length - 1 if (level === "") { - var key5 = levels.slice(0, j).join() + var key5 = levels.slice(0, j0).join() if (counters[key5] == null) counters[key5] = 0 level = counters[key5]++ } @@ -1325,7 +1429,7 @@ var coreRouter = function($window) { } var _21 = function($window, redrawService0) { var routeService = coreRouter($window) - var identity = function(v) {return v} + var identity = function(v0) {return v0} var render1, component, attrs3, currentPath, lastUpdate var route = function(root, defaultRoute, routes) { if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined") diff --git a/mithril.min.js b/mithril.min.js index 2ec17ce2..40caf8b5 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,45 +1,47 @@ -(function(){function x(b,d,e,g,u,l){return{tag:b,key:d,attrs:e,children:g,text:u,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function M(b){for(var d in b)if(C.call(b,d))return!1;return!0}function w(b){if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");var d=arguments[1],e=2;if(null==d)d={};else if("object"!==typeof d||null!=d.tag||Array.isArray(d))d={},e=1;if(arguments.length=== -e+1){var g=arguments[e];Array.isArray(g)||(g=[g])}else for(g=[];ea.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(A){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"=== -typeof a)if(Array.isArray(b))for(var d=0;dk.status||304===k.status||U.test(a.url))d(r(a.type,b));else{var g=Error(k.responseText);g.code=k.status;g.response=b;e(g)}}catch(V){e(V)}};g&&null!=a.data?k.send(a.data):k.send()});return!0===a.background?A:k(A)},jsonp:function(a,p){var k=e();a=g(a,p);var h=new d(function(d,e){var g=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,k=b.document.createElement("script");b[g]=function(e){k.parentNode.removeChild(k);d(r(a.type,e));delete b[g]};k.onerror=function(){k.parentNode.removeChild(k); -e(Error("JSONP request failed"));delete b[g]};null==a.data&&(a.data={});a.url=u(a.url,a.data);a.data[a.callbackKey||"callback"]=g;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?h:k(h)},setCompletionCallback:function(a){y=a}}}(window,m),Q=function(b){function d(a,c){if(a.state!==c)throw Error("`vnode.state` must not be modified");}function e(a){var c=a.state;try{return this.apply(c,arguments)}finally{d(a,c)}}function g(a,c,f,b,d,e,g){for(;f'+c.children+"",n=n.firstChild):n.innerHTML=c.children;c.dom=n.firstChild;c.domSize=n.childNodes.length;for(c=z.createDocumentFragment();f=n.firstChild;)c.appendChild(f);y(a,c,b)}function h(a, -c,b,d,e,h){if(c!==b&&(null!=c||null!=b))if(null==c)g(a,b,0,b.length,d,e,h);else if(null==b)A(c,0,c.length);else{for(var n=0,f=0,q=!0,l=!0;f=f&&B>=n;)if(v=c[f],q=b[n],null==v)f++;else if(null==q)n++;else if(v.key===q.key)f++,n++,v!==q&&p(a,v,q,d,t(c,f,e),h);else if(q=b[B],null==v)f++;else if(null== -q)B--;else if(v.key===q.key)f++,n=f&&B>=n;){v=c[l];q=b[B];if(null==v)l--;else{if(null!=q)if(v.key===q.key)v!==q&&p(a,v,q,d,e,h),null!=q.dom&&(e=q.dom),l--;else{if(null==m){m=c;v=f;for(var z=l,x={};vl&&A(c,n,c.length);b.length>l&&g(a,b,n,b.length,d,e,h)}}}function p(b,c,f,d,g,t){var n=c.tag;if(n===f.tag){f.state=c.state;f.events=c.events;var q;var A;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(q=e.call(f.attrs.onbeforeupdate,f,c));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&& -(A=e.call(f.state.onbeforeupdate,f,c));void 0===q&&void 0===A||q||A?q=!1:(f.dom=c.dom,f.domSize=c.domSize,f.instance=c.instance,q=!0);if(!q)if("string"===typeof n)switch(null!=f.attrs&&J(f.attrs,f,d),n){case "#":c.children.toString()!==f.children.toString()&&(c.dom.nodeValue=f.children);f.dom=c.dom;break;case "<":c.children!==f.children?(r(c),l(b,f,t,g)):(f.dom=c.dom,f.domSize=c.domSize);break;case "[":h(b,c.children,f.children,d,g,t);c=0;d=f.children;f.dom=null;if(null!=d){for(var m=0;mc.indexOf("?")?"?":"&";c+=e+d}return c}function h(c){try{return""!==c?JSON.parse(c):null}catch(D){throw Error(c);}}function n(c){return c.responseText}function t(c,a){if("function"=== +typeof c)if(Array.isArray(a))for(var d=0;dg.status||304===g.status||Y.test(c.url))d(t(c.type,a));else{var f=Error(g.responseText);f.code=g.status;f.response=a;e(f)}}catch(Z){e(Z)}};f&&null!=c.data?g.send(c.data):g.send()});return!0===c.background?D:E(D)},jsonp:function(c,n){var h=e();c=f(c,n);var D=new d(function(d,e){var f=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+g++,n=a.document.createElement("script");a[f]=function(e){n.parentNode.removeChild(n);d(t(c.type,e));delete a[f]};n.onerror=function(){n.parentNode.removeChild(n); +e(Error("JSONP request failed"));delete a[f]};null==c.data&&(c.data={});c.url=v(c.url,c.data);c.data[c.callbackKey||"callback"]=f;n.src=l(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?D:h(D)},setCompletionCallback:function(c){C=c}}}(window,k),U=function(a){function d(p,b){if(p.state!==b)throw Error("`vnode.state` must not be modified");}function e(p){var b=p.state;try{return this.apply(b,arguments)}finally{d(p,b)}}function f(p,b,c,a,d,e,f){for(;c'+b.children+"",p=p.firstChild):p.innerHTML=b.children;b.dom=p.firstChild;b.domSize=p.childNodes.length;for(b=A.createDocumentFragment();m=p.firstChild;)b.appendChild(m);C(c,b,a)}function h(p, +b,c,a,d,e){if(b!==c&&(null!=b||null!=c))if(null==b||0===b.length)f(p,c,0,c.length,a,d,e);else if(null==c||0===c.length)D(b,0,b.length);else{for(var m=0,r=0,h=null,q=null;r=r&&h>=m;)if(k=b[q],y=c[h],null==k)q--;else if(null==y)h--;else if(k.key===y.key)k!==y&&n(p, +k,y,a,d,e),null!=y.dom&&(d=y.dom),q--,h--;else break;for(;q>=r&&h>=m;)if(x=b[r],u=c[m],null==x)r++;else if(null==u)m++;else if(x.key===u.key)r++,m++,x!==u&&n(p,x,u,a,g(b,r,d),e);else break;for(;q>=r&&h>=m;){if(null==x)r++;else if(null==u)m++;else if(null==k)q--;else if(null==y)h--;else if(m===h)break;else{if(x.key!==y.key||k.key!==u.key)break;B=g(b,r,d);C(p,t(k),B);k!==u&&n(p,k,u,a,B,e);++m<=--h&&C(p,t(x),d);x!==y&&n(p,x,y,a,d,e);null!=y.dom&&(d=y.dom);r++;q--}k=b[q];y=c[h];x=b[r];u=c[m]}for(;q>= +r&&h>=m;){if(null==k)q--;else if(null==y)h--;else if(k.key===y.key)k!==y&&n(p,k,y,a,d,e),null!=y.dom&&(d=y.dom),q--,h--;else break;k=b[q];y=c[h]}if(m>h)D(b,r,q+1);else if(r>q)f(p,c,m,h+1,a,d,e);else{u=d;k=h-m+1;x=Array(k);var A=2147483647,z=0;for(B=0;B=m;B--){if(null==l){l=b;k=r;y=q+1;for(var w={};k=m;B--)u=c[B],-1===x[B-m]?v(p,u,a,e,d):b[r]===B-m?r--:C(p,t(u),d),null!=u.dom&&(d=c[B].dom)}else for(B=h;B>=m;B--)u=c[B],-1===x[B-m]&&v(p, +u,a,e,d),null!=u.dom&&(d=c[B].dom)}}else{h=b.lengthh&&D(b,m,b.length);c.length>h&&f(p,c,m,c.length,a,d,e)}}}function n(p,b,a,d,f,g){var m=b.tag;if(m===a.tag){a.state=b.state;a.events=b.events;var r;var k;null!=a.attrs&&"function"===typeof a.attrs.onbeforeupdate&&(r=e.call(a.attrs.onbeforeupdate,a,b));"string"!==typeof a.tag&&"function"=== +typeof a.state.onbeforeupdate&&(k=e.call(a.state.onbeforeupdate,a,b));void 0===r&&void 0===k||r||k?r=!1:(a.dom=b.dom,a.domSize=b.domSize,a.instance=b.instance,r=!0);if(!r)if("string"===typeof m)switch(null!=a.attrs&&N(a.attrs,a,d),m){case "#":b.children.toString()!==a.children.toString()&&(b.dom.nodeValue=a.children);a.dom=b.dom;break;case "<":b.children!==a.children?(t(b),l(p,a,g,f)):(a.dom=b.dom,a.domSize=b.domSize);break;case "[":h(p,b.children,a.children,d,f,g);b=0;d=a.children;a.dom=null;if(null!= +d){for(var q=0;q Date: Fri, 1 Jun 2018 09:32:55 +0200 Subject: [PATCH 249/301] [ospec] don't allocate task for tests that will be skipped in o.only mode, fix stack overflow --- ospec/ospec.js | 15 ++++----------- ospec/tests/test-ospec.js | 8 +++++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index ea542f82..99ca8b4a 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -101,20 +101,13 @@ else window.o = m() pre = [].concat(pre, spec["\x01beforeEach"] || []) post = [].concat(spec["\x01afterEach"] || [], post) series([].concat(spec["\x01before"] || [], Object.keys(spec).reduce(function(tasks, key) { - if (key.charCodeAt(0) !== 1) { - tasks.push(new Task(function(done, timeout) { - timeout(Infinity) - if (only !== null && spec[key].fn !== only && spec[key] instanceof Task) return done() - + if (key.charCodeAt(0) !== 1 && (only === null || spec[key].fn === only || !(spec[key] instanceof Task))) { + tasks.push(new Task(function(done) { + o.timeout(Infinity) subjects.push(key) - var pop = new Task(function pop() { - subjects.pop() - done() - }, null) - + var pop = new Task(function pop() {subjects.pop(), done()}, null) if (spec[key] instanceof Task) series([].concat(pre, spec[key], post, pop), defaultDelay) else test(spec[key], pre, post, pop, defaultDelay) - }, null)) } return tasks diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index d652ad90..90c26ae0 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -37,8 +37,14 @@ if (typeof process !== "undefined") { o("o.only", function(done) { var oo = o.new() + oo.spec("won't run", function() { + oo("nope, skipped", function() { + o(true).equals(false) + }) + }) + oo.spec("ospec", function() { - oo("skipped", function() { + oo("skipped as well", function() { oo(true).equals(false) }) oo.only(".only()", function() { From a23216b9877765bd8e933268140bf5e6d878d9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Jun 2018 13:42:14 +0200 Subject: [PATCH 250/301] [ospec] record errors thrown in tests as failures --- ospec/ospec.js | 18 ++++++++++++------ ospec/tests/test-ospec.js | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index 99ca8b4a..f27021bf 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -179,12 +179,18 @@ else window.o = m() startTimer() } } else { - var p = fn() - if (p && p.then) { - startTimer() - p.then(function() { done() }, done) - } else { - nextTickish(next) + try{ + var p = fn() + if (p && p.then) { + startTimer() + p.then(function() { done() }, done) + } else { + nextTickish(next) + } + } catch (e) { + if (task.err != null) finalizeAsync(e) + // The errors of internal tasks (which don't have an Err) are ospec bugs and must be rethrown. + else throw e } } globalTimeout = noTimeoutRightNow diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 90c26ae0..537890a3 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -281,6 +281,26 @@ o.spec("ospec", function() { }) }) + o.spec("throwing in test context is recoreded as a failure", function() { + var oo + o.beforeEach(function(){oo = o.new()}) + o.afterEach(function() { + oo.run(function(results) { + o(results.length).equals(1) + o(results[0].pass).equals(false) + }) + }) + o("sync test", function() { + oo("throw in sync test", function() {throw new Error}) + }) + o("async test", function() { + oo("throw in async test", function(done) { + throw new Error + done() // eslint-disable-line no-unreachable + }) + }) + }) + o.spec("timeout", function () { o("when using done()", function(done) { var oo = o.new() From 14695c9cda4cf9a53284c730078b15d33ad6c8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Jun 2018 19:12:58 +0200 Subject: [PATCH 251/301] [ospec] Allow more than one o.only() test --- ospec/ospec.js | 7 ++++--- ospec/tests/test-ospec.js | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ospec/ospec.js b/ospec/ospec.js index f27021bf..2706f6ac 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -4,7 +4,7 @@ if (typeof module !== "undefined") module["exports"] = m() else window.o = m() })(function init(name) { - var spec = {}, subjects = [], results, only = null, ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty + var spec = {}, subjects = [], results, only = [], ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var globalTimeout = noTimeoutRightNow var currentTestError = null @@ -43,7 +43,8 @@ else window.o = m() highlight("/!\\ WARNING /!\\ o.only() mode") + "\n" + o.cleanStackTrace(ensureStackTrace(new Error)) + "\n", cStyle("red"), "" ) - o(subject, only = predicate) + only.push(predicate) + o(subject, predicate) } o.spy = function(fn) { var spy = function() { @@ -101,7 +102,7 @@ else window.o = m() pre = [].concat(pre, spec["\x01beforeEach"] || []) post = [].concat(spec["\x01afterEach"] || [], post) series([].concat(spec["\x01before"] || [], Object.keys(spec).reduce(function(tasks, key) { - if (key.charCodeAt(0) !== 1 && (only === null || spec[key].fn === only || !(spec[key] instanceof Task))) { + if (key.charCodeAt(0) !== 1 && (only.length === 0 || only.indexOf(spec[key].fn) !== -1 || !(spec[key] instanceof Task))) { tasks.push(new Task(function(done) { o.timeout(Infinity) subjects.push(key) diff --git a/ospec/tests/test-ospec.js b/ospec/tests/test-ospec.js index 537890a3..43f4e0bc 100644 --- a/ospec/tests/test-ospec.js +++ b/ospec/tests/test-ospec.js @@ -50,11 +50,16 @@ o("o.only", function(done) { oo.only(".only()", function() { oo(2).equals(2) }, true) + oo.only("another .only()", function(done) { + done("that fails") + }, true) }) oo.run(function(results){ - o(results.length).equals(1) + o(results.length).equals(2) o(results[0].pass).equals(true) + o(results[1].pass).equals(false) + done() }) }) From 9016091adf8ef71f46380806b0a027479bcba1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Jun 2018 20:18:24 +0200 Subject: [PATCH 252/301] [ospec] docs and change log --- ospec/README.md | 17 ++++++++++++++--- ospec/change-log.md | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ospec/README.md b/ospec/README.md index 4b71e74f..bbc929c4 100644 --- a/ospec/README.md +++ b/ospec/README.md @@ -271,20 +271,31 @@ o.spec("math", function() { }) ``` -### Running only one test +### Running only some tests -A test can be temporarily made to run exclusively by calling `o.only()` instead of `o`. This is useful when troubleshooting regressions, to zero-in on a failing test, and to avoid saturating console log w/ irrelevant debug information. +One or more tests can be temporarily made to run exclusively by calling `o.only()` instead of `o`. This is useful when troubleshooting regressions, to zero-in on a failing test, and to avoid saturating console log w/ irrelevant debug information. ```javascript o.spec("math", function() { + // will not run o("addition", function() { o(1 + 1).equals(2) }) - //only this test will be run, regardless of how many groups there are + // this test will be run, regardless of how many groups there are o.only("subtraction", function() { o(1 - 1).notEquals(2) }) + + // will not run + o("multiplication", function() { + o(2 * 2).equals(4) + }) + + // this test will be run, regardless of how many groups there are + o.only("division", function() { + o(6 / 2).notEquals(2) + }) }) ``` diff --git a/ospec/change-log.md b/ospec/change-log.md index 095a0743..01d0e884 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -12,12 +12,15 @@ _2018-xx-yy_ - Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - deprecate the `timeout` parameter in async tests in favour of `o.timeout()` for setting the timeout delay. The `timeout` parameter still works for v3, and will be removed in v4 ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - add `o.defaultTimeout()` for setting the the timeout delay for the current spec and its children ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- adds the possibility select more than one test with o.only ([#2171](https://github.com/MithrilJS/mithril.js/pull/2171)) ### Bug fixes - Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't try to report internal errors as assertion failures, throw them instead ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Don't ignore, silently, tests whose name start with the test suite meta-information sequence (was `"__"` up to this version) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Fix the `done()` call detection logic [#2158](https://github.com/MithrilJS/mithril.js/issues/2158) and assorted fixes (accept non-English names, tolerate comments) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) +- Catch exceptions thrown in synchronous tests and report them as assertion failures ([#2171](https://github.com/MithrilJS/mithril.js/pull/2171)) +- Fix a stack overflow when using `o.only()` with a large test suite ([#2171](https://github.com/MithrilJS/mithril.js/pull/2171)) ## 2.1.0 _2018-05-25_ From 4197cf0ae11185a0aa7b4879e8de443ea9b18ea5 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Gerardy Date: Mon, 29 May 2017 23:17:04 +0200 Subject: [PATCH 253/301] Enable the tests for #1804 --- render/render.js | 3 +++ render/tests/test-attributes.js | 19 ++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/render/render.js b/render/render.js index 41fd6100..9574e01d 100644 --- a/render/render.js +++ b/render/render.js @@ -725,6 +725,9 @@ module.exports = function($window) { } else element.setAttribute(key === "className" ? "class" : key, value) } + } + function removeAttr(vnode, key, old, ns) { + } function setLateAttrs(vnode) { var attrs = vnode.attrs diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 62cb4196..5c1f13bc 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -44,11 +44,10 @@ o.spec("attributes", function() { o(b.dom.hasAttribute("id")).equals(true) o(b.dom.getAttribute("id")).equals("test") + // #1804 render(root, [c]); - // #1804 - // TODO: uncomment - // o(c.dom.hasAttribute("id")).equals(false) + o(c.dom.hasAttribute("id")).equals(false) }) }) o.spec("customElements", function(){ @@ -147,7 +146,7 @@ o.spec("attributes", function() { o("a lack of attribute removes `value`", function() { var a = {tag: "input", attrs: {}} var b = {tag: "input", attrs: {value: "test"}} - // var c = {tag: "input", attrs: {}} + var c = {tag: "input", attrs: {}} render(root, [a]) @@ -158,10 +157,9 @@ o.spec("attributes", function() { o(a.dom.value).equals("test") // https://github.com/MithrilJS/mithril.js/issues/1804#issuecomment-304521235 - // TODO: Uncomment - // render(root, [c]) + render(root, [c]) - // o(a.dom.value).equals("") + o(a.dom.value).equals("") }) o("can be set as number", function() { var a = {tag: "input", attrs: {value: 1}} @@ -276,17 +274,16 @@ o.spec("attributes", function() { o.spec("textarea.value", function() { o("can be removed by not passing a value", function() { var a = {tag: "textarea", attrs: {value:"x"}} - // var b = {tag: "textarea", attrs: {}} + var b = {tag: "textarea", attrs: {}} render(root, [a]) o(a.dom.value).equals("x") // https://github.com/MithrilJS/mithril.js/issues/1804#issuecomment-304521235 - // TODO: Uncomment - // render(root, [b]) + render(root, [b]) - // o(b.dom.value).equals("") + o(b.dom.value).equals("") }) o("isn't set when equivalent to the previous value and focused", function() { var $window = domMock({spy: o.spy}) From dc15acd7919ffc2e052ebe96f966c7276dc960f2 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Gerardy Date: Mon, 29 May 2017 23:27:03 +0200 Subject: [PATCH 254/301] Improve attrs setting performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit before: > mutate styles/properties x 7,999 ops/sec ±10.87% (46 runs sampled) after: > mutate styles/properties x 16,104 ops/sec ±4.36% (66 runs sampled) --- render/render.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/render/render.js b/render/render.js index 9574e01d..0523a89b 100644 --- a/render/render.js +++ b/render/render.js @@ -692,10 +692,9 @@ module.exports = function($window) { return } if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value === undefined) return - var element = vnode.dom - if (key.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key, value) - else if (key === "style") updateStyle(element, old, value) - else if (key in element && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { + if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key, value) + else if (key === "style") updateStyle(vnode.dom, old, value) + else if (key in vnode.dom && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { if (key === "value") { var normalized = "" + value // eslint-disable-line no-implicit-coercion //setting input[value] to same value by typing on focused element moves cursor to end in Chrome @@ -713,17 +712,17 @@ module.exports = function($window) { } // If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur. if (vnode.tag === "input" && key === "type") { - element.setAttribute(key, value) + vnode.dom.setAttribute(key, value) return } - element[key] = value + vnode.dom[key] = value } else { if (typeof value === "boolean") { - if (value) element.setAttribute(key, "") - else element.removeAttribute(key) + if (value) vnode.dom.setAttribute(key, "") + else vnode.dom.removeAttribute(key) } - else element.setAttribute(key === "className" ? "class" : key, value) + else vnode.dom.setAttribute(key === "className" ? "class" : key, value) } } function removeAttr(vnode, key, old, ns) { From 5b51b682eeadf1352cc57d4ac7334f9b88dbc96d Mon Sep 17 00:00:00 2001 From: Pierre-Yves Gerardy Date: Tue, 30 May 2017 14:12:23 +0200 Subject: [PATCH 255/301] Improve attrs removal, fix #1804 --- render/render.js | 82 ++++++++++++++++++--------------- render/tests/test-attributes.js | 10 ++-- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/render/render.js b/render/render.js index 0523a89b..8fc19d79 100644 --- a/render/render.js +++ b/render/render.js @@ -115,7 +115,7 @@ module.exports = function($window) { insertNode(parent, element, nextSibling) - if (vnode.attrs != null && vnode.attrs.contenteditable != null) { + if (attrs != null && attrs.contenteditable != null) { setContentEditable(vnode) } else { @@ -126,7 +126,7 @@ module.exports = function($window) { if (vnode.children != null) { var children = vnode.children createNodes(element, children, 0, children.length, hooks, null, ns) - setLateAttrs(vnode) + if (vnode.tag === "select" && attrs != null) setLateSelectAttrs(vnode, attrs) } } } @@ -687,37 +687,23 @@ module.exports = function($window) { function setAttr(vnode, key, old, value, ns) { if (key === "key" || key === "is" || isLifecycleMethod(key)) return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) - if (typeof value === "undefined" && key === "value" && old !== value) { - vnode.dom.value = "" - return - } - if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value === undefined) return + if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value == null) return if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key, value) else if (key === "style") updateStyle(vnode.dom, old, value) - else if (key in vnode.dom && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { + else if (key in vnode.dom && !isAttribute(key) && ns === undefined && !isCustomElement(vnode.tag, vnode.attrs)) { if (key === "value") { var normalized = "" + value // eslint-disable-line no-implicit-coercion //setting input[value] to same value by typing on focused element moves cursor to end in Chrome if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return //setting select[value] to same value while having select open blinks select dropdown in Chrome - if (vnode.tag === "select") { - if (value === null) { - if (vnode.dom.selectedIndex === -1 && vnode.dom === $doc.activeElement) return - } else { - if (old !== null && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return - } - } + if (vnode.tag === "select" && old !== null && vnode.dom.value === normalized) return //setting option[value] to same value while having select open blinks select dropdown in Chrome - if (vnode.tag === "option" && old != null && vnode.dom.value === normalized) return + if (vnode.tag === "option" && old !== null && vnode.dom.value === normalized) return } // If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur. - if (vnode.tag === "input" && key === "type") { - vnode.dom.setAttribute(key, value) - return - } - vnode.dom[key] = value - } - else { + if (vnode.tag === "input" && key === "type") vnode.dom.setAttribute(key, value) + else vnode.dom[key] = value + } else { if (typeof value === "boolean") { if (value) vnode.dom.setAttribute(key, "") else vnode.dom.removeAttribute(key) @@ -726,14 +712,40 @@ module.exports = function($window) { } } function removeAttr(vnode, key, old, ns) { - - } - function setLateAttrs(vnode) { - var attrs = vnode.attrs - if (vnode.tag === "select" && attrs != null) { - if ("value" in attrs) setAttr(vnode, "value", null, attrs.value, undefined) - if ("selectedIndex" in attrs) setAttr(vnode, "selectedIndex", null, attrs.selectedIndex, undefined) + if (key === "key" || key === "is" || old == null || isLifecycleMethod(key)) return + var nsLastIndex = key.indexOf(":") + if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") { + vnode.dom.removeAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1)) } + else if (key[0] === "o" && key[1] === "n" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined) + else if (key === "style") updateStyle(vnode.dom, old, null) + else if ( + key in vnode.dom && !isAttribute(key) + && key !== "className" + && !(vnode.tag === "option" && key === "value") + && !(vnode.tag === "input" && key === "type") + && ns === undefined + && !isCustomElement(vnode.tag, vnode.attrs || {}) + ) { + vnode.dom[key] = null + } else { + if (old !== false) vnode.dom.removeAttribute(key === "className" ? "class" : key) + } + } + function setLateSelectAttrs(vnode, attrs) { + if ("value" in attrs) { + if(attrs.value === null) { + if (vnode.dom.selectedIndex !== -1) vnode.dom.value = null + } else { + /*eslint-disable no-implicit-coercion*/ + var normalized = "" + attrs.value + /*eslint-enable no-implicit-coercion*/ + if (vnode.dom.value !== normalized || vnode.dom.selectedIndex === -1) { + vnode.dom.value = normalized + } + } + } + if ("selectedIndex" in attrs) setAttr(vnode, "selectedIndex", null, attrs.selectedIndex, undefined) } function updateAttrs(vnode, old, attrs, ns) { if (attrs != null) { @@ -743,10 +755,8 @@ module.exports = function($window) { } if (old != null) { for (var key in old) { - if (attrs == null || !(key in attrs)) { - if (key === "className") key = "class" - if (key[0] === "o" && key[1] === "n" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined) - else if (key !== "key") vnode.dom.removeAttribute(key) + if (attrs == null || attrs[key] == null) { + removeAttr(vnode, key, old[key], ns) } } } @@ -760,8 +770,8 @@ module.exports = function($window) { function isAttribute(attr) { return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type" } - function isCustomElement(vnode){ - return vnode.attrs.is || vnode.tag.indexOf("-") > -1 + function isCustomElement(tag, attrs){ + return attrs.is || tag.indexOf("-") > -1 } //style diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 5c1f13bc..8059e887 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -373,15 +373,15 @@ o.spec("attributes", function() { o(a.dom.value).equals("1") }) - o("null becomes 'null'", function() { + o("null removes the attribute", function() { var a = {tag: "option", attrs: {value: null}} var b = {tag: "option", attrs: {value: "test"}} var c = {tag: "option", attrs: {value: null}} render(root, [a]); - o(a.dom.value).equals("null") - o(a.dom.getAttribute("value")).equals("null") + o(a.dom.value).equals("") + o(a.dom.hasAttribute("value")).equals(false) render(root, [b]); @@ -390,8 +390,8 @@ o.spec("attributes", function() { render(root, [c]); - o(c.dom.value).equals("null") - o(c.dom.getAttribute("value")).equals("null") + o(c.dom.value).equals("") + o(c.dom.hasAttribute("value")).equals(false) }) o("'' and 0 are different values", function() { var a = {tag: "option", attrs: {value: 0}, children:[{tag:"#", children:""}]} From b39f4f683dfaea59df1556b91e8abb340433c275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 16:52:42 +0200 Subject: [PATCH 256/301] [domMock] Better accuracy for namespaced elements --- test-utils/domMock.js | 18 ++++++++--- test-utils/tests/test-domMock.js | 51 +++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/test-utils/domMock.js b/test-utils/domMock.js index c45b34e9..148b840d 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -18,6 +18,9 @@ module.exports = function(options) { options = options || {} var spy = options.spy || function(f){return f} var spymap = [] + + var hasOwn = ({}.hasOwnProperty) + function registerSpies(element, spies) { if(options.spy) { var i = spymap.indexOf(element) @@ -127,9 +130,8 @@ module.exports = function(options) { // this is the correct kind of conversion, passing a Symbol throws in browsers too. var nodeValue = "" + value /*eslint-enable no-implicit-coercion*/ - this.attributes[name] = { - namespaceURI: null, + namespaceURI: hasOwn.call(this.attributes, name) ? this.attributes[name].namespaceURI : null, get value() {return nodeValue}, set value(value) { /*eslint-disable no-implicit-coercion*/ @@ -404,8 +406,16 @@ module.exports = function(options) { if (element.nodeName === "A") { Object.defineProperty(element, "href", { - get: function() {return this.attributes["href"] === undefined ? "" : "[FIXME implement]"}, - set: function(value) {this.setAttribute("href", value)}, + get: function() { + if (this.namespaceURI === "http://www.w3.org/2000/svg") { + var val = this.hasAttribute("href") ? this.attributes.href.value : "" + return {baseVal: val, animVal: val} + } else return this.attributes["href"] === undefined ? "" : "[FIXME implement]" + }, + set: function(value) { + // This is a readonly attribute for SVG, todo investigate MathML which may have yet another IDL + if (this.namespaceURI !== "http://www.w3.org/2000/svg") this.setAttribute("href", value) + }, enumerable: true, }) } diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index e27d0bee..4662ef52 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -364,6 +364,12 @@ o.spec("domMock", function() { o(div.getAttribute("id")).equals("aaa") }) + o("works for attributes with a namespace", function() { + var div = $document.createElement("div") + div.setAttributeNS("http://www.w3.org/1999/xlink", "href", "aaa") + + o(div.getAttribute("href")).equals("aaa") + }) }) o.spec("setAttribute", function() { @@ -429,18 +435,40 @@ o.spec("domMock", function() { o.spec("setAttributeNS", function() { o("works", function() { - var div = $document.createElement("div") - div.setAttributeNS("http://www.w3.org/1999/xlink", "href", "aaa") + var a = $document.createElementNS("http://www.w3.org/2000/svg", "a") + a.setAttributeNS("http://www.w3.org/1999/xlink", "href", "/aaa") - o(div.attributes["href"].value).equals("aaa") - o(div.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + o(a.href).deepEquals({baseVal: "/aaa", animVal: "/aaa"}) + o(a.attributes["href"].value).equals("/aaa") + o(a.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") }) o("works w/ number", function() { - var div = $document.createElement("div") - div.setAttributeNS("http://www.w3.org/1999/xlink", "href", 123) + var a = $document.createElementNS("http://www.w3.org/2000/svg", "a") + a.setAttributeNS("http://www.w3.org/1999/xlink", "href", 123) - o(div.attributes["href"].value).equals("123") - o(div.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + o(a.href).deepEquals({baseVal: "123", animVal: "123"}) + o(a.attributes["href"].value).equals("123") + o(a.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + }) + o("attributes with a namespace can be querried, updated and removed with non-NS functions", function() { + var a = $document.createElementNS("http://www.w3.org/2000/svg", "a") + a.setAttributeNS("http://www.w3.org/1999/xlink", "href", "/aaa") + + o(a.hasAttribute("href")).equals(true) + o(a.getAttribute("href")).equals("/aaa") + + a.setAttribute("href", "/bbb") + + o(a.href).deepEquals({baseVal: "/bbb", animVal: "/bbb"}) + o(a.getAttribute("href")).equals("/bbb") + o(a.attributes["href"].value).equals("/bbb") + o(a.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + + a.removeAttribute("href") + + o(a.hasAttribute("href")).equals(false) + o(a.getAttribute("href")).equals(null) + o("href" in a.attributes).equals(false) }) }) @@ -1266,6 +1294,13 @@ o.spec("domMock", function() { o(a.href).notEquals("") o(a.attributes["href"].value).equals("") }) + o("property is read-only for SVG elements", function() { + var a = $document.createElementNS("http://www.w3.org/2000/svg", "a") + a.href = "/foo" + + o(a.href).deepEquals({baseVal: "", animVal: ""}) + o("href" in a.attributes).equals(false) + }) }) o.spec("input[checked]", function() { o("only exists in input elements", function() { From 2469505b1bd2cb69930391c90efe33902db2dd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 16:54:44 +0200 Subject: [PATCH 257/301] Move xlink:href test to the proper file --- render/tests/test-attributes.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 8059e887..379939e9 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -349,7 +349,7 @@ o.spec("attributes", function() { o(canvas.dom.width).equals(100) }) }) - o.spec("svg class", function() { + o.spec("svg", function() { o("when className is specified then it should be added as a class", function() { var a = {tag: "svg", attrs: {className: "test"}} @@ -357,7 +357,26 @@ o.spec("attributes", function() { o(a.dom.attributes["class"].value).equals("test") }) + o("removes xlink:href", function() { + var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ + {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {"xlink:href": "javascript:;"}} + ]} + render(root, [vnode]) + + o(vnode.dom.nodeName).equals("svg") + o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") + o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + + vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ + {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {}} + ]} + render(root, [vnode]) + + o(vnode.dom.nodeName).equals("svg") + o(vnode.dom.firstChild.attributes["xlink:href"]).equals(undefined) + }) }) + o.spec("option.value", function() { o("can be set as text", function() { var a = {tag: "option", attrs: {value: "test"}} From 49210838985cfd37073405b470ddef2ff21b2078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 17:06:57 +0200 Subject: [PATCH 258/301] [render/render] Fix xlink:href handling --- docs/change-log.md | 4 +--- render/render.js | 10 ++++------ render/tests/test-attributes.js | 17 ++++++++++------- render/tests/test-createElement.js | 25 ++++--------------------- 4 files changed, 19 insertions(+), 37 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index b38fdb03..682af63c 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -40,9 +40,7 @@ - API: `m.route.set()` causes all mount points to be redrawn ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - render/attrs: Using style objects in hyperscript calls will now properly diff style properties from one render to another as opposed to re-writing all element style properties every render. -- render/attrs: `xlink:href` attributes are now correctly removed -- render/attrs: fix element value don't change if new value is undefined [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) -(https://github.com/MithrilJS/mithril.js/pull/2130) +- render/attrs All vnodes attributes are properly removed when absent or set to `null` or `undefined` [#1804](https://github.com/MithrilJS/mithril.js/issues/1804) [#2082](https://github.com/MithrilJS/mithril.js/issues/2082) ([#1865](https://github.com/MithrilJS/mithril.js/pull/1865), [#2130](https://github.com/MithrilJS/mithril.js/pull/2130)) - render/core: Render state correctly on select change event [#1916](https://github.com/MithrilJS/mithril.js/issues/1916) ([#1918](https://github.com/MithrilJS/mithril.js/pull/1918) [@robinchew](https://github.com/robinchew), [#2052](https://github.com/MithrilJS/mithril.js/pull/2052)) - render/core: fix various updateNodes/removeNodes issues when the pool and fragments are involved [#1990](https://github.com/MithrilJS/mithril.js/issues/1990), [#1991](https://github.com/MithrilJS/mithril.js/issues/1991), [#2003](https://github.com/MithrilJS/mithril.js/issues/2003), [#2021](https://github.com/MithrilJS/mithril.js/pull/2021) - render/core: fix crashes when the keyed vnodes with the same `key` had different `tag` values [#2128](https://github.com/MithrilJS/mithril.js/issues/2128) [@JacksonJN](https://github.com/JacksonJN) ([#2130](https://github.com/MithrilJS/mithril.js/pull/2130)) diff --git a/render/render.js b/render/render.js index 8fc19d79..7323a583 100644 --- a/render/render.js +++ b/render/render.js @@ -688,7 +688,7 @@ module.exports = function($window) { if (key === "key" || key === "is" || isLifecycleMethod(key)) return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value == null) return - if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key, value) + if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) else if (key === "style") updateStyle(vnode.dom, old, value) else if (key in vnode.dom && !isAttribute(key) && ns === undefined && !isCustomElement(vnode.tag, vnode.attrs)) { if (key === "value") { @@ -713,11 +713,7 @@ module.exports = function($window) { } function removeAttr(vnode, key, old, ns) { if (key === "key" || key === "is" || old == null || isLifecycleMethod(key)) return - var nsLastIndex = key.indexOf(":") - if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") { - vnode.dom.removeAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1)) - } - else if (key[0] === "o" && key[1] === "n" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined) + if (key[0] === "o" && key[1] === "n" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined) else if (key === "style") updateStyle(vnode.dom, old, null) else if ( key in vnode.dom && !isAttribute(key) @@ -729,6 +725,8 @@ module.exports = function($window) { ) { vnode.dom[key] = null } else { + var nsLastIndex = key.indexOf(":") + if (nsLastIndex !== -1) key = key.slice(nsLastIndex + 1) if (old !== false) vnode.dom.removeAttribute(key === "className" ? "class" : key) } } diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 379939e9..ed41961e 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -357,24 +357,27 @@ o.spec("attributes", function() { o(a.dom.attributes["class"].value).equals("test") }) - o("removes xlink:href", function() { + /* eslint-disable no-script-url */ + o("handles xlink:href", function() { var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {"xlink:href": "javascript:;"}} ]} render(root, [vnode]) - + o(vnode.dom.nodeName).equals("svg") - o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") - o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") - + o(vnode.dom.firstChild.attributes["href"].value).equals("javascript:;") + o(vnode.dom.firstChild.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {}} ]} render(root, [vnode]) - + o(vnode.dom.nodeName).equals("svg") - o(vnode.dom.firstChild.attributes["xlink:href"]).equals(undefined) + o("href" in vnode.dom.firstChild.attributes).equals(false) }) + /* eslint-enable no-script-url */ + }) o.spec("option.value", function() { diff --git a/render/tests/test-createElement.js b/render/tests/test-createElement.js index c2dc1d90..ea4d01c8 100644 --- a/render/tests/test-createElement.js +++ b/render/tests/test-createElement.js @@ -1,4 +1,3 @@ -/* eslint-disable no-script-url */ "use strict" var o = require("../../ospec/ospec") @@ -54,6 +53,7 @@ o.spec("createElement", function() { o(vnode.dom.childNodes[0].nodeName).equals("A") o(vnode.dom.childNodes[1].nodeName).equals("B") }) + /* eslint-disable no-script-url */ o("creates svg", function() { var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {"xlink:href": "javascript:;"}}, @@ -65,36 +65,19 @@ o.spec("createElement", function() { o(vnode.dom.namespaceURI).equals("http://www.w3.org/2000/svg") o(vnode.dom.firstChild.nodeName).equals("a") o(vnode.dom.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg") - o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") - o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") + o(vnode.dom.firstChild.attributes["href"].value).equals("javascript:;") + o(vnode.dom.firstChild.attributes["href"].namespaceURI).equals("http://www.w3.org/1999/xlink") o(vnode.dom.childNodes[1].nodeName).equals("foreignObject") o(vnode.dom.childNodes[1].firstChild.nodeName).equals("body") o(vnode.dom.childNodes[1].firstChild.namespaceURI).equals("http://www.w3.org/1999/xhtml") }) + /* eslint-enable no-script-url */ o("sets attributes correctly for svg", function() { var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", attrs: {viewBox: "0 0 100 100"}} render(root, [vnode]) o(vnode.dom.attributes["viewBox"].value).equals("0 0 100 100") }) - o("removes xlink:href", function() { - var vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ - {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {"xlink:href": "javascript:;"}} - ]} - render(root, [vnode]) - - o(vnode.dom.nodeName).equals("svg") - o(vnode.dom.firstChild.attributes["xlink:href"].value).equals("javascript:;") - o(vnode.dom.firstChild.attributes["xlink:href"].namespaceURI).equals("http://www.w3.org/1999/xlink") - - vnode = {tag: "svg", ns: "http://www.w3.org/2000/svg", children: [ - {tag: "a", ns: "http://www.w3.org/2000/svg", attrs: {}} - ]} - render(root, [vnode]) - - o(vnode.dom.nodeName).equals("svg") - o(vnode.dom.firstChild.attributes["xlink:href"]).equals(undefined) - }) o("creates mathml", function() { var vnode = {tag: "math", ns: "http://www.w3.org/1998/Math/MathML", children: [{tag: "mrow", ns: "http://www.w3.org/1998/Math/MathML"}]} render(root, [vnode]) From cfa128a5cd082832108f0dd33c51ece25f182940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 17:14:57 +0200 Subject: [PATCH 259/301] [render/render] make updateAttrs smarter about null values --- render/render.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/render/render.js b/render/render.js index 7323a583..bf8080f3 100644 --- a/render/render.js +++ b/render/render.js @@ -685,9 +685,8 @@ module.exports = function($window) { } } function setAttr(vnode, key, old, value, ns) { - if (key === "key" || key === "is" || isLifecycleMethod(key)) return + if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) - if ((old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || value == null) return if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) else if (key === "style") updateStyle(vnode.dom, old, value) else if (key in vnode.dom && !isAttribute(key) && ns === undefined && !isCustomElement(vnode.tag, vnode.attrs)) { @@ -751,10 +750,11 @@ module.exports = function($window) { setAttr(vnode, key, old && old[key], attrs[key], ns) } } + var val if (old != null) { for (var key in old) { - if (attrs == null || attrs[key] == null) { - removeAttr(vnode, key, old[key], ns) + if (((val = old[key]) != null) && (attrs == null || attrs[key] == null)) { + removeAttr(vnode, key, val, ns) } } } From 1fdc9278c7c1db8a4ef2f80e4835ea699ce25264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 17:33:35 +0200 Subject: [PATCH 260/301] [benchmark] add consecutive nullish values to the attrs test --- performance/test-perf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/performance/test-perf.js b/performance/test-perf.js index a2b79421..8ce4e969 100644 --- a/performance/test-perf.js +++ b/performance/test-perf.js @@ -233,7 +233,7 @@ suite.add({ var counter = 0 var keyLooper = function (n) { return function (c) { return c % n ? (c + "px") : c } } var get = function (obj, i) { return obj[i%obj.length] } - var classes = ["foo", "foo bar", "", "baz-bat", null, "fooga"] + var classes = ["foo", "foo bar", "", "baz-bat", null, "fooga", null, null, undefined] var styles = [] var multivalue = ["0 1px", "0 0 1px 0", "0", "1px", "20px 10px", "7em 5px", "1px 0 5em 2px"] var stylekeys = [ From 6283aa4a7dd826e9d394f8795d5edf85f9570f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 31 May 2018 23:49:05 +0200 Subject: [PATCH 261/301] [render/render] Test for removing styles and assorted domMock changes --- render/tests/test-updateElement.js | 66 ++++++++++++++++++++++++++++++ test-utils/domMock.js | 2 +- test-utils/tests/test-domMock.js | 3 ++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/render/tests/test-updateElement.js b/render/tests/test-updateElement.js index 0e0332b7..8a190a4c 100644 --- a/render/tests/test-updateElement.js +++ b/render/tests/test-updateElement.js @@ -205,6 +205,72 @@ o.spec("updateElement", function() { o(updated.dom.style.color).equals("red") }) + o("setting style to `null` removes all styles", function() { + var vnode = {"tag": "p", attrs: {style: "background-color: red"}} + var updated = {"tag": "p", attrs: {style: null}} + + render(root, [vnode]) + + o("style" in vnode.dom.attributes).equals(true) + o(vnode.dom.attributes.style.value).equals("background-color: red;") + + render(root, [updated]) + + //browsers disagree here + try { + + o(updated.dom.attributes.style.value).equals("") + + } catch (e) { + + o("style" in updated.dom.attributes).equals(false) + + } + }) + o("setting style to `undefined` removes all styles", function() { + var vnode = {"tag": "p", attrs: {style: "background-color: red"}} + var updated = {"tag": "p", attrs: {style: undefined}} + + render(root, [vnode]) + + o("style" in vnode.dom.attributes).equals(true) + o(vnode.dom.attributes.style.value).equals("background-color: red;") + + render(root, [updated]) + + //browsers disagree here + try { + + o(updated.dom.attributes.style.value).equals("") + + } catch (e) { + + o("style" in updated.dom.attributes).equals(false) + + } + }) + o("not setting style removes all styles", function() { + var vnode = {"tag": "p", attrs: {style: "background-color: red"}} + var updated = {"tag": "p", attrs: {}} + + render(root, [vnode]) + + o("style" in vnode.dom.attributes).equals(true) + o(vnode.dom.attributes.style.value).equals("background-color: red;") + + render(root, [updated]) + + //browsers disagree here + try { + + o(updated.dom.attributes.style.value).equals("") + + } catch (e) { + + o("style" in updated.dom.attributes).equals(false) + + } + }) o("replaces el", function() { var vnode = {tag: "a"} var updated = {tag: "b"} diff --git a/test-utils/domMock.js b/test-utils/domMock.js index 148b840d..7a5c5b74 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -247,7 +247,7 @@ module.exports = function(options) { } } } - cssText = buf.join(" ") + element.setAttribute("style", cssText = buf.join(" ")) } } }) diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index 4662ef52..805f7b92 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -618,6 +618,7 @@ o.spec("domMock", function() { o(div.style.backgroundColor).equals("red") o(div.style.borderBottom).equals("1px solid red") + o(div.attributes.style.value).equals("background-color: red; border-bottom: 1px solid red;") }) o("removing via setting style.cssText string works", function() { var div = $document.createElement("div") @@ -625,6 +626,7 @@ o.spec("domMock", function() { div.style.cssText = "" o(div.style.background).equals("") + o(div.attributes.style.value).equals("") }) o("the final semicolon is optional when setting style.cssText", function() { var div = $document.createElement("div") @@ -632,6 +634,7 @@ o.spec("domMock", function() { o(div.style.background).equals("red") o(div.style.cssText).equals("background: red;") + o(div.attributes.style.value).equals("background: red;") }) o("'cssText' as a property name is ignored when setting style.cssText", function(){ var div = $document.createElement("div") From 3f5cabc5c5234a81c7f455fbe5afd7cde2a957b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Fri, 1 Jun 2018 21:24:02 +0200 Subject: [PATCH 262/301] Chore: Normalize the way we use eslint-disable --- docs/lint.js | 10 ++++++---- ospec/ospec.js | 7 +++---- render/render.js | 8 ++------ render/tests/test-attributes.js | 2 -- render/tests/test-updateNodesFuzzer.js | 4 +--- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/docs/lint.js b/docs/lint.js index 2fb39e3b..9fcb93b4 100644 --- a/docs/lint.js +++ b/docs/lint.js @@ -101,12 +101,14 @@ function ensureLinkIsValid(file, data) { } function initMocks() { - global.window = require("../test-utils/browserMock")() // eslint-disable-line global-require + /* eslint-disable global-require */ + global.window = require("../test-utils/browserMock")() global.document = window.document - global.m = require("../index") // eslint-disable-line global-require - global.o = require("../ospec/ospec") // eslint-disable-line global-require - global.stream = require("../stream") // eslint-disable-line global-require + global.m = require("../index") + global.o = require("../ospec/ospec") + global.stream = require("../stream") global.alert = function() {} + /* eslint-enable global-require */ //routes consumed by request.md global.window.$defineRoutes({ diff --git a/ospec/ospec.js b/ospec/ospec.js index 2706f6ac..fcbc9915 100644 --- a/ospec/ospec.js +++ b/ospec/ospec.js @@ -1,4 +1,3 @@ -/* eslint-disable global-require, no-bitwise, no-process-exit */ "use strict" ;(function(m) { if (typeof module !== "undefined") module["exports"] = m() @@ -92,7 +91,7 @@ else window.o = m() if (typeof reporter === "function") reporter(results) else { var errCount = o.report(results) - if (hasProcess && errCount !== 0) process.exit(1) + if (hasProcess && errCount !== 0) process.exit(1) // eslint-disable-line no-process-exit } }) }, null), 200 /*default timeout delay*/) @@ -225,7 +224,7 @@ else window.o = m() } function deepEqual(a, b) { if (a === b) return true - if (a === null ^ b === null || a === undefined ^ b === undefined) return false + if (a === null ^ b === null || a === undefined ^ b === undefined) return false // eslint-disable-line no-bitwise if (typeof a === "object" && typeof b === "object") { var aIsArgs = isArguments(a), bIsArgs = isArguments(b) if (a.constructor === Object && b.constructor === Object && !aIsArgs && !bIsArgs) { @@ -287,7 +286,7 @@ else window.o = m() results[assertion.i].error = error != null ? error : ensureStackTrace(new Error) } function serialize(value) { - if (hasProcess) return require("util").inspect(value) + if (hasProcess) return require("util").inspect(value) // eslint-disable-line global-require if (value === null || (typeof value === "object" && !(value instanceof Array)) || typeof value === "number") return String(value) else if (typeof value === "function") return value.name || "" try {return JSON.stringify(value)} catch (e) {return String(value)} diff --git a/render/render.js b/render/render.js index bf8080f3..c8181ad1 100644 --- a/render/render.js +++ b/render/render.js @@ -556,9 +556,7 @@ module.exports = function($window) { u = 0 v = result.length - 1 while (u < v) { - /*eslint-disable no-bitwise*/ - var c = ((u + v) / 2) | 0 - /*eslint-enable no-bitwise*/ + var c = ((u + v) / 2) | 0 // eslint-disable-line no-bitwise if (a[result[c]] < a[i]) { u = c + 1 } @@ -734,9 +732,7 @@ module.exports = function($window) { if(attrs.value === null) { if (vnode.dom.selectedIndex !== -1) vnode.dom.value = null } else { - /*eslint-disable no-implicit-coercion*/ - var normalized = "" + attrs.value - /*eslint-enable no-implicit-coercion*/ + var normalized = "" + attrs.value // eslint-disable-line no-implicit-coercion if (vnode.dom.value !== normalized || vnode.dom.selectedIndex === -1) { vnode.dom.value = normalized } diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index ed41961e..00b91f1d 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -377,9 +377,7 @@ o.spec("attributes", function() { o("href" in vnode.dom.firstChild.attributes).equals(false) }) /* eslint-enable no-script-url */ - }) - o.spec("option.value", function() { o("can be set as text", function() { var a = {tag: "option", attrs: {value: "test"}} diff --git a/render/tests/test-updateNodesFuzzer.js b/render/tests/test-updateNodesFuzzer.js index db5cafa7..8580c139 100644 --- a/render/tests/test-updateNodesFuzzer.js +++ b/render/tests/test-updateNodesFuzzer.js @@ -61,9 +61,7 @@ function longestIncreasingSubsequence(a) { v = result.length - 1 while (u < v) { - /*eslint-disable no-bitwise*/ - var c = ((u + v) / 2) | 0 - /*eslint-enable no-bitwise*/ + var c = ((u + v) / 2) | 0 // eslint-disable-line no-bitwise if (a[result[c]] < a[i]) { u = c + 1 } else { From 4ca2b362f72fac15dd4b8d58c06a2af8148e328c Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Fri, 1 Jun 2018 19:28:42 +0000 Subject: [PATCH 263/301] Bundled output for commit 3f5cabc5c5234a81c7f455fbe5afd7cde2a957b8 [skip ci] --- README.md | 2 +- mithril.js | 94 ++++++++++++++++++++++++++----------------------- mithril.min.js | 95 +++++++++++++++++++++++++------------------------- 3 files changed, 99 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index a7347635..fa0159a9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.71 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.86 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 7478e740..567d2c4c 100644 --- a/mithril.js +++ b/mithril.js @@ -507,7 +507,7 @@ var coreRenderer = function($window) { setAttrs(vnode, attrs2, ns) } insertNode(parent, element, nextSibling) - if (vnode.attrs != null && vnode.attrs.contenteditable != null) { + if (attrs2 != null && attrs2.contenteditable != null) { setContentEditable(vnode) } else { @@ -518,7 +518,7 @@ var coreRenderer = function($window) { if (vnode.children != null) { var children1 = vnode.children createNodes(element, children1, 0, children1.length, hooks, null, ns) - setLateAttrs(vnode) + if (vnode.tag === "select" && attrs2 != null) setLateSelectAttrs(vnode, attrs2) } } } @@ -940,9 +940,7 @@ var coreRenderer = function($window) { u = 0 v = result.length - 1 while (u < v) { - /*eslint-disable no-bitwise*/ - var c = ((u + v) / 2) | 0 - /*eslint-enable no-bitwise*/ + var c = ((u + v) / 2) | 0 // eslint-disable-line no-bitwise if (a[result[c]] < a[i]) { u = c + 1 } @@ -1064,66 +1062,74 @@ var coreRenderer = function($window) { } } function setAttr(vnode, key2, old, value, ns) { - if (key2 === "key" || key2 === "is" || isLifecycleMethod(key2)) return + if (key2 === "key" || key2 === "is" || value == null || isLifecycleMethod(key2) || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object") return if (key2[0] === "o" && key2[1] === "n") return updateEvent(vnode, key2, value) - if (typeof value === "undefined" && key2 === "value" && old !== value) { - vnode.dom.value = "" - return - } - if ((old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || value === undefined) return - var element = vnode.dom - if (key2.slice(0, 6) === "xlink:") element.setAttributeNS("http://www.w3.org/1999/xlink", key2, value) - else if (key2 === "style") updateStyle(element, old, value) - else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) { + if (key2.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(6), value) + else if (key2 === "style") updateStyle(vnode.dom, old, value) + else if (key2 in vnode.dom && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode.tag, vnode.attrs)) { if (key2 === "value") { var normalized = "" + value // eslint-disable-line no-implicit-coercion //setting input[value] to same value by typing on focused element moves cursor to end in Chrome if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return //setting select[value] to same value while having select open blinks select dropdown in Chrome - if (vnode.tag === "select") { - if (value === null) { - if (vnode.dom.selectedIndex === -1 && vnode.dom === $doc.activeElement) return - } else { - if (old !== null && vnode.dom.value === normalized && vnode.dom === $doc.activeElement) return - } - } + if (vnode.tag === "select" && old !== null && vnode.dom.value === normalized) return //setting option[value] to same value while having select open blinks select dropdown in Chrome - if (vnode.tag === "option" && old != null && vnode.dom.value === normalized) return + if (vnode.tag === "option" && old !== null && vnode.dom.value === normalized) return } // If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error1 will occur. - if (vnode.tag === "input" && key2 === "type") { - element.setAttribute(key2, value) - return - } - element[key2] = value - } - else { + if (vnode.tag === "input" && key2 === "type") vnode.dom.setAttribute(key2, value) + else vnode.dom[key2] = value + } else { if (typeof value === "boolean") { - if (value) element.setAttribute(key2, "") - else element.removeAttribute(key2) + if (value) vnode.dom.setAttribute(key2, "") + else vnode.dom.removeAttribute(key2) } - else element.setAttribute(key2 === "className" ? "class" : key2, value) + else vnode.dom.setAttribute(key2 === "className" ? "class" : key2, value) } } - function setLateAttrs(vnode) { - var attrs2 = vnode.attrs - if (vnode.tag === "select" && attrs2 != null) { - if ("value" in attrs2) setAttr(vnode, "value", null, attrs2.value, undefined) - if ("selectedIndex" in attrs2) setAttr(vnode, "selectedIndex", null, attrs2.selectedIndex, undefined) + function removeAttr(vnode, key2, old, ns) { + if (key2 === "key" || key2 === "is" || old == null || isLifecycleMethod(key2)) return + if (key2[0] === "o" && key2[1] === "n" && !isLifecycleMethod(key2)) updateEvent(vnode, key2, undefined) + else if (key2 === "style") updateStyle(vnode.dom, old, null) + else if ( + key2 in vnode.dom && !isAttribute(key2) + && key2 !== "className" + && !(vnode.tag === "option" && key2 === "value") + && !(vnode.tag === "input" && key2 === "type") + && ns === undefined + && !isCustomElement(vnode.tag, vnode.attrs || {}) + ) { + vnode.dom[key2] = null + } else { + var nsLastIndex = key2.indexOf(":") + if (nsLastIndex !== -1) key2 = key2.slice(nsLastIndex + 1) + if (old !== false) vnode.dom.removeAttribute(key2 === "className" ? "class" : key2) } } + function setLateSelectAttrs(vnode, attrs2) { + if ("value" in attrs2) { + if(attrs2.value === null) { + if (vnode.dom.selectedIndex !== -1) vnode.dom.value = null + } else { + var normalized = "" + attrs2.value // eslint-disable-line no-implicit-coercion + if (vnode.dom.value !== normalized || vnode.dom.selectedIndex === -1) { + vnode.dom.value = normalized + } + } + } + if ("selectedIndex" in attrs2) setAttr(vnode, "selectedIndex", null, attrs2.selectedIndex, undefined) + } function updateAttrs(vnode, old, attrs2, ns) { if (attrs2 != null) { for (var key2 in attrs2) { setAttr(vnode, key2, old && old[key2], attrs2[key2], ns) } } + var val if (old != null) { for (var key2 in old) { - if (attrs2 == null || !(key2 in attrs2)) { - if (key2 === "className") key2 = "class" - if (key2[0] === "o" && key2[1] === "n" && !isLifecycleMethod(key2)) updateEvent(vnode, key2, undefined) - else if (key2 !== "key") vnode.dom.removeAttribute(key2) + if (((val = old[key2]) != null) && (attrs2 == null || attrs2[key2] == null)) { + removeAttr(vnode, key2, val, ns) } } } @@ -1137,8 +1143,8 @@ var coreRenderer = function($window) { function isAttribute(attr) { return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type" } - function isCustomElement(vnode){ - return vnode.attrs.is || vnode.tag.indexOf("-") > -1 + function isCustomElement(tag, attrs2){ + return attrs2.is || tag.indexOf("-") > -1 } //style function updateStyle(element, old, style) { diff --git a/mithril.min.js b/mithril.min.js index 40caf8b5..414d2792 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,47 +1,48 @@ -(function(){function z(a,d,e,f,v,l){return{tag:a,key:d,attrs:e,children:f,text:v,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0}}function Q(a){for(var d in a)if(H.call(a,d))return!1;return!0}function w(a){if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");var d=arguments[1],e=2;if(null==d)d={};else if("object"!==typeof d||null!=d.tag||Array.isArray(d))d={},e=1;if(arguments.length=== -e+1){var f=arguments[e];Array.isArray(f)||(f=[f])}else for(f=[];ec.indexOf("?")?"?":"&";c+=e+d}return c}function h(c){try{return""!==c?JSON.parse(c):null}catch(D){throw Error(c);}}function n(c){return c.responseText}function t(c,a){if("function"=== -typeof c)if(Array.isArray(a))for(var d=0;dg.status||304===g.status||Y.test(c.url))d(t(c.type,a));else{var f=Error(g.responseText);f.code=g.status;f.response=a;e(f)}}catch(Z){e(Z)}};f&&null!=c.data?g.send(c.data):g.send()});return!0===c.background?D:E(D)},jsonp:function(c,n){var h=e();c=f(c,n);var D=new d(function(d,e){var f=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+g++,n=a.document.createElement("script");a[f]=function(e){n.parentNode.removeChild(n);d(t(c.type,e));delete a[f]};n.onerror=function(){n.parentNode.removeChild(n); -e(Error("JSONP request failed"));delete a[f]};null==c.data&&(c.data={});c.url=v(c.url,c.data);c.data[c.callbackKey||"callback"]=f;n.src=l(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?D:h(D)},setCompletionCallback:function(c){C=c}}}(window,k),U=function(a){function d(p,b){if(p.state!==b)throw Error("`vnode.state` must not be modified");}function e(p){var b=p.state;try{return this.apply(b,arguments)}finally{d(p,b)}}function f(p,b,c,a,d,e,f){for(;c'+b.children+"",p=p.firstChild):p.innerHTML=b.children;b.dom=p.firstChild;b.domSize=p.childNodes.length;for(b=A.createDocumentFragment();m=p.firstChild;)b.appendChild(m);C(c,b,a)}function h(p, -b,c,a,d,e){if(b!==c&&(null!=b||null!=c))if(null==b||0===b.length)f(p,c,0,c.length,a,d,e);else if(null==c||0===c.length)D(b,0,b.length);else{for(var m=0,r=0,h=null,q=null;r=r&&h>=m;)if(k=b[q],y=c[h],null==k)q--;else if(null==y)h--;else if(k.key===y.key)k!==y&&n(p, -k,y,a,d,e),null!=y.dom&&(d=y.dom),q--,h--;else break;for(;q>=r&&h>=m;)if(x=b[r],u=c[m],null==x)r++;else if(null==u)m++;else if(x.key===u.key)r++,m++,x!==u&&n(p,x,u,a,g(b,r,d),e);else break;for(;q>=r&&h>=m;){if(null==x)r++;else if(null==u)m++;else if(null==k)q--;else if(null==y)h--;else if(m===h)break;else{if(x.key!==y.key||k.key!==u.key)break;B=g(b,r,d);C(p,t(k),B);k!==u&&n(p,k,u,a,B,e);++m<=--h&&C(p,t(x),d);x!==y&&n(p,x,y,a,d,e);null!=y.dom&&(d=y.dom);r++;q--}k=b[q];y=c[h];x=b[r];u=c[m]}for(;q>= -r&&h>=m;){if(null==k)q--;else if(null==y)h--;else if(k.key===y.key)k!==y&&n(p,k,y,a,d,e),null!=y.dom&&(d=y.dom),q--,h--;else break;k=b[q];y=c[h]}if(m>h)D(b,r,q+1);else if(r>q)f(p,c,m,h+1,a,d,e);else{u=d;k=h-m+1;x=Array(k);var A=2147483647,z=0;for(B=0;B=m;B--){if(null==l){l=b;k=r;y=q+1;for(var w={};k=m;B--)u=c[B],-1===x[B-m]?v(p,u,a,e,d):b[r]===B-m?r--:C(p,t(u),d),null!=u.dom&&(d=c[B].dom)}else for(B=h;B>=m;B--)u=c[B],-1===x[B-m]&&v(p, -u,a,e,d),null!=u.dom&&(d=c[B].dom)}}else{h=b.lengthh&&D(b,m,b.length);c.length>h&&f(p,c,m,c.length,a,d,e)}}}function n(p,b,a,d,f,g){var m=b.tag;if(m===a.tag){a.state=b.state;a.events=b.events;var r;var k;null!=a.attrs&&"function"===typeof a.attrs.onbeforeupdate&&(r=e.call(a.attrs.onbeforeupdate,a,b));"string"!==typeof a.tag&&"function"=== -typeof a.state.onbeforeupdate&&(k=e.call(a.state.onbeforeupdate,a,b));void 0===r&&void 0===k||r||k?r=!1:(a.dom=b.dom,a.domSize=b.domSize,a.instance=b.instance,r=!0);if(!r)if("string"===typeof m)switch(null!=a.attrs&&N(a.attrs,a,d),m){case "#":b.children.toString()!==a.children.toString()&&(b.dom.nodeValue=a.children);a.dom=b.dom;break;case "<":b.children!==a.children?(t(b),l(p,a,g,f)):(a.dom=b.dom,a.domSize=b.domSize);break;case "[":h(p,b.children,a.children,d,f,g);b=0;d=a.children;a.dom=null;if(null!= -d){for(var q=0;qc.indexOf("?")?"?":"&";c+=e+d}return c}function h(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error(c);}}function n(c){return c.responseText}function m(c,a){if("function"=== +typeof c)if(Array.isArray(a))for(var d=0;dl.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var h=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script");a[g]=function(e){n.parentNode.removeChild(n);d(m(c.type,e));delete a[g]};n.onerror=function(){n.parentNode.removeChild(n); +e(Error("JSONP request failed"));delete a[g]};null==c.data&&(c.data={});c.url=q(c.url,c.data);c.data[c.callbackKey||"callback"]=g;n.src=k(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?x:h(x)},setCompletionCallback:function(c){C=c}}}(window,p),V=function(a){function d(t,b){if(t.state!==b)throw Error("`vnode.state` must not be modified");}function e(t){var b=t.state;try{return this.apply(b,arguments)}finally{d(t,b)}}function g(t,b,f,c,a,d,e){for(;f'+b.children+"",a=a.firstChild):a.innerHTML=b.children;b.dom=a.firstChild;b.domSize=a.childNodes.length; +for(b=D.createDocumentFragment();f=a.firstChild;)b.appendChild(f);C(t,b,c)}function h(t,b,f,c,a,d){if(b!==f&&(null!=b||null!=f))if(null==b||0===b.length)g(t,f,0,f.length,c,a,d);else if(null==f||0===f.length)x(b,0,b.length);else{for(var e=0,h=0,v=null,k=null;h=h&& +v>=e;)if(A=b[k],y=f[v],null==A)k--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),k--,v--;else break;for(;k>=h&&v>=e;)if(r=b[h],u=f[e],null==r)h++;else if(null==u)e++;else if(r.key===u.key)h++,e++,r!==u&&n(t,r,u,c,l(b,h,a),d);else break;for(;k>=h&&v>=e;){if(null==r)h++;else if(null==u)e++;else if(null==A)k--;else if(null==y)v--;else if(e===v)break;else{if(r.key!==y.key||A.key!==u.key)break;B=l(b,h,a);C(t,m(A),B);A!==u&&n(t,A,u,c,B,d);++e<=--v&&C(t,m(r),a);r!== +y&&n(t,r,y,c,a,d);null!=y.dom&&(a=y.dom);h++;k--}A=b[k];y=f[v];r=b[h];u=f[e]}for(;k>=h&&v>=e;){if(null==A)k--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),k--,v--;else break;A=b[k];y=f[v]}if(e>v)x(b,h,k+1);else if(h>k)g(t,f,e,v+1,c,a,d);else{u=a;A=v-e+1;r=Array(A);var G=2147483647,z=0;for(B=0;B=e;B--){if(null==p){p=b;A=h;y=k+1;for(var w={};A=e;B--)u=f[B],-1===r[B-e]?q(t,u,c,d,a):b[h]===B-e? +h--:C(t,m(u),a),null!=u.dom&&(a=f[B].dom)}else for(B=v;B>=e;B--)u=f[B],-1===r[B-e]&&q(t,u,c,d,a),null!=u.dom&&(a=f[B].dom)}}else{v=b.lengthv&&x(b,e,b.length);f.length>v&&g(t,f,e,f.length,c,a,d)}}}function n(a,b,f,d,g,l){var t=b.tag;if(t===f.tag){f.state=b.state;f.events=b.events;var v;var x;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&& +(v=e.call(f.attrs.onbeforeupdate,f,b));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(x=e.call(f.state.onbeforeupdate,f,b));void 0===v&&void 0===x||v||x?v=!1:(f.dom=b.dom,f.domSize=b.domSize,f.instance=b.instance,v=!0);if(!v)if("string"===typeof t)switch(null!=f.attrs&&L(f.attrs,f,d),t){case "#":b.children.toString()!==f.children.toString()&&(b.dom.nodeValue=f.children);f.dom=b.dom;break;case "<":b.children!==f.children?(m(b),k(a,f,l,g)):(f.dom=b.dom,f.domSize=b.domSize);break; +case "[":h(a,b.children,f.children,d,g,l);b=0;d=f.children;f.dom=null;if(null!=d){for(var p=0;p Date: Sat, 2 Jun 2018 23:03:30 +0200 Subject: [PATCH 264/301] [performance testing] add classes in some selectors for the attrs test --- performance/test-perf.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/performance/test-perf.js b/performance/test-perf.js index 8ce4e969..185d5cfc 100644 --- a/performance/test-perf.js +++ b/performance/test-perf.js @@ -52,6 +52,7 @@ scratch = doc.createElement("div"); // Initialize benchmark suite var suite = new B.Suite("mithril perf") +var xuite = {add: function(options) {console.log("skipping " + options.name)}} // eslint-disable-line no-unused-vars suite.on("start", function() { this.start = Date.now(); @@ -228,7 +229,7 @@ suite.add({ suite.add({ name : "mutate styles/properties", - + // minSamples: 100, onStart : function () { var counter = 0 var keyLooper = function (n) { return function (c) { return c % n ? (c + "px") : c } } @@ -259,19 +260,19 @@ suite.add({ this.count = 0 this.app = function (index) { - return m("div", + return m("div.booga", { class: get(classes, index), "data-index": index, title: index.toString(36) }, - m("input", {type: "checkbox", checked: index % 3 == 0}), + m("input.dooga", {type: "checkbox", checked: index % 3 == 0}), m("input", {value: "test " + (Math.floor(index / 4)), disabled: index % 10 ? null : true}), m("div", {class: get(classes, index * 11)}, m("p", {style: get(styles, index)}, "p1"), m("p", {style: get(styles, index + 1)}, "p2"), m("p", {style: get(styles, index * 2)}, "p3"), - m("p", {style: get(styles, index * 3 + 1)}, "p4") + m("p.zooga", {style: get(styles, index * 3 + 1), className: get(classes, index * 7)}, "p4") ) ) } From 92b22fe8e6b81d4056e1234e1c1a8355535ea1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 2 Jun 2018 23:09:50 +0200 Subject: [PATCH 265/301] [render/hyperscript] have the attrs take precedence over the selector, improve class normalization fix #1773 fix #2172 --- render/hyperscript.js | 26 +++++++++---------- render/tests/test-hyperscript.js | 44 +++++++++++++++++--------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/render/hyperscript.js b/render/hyperscript.js index 8573559c..b7499993 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -31,7 +31,8 @@ function compileSelector(selector) { function execSelector(state, attrs, children) { var hasAttrs = false, childList, text - var className = attrs.className || attrs.class + var classAttr = hasOwn.call(attrs, "class") ? "class" : "className" + var className = attrs[classAttr] if (!isEmpty(state.attrs) && !isEmpty(attrs)) { var newAttrs = {} @@ -46,21 +47,18 @@ function execSelector(state, attrs, children) { } for (var key in state.attrs) { - if (hasOwn.call(state.attrs, key)) { + if (hasOwn.call(state.attrs, key) && key !== "className" && !hasOwn.call(attrs, key)){ attrs[key] = state.attrs[key] } } - - if (className !== undefined) { - if (attrs.class !== undefined) { - attrs.class = undefined - attrs.className = className - } - - if (state.attrs.className != null) { - attrs.className = state.attrs.className + " " + className - } - } + if (className || state.attrs.className) attrs[classAttr] = + className + ? state.attrs.className + ? state.attrs.className + " " + className + : className + : state.attrs.className + ? state.attrs.className + : null for (var key in attrs) { if (hasOwn.call(attrs, key) && key !== "key") { @@ -75,7 +73,7 @@ function execSelector(state, attrs, children) { childList = children } - return Vnode(state.tag, attrs.key, hasAttrs ? attrs : undefined, childList, text) + return Vnode(state.tag, attrs.key, hasAttrs ? attrs : null, childList, text) } function hyperscript(selector) { diff --git a/render/tests/test-hyperscript.js b/render/tests/test-hyperscript.js index f221bef7..83932527 100644 --- a/render/tests/test-hyperscript.js +++ b/render/tests/test-hyperscript.js @@ -16,53 +16,46 @@ o.spec("hyperscript", function() { o(vnode.tag).equals("a") }) - o("v1.0.1 bug-for-bug regression suite", function(){ + o("class and className normalization", function(){ o(m("a", { class: null }).attrs).deepEquals({ - class: undefined, - className: null + class: null }) o(m("a", { class: undefined }).attrs).deepEquals({ - class: undefined, + class: undefined }) o(m("a", { class: false }).attrs).deepEquals({ - class: undefined, - className: false + class: false }) o(m("a", { class: true }).attrs).deepEquals({ - class: undefined, - className: true + class: true }) o(m("a.x", { class: null }).attrs).deepEquals({ - class: undefined, - className: "x null" + class: "x" }) o(m("a.x", { class: undefined }).attrs).deepEquals({ - class: undefined, - className: "x" + class: "x" }) o(m("a.x", { class: false }).attrs).deepEquals({ - class: undefined, - className: "x false" + class: "x" }) o(m("a.x", { class: true }).attrs).deepEquals({ - class: undefined, - className: "x true" + class: "x true" }) o(m("a", { className: null @@ -272,7 +265,7 @@ o.spec("hyperscript", function() { var vnode = m("div", {key:"a"}) o(vnode.tag).equals("div") - o(vnode.attrs).equals(undefined) + o(vnode.attrs).equals(null) o(vnode.key).equals("a") }) o("handles many attrs", function() { @@ -295,7 +288,7 @@ o.spec("hyperscript", function() { o("handles merging classes w/ class property", function() { var vnode = m(".a", {class: "b"}) - o(vnode.attrs.className).equals("a b") + o(vnode.attrs.class).equals("a b") }) o("handles merging classes w/ className property", function() { var vnode = m(".a", {className: "b"}) @@ -490,20 +483,20 @@ o.spec("hyperscript", function() { o("handles children without attr", function() { var vnode = m("div", [m("i"), m("s")]) - o(vnode.attrs).equals(undefined) + o(vnode.attrs).equals(null) o(vnode.children[0].tag).equals("i") o(vnode.children[1].tag).equals("s") }) o("handles child without attr unwrapped", function() { var vnode = m("div", m("i")) - o(vnode.attrs).equals(undefined) + o(vnode.attrs).equals(null) o(vnode.children[0].tag).equals("i") }) o("handles children without attr unwrapped", function() { var vnode = m("div", m("i"), m("s")) - o(vnode.attrs).equals(undefined) + o(vnode.attrs).equals(null) o(vnode.children[0].tag).equals("i") o(vnode.children[1].tag).equals("s") }) @@ -524,6 +517,15 @@ o.spec("hyperscript", function() { m(".a", attrs) o(attrs).deepEquals({a: "b"}) }) + o("non-nullish attr takes precedence over selector", function() { + o(m("[a=b]", {a: "c"}).attrs).deepEquals({a: "c"}) + }) + o("null attr takes precedence over selector", function() { + o(m("[a=b]", {a: null}).attrs).deepEquals({a: null}) + }) + o("undefined attr takes precedence over selector", function() { + o(m("[a=b]", {a: undefined}).attrs).deepEquals({a: undefined}) + }) o("handles fragment children without attr unwrapped", function() { var vnode = m("div", [m("i")], [m("s")]) From 8daa386e5ec60a317d41d0022300f6a67fde3009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Wed, 6 Jun 2018 19:33:50 +0200 Subject: [PATCH 266/301] [render/test] add a render/hyperscript integration suite for classes --- .../test-render-hyperscript-integration.js | 614 ++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 render/tests/test-render-hyperscript-integration.js diff --git a/render/tests/test-render-hyperscript-integration.js b/render/tests/test-render-hyperscript-integration.js new file mode 100644 index 00000000..73d96a8f --- /dev/null +++ b/render/tests/test-render-hyperscript-integration.js @@ -0,0 +1,614 @@ +"use strict" + +var o = require("../../ospec/ospec") +var m = require("../../render/hyperscript") +var domMock = require("../../test-utils/domMock") +var vdom = require("../../render/render") + +o.spec("render/hyperscript integration", function() { + var $window, root, render + o.beforeEach(function() { + $window = domMock() + root = $window.document.createElement("div") + render = vdom($window).render + }) + o.spec("setting class", function() { + o("selector only", function() { + render(root, m(".foo")) + + o(root.firstChild.className).equals("foo") + }) + o("class only", function() { + render(root, m("div", {class: "foo"})) + + o(root.firstChild.className).equals("foo") + }) + o("className only", function() { + render(root, m("div", {className: "foo"})) + + o(root.firstChild.className).equals("foo") + }) + o("selector and class", function() { + render(root, m(".bar", {class: "foo"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar", "foo"]) + }) + o("selector and className", function() { + render(root, m(".bar", {className: "foo"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar", "foo"]) + }) + o("selector and a null class", function() { + render(root, m(".foo", {class: null})) + + o(root.firstChild.className).equals("foo") + }) + o("selector and a null className", function() { + render(root, m(".foo", {className: null})) + + o(root.firstChild.className).equals("foo") + }) + o("selector and an undefined class", function() { + render(root, m(".foo", {class: undefined})) + + o(root.firstChild.className).equals("foo") + }) + o("selector and an undefined className", function() { + render(root, m(".foo", {className: undefined})) + + o(root.firstChild.className).equals("foo") + }) + }) + o.spec("updating class", function() { + o.spec("from selector only", function() { + o("to selector only", function() { + render(root, m(".foo1")) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".foo1")) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".foo1")) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".foo1")) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".foo1")) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo1")) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo1")) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo1")) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo1")) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from class only", function() { + o("to selector only", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m("div", {class: "foo2"})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m("div", {class: "foo2"})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m("div", {class: "foo2"})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from ", function() { + o("to selector only", function() { + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from className only", function() { + o("to selector only", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m("div", {className: "foo1"})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m("div", {className: "foo1"})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m("div", {className: "foo1"})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from selector and class", function() { + o("to selector only", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".bar1", {class: "foo1"})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from selector and className", function() { + o("to selector only", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".bar1", {className: "foo1"})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from and a null class", function() { + o("to selector only", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".foo1", {class: null})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".foo1", {class: null})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo1", {class: null})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from selector and a null className", function() { + o("to selector only", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".foo1", {className: null})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".foo1", {className: null})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo1", {className: null})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from selector and an undefined class", function() { + o("to selector only", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo1", {class: undefined})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + o.spec("from selector and an undefined className", function() { + o("to selector only", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".foo2")) + + o(root.firstChild.className).equals("foo2") + }) + o("to class only", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m("div", {class: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to className only", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m("div", {className: "foo2"})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and class", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".bar2", {class: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and className", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".bar2", {className: "foo2"})) + + o(root.firstChild.className.split(" ").sort()).deepEquals(["bar2", "foo2"]) + }) + o("to selector and a null class", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".foo2", {class: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and a null className", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".foo2", {className: null})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined class", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".foo2", {class: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + o("to selector and an undefined className", function() { + render(root, m(".foo1", {className: undefined})) + render(root, m(".foo2", {className: undefined})) + + o(root.firstChild.className).equals("foo2") + }) + }) + }) +}) From 15cf47a829a4589539ec870b77e06155ae46b74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 7 Jun 2018 00:24:14 +0200 Subject: [PATCH 267/301] [performance] use individual files rather than the build, revamp the attrs code to reduce variance, reset the scratch pad more reliably --- performance/index.html | 4 +++- performance/test-perf.js | 47 ++++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/performance/index.html b/performance/index.html index a0f288c5..402eee8b 100644 --- a/performance/index.html +++ b/performance/index.html @@ -13,7 +13,9 @@ - + + + diff --git a/performance/test-perf.js b/performance/test-perf.js index 185d5cfc..020960c4 100644 --- a/performance/test-perf.js +++ b/performance/test-perf.js @@ -31,7 +31,7 @@ var browserMock = require("../test-utils/browserMock") // Do this silly dance so browser testing works var B = typeof Benchmark === "undefined" ? require("benchmark") : Benchmark -var m, scratch; +var scratch; // set up browser env on before running tests var doc = typeof document !== "undefined" ? document : null @@ -43,12 +43,16 @@ if(!doc) { doc = mock.document } -// Have to include mithril AFTER browser polyfill is set up -m = require("../mithril") // eslint-disable-line global-require +var m = require("../render/hyperscript") +m.render = require("../render/render")(window).render -scratch = doc.createElement("div"); -(doc.body || doc.documentElement).appendChild(scratch) +function resetScratch() { + doc.documentElement.innerHTML = "
" + scratch = doc.documentElement.firstChild +} + +resetScratch() // Initialize benchmark suite var suite = new B.Suite("mithril perf") @@ -61,7 +65,7 @@ suite.on("start", function() { suite.on("cycle", function(e) { console.log(e.target.toString()) - scratch.innerHTML = "" + resetScratch() }) suite.on("complete", function() { @@ -260,21 +264,26 @@ suite.add({ this.count = 0 this.app = function (index) { - return m("div.booga", - { - class: get(classes, index), - "data-index": index, - title: index.toString(36) - }, - m("input.dooga", {type: "checkbox", checked: index % 3 == 0}), - m("input", {value: "test " + (Math.floor(index / 4)), disabled: index % 10 ? null : true}), - m("div", {class: get(classes, index * 11)}, - m("p", {style: get(styles, index)}, "p1"), - m("p", {style: get(styles, index + 1)}, "p2"), - m("p", {style: get(styles, index * 2)}, "p3"), - m("p.zooga", {style: get(styles, index * 3 + 1), className: get(classes, index * 7)}, "p4") + var last = index + 300 + var vnodes = [] + for (; index < last; index++) vnodes.push( + m("div.booga", + { + class: get(classes, index), + "data-index": index, + title: index.toString(36) + }, + m("input.dooga", {type: "checkbox", checked: index % 3 == 0}), + m("input", {value: "test " + (Math.floor(index / 4)), disabled: index % 10 ? null : true}), + m("div", {class: get(classes, index * 11)}, + m("p", {style: get(styles, index)}, "p1"), + m("p", {style: get(styles, index + 1)}, "p2"), + m("p", {style: get(styles, index * 2)}, "p3"), + m("p.zooga", {style: get(styles, index * 3 + 1), className: get(classes, index * 7)}, "p4") + ) ) ) + return vnodes } }, From 32b319d140dfba14379d1969af929842dcb7cf58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 7 Jun 2018 00:46:10 +0200 Subject: [PATCH 268/301] [render/hyperscript] Normalize to class attrs to className, ignore only nullish values --- render/hyperscript.js | 10 ++++++---- render/tests/test-hyperscript.js | 24 +++++++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/render/hyperscript.js b/render/hyperscript.js index b7499993..36eabbc5 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -51,15 +51,17 @@ function execSelector(state, attrs, children) { attrs[key] = state.attrs[key] } } - if (className || state.attrs.className) attrs[classAttr] = - className - ? state.attrs.className + if (className != null || state.attrs.className != null) attrs.className = + className != null + ? state.attrs.className != null ? state.attrs.className + " " + className : className - : state.attrs.className + : state.attrs.className != null ? state.attrs.className : null + if (classAttr === "class") attrs.class = null + for (var key in attrs) { if (hasOwn.call(attrs, key) && key !== "key") { hasAttrs = true diff --git a/render/tests/test-hyperscript.js b/render/tests/test-hyperscript.js index 83932527..21924dee 100644 --- a/render/tests/test-hyperscript.js +++ b/render/tests/test-hyperscript.js @@ -25,37 +25,43 @@ o.spec("hyperscript", function() { o(m("a", { class: undefined }).attrs).deepEquals({ - class: undefined + class: null }) o(m("a", { class: false }).attrs).deepEquals({ - class: false + class: null, + className: false }) o(m("a", { class: true }).attrs).deepEquals({ - class: true + class: null, + className: true }) o(m("a.x", { class: null }).attrs).deepEquals({ - class: "x" + class: null, + className: "x" }) o(m("a.x", { class: undefined }).attrs).deepEquals({ - class: "x" + class: null, + className: "x" }) o(m("a.x", { class: false }).attrs).deepEquals({ - class: "x" + class: null, + className: "x false" }) o(m("a.x", { class: true }).attrs).deepEquals({ - class: "x true" + class: null, + className: "x true" }) o(m("a", { className: null @@ -90,7 +96,7 @@ o.spec("hyperscript", function() { o(m("a.x", { className: false }).attrs).deepEquals({ - className: "x" + className: "x false" }) o(m("a.x", { className: true @@ -288,7 +294,7 @@ o.spec("hyperscript", function() { o("handles merging classes w/ class property", function() { var vnode = m(".a", {class: "b"}) - o(vnode.attrs.class).equals("a b") + o(vnode.attrs.className).equals("a b") }) o("handles merging classes w/ className property", function() { var vnode = m(".a", {className: "b"}) From fed0846a11f71850278e2e18d23bb026617c3faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Thu, 7 Jun 2018 14:48:47 +0200 Subject: [PATCH 269/301] [docs] #2174 docs and change log --- docs/change-log.md | 2 ++ docs/hyperscript.md | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 682af63c..e77780f8 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -24,6 +24,8 @@ - API: `m.mount()` will only render its own root when called, it will not trigger a `redraw()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Assigning to `vnode.state` (as in `vnode.state = ...`) is no longer supported. Instead, an error is thrown if `vnode.state` changes upon the invocation of a lifecycle hook. - API: `m.request` will no longer reject the Promise on server errors (eg. status >= 400) if the caller supplies an `extract` callback. This gives applications more control over handling server responses. +- hyperscript: when attributes have a `null` or `undefined` value, they are treated as if they were absent. [#1773](https://github.com/MithrilJS/mithril.js/issues/1773) ([#2174](https://github.com/MithrilJS/mithril.js/pull/2174)) +- hyperscript: when an attribute is defined on both the first and second argument (as a CSS selector and an `attrs` field, respectively), the latter takes precedence, except for `class` attributes that are still added together. [#2172](https://github.com/MithrilJS/mithril.js/issues/2172) ([#2174](https://github.com/MithrilJS/mithril.js/pull/2174)) #### News diff --git a/docs/hyperscript.md b/docs/hyperscript.md index 8ebe297b..26b0a27d 100644 --- a/docs/hyperscript.md +++ b/docs/hyperscript.md @@ -5,6 +5,7 @@ - [How it works](#how-it-works) - [Flexibility](#flexibility) - [CSS selectors](#css-selectors) +- [Attributes passed as the second argument](attributes-passed-as-the-second-argument) - [DOM attributes](#dom-attributes) - [Style attribute](#style-attribute) - [Events](#events) @@ -144,7 +145,23 @@ m("a.link[href=/]", { // Home ``` -If there are class names in both first and second arguments of `m()`, they are merged together as you would expect. +### Attributes passed as the second argument + +You can pass attributes, properties, events and lifecycle hooks in the second, optional argument (see the next sections for details). + +```JS +m("button", { + class: "my-button", + onclick: function() {/* ... */}, + oncreate: function() {/* ... */} +}) +``` + +If the value of such an attribute is `null` or `undefined`, it is treated as if the attribute was absent. + +If there are class names in both first and second arguments of `m()`, they are merged together as you would expect. If the value of the class in the second argument is `null`or `undefined`, it is ignored. + +If another attribute is present in both the first and the second argument, the second one takes precedence even if it is is `null` or `undefined`. --- From 6bf7be888765b1dd1110b8111b0cbbb3eb2bef02 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Thu, 7 Jun 2018 16:11:30 +0000 Subject: [PATCH 270/301] Bundled output for commit fed0846a11f71850278e2e18d23bb026617c3faa [skip ci] --- README.md | 2 +- mithril.js | 25 ++++++------- mithril.min.js | 96 +++++++++++++++++++++++++------------------------- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index fa0159a9..881fab6e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.86 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.89 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 567d2c4c..5f87c706 100644 --- a/mithril.js +++ b/mithril.js @@ -41,7 +41,8 @@ function compileSelector(selector) { } function execSelector(state, attrs, children) { var hasAttrs = false, childList, text - var className = attrs.className || attrs.class + var classAttr = hasOwn.call(attrs, "class") ? "class" : "className" + var className = attrs[classAttr] if (!isEmpty(state.attrs) && !isEmpty(attrs)) { var newAttrs = {} for(var key in attrs) { @@ -52,19 +53,19 @@ function execSelector(state, attrs, children) { attrs = newAttrs } for (var key in state.attrs) { - if (hasOwn.call(state.attrs, key)) { + if (hasOwn.call(state.attrs, key) && key !== "className" && !hasOwn.call(attrs, key)){ attrs[key] = state.attrs[key] } } - if (className !== undefined) { - if (attrs.class !== undefined) { - attrs.class = undefined - attrs.className = className - } - if (state.attrs.className != null) { - attrs.className = state.attrs.className + " " + className - } - } + if (className != null || state.attrs.className != null) attrs.className = + className != null + ? state.attrs.className != null + ? state.attrs.className + " " + className + : className + : state.attrs.className != null + ? state.attrs.className + : null + if (classAttr === "class") attrs.class = null for (var key in attrs) { if (hasOwn.call(attrs, key) && key !== "key") { hasAttrs = true @@ -76,7 +77,7 @@ function execSelector(state, attrs, children) { } else { childList = children } - return Vnode(state.tag, attrs.key, hasAttrs ? attrs : undefined, childList, text) + return Vnode(state.tag, attrs.key, hasAttrs ? attrs : null, childList, text) } function hyperscript(selector) { if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") { diff --git a/mithril.min.js b/mithril.min.js index 414d2792..71795996 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,48 +1,48 @@ -(function(){function z(a,d,e,g,q,k){return{tag:a,key:d,attrs:e,children:g,text:q,dom:k,domSize:void 0,state:void 0,events:void 0,instance:void 0}}function Q(a){for(var d in a)if(I.call(a,d))return!1;return!0}function w(a){if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");var d=arguments[1],e=2;if(null==d)d={};else if("object"!==typeof d||null!=d.tag||Array.isArray(d))d={},e=1;if(arguments.length=== -e+1){var g=arguments[e];Array.isArray(g)||(g=[g])}else for(g=[];ec.indexOf("?")?"?":"&";c+=e+d}return c}function h(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error(c);}}function n(c){return c.responseText}function m(c,a){if("function"=== -typeof c)if(Array.isArray(a))for(var d=0;dl.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var h=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script");a[g]=function(e){n.parentNode.removeChild(n);d(m(c.type,e));delete a[g]};n.onerror=function(){n.parentNode.removeChild(n); -e(Error("JSONP request failed"));delete a[g]};null==c.data&&(c.data={});c.url=q(c.url,c.data);c.data[c.callbackKey||"callback"]=g;n.src=k(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?x:h(x)},setCompletionCallback:function(c){C=c}}}(window,p),V=function(a){function d(t,b){if(t.state!==b)throw Error("`vnode.state` must not be modified");}function e(t){var b=t.state;try{return this.apply(b,arguments)}finally{d(t,b)}}function g(t,b,f,c,a,d,e){for(;f'+b.children+"",a=a.firstChild):a.innerHTML=b.children;b.dom=a.firstChild;b.domSize=a.childNodes.length; -for(b=D.createDocumentFragment();f=a.firstChild;)b.appendChild(f);C(t,b,c)}function h(t,b,f,c,a,d){if(b!==f&&(null!=b||null!=f))if(null==b||0===b.length)g(t,f,0,f.length,c,a,d);else if(null==f||0===f.length)x(b,0,b.length);else{for(var e=0,h=0,v=null,k=null;h=h&& -v>=e;)if(A=b[k],y=f[v],null==A)k--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),k--,v--;else break;for(;k>=h&&v>=e;)if(r=b[h],u=f[e],null==r)h++;else if(null==u)e++;else if(r.key===u.key)h++,e++,r!==u&&n(t,r,u,c,l(b,h,a),d);else break;for(;k>=h&&v>=e;){if(null==r)h++;else if(null==u)e++;else if(null==A)k--;else if(null==y)v--;else if(e===v)break;else{if(r.key!==y.key||A.key!==u.key)break;B=l(b,h,a);C(t,m(A),B);A!==u&&n(t,A,u,c,B,d);++e<=--v&&C(t,m(r),a);r!== -y&&n(t,r,y,c,a,d);null!=y.dom&&(a=y.dom);h++;k--}A=b[k];y=f[v];r=b[h];u=f[e]}for(;k>=h&&v>=e;){if(null==A)k--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),k--,v--;else break;A=b[k];y=f[v]}if(e>v)x(b,h,k+1);else if(h>k)g(t,f,e,v+1,c,a,d);else{u=a;A=v-e+1;r=Array(A);var G=2147483647,z=0;for(B=0;B=e;B--){if(null==p){p=b;A=h;y=k+1;for(var w={};A=e;B--)u=f[B],-1===r[B-e]?q(t,u,c,d,a):b[h]===B-e? -h--:C(t,m(u),a),null!=u.dom&&(a=f[B].dom)}else for(B=v;B>=e;B--)u=f[B],-1===r[B-e]&&q(t,u,c,d,a),null!=u.dom&&(a=f[B].dom)}}else{v=b.lengthv&&x(b,e,b.length);f.length>v&&g(t,f,e,f.length,c,a,d)}}}function n(a,b,f,d,g,l){var t=b.tag;if(t===f.tag){f.state=b.state;f.events=b.events;var v;var x;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&& -(v=e.call(f.attrs.onbeforeupdate,f,b));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(x=e.call(f.state.onbeforeupdate,f,b));void 0===v&&void 0===x||v||x?v=!1:(f.dom=b.dom,f.domSize=b.domSize,f.instance=b.instance,v=!0);if(!v)if("string"===typeof t)switch(null!=f.attrs&&L(f.attrs,f,d),t){case "#":b.children.toString()!==f.children.toString()&&(b.dom.nodeValue=f.children);f.dom=b.dom;break;case "<":b.children!==f.children?(m(b),k(a,f,l,g)):(f.dom=b.dom,f.domSize=b.domSize);break; -case "[":h(a,b.children,f.children,d,g,l);b=0;d=f.children;f.dom=null;if(null!=d){for(var p=0;pc.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error(c); +}}function n(c){return c.responseText}function m(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dl.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var k=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script");a[g]=function(e){n.parentNode.removeChild(n); +d(m(c.type,e));delete a[g]};n.onerror=function(){n.parentNode.removeChild(n);e(Error("JSONP request failed"));delete a[g]};null==c.data&&(c.data={});c.url=q(c.url,c.data);c.data[c.callbackKey||"callback"]=g;n.src=h(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?x:k(x)},setCompletionCallback:function(c){C=c}}}(window,p),V=function(a){function d(t,b){if(t.state!==b)throw Error("`vnode.state` must not be modified");}function e(t){var b=t.state;try{return this.apply(b, +arguments)}finally{d(t,b)}}function g(t,b,f,c,a,d,e){for(;f'+ +b.children+"",a=a.firstChild):a.innerHTML=b.children;b.dom=a.firstChild;b.domSize=a.childNodes.length;for(b=D.createDocumentFragment();f=a.firstChild;)b.appendChild(f);C(t,b,c)}function k(t,b,f,c,a,d){if(b!==f&&(null!=b||null!=f))if(null==b||0===b.length)g(t,f,0,f.length,c,a,d);else if(null==f||0===f.length)x(b,0,b.length);else{for(var e=0,k=0,v=null,h=null;k=k&&v>=e;)if(A=b[h],y=f[v],null==A)h--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),h--,v--;else break;for(;h>=k&&v>=e;)if(r=b[k],u=f[e],null==r)k++;else if(null==u)e++;else if(r.key===u.key)k++,e++,r!==u&&n(t,r,u,c,l(b,k,a),d);else break;for(;h>=k&&v>=e;){if(null==r)k++;else if(null==u)e++;else if(null==A)h--;else if(null==y)v--;else if(e===v)break;else{if(r.key!== +y.key||A.key!==u.key)break;B=l(b,k,a);C(t,m(A),B);A!==u&&n(t,A,u,c,B,d);++e<=--v&&C(t,m(r),a);r!==y&&n(t,r,y,c,a,d);null!=y.dom&&(a=y.dom);k++;h--}A=b[h];y=f[v];r=b[k];u=f[e]}for(;h>=k&&v>=e;){if(null==A)h--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),h--,v--;else break;A=b[h];y=f[v]}if(e>v)x(b,k,h+1);else if(k>h)g(t,f,e,v+1,c,a,d);else{u=a;A=v-e+1;r=Array(A);var G=2147483647,z=0;for(B=0;B=e;B--){if(null==p){p=b;A=k;y=h+1;for(var w= +{};A=e;B--)u=f[B],-1===r[B-e]?q(t,u,c,d,a):b[k]===B-e?k--:C(t,m(u),a),null!=u.dom&&(a=f[B].dom)}else for(B=v;B>=e;B--)u=f[B],-1===r[B-e]&&q(t,u,c,d,a),null!=u.dom&&(a=f[B].dom)}}else{v=b.lengthv&&x(b,e,b.length);f.length>v&&g(t,f,e,f.length,c,a,d)}}}function n(a,b,f,d,g,l){var t=b.tag;if(t=== +f.tag){f.state=b.state;f.events=b.events;var v;var x;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(v=e.call(f.attrs.onbeforeupdate,f,b));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(x=e.call(f.state.onbeforeupdate,f,b));void 0===v&&void 0===x||v||x?v=!1:(f.dom=b.dom,f.domSize=b.domSize,f.instance=b.instance,v=!0);if(!v)if("string"===typeof t)switch(null!=f.attrs&&L(f.attrs,f,d),t){case "#":b.children.toString()!==f.children.toString()&&(b.dom.nodeValue=f.children); +f.dom=b.dom;break;case "<":b.children!==f.children?(m(b),h(a,f,l,g)):(f.dom=b.dom,f.domSize=b.domSize);break;case "[":k(a,b.children,f.children,d,g,l);b=0;d=f.children;f.dom=null;if(null!=d){for(var p=0;p Date: Mon, 11 Jun 2018 09:46:58 -0700 Subject: [PATCH 271/301] [render/render] Prevent activeElement.focus on SVGs, fix #1983 --- render/render.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/render.js b/render/render.js index c8181ad1..f95d40cd 100644 --- a/render/render.js +++ b/render/render.js @@ -867,7 +867,7 @@ module.exports = function($window) { updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement - if (active != null && $doc.activeElement !== active) active.focus() + if (active != null && $doc.activeElement !== active && typeof active.focus === "function") active.focus() for (var i = 0; i < hooks.length; i++) hooks[i]() } From 6dee1571a19ac6a730038ddcfc6f939cb0b7749a Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 11 Jun 2018 20:06:53 +0000 Subject: [PATCH 272/301] Bundled output for commit 571b60830b2d501494066425eb4e1b4bc8c11f5a [skip ci] --- README.md | 2 +- mithril.js | 2 +- mithril.min.js | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 881fab6e..5f5e96ac 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.89 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.90 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 5f87c706..6611f9d9 100644 --- a/mithril.js +++ b/mithril.js @@ -1240,7 +1240,7 @@ var coreRenderer = function($window) { updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement - if (active != null && $doc.activeElement !== active) active.focus() + if (active != null && $doc.activeElement !== active && typeof active.focus === "function") active.focus() for (var i = 0; i < hooks.length; i++) hooks[i]() } return {render: render, setEventCallback: setEventCallback} diff --git a/mithril.min.js b/mithril.min.js index 71795996..e8c9051b 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -36,13 +36,13 @@ null!==c&&a.dom.value===e||"option"===a.tag&&null!==c&&a.dom.value===e))return;" (a.style[d]="")}else if(b===c&&(a.style.cssText="",b=null),null==c)a.style.cssText="";else if("string"===typeof c)a.style.cssText=c;else for(d in"string"===typeof b&&(a.style.cssText=""),c)a.style[d]=c[d]}function M(){}function U(a,b,c){null!=a.events?a.events[b]!==c&&(null==c||"function"!==typeof c&&"object"!==typeof c?(null!=a.events[b]&&a.dom.removeEventListener(b.slice(2),a.events,!1),a.events[b]=void 0):(null==a.events[b]&&a.dom.addEventListener(b.slice(2),a.events,!1),a.events[b]=c)):null== c||"function"!==typeof c&&"object"!==typeof c||(a.events=new M,a.dom.addEventListener(b.slice(2),a.events,!1),a.events[b]=c)}function N(a,b,c){"function"===typeof a.oninit&&e.call(a.oninit,b);"function"===typeof a.oncreate&&c.push(e.bind(a.oncreate,b))}function L(a,b,c){"function"===typeof a.onupdate&&c.push(e.bind(a.onupdate,b))}var D=a.document;D.createDocumentFragment();var H={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},I,J={caption:"table",thead:"table",tbody:"table", tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"};M.prototype=Object.create(null);M.prototype.handleEvent=function(a){var b=this["on"+a.type];"function"===typeof b?b.call(a.target,a):"function"===typeof b.handleEvent&&b.handleEvent(a);"function"===typeof I&&I.call(a.target,a)};return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=D.activeElement,e=a.namespaceURI;null==a.vnodes&&(a.textContent= -"");Array.isArray(b)||(b=[b]);k(a,a.vnodes,z.normalizeChildren(b),c,null,"http://www.w3.org/1999/xhtml"===e?void 0:e);a.vnodes=b;null!=d&&D.activeElement!==d&&d.focus();for(d=0;d Date: Wed, 13 Jun 2018 11:23:22 +0200 Subject: [PATCH 273/301] Use parcel instead of webpack for quickstart. (#2182) much simpler --- docs/installation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 5689bc25..5dd6434b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -23,17 +23,17 @@ $ npm install mithril --save --- -### Quick start with Webpack +### Quick start with [Parcel](https://parceljs.org/) 1. Initialize the directory as an npm package ```bash $ npm init --yes ``` -2. install required tools +2. Install the required tools. ```bash $ npm install mithril --save -$ npm install webpack webpack-cli --save-dev +$ npm install parcel-bundler --save-dev ``` 3. Add a "start" entry to the scripts section in `package.json`. @@ -41,7 +41,7 @@ $ npm install webpack webpack-cli --save-dev { // ... "scripts": { - "start": "webpack src/index.js --output bin/app.js -d --watch" + "start": "parcel src/index.html" } } ``` @@ -52,20 +52,20 @@ import m from "mithril"; m.render(document.body, "hello world"); ``` -5. create `index.html` +5. Create `index.html`. ```html - + ``` -6. run bundler +6. Run the bundler. ```bash $ npm start ``` -7. open `index.html` in a browser +7. Click the shown link to open it in the browser. #### Step by step From f39081b2a51132084dd49d34626093b5f12eeeed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 23 Jun 2018 22:09:12 +0200 Subject: [PATCH 274/301] [opec] v3.0.0 --- ospec/change-log.md | 5 ++++- ospec/package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 01d0e884..14337b57 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -4,6 +4,9 @@ ## Upcoming... _2018-xx-yy_ + +## 3.0.0 +_2018-06-20_ ### Breaking - Better input checking to prevent misuses of the library. Misues of the library will now throw errors, rather than report failures. This may uncover bugs in your test suites. Since it is potentially a disruptive update this change triggers a semver major bump. ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - Change the reserved character for hooks and test suite meta-information from `"__"` to `"\x01"`. Tests whose name start with `"\0x01"` will be rejected ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) @@ -12,7 +15,7 @@ _2018-xx-yy_ - Give async timeout a stack trace that points to the problematic test ([#2154](https://github.com/MithrilJS/mithril.js/pull/2154) [@gilbert](github.com/gilbert), [#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - deprecate the `timeout` parameter in async tests in favour of `o.timeout()` for setting the timeout delay. The `timeout` parameter still works for v3, and will be removed in v4 ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) - add `o.defaultTimeout()` for setting the the timeout delay for the current spec and its children ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) -- adds the possibility select more than one test with o.only ([#2171](https://github.com/MithrilJS/mithril.js/pull/2171)) +- adds the possibility to select more than one test with o.only ([#2171](https://github.com/MithrilJS/mithril.js/pull/2171)) ### Bug fixes - Detect duplicate calls to `done()` properly [#2162](https://github.com/MithrilJS/mithril.js/issues/2162) ([#2167](https://github.com/MithrilJS/mithril.js/pull/2167)) diff --git a/ospec/package.json b/ospec/package.json index 2f9113b5..9ac0497f 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "2.1.0", + "version": "3.0.0", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From 85c1e99d9dd592703f481c4b1ec212d52767c657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Tue, 26 Jun 2018 15:39:53 +0200 Subject: [PATCH 275/301] [docs] Update the TOC of installation.md --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 5dd6434b..d5719b4e 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,7 +2,7 @@ - [CDN](#cdn) - [NPM](#npm) -- [Quick start with Webpack](#quick-start-with-webpack) +- [Quick start with Parcel](#quick-start-with-parcel) - [TypeScript](#typescript) ### CDN From 28a5c1302701df584eb4059c99401be09631cb92 Mon Sep 17 00:00:00 2001 From: kevinkace Date: Thu, 28 Jun 2018 09:47:48 -0700 Subject: [PATCH 276/301] Update onbeforeremove animation example to use animationend event --- docs/animation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/animation.md b/docs/animation.md index 54138756..95dd4c0c 100644 --- a/docs/animation.md +++ b/docs/animation.md @@ -75,7 +75,7 @@ var FancyComponent = { onbeforeremove: function(vnode) { vnode.dom.classList.add("exit") return new Promise(function(resolve) { - setTimeout(resolve, 500) + vnode.dom.addEventListener("animationend", resolve) }) }, view: function() { @@ -86,7 +86,7 @@ var FancyComponent = { `vnode.dom` points to the root DOM element of the component (`
`). We use the classList API here to add an `exit` class to `
`. -Then we return a [Promise](promise.md) that resolves after half a second. When we return a promise from `onbeforeremove`, Mithril waits until the promise is resolved and only then it removes the element. In this case, it waits half a second, giving the exit animation the exact time it needs to complete. +Then we return a [Promise](promise.md) that resolves when the `animationend` event fires. When we return a promise from `onbeforeremove`, Mithril waits until the promise is resolved and only then it removes the element. In this case, it waits for the exit animation to finish. We can verify that both the enter and exit animations work by mounting the `Toggler` component: From ecfa59c0164ff4e19a94699f0029170c6e28a65f Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Sat, 30 Jun 2018 02:45:00 +0200 Subject: [PATCH 277/301] Fix glob inclusion on npm install --- ospec/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ospec/package.json b/ospec/package.json index 9ac0497f..8f990a04 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -13,7 +13,7 @@ "ospec": "./bin/ospec" }, "repository": "MithrilJS/mithril.js", - "devDependencies": { + "dependencies": { "glob": "^7.1.2" } } From e46d03f467a5fd2b0e0b5181cd1d6998860431ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Yves=20G=C3=A9rardy?= Date: Sat, 30 Jun 2018 20:27:24 +0200 Subject: [PATCH 278/301] [ospec] v3.0.1 --- ospec/change-log.md | 6 ++++++ ospec/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ospec/change-log.md b/ospec/change-log.md index 14337b57..58763d96 100644 --- a/ospec/change-log.md +++ b/ospec/change-log.md @@ -5,6 +5,12 @@ _2018-xx-yy_ +## 3.0.1 +_2018-06-30_ + +### Bug fix +- Move `glob` from `devDependencies` to `dependencies`, fix the test runner ([#2186](https://github.com/MithrilJS/mithril.js/pull/2186) [@porsager](https://github.com/porsager) + ## 3.0.0 _2018-06-20_ ### Breaking diff --git a/ospec/package.json b/ospec/package.json index 8f990a04..62e766b8 100644 --- a/ospec/package.json +++ b/ospec/package.json @@ -1,6 +1,6 @@ { "name": "ospec", - "version": "3.0.0", + "version": "3.0.1", "description": "Noiseless testing framework", "main": "ospec.js", "directories": { From fd7cf8041e19b7cb7771ef6045a9bde9df6c09d4 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Mon, 6 Aug 2018 13:35:50 +0200 Subject: [PATCH 279/301] [request] Clearer error message for JSON deserialization failure (#2195) --- docs/change-log.md | 1 + request/request.js | 2 +- request/tests/test-request.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index e77780f8..8734fc55 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -32,6 +32,7 @@ - API: Introduction of `m.redraw.sync()` ([#1592](https://github.com/MithrilJS/mithril.js/pull/1592)) - API: Event handlers may also be objects with `handleEvent` methods ([#1939](https://github.com/MithrilJS/mithril.js/issues/1939)). - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) +- API: `m.request` better error message on JSON parse error - ([#2195](https://github.com/MithrilJS/mithril.js/pull/2195), [@codeclown](https://github.com/codeclown)) - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) - Mocks: add limited support for the DOMParser API ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) - API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) diff --git a/request/request.js b/request/request.js index 8424f889..37d92b31 100644 --- a/request/request.js +++ b/request/request.js @@ -162,7 +162,7 @@ module.exports = function($window, Promise) { function deserialize(data) { try {return data !== "" ? JSON.parse(data) : null} - catch (e) {throw new Error(data)} + catch (e) {throw new Error("Invalid JSON: " + data)} } function extract(xhr) {return xhr.responseText} diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 52f840ef..6efa5ef2 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -494,7 +494,7 @@ o.spec("xhr", function() { } }) xhr({method: "GET", url: "/item"}).catch(function(e) { - o(e.message).equals("error") + o(e.message).equals("Invalid JSON: error") }).then(done) }) o("triggers all branched catches upon rejection", function(done) { From 4d0047380c1fdb10c5e5d23d2be1b72471ffd855 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 6 Aug 2018 11:37:45 +0000 Subject: [PATCH 280/301] Bundled output for commit fd7cf8041e19b7cb7771ef6045a9bde9df6c09d4 [skip ci] --- README.md | 2 +- mithril.js | 2 +- mithril.min.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5f5e96ac..20b7f573 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.90 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.91 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 6611f9d9..797783b3 100644 --- a/mithril.js +++ b/mithril.js @@ -389,7 +389,7 @@ var _9 = function($window, Promise) { } function deserialize(data) { try {return data !== "" ? JSON.parse(data) : null} - catch (e) {throw new Error(data)} + catch (e) {throw new Error("Invalid JSON: " + data)} } function extract(xhr) {return xhr.responseText} function cast(type0, data) { diff --git a/mithril.min.js b/mithril.min.js index e8c9051b..a571c177 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -8,8 +8,8 @@ d);for(var e=0;ec.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error(c); -}}function n(c){return c.responseText}function m(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dc.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error("Invalid JSON: "+ +c);}}function n(c){return c.responseText}function m(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dl.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var k=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script");a[g]=function(e){n.parentNode.removeChild(n); From d64e0a950f00e5d24a367bd2f4eb32b052c67e83 Mon Sep 17 00:00:00 2001 From: Rasmus Porsager Date: Wed, 8 Aug 2018 16:06:21 +0200 Subject: [PATCH 281/301] Fix #1714 conditionally halting stream (#2200) * Fix #1714 conditionally halting stream * Add note in changelog --- docs/change-log.md | 1 + stream/stream.js | 2 +- stream/tests/test-stream.js | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/change-log.md b/docs/change-log.md index 8734fc55..67043e4d 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -26,6 +26,7 @@ - API: `m.request` will no longer reject the Promise on server errors (eg. status >= 400) if the caller supplies an `extract` callback. This gives applications more control over handling server responses. - hyperscript: when attributes have a `null` or `undefined` value, they are treated as if they were absent. [#1773](https://github.com/MithrilJS/mithril.js/issues/1773) ([#2174](https://github.com/MithrilJS/mithril.js/pull/2174)) - hyperscript: when an attribute is defined on both the first and second argument (as a CSS selector and an `attrs` field, respectively), the latter takes precedence, except for `class` attributes that are still added together. [#2172](https://github.com/MithrilJS/mithril.js/issues/2172) ([#2174](https://github.com/MithrilJS/mithril.js/pull/2174)) +- stream: when a stream conditionally returns HALT, dependant stream will also end ([#2200](https://github.com/MithrilJS/mithril.js/pull/2200)) #### News diff --git a/stream/stream.js b/stream/stream.js index 20fd6378..9bf1fed5 100644 --- a/stream/stream.js +++ b/stream/stream.js @@ -53,7 +53,7 @@ function updateDependency(stream, mustSync) { var state = stream._state, parents = state.parents if (parents.length > 0 && parents.every(active) && (mustSync || parents.some(changed))) { var value = stream._state.derive() - if (value === HALT) return false + if (value === HALT) return unregisterStream(stream) updateState(stream, value) } } diff --git a/stream/tests/test-stream.js b/stream/tests/test-stream.js index 7ea944d7..69ca811d 100644 --- a/stream/tests/test-stream.js +++ b/stream/tests/test-stream.js @@ -164,6 +164,27 @@ o.spec("stream", function() { o(b()).equals(undefined) o(count).equals(0) }) + o("combine can conditionaly halt", function() { + var count = 0 + var halt = false + var a = Stream(1) + var b = Stream.combine(function(a) { + if (halt) { + return Stream.HALT + } + return a() + }, [a])["fantasy-land/map"](function(a) { + count++ + return a + }) + o(b()).equals(1) + o(count).equals(1) + halt = true + count = 0 + a(2) + o(b()).equals(1) + o(count).equals(0) + }) o("combine will throw with a helpful error if given non-stream values", function () { var spy = o.spy() var a = Stream(1) From af90b6b4a6993d610ef6292bd8da3831c87958cd Mon Sep 17 00:00:00 2001 From: Stephan Hoyer Date: Fri, 20 Jul 2018 13:05:48 +0200 Subject: [PATCH 282/301] Add support for setting `responseType` of xhr via m.request options --- docs/change-log.md | 1 + docs/request.md | 1 + request/request.js | 2 ++ request/tests/test-request.js | 14 ++++++++++++++ 4 files changed, 18 insertions(+) diff --git a/docs/change-log.md b/docs/change-log.md index 67043e4d..ab824fa9 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -35,6 +35,7 @@ - API: `m.route.link` accepts an optional `options` object ([#1930](https://github.com/MithrilJS/mithril.js/pull/1930)) - API: `m.request` better error message on JSON parse error - ([#2195](https://github.com/MithrilJS/mithril.js/pull/2195), [@codeclown](https://github.com/codeclown)) - API: `m.request` supports `timeout` as attr - ([#1966](https://github.com/MithrilJS/mithril.js/pull/1966)) +- API: `m.request` supports `responseType` as attr - ([#2193](https://github.com/MithrilJS/mithril.js/pull/2193)) - Mocks: add limited support for the DOMParser API ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) - API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097)) - render/core: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122)) diff --git a/docs/request.md b/docs/request.md index 44bb954b..3412ebea 100644 --- a/docs/request.md +++ b/docs/request.md @@ -50,6 +50,7 @@ Argument | Type | Required | Descr `options.password` | `String` | No | A password for HTTP authorization. Defaults to `undefined`. This option is provided for `XMLHttpRequest` compatibility, but you should avoid using it because it sends the password in plain text over the network. `options.withCredentials` | `Boolean` | No | Whether to send cookies to 3rd party domains. Defaults to `false` `options.timeout` | `Number` | No | The amount of milliseconds a request can take before automatically being [terminated](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout). Defaults to `undefined`. +`options.responseType` | `String` | No | The expected [type](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) of the response. Defaults to `undefined`. `options.config` | `xhr = Function(xhr)` | No | Exposes the underlying XMLHttpRequest object for low-level configuration. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). `options.headers` | `Object` | No | Headers to append to the request before sending it (applied right before `options.config`). `options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). diff --git a/request/request.js b/request/request.js index 37d92b31..d40f8d06 100644 --- a/request/request.js +++ b/request/request.js @@ -76,6 +76,8 @@ module.exports = function($window, Promise) { if (args.withCredentials) xhr.withCredentials = args.withCredentials if (args.timeout) xhr.timeout = args.timeout + + if (args.responseType) xhr.responseType = args.responseType for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) { xhr.setRequestHeader(key, args.headers[key]) diff --git a/request/tests/test-request.js b/request/tests/test-request.js index 6efa5ef2..e69a93d7 100644 --- a/request/tests/test-request.js +++ b/request/tests/test-request.js @@ -449,6 +449,20 @@ o.spec("xhr", function() { } }) }) + o("set responseType to xhr instance", function() { + mock.$defineRoutes({ + "GET /item": function() { + return {status: 200, responseText: ""} + } + }) + return xhr({ + method: "GET", url: "/item", + responseType: "blob", + config: function(xhr) { + o(xhr.responseType).equals("blob") + } + }) + }) /*o("data maintains after interpolate", function() { mock.$defineRoutes({ "PUT /items/:x": function() { From 8ae094fd8546b626a31973701d744b78c49fcb4a Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 20 Aug 2018 09:31:58 +0000 Subject: [PATCH 283/301] Bundled output for commit af90b6b4a6993d610ef6292bd8da3831c87958cd [skip ci] --- README.md | 2 +- mithril.js | 2 ++ mithril.min.js | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 20b7f573..d543e3d0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.91 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.92 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 797783b3..0b46c1ac 100644 --- a/mithril.js +++ b/mithril.js @@ -314,6 +314,8 @@ var _9 = function($window, Promise) { } if (args.withCredentials) xhr.withCredentials = args.withCredentials if (args.timeout) xhr.timeout = args.timeout + + if (args.responseType) xhr.responseType = args.responseType for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) { xhr.setRequestHeader(key, args.headers[key]) } diff --git a/mithril.min.js b/mithril.min.js index a571c177..070304ac 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -11,13 +11,13 @@ g){if(Array.isArray(g))for(var k=0;kc.indexOf("?")?"?":"&";c+=e+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(x){throw Error("Invalid JSON: "+ c);}}function n(c){return c.responseText}function m(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;dl.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var k=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script");a[g]=function(e){n.parentNode.removeChild(n); -d(m(c.type,e));delete a[g]};n.onerror=function(){n.parentNode.removeChild(n);e(Error("JSONP request failed"));delete a[g]};null==c.data&&(c.data={});c.url=q(c.url,c.data);c.data[c.callbackKey||"callback"]=g;n.src=h(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?x:k(x)},setCompletionCallback:function(c){C=c}}}(window,p),V=function(a){function d(t,b){if(t.state!==b)throw Error("`vnode.state` must not be modified");}function e(t){var b=t.state;try{return this.apply(b, -arguments)}finally{d(t,b)}}function g(t,b,f,c,a,d,e){for(;f'+ +l.setRequestHeader("Content-Type","application/json; charset=utf-8");c.deserialize!==k||c.headers&&c.headers.hasOwnProperty("Accept")||l.setRequestHeader("Accept","application/json, text/*");c.withCredentials&&(l.withCredentials=c.withCredentials);c.timeout&&(l.timeout=c.timeout);c.responseType&&(l.responseType=c.responseType);for(var C in c.headers)({}).hasOwnProperty.call(c.headers,C)&&l.setRequestHeader(C,c.headers[C]);"function"===typeof c.config&&(l=c.config(l,c)||l);l.onreadystatechange=function(){if(!E&& +4===l.readyState)try{var a=c.extract!==n?c.extract(l,c):c.deserialize(c.extract(l,c));if(c.extract!==n||200<=l.status&&300>l.status||304===l.status||Z.test(c.url))d(m(c.type,a));else{var g=Error(l.responseText);g.code=l.status;g.response=a;e(g)}}catch(aa){e(aa)}};g&&null!=c.data?l.send(c.data):l.send()});return!0===c.background?x:E(x)},jsonp:function(c,n){var k=e();c=g(c,n);var x=new d(function(d,e){var g=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+l++,n=a.document.createElement("script"); +a[g]=function(e){n.parentNode.removeChild(n);d(m(c.type,e));delete a[g]};n.onerror=function(){n.parentNode.removeChild(n);e(Error("JSONP request failed"));delete a[g]};null==c.data&&(c.data={});c.url=q(c.url,c.data);c.data[c.callbackKey||"callback"]=g;n.src=h(c.url,c.data);a.document.documentElement.appendChild(n)});return!0===c.background?x:k(x)},setCompletionCallback:function(c){C=c}}}(window,p),V=function(a){function d(t,b){if(t.state!==b)throw Error("`vnode.state` must not be modified");}function e(t){var b= +t.state;try{return this.apply(b,arguments)}finally{d(t,b)}}function g(t,b,f,c,a,d,e){for(;f'+ b.children+"",a=a.firstChild):a.innerHTML=b.children;b.dom=a.firstChild;b.domSize=a.childNodes.length;for(b=D.createDocumentFragment();f=a.firstChild;)b.appendChild(f);C(t,b,c)}function k(t,b,f,c,a,d){if(b!==f&&(null!=b||null!=f))if(null==b||0===b.length)g(t,f,0,f.length,c,a,d);else if(null==f||0===f.length)x(b,0,b.length);else{for(var e=0,k=0,v=null,h=null;k=k&&v>=e;)if(A=b[h],y=f[v],null==A)h--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),h--,v--;else break;for(;h>=k&&v>=e;)if(r=b[k],u=f[e],null==r)k++;else if(null==u)e++;else if(r.key===u.key)k++,e++,r!==u&&n(t,r,u,c,l(b,k,a),d);else break;for(;h>=k&&v>=e;){if(null==r)k++;else if(null==u)e++;else if(null==A)h--;else if(null==y)v--;else if(e===v)break;else{if(r.key!== y.key||A.key!==u.key)break;B=l(b,k,a);C(t,m(A),B);A!==u&&n(t,A,u,c,B,d);++e<=--v&&C(t,m(r),a);r!==y&&n(t,r,y,c,a,d);null!=y.dom&&(a=y.dom);k++;h--}A=b[h];y=f[v];r=b[k];u=f[e]}for(;h>=k&&v>=e;){if(null==A)h--;else if(null==y)v--;else if(A.key===y.key)A!==y&&n(t,A,y,c,a,d),null!=y.dom&&(a=y.dom),h--,v--;else break;A=b[h];y=f[v]}if(e>v)x(b,k,h+1);else if(k>h)g(t,f,e,v+1,c,a,d);else{u=a;A=v-e+1;r=Array(A);var G=2147483647,z=0;for(B=0;B=e;B--){if(null==p){p=b;A=k;y=h+1;for(var w= From e62f0f38f63217bf85f358b67fd057f14dfacbe9 Mon Sep 17 00:00:00 2001 From: cavemansspa Date: Tue, 21 Aug 2018 12:40:15 -0400 Subject: [PATCH 284/301] Doc update for unpkg src attr (#2205) * Add https: to unpkg src attr * [docs] Credit @cavemansspa --- docs/change-log.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index ab824fa9..3836a05a 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -55,7 +55,7 @@ - render/events: `Object.prototype` properties can no longer interfere with event listener calls. - render/events: Event handlers, when set to literally `undefined` (or any non-function), are now correctly removed. - render/hooks: fixed an ommission that caused `oninit` to be called unnecessarily in some cases [#1992](https://github.com/MithrilJS/mithril.js/issues/1992) -- docs: fix typo ([#2104](https://github.com/MithrilJS/mithril.js/pull/2104) [@mikeyb](https://github.com/mikeyb)) +- docs: tweaks: ([#2104](https://github.com/MithrilJS/mithril.js/pull/2104) [@mikeyb](https://github.com/mikeyb), [#2205](https://github.com/MithrilJS/mithril.js/pull/2205), [@cavemansspa](https://github.com/cavemansspa)) --- ### v1.1.7 diff --git a/docs/index.md b/docs/index.md index 64018eff..97dd2b13 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,7 +56,7 @@ Let's create an HTML file to follow along: ```markup - +