Runtime-deprecate ospec, change change-log to changelog, fix a few assorted bugs (#2578)

This commit is contained in:
Isiah Meadows 2020-09-29 13:27:07 -07:00 committed by GitHub
parent 1630b06106
commit 9f0dc2ab46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 484 additions and 410 deletions

View file

@ -1,3 +0,0 @@
# Code of Conduct
Please see https://mithril.js.org/code-of-conduct.html.

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
open_collective: mithriljs

View file

@ -12,17 +12,18 @@ assignees: isiahmeadows
Optional: Provide the exact version of Mithril you're experiencing issues with.
This could matter, even if it's really old like version 0.1.0. Do note that bugs
in older versions are commonly fixed in newer versions and that newer versions
do end up with a lot more features than older versions, so it's unlikely we'll
are much more actively maintained than older versions, so it's unlikely we'll
add new features to older versions like 0.1.x.
-->
**Mithril version:**
<!--
Optional: Provide the name and version of both the browser and operating system
you're running Mithril on. If it's multiple, feel free to list multiple. This
could matter, even if it's super ancient like IE 6 on Windows XP.
Optional: Provide the name and version of both the platform (Chrome, Node, etc.)
and operating system you're running Mithril on. If it's multiple, feel free to
list multiple. This could matter, even if it's super ancient like IE 6 on
Windows XP.
-->
**Browser and OS:**
**Platform and OS:**
<!--
Optional: Provide a link to your project, if it happens to be open source or if

View file

@ -28,4 +28,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`
- [ ] I have updated `docs/changelog.md`

View file

@ -13,11 +13,133 @@ var censor = require("../util/censor")
var sentinel = {}
module.exports = function($window, mountRedraw) {
var fireAsync
var callAsync = $window == null
// In case Mithril's loaded globally without the DOM, let's not break
? null
: typeof $window.setImmediate === "function" ? $window.setImmediate : $window.setTimeout
var p = Promise.resolve()
var scheduled = false
// state === 0: init
// state === 1: scheduled
// state === 2: done
var ready = false
var state = 0
var compiled, fallbackRoute
var currentResolver = sentinel, component, attrs, currentPath, lastUpdate
var RouterRoot = {
onbeforeupdate: function() {
state = state ? 2 : 1
return !(!state || sentinel === currentResolver)
},
onremove: function() {
$window.removeEventListener("popstate", fireAsync, false)
$window.removeEventListener("hashchange", resolveRoute, false)
},
view: function() {
if (!state || sentinel === currentResolver) return
// Wrap in a fragment to preserve existing key semantics
var vnode = [Vnode(component, attrs.key, attrs)]
if (currentResolver) vnode = currentResolver.render(vnode[0])
return vnode
},
}
var SKIP = route.SKIP = {}
function resolveRoute() {
scheduled = false
// Consider the pathname holistically. The prefix might even be invalid,
// but that's not our problem.
var prefix = $window.location.hash
if (route.prefix[0] !== "#") {
prefix = $window.location.search + prefix
if (route.prefix[0] !== "?") {
prefix = $window.location.pathname + prefix
if (prefix[0] !== "/") prefix = "/" + prefix
}
}
// This seemingly useless `.concat()` speeds up the tests quite a bit,
// since the representation is consistently a relatively poorly
// optimized cons string.
var path = prefix.concat()
.replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
.slice(route.prefix.length)
var data = parsePathname(path)
assign(data.params, $window.history.state)
function reject(e) {
console.error(e)
setPath(fallbackRoute, null, {replace: true})
}
loop(0)
function loop(i) {
// state === 0: init
// state === 1: scheduled
// state === 2: done
for (; i < compiled.length; i++) {
if (compiled[i].check(data)) {
var payload = compiled[i].component
var matchedRoute = compiled[i].route
var localComp = payload
var update = lastUpdate = function(comp) {
if (update !== lastUpdate) return
if (comp === SKIP) return loop(i + 1)
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
attrs = data.params, currentPath = path, lastUpdate = null
currentResolver = payload.render ? payload : null
if (state === 2) mountRedraw.redraw()
else {
state = 2
mountRedraw.redraw.sync()
}
}
// There's no understating how much I *wish* I could
// use `async`/`await` here...
if (payload.view || typeof payload === "function") {
payload = {}
update(localComp)
}
else if (payload.onmatch) {
p.then(function () {
return payload.onmatch(data.params, path, matchedRoute)
}).then(update, path === fallbackRoute ? null : reject)
}
else update("div")
return
}
}
if (path === fallbackRoute) {
throw new Error("Could not resolve default route " + fallbackRoute + ".")
}
setPath(fallbackRoute, null, {replace: true})
}
}
// Set it unconditionally so `m.route.set` and `m.route.Link` both work,
// even if neither `pushState` nor `hashchange` are supported. It's
// cleared if `hashchange` is used, since that makes it automatically
// async.
function fireAsync() {
if (!scheduled) {
scheduled = true
// TODO: just do `mountRedraw.redraw()` here and elide the timer
// dependency. Note that this will muck with tests a *lot*, so it's
// not as easy of a change as it sounds.
callAsync(resolveRoute)
}
}
function setPath(path, data, options) {
path = buildPathname(path, data)
if (fireAsync != null) {
if (ready) {
fireAsync()
var state = options ? options.state : null
var title = options ? options.title : null
@ -29,18 +151,10 @@ module.exports = function($window, mountRedraw) {
}
}
var currentResolver = sentinel, component, attrs, currentPath, lastUpdate
var SKIP = route.SKIP = {}
function route(root, defaultRoute, routes) {
if (!root) throw new TypeError("DOM element being rendered to does not exist.")
// 0 = start
// 1 = init
// 2 = ready
var state = 0
var compiled = Object.keys(routes).map(function(route) {
compiled = Object.keys(routes).map(function(route) {
if (route[0] !== "/") throw new SyntaxError("Routes must start with a '/'.")
if ((/:([^\/\.-]+)(\.{3})?:/).test(route)) {
throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.")
@ -51,13 +165,7 @@ module.exports = function($window, mountRedraw) {
check: compileTemplate(route),
}
})
var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
var p = Promise.resolve()
var scheduled = false
var onremove
fireAsync = null
fallbackRoute = defaultRoute
if (defaultRoute != null) {
var defaultData = parsePathname(defaultRoute)
@ -66,116 +174,14 @@ module.exports = function($window, mountRedraw) {
}
}
function resolveRoute() {
scheduled = false
// Consider the pathname holistically. The prefix might even be invalid,
// but that's not our problem.
var prefix = $window.location.hash
if (route.prefix[0] !== "#") {
prefix = $window.location.search + prefix
if (route.prefix[0] !== "?") {
prefix = $window.location.pathname + prefix
if (prefix[0] !== "/") prefix = "/" + prefix
}
}
// This seemingly useless `.concat()` speeds up the tests quite a bit,
// since the representation is consistently a relatively poorly
// optimized cons string.
var path = prefix.concat()
.replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
.slice(route.prefix.length)
var data = parsePathname(path)
assign(data.params, $window.history.state)
function reject(e) {
console.error(e)
setPath(defaultRoute, null, {replace: true})
}
loop(0)
function loop(i) {
// 0 = init
// 1 = scheduled
// 2 = done
for (; i < compiled.length; i++) {
if (compiled[i].check(data)) {
var payload = compiled[i].component
var matchedRoute = compiled[i].route
var localComp = payload
var update = lastUpdate = function(comp) {
if (update !== lastUpdate) return
if (comp === SKIP) return loop(i + 1)
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
attrs = data.params, currentPath = path, lastUpdate = null
currentResolver = payload.render ? payload : null
if (state === 2) mountRedraw.redraw()
else {
state = 2
mountRedraw.redraw.sync()
}
}
// There's no understating how much I *wish* I could
// use `async`/`await` here...
if (payload.view || typeof payload === "function") {
payload = {}
update(localComp)
}
else if (payload.onmatch) {
p.then(function () {
return payload.onmatch(data.params, path, matchedRoute)
}).then(update, path === defaultRoute ? null : reject)
}
else update("div")
return
}
}
if (path === defaultRoute) {
throw new Error("Could not resolve default route " + defaultRoute + ".")
}
setPath(defaultRoute, null, {replace: true})
}
}
// Set it unconditionally so `m.route.set` and `m.route.Link` both work,
// even if neither `pushState` nor `hashchange` are supported. It's
// cleared if `hashchange` is used, since that makes it automatically
// async.
fireAsync = function() {
if (!scheduled) {
scheduled = true
callAsync(resolveRoute)
}
}
if (typeof $window.history.pushState === "function") {
onremove = function() {
$window.removeEventListener("popstate", fireAsync, false)
}
$window.addEventListener("popstate", fireAsync, false)
} else if (route.prefix[0] === "#") {
fireAsync = null
onremove = function() {
$window.removeEventListener("hashchange", resolveRoute, false)
}
$window.addEventListener("hashchange", resolveRoute, false)
}
mountRedraw.mount(root, {
onbeforeupdate: function() {
state = state ? 2 : 1
return !(!state || sentinel === currentResolver)
},
onremove: onremove,
view: function() {
if (!state || sentinel === currentResolver) return
// Wrap in a fragment to preserve existing key semantics
var vnode = [Vnode(component, attrs.key, attrs)]
if (currentResolver) vnode = currentResolver.render(vnode[0])
return vnode
},
})
ready = true
mountRedraw.mount(root, RouterRoot)
resolveRoute()
}
route.set = function(path, data, options) {

View file

@ -1,7 +1,7 @@
"use strict"
// Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")
var throttleMocker = require("../../test-utils/throttleMock")

View file

@ -1,7 +1,7 @@
"use strict"
// Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec")
var o = require("ospec")
var browserMock = require("../../test-utils/browserMock")
var throttleMocker = require("../../test-utils/throttleMock")
@ -26,14 +26,13 @@ o.spec("route", function() {
// Use precisely what `m.route` uses, for consistency and to ensure timings
// are aligned.
var waitFunc = typeof setImmediate === "function" ? setImmediate : setTimeout
function waitCycles(n) {
n = Math.max(n, 1)
return new Promise(function(resolve) {
return loop()
function loop() {
if (n === 0) resolve()
else { n--; waitFunc(loop) }
else { n--; setTimeout(loop, 4) }
}
})
}
@ -75,6 +74,8 @@ o.spec("route", function() {
o.beforeEach(function() {
currentTest = nextID++
$window = browserMock(env)
$window.setTimeout = setTimeout
// $window.setImmediate = setImmediate
throttleMock = throttleMocker()
root = $window.document.body

View file

@ -1,12 +1,10 @@
"use strict"
// Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec")
var callAsync = require("../../test-utils/callAsync")
var o = require("ospec")
var browserMock = require("../../test-utils/browserMock")
var throttleMocker = require("../../test-utils/throttleMock")
var callAsync = require("../../test-utils/callAsync")
var apiMountRedraw = require("../../api/mount-redraw")
var coreRenderer = require("../../render/render")
var apiRouter = require("../../api/router")
@ -20,6 +18,7 @@ o.spec("route.get/route.set", function() {
o.beforeEach(function() {
$window = browserMock(env)
throttleMock = throttleMocker()
$window.setTimeout = setTimeout
root = $window.document.body
@ -87,7 +86,7 @@ o.spec("route.get/route.set", function() {
route.set("/b")
o(spy1.callCount).equals(1)
o(spy2.callCount).equals(0)
callAsync(function() {
setTimeout(function() {
throttleMock.fire()
o(spy1.callCount).equals(1)
@ -111,10 +110,10 @@ o.spec("route.get/route.set", function() {
route.set("/c")
o(spy1.callCount).equals(0)
o(spy2.callCount).equals(1)
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/b")
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/a")
throttleMock.fire()
@ -134,7 +133,7 @@ o.spec("route.get/route.set", function() {
})
route.set("/other/x/y/z?c=d#e=f")
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire()
@ -150,7 +149,7 @@ o.spec("route.get/route.set", function() {
})
route.set(encodeURI("/ö?ö=ö#ö=ö"))
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/ö?ö=ö#ö=ö")
throttleMock.fire()
@ -166,7 +165,7 @@ o.spec("route.get/route.set", function() {
})
route.set("/ö?ö=ö#ö=ö")
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/ö?ö=ö#ö=ö")
throttleMock.fire()
@ -182,7 +181,7 @@ o.spec("route.get/route.set", function() {
})
route.set("/other/x/y/z?c=d#e=f")
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire()
@ -197,11 +196,11 @@ o.spec("route.get/route.set", function() {
"/other/:a/:b...": {view: function() {}},
})
callAsync(function() {
setTimeout(function() {
$window.history.pushState(null, null, prefix + "/other/x/y/z?c=d#e=f")
$window.onpopstate()
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire()
@ -219,7 +218,7 @@ o.spec("route.get/route.set", function() {
})
route.set("/other/:a/:b", {a: "x", b: "y/z", c: "d", e: "f"})
callAsync(function() {
setTimeout(function() {
// Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y%2Fz?c=d&e=f")
throttleMock.fire()
@ -236,7 +235,7 @@ o.spec("route.get/route.set", function() {
route.set("/other", null, {replace: true})
callAsync(function() {
setTimeout(function() {
throttleMock.fire()
$window.history.back()
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + "/")
@ -253,7 +252,7 @@ o.spec("route.get/route.set", function() {
route.set("/other", null, {replace: false})
callAsync(function() {
setTimeout(function() {
throttleMock.fire()
$window.history.back()
var slash = prefix[0] === "/" ? "" : "/"
@ -270,7 +269,7 @@ o.spec("route.get/route.set", function() {
})
route.set("/other", null, {state: {a: 1}})
callAsync(function() {
setTimeout(function() {
throttleMock.fire()
o($window.history.state).deepEquals({a: 1})
done()

View file

@ -9,8 +9,8 @@
- [v1.x changelog](https://mithril.js.org/archive/v1.1.7/change-log.html)
- [v1.x docs](https://mithril.js.org/archive/v1.1.7/index.html)
- [v0.2 docs](https://mithril.js.org/archive/v0.2.5/index.html)
- [`ospec` change log](https://github.com/MithrilJS/mithril.js/blob/master/ospec/change-log.md)
- [`mithril/stream` change log](https://github.com/MithrilJS/mithril.js/blob/master/stream/change-log.md)
- [`ospec` change log](https://github.com/MithrilJS/ospec/blob/master/changelog.md)
- [`mithril-stream` change log](#mithril-stream-change-log)
---
@ -20,6 +20,8 @@
*Note for later: release as semver-minor.*
PSA: changes to [`mithril/stream`](stream.md) are now specified in this changelog. I've also moved the old stream changelog into this file [here](#mithril-stream-change-log).
- Reduced package download size substantially by removing the archive of previous releases' documentation. ([#2561](https://github.com/MithrilJS/mithril.js/pull/2561) [@cztomsik](https://github.com/cztomsik))
- Improved error messages in multiple places. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows))
- The redraw reentrancy check was moved from `m.mount` to `m.render` and its error message was updated accordingly. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows))
@ -31,6 +33,9 @@
- Re-add stream bundles. ([#2539](https://github.com/MithrilJS/mithril.js/pull/2539) [@isiahmeadows](https://github.com/isiahmeadows))
- Remove extra isLifecycleMethod call from removeAttr. ([#2594](https://github.com/MithrilJS/mithril.js/pull/2594) [@ZeikJT](https://github.com/zeikjt))
- Fix issue where ending a stream in the middle of a stream callback would result in erroneous parent stream state for the rest of that emit. ([#2603](https://github.com/MithrilJS/mithril.js/pull/2603) [@isiahmeadows](https://github.com/isiahmeadows))
- Fix issue where new redraw handlers weren't copied over on update. ([#2578](https://github.com/MithrilJS/mithril.js/pull/2578) [@isiahmeadows](https://github.com/isiahmeadows))
- Make changes to file inputs gracefully handled, and don't break if the current value and old value mismatch (and the new value isn't empty), but instead just log an error. ([#2578](https://github.com/MithrilJS/mithril.js/pull/2578) [@isiahmeadows](https://github.com/isiahmeadows))
- This mainly exists just to kick the can down the road - this is the only case I'm aware of where the DOM itself would be responsible for throwing an error. A proper fix to the greater issue of error handling is much more complex, and I'd rather not block users any longer over this one specific issue.
Important note: if you were using any of these undocumented tools, they are no longer available as of this release. This is not considered a breaking change as they were written for internal usage and as of v2 are all 100% unsupported in userland.
@ -181,3 +186,22 @@ _2019-07-24_
- docs: clarify valid key usage ([#2452](https://github.com/MithrilJS/mithril.js/pull/2452) [@isiahmeadows](https://github.com/isiahmeadows))
- route: don't pollute globals ([#2453](https://github.com/MithrilJS/mithril.js/pull/2453) [@isiahmeadows](https://github.com/isiahmeadows))
- request: track xhr replacements correctly ([#2455](https://github.com/MithrilJS/mithril.js/pull/2455) [@isiahmeadows](https://github.com/isiahmeadows))
## `mithril-stream` change log
Formerly, `mithril/stream` was available standalone as the package `mithril-stream`, but this package has been deprecated and is no longer updated. The changelog for that package prior to being merged back into Mithril proper is below.
### 2.0.0
_2019-02-07_
- when a stream conditionally returns HALT, dependant stream will also end ([#2200](https://github.com/MithrilJS/mithril.js/pull/2200), [#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
- Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` ([#1944](https://github.com/MithrilJS/mithril.js/issues/1944))
- renamed HALT to SKIP ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- rewrote implementation ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- Removed `valueOf` & `toString` methods ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150))
- fixed `stream.end` propagation ([#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
### 1.1.0
_2017-07-13_
- 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))

View file

@ -25,6 +25,6 @@
- [Code of Conduct](code-of-conduct.md)
- Misc
- [Framework comparison](framework-comparison.md)
- [Change log/Migration](change-log.md)
- [Change log/Migration](changelog.md)
- [v1 Documentation](https://mithril.js.org/archive/v1.1.7/)
- [v0.2 Documentation](https://mithril.js.org/archive/v0.2.5/)

View file

@ -4,7 +4,6 @@
- [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
@ -18,7 +17,7 @@ $ git pull --rebase mithriljs next
```
2. Determine patch level of the change
3. Update information in `docs/change-log.md` to match reality of the new version being prepared for release.
3. Update information in `docs/changelog.md` to match reality of the new version being prepared for release.
- Don't forget to add today's date under the version heading!
4. Replace all existing references to `mithril@next` to `mithril` if moving from a release candidate to stable.
- Note: if making an initial release candidate, don't forget to move all the playground snippets to pull from `mithril@next`!
@ -96,11 +95,11 @@ $ git push mithriljs next
### Update the GitHub release
16. The GitHub Release will require a manual description & title to be added. I suggest coming up with a fun title & then copying the `docs/change-log.md` entry for the build.
16. The GitHub Release will require a manual description & title to be added. I suggest coming up with a fun title & then copying the `docs/changelog.md` entry for the build.
## Updating mithril.js.org
Fixes to documentation can land whenever, updates to the site are published via Travis.
Fixes to documentation can land whenever, updates to the site are built and published via `scripts/update-docs.js`.
```bash
# These steps assume that MithrilJS/mithril.js is a git remote named "mithriljs"
@ -115,69 +114,9 @@ $ git checkout next -- ./docs
# Manually ensure that no new feature docs were added
$ git push mithriljs
$ node scripts/update-docs
```
After the Travis build completes the updated docs should appear on https://mithril.js.org in a few minutes.
After the docs build completes, the updated docs should appear on https://mithril.js.org in a few minutes.
**Note:** When updating the stable version with a release candidate out, ***make sure to update the index + navigation to point to the new stable version!!!***
## Releasing a new ospec version
1. Ensure your local branch is up to date
```bash
$ git checkout 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. Update `ospec/change-log.md` to match new version being prepared for release.
- Don't forget to add today's date under the version heading!
5. Commit changes to `next`
```
$ git add .
$ git commit -m "chore(ospec): ospec@<version>"
# 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 checkout 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@<version>"
```
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
```

View file

@ -3,6 +3,12 @@
if (typeof module !== "undefined") module["exports"] = m()
else window.o = m()
})(function init(name) {
console.warn(
"Please switch to the `ospec` package to remove this warning and see " +
"the most recent features. Using the `ospec` bundled within Mithril " +
"is deprecated, and it will be removed in the next major release."
)
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

View file

@ -6,7 +6,11 @@ var o, callAsync
if (typeof require !== "undefined") {
/* eslint-disable global-require */
callAsync = require("../../test-utils/callAsync")
var warn = console.warn
// Let's drop the warning to leave the console a little less noisy.
console.warn = function() {}
o = require("../ospec")
console.warn = warn
/* eslint-enable global-require */
} else {
callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout

31
package-lock.json generated
View file

@ -259,8 +259,7 @@
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
@ -291,7 +290,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -523,8 +521,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"core-util-is": {
"version": "1.0.2",
@ -1152,8 +1149,7 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "2.1.0",
@ -1229,7 +1225,6 @@
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -1437,7 +1432,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@ -1446,8 +1440,7 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"inquirer": {
"version": "6.5.2",
@ -2035,7 +2028,6 @@
"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.7"
}
@ -2226,7 +2218,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
@ -2260,6 +2251,14 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"ospec": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ospec/-/ospec-4.1.1.tgz",
"integrity": "sha512-fgWIk1eLDidfB+ixTo3PL3HuuO6iX2LhgWxdnWwqRu2rJdpTowgeAP0RHgt3DSUVyszs964fMuq1tB7Ov2C38A==",
"requires": {
"glob": "^7.1.3"
}
},
"p-finally": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
@ -2306,8 +2305,7 @@
"path-is-absolute": {
"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
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-key": {
"version": "2.0.1",
@ -3137,8 +3135,7 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"write": {
"version": "1.0.3",

View file

@ -5,7 +5,7 @@
"author": "Leo Horie",
"license": "MIT",
"unpkg": "mithril.min.js",
"repository": "MithrilJS/mithril.js",
"repository": "github:MithrilJS/mithril.js",
"scripts": {
"precommit": "lint-staged",
"watch": "run-p watch:**",
@ -24,7 +24,7 @@
"perf": "node performance/test-perf.js",
"pretest": "npm run lint",
"test": "run-s test:js",
"test:js": "node ospec/bin/ospec",
"test:js": "ospec",
"cover": "istanbul cover --print both ospec/bin/ospec",
"release": "npm version -m 'v%s'",
"version": "npm run build && git add mithril.js mithril.min.js stream.js stream.min.js README.md"
@ -45,6 +45,7 @@
"marked": "^0.7.0",
"minimist": "^1.2.0",
"npm-run-all": "^4.1.5",
"ospec": "^4.0.1",
"pinpoint": "^1.1.0",
"request": "^2.88.0",
"request-promise-native": "^1.0.7",
@ -61,5 +62,7 @@
"git add"
]
},
"dependencies": {}
"dependencies": {
"ospec": "*"
}
}

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var buildPathname = require("../../pathname/build")
o.spec("buildPathname", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var parsePathname = require("../../pathname/parse")
var compileTemplate = require("../../pathname/compileTemplate")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var parsePathname = require("../../pathname/parse")
o.spec("parsePathname", function() {

View file

@ -6,7 +6,7 @@ var o, callAsync, Promise
if (typeof require !== "undefined") {
/* eslint-disable global-require */
callAsync = require("../../test-utils/callAsync")
o = require("../../ospec/ospec")
o = require("ospec")
Promise = require("../../promise/polyfill")
/* eslint-enable global-require */
} else {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var buildQueryString = require("../../querystring/build")
o.spec("buildQueryString", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var parseQueryString = require("../../querystring/parse")
o.spec("parseQueryString", function() {

View file

@ -726,12 +726,18 @@ module.exports = function($window) {
//attrs
function setAttrs(vnode, attrs, ns) {
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.
//
// Also, the DOM does things to inputs based on the value, so it needs set first.
// See: https://github.com/MithrilJS/mithril.js/issues/2622
if (vnode.tag === "input" && attrs.type != null) vnode.dom.setAttribute("type", attrs.type)
var isFileInput = attrs != null && vnode.tag === "input" && attrs.type === "file"
for (var key in attrs) {
setAttr(vnode, key, null, attrs[key], ns)
setAttr(vnode, key, null, attrs[key], ns, isFileInput)
}
}
function setAttr(vnode, key, old, value, ns) {
if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return
function setAttr(vnode, key, old, value, ns, isFileInput) {
if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || key === "type" && vnode.tag === "input") return
if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, 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)
@ -740,16 +746,18 @@ module.exports = function($window) {
// Only do the coercion if we're actually going to check the value.
/* eslint-disable 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 === "" + value && vnode.dom === activeElement()) return
//setting input[type=file][value] to same value causes an error to be generated if it's non-empty
if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && (isFileInput || vnode.dom === activeElement())) return
//setting select[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "select" && old !== null && vnode.dom.value === "" + value) 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 === "" + value) return
//setting input[type=file][value] to different value is an error if it's non-empty
// Not ideal, but it at least works around the most common source of uncaught exceptions for now.
if (isFileInput && "" + value !== "") { console.error("`value` is read-only on file inputs!"); return }
/* eslint-enable no-implicit-coercion */
}
// 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)
else vnode.dom[key] = value
vnode.dom[key] = value
} else {
if (typeof value === "boolean") {
if (value) vnode.dom.setAttribute(key, "")
@ -793,8 +801,14 @@ module.exports = function($window) {
}
function updateAttrs(vnode, old, attrs, ns) {
if (attrs != null) {
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.
//
// Also, the DOM does things to inputs based on the value, so it needs set first.
// See: https://github.com/MithrilJS/mithril.js/issues/2622
if (vnode.tag === "input" && attrs.type != null) vnode.dom.setAttribute("type", attrs.type)
var isFileInput = vnode.tag === "input" && attrs.type === "file"
for (var key in attrs) {
setAttr(vnode, key, old && old[key], attrs[key], ns)
setAttr(vnode, key, old && old[key], attrs[key], ns, isFileInput)
}
}
var val
@ -897,6 +911,7 @@ module.exports = function($window) {
//event
function updateEvent(vnode, key, value) {
if (vnode.events != null) {
vnode.events._ = currentRedraw
if (vnode.events[key] === value) return
if (value != null && (typeof value === "function" || typeof value === "object")) {
if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false)

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,18 +1,18 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")
o.spec("event", function() {
var $window, root, redraw, render
var $window, root, redraw, render, reallyRender
o.beforeEach(function() {
$window = domMock()
root = $window.document.body
redraw = o.spy()
var renderer = vdom($window)
reallyRender = vdom($window)
render = function(dom, vnode) {
return renderer(dom, vnode, redraw)
return reallyRender(dom, vnode, redraw)
}
})
@ -355,4 +355,32 @@ o.spec("event", function() {
o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0)
})
o("handles changed spy", function() {
var div1 = {tag: "div", attrs: {ontransitionend: function() {}}}
reallyRender(root, [div1], redraw)
var e = $window.document.createEvent("HTMLEvents")
e.initEvent("transitionend", true, true)
div1.dom.dispatchEvent(e)
o(redraw.callCount).equals(1)
o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0)
var replacementRedraw = o.spy()
var div2 = {tag: "div", attrs: {ontransitionend: function() {}}}
reallyRender(root, [div2], replacementRedraw)
var e = $window.document.createEvent("HTMLEvents")
e.initEvent("transitionend", true, true)
div2.dom.dispatchEvent(e)
o(redraw.callCount).equals(1)
o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0)
o(replacementRedraw.callCount).equals(1)
o(replacementRedraw.this).equals(undefined)
o(replacementRedraw.args.length).equals(0)
})
})

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var fragment = require("../../render/fragment")
var m = require("../../render/hyperscript")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var m = require("../../render/hyperscript")
o.spec("hyperscript", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")
@ -86,6 +86,89 @@ o.spec("form inputs", function() {
o(updated.dom.checked).equals(true)
})
o("syncs file input value attribute if DOM value differs from vdom value and is empty", function() {
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
input.dom.value = "test.png"
try {
console.error = spy
render(root, [updated])
} finally {
console.error = error
}
o(updated.dom.value).equals("")
o(spy.callCount).equals(0)
})
o("warns and ignores file input value attribute if DOM value differs from vdom value and is non-empty", function() {
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated = {tag: "input", attrs: {type: "file", value: "other.png", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
input.dom.value = "test.png"
try {
console.error = spy
render(root, [updated])
} finally {
console.error = error
}
o(updated.dom.value).equals("test.png")
o(spy.callCount).equals(1)
})
o("retains file input value attribute if DOM value is the same as vdom value and is non-empty", function() {
var $window = domMock(o)
var render = vdom($window)
var root = $window.document.createElement("div")
$window.document.body.appendChild(root)
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated1 = {tag: "input", attrs: {type: "file", value: "test.png", onclick: function() {}}}
var updated2 = {tag: "input", attrs: {type: "file", value: "test.png", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
// Verify our assumptions about the outer element state
o($window.__getSpies(input.dom).valueSetter.callCount).equals(0)
input.dom.value = "test.png"
o($window.__getSpies(input.dom).valueSetter.callCount).equals(1)
try {
console.error = spy
render(root, [updated1])
} finally {
console.error = error
}
o(updated1.dom.value).equals("test.png")
o(spy.callCount).equals(0)
o($window.__getSpies(updated1.dom).valueSetter.callCount).equals(1)
try {
console.error = spy
render(root, [updated2])
} finally {
console.error = error
}
o(updated2.dom.value).equals("test.png")
o(spy.callCount).equals(0)
o($window.__getSpies(updated2.dom).valueSetter.callCount).equals(1)
})
})
o.spec("select", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var Vnode = require("../../render/vnode")
o.spec("normalize", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var Vnode = require("../../render/vnode")
o.spec("normalizeChildren", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var m = require("../../render/hyperscript")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var callAsync = require("../../test-utils/callAsync")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var m = require("../../render/hyperscript")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var trust = require("../../render/trust")
o.spec("trust", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var xhrMock = require("../../test-utils/xhrMock")
var Request = require("../../request/request")
var PromisePolyfill = require("../../promise/promise")

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var callAsync = require("../../test-utils/callAsync")
var xhrMock = require("../../test-utils/xhrMock")
var Request = require("../../request/request")

View file

@ -143,7 +143,7 @@ class Generator {
let anchor = text.toLowerCase()
.replace(/<(\/?)code>/g, "")
.replace(/<a.*?>.+?<\/a>/g, "")
.replace(/\.|\[|\]|&quot;|\/|\(|\)/g, "")
.replace(/[.`[\]\/()]|&quot;/g, "")
.replace(/\s/g, "-");
const anchorId = anchorIds.get(anchor)

View file

@ -278,8 +278,8 @@ async function lintAll({useCache}) {
await new Promise((resolve, reject) => {
const glob = new Glob(path.resolve(__dirname, "../**/*.md"), {
ignore: [
"**/change-log.md",
"**/migration-v02x.md",
"**/changelog.md",
"**/migration-*.md",
"**/node_modules/**",
],
nodir: true,
@ -304,10 +304,10 @@ if (require.main === module) {
exec: lintAll,
watch() {
require("chokidar")
.watch(path.resolve(__dirname, "../**/*.md"), {
ignored: [
"**/change-log.md",
"**/migration-v02x.md",
.watch(path.resolve(__dirname, "../docs/**/*.md"), {
ignore: [
"**/changelog.md",
"**/migration-*.md",
"**/node_modules/**",
],
})

View file

@ -123,7 +123,7 @@ async function release({increment, preid, publish}) {
console.error(`
Copy the parts listed in "Upcoming" to a new section "### v${version}" in
docs/change-log.md and clear that section out. Also, add today's date under the
docs/changelog.md and clear that section out. Also, add today's date under the
new section's heading to match the others and don't forget to update the table
of contents accordingly.
`)
@ -138,7 +138,7 @@ of contents accordingly.
// Verify the changelog was updated, and give a chance to retry if it's
// prematurely continued.
const changes = getChanges()
const isChangelog = /^[ M][ M] docs\/change-log\.md$/
const isChangelog = /^[ M][ M] docs\/changelog\.md$/
const errors = []
console.log("changes", changes)

View file

@ -2,22 +2,24 @@
const fs = require("fs")
const util = require("util")
const path = require("path")
const access = util.promisify(fs.access)
const writeFile = util.promisify(fs.writeFile)
const unlink = util.promisify(fs.unlink)
const o = require("../../ospec/ospec")
const o = require("ospec")
const bundle = require("../_bundler-impl")
o.spec("bundler", async () => {
let filesCreated
const ns = "./"
const root = path.resolve(__dirname, "../..")
const p = (file) => path.join(root, file)
async function write(filepath, data) {
try {
await access(ns + filepath)
await access(p(filepath))
} catch (e) {
return writeFile(ns + filepath, data, "utf8")
return writeFile(p(filepath), data, "utf8")
}
throw new Error(`Don't call \`write('${filepath}')\`. Cannot overwrite file.`)
}
@ -28,7 +30,7 @@ o.spec("bundler", async () => {
}
o.afterEach(() => Promise.all(
filesCreated.map((filepath) => unlink(ns + filepath))
filesCreated.map((filepath) => unlink(p(filepath)))
))
o("relative imports works", async () => {
@ -37,7 +39,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1\n}());")
})
o("relative imports works with semicolons", async () => {
await setup({
@ -45,7 +47,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1;",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1;\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1;\n}());")
})
o("relative imports works with let", async () => {
await setup({
@ -53,7 +55,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nlet b = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nlet b = 1\n}());")
})
o("relative imports works with const", async () => {
await setup({
@ -61,7 +63,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nconst b = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nconst b = 1\n}());")
})
o("relative imports works with assignment", async () => {
await setup({
@ -69,7 +71,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = {}\na.b = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar a = {}\na.b = 1\n}());")
})
o("relative imports works with reassignment", async () => {
await setup({
@ -77,7 +79,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = {}\nb = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b = {}\nb = 1\n}());")
})
o("relative imports removes extra use strict", async () => {
await setup({
@ -85,7 +87,7 @@ o.spec("bundler", async () => {
"b.js": '"use strict"\nmodule.exports = 1',
})
o(await bundle(ns + "a.js")).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
o(await bundle(p("a.js"))).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
})
o("relative imports removes extra use strict using single quotes", async () => {
await setup({
@ -93,7 +95,7 @@ o.spec("bundler", async () => {
"b.js": "'use strict'\nmodule.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\n'use strict'\nvar b = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\n'use strict'\nvar b = 1\n}());")
})
o("relative imports removes extra use strict using mixed quotes", async () => {
await setup({
@ -101,7 +103,7 @@ o.spec("bundler", async () => {
"b.js": "'use strict'\nmodule.exports = 1",
})
o(await bundle(ns + "a.js")).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
o(await bundle(p("a.js"))).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
})
o("works w/ window", async () => {
await setup({
@ -109,7 +111,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {return a}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nwindow.a = 1\nvar b = function() {return a}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nwindow.a = 1\nvar b = function() {return a}\n}());")
})
o("works without assignment", async () => {
await setup({
@ -117,7 +119,7 @@ o.spec("bundler", async () => {
"b.js": "1 + 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\n1 + 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\n1 + 1\n}());")
})
o("works if used fluently", async () => {
await setup({
@ -125,7 +127,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = []",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\n}());")
})
o("works if used fluently w/ multiline", async () => {
await setup({
@ -133,7 +135,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = []",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0\n\t.toString()\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0\n\t.toString()\n}());")
})
o("works if used w/ curry", async () => {
await setup({
@ -141,7 +143,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = function() {}\nvar b = _0()\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = function() {}\nvar b = _0()\n}());")
})
o("works if used w/ curry w/ multiline", async () => {
await setup({
@ -149,7 +151,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = function() {}\nvar b = _0\n()\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = function() {}\nvar b = _0\n()\n}());")
})
o("works if used fluently in one place and not in another", async () => {
await setup({
@ -158,7 +160,7 @@ o.spec("bundler", async () => {
"c.js": 'var b = require("./b")\nmodule.exports = function() {return b}',
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\nvar b0 = _0\nvar c = function() {return b0}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\nvar b0 = _0\nvar c = function() {return b0}\n}());")
})
o("works if used in sequence", async () => {
await setup({
@ -167,7 +169,7 @@ o.spec("bundler", async () => {
"c.js": "var x\nmodule.exports = 2",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1\nvar x\nvar c = 2\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1\nvar x\nvar c = 2\n}());")
})
o("works if assigned to property", async () => {
await setup({
@ -176,7 +178,7 @@ o.spec("bundler", async () => {
"c.js": "var cc = 2\nmodule.exports = cc",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar x = {}\nvar bb = 1\nx.b = bb\nvar cc = 2\nx.c = cc\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar x = {}\nvar bb = 1\nx.b = bb\nvar cc = 2\nx.c = cc\n}());")
})
o("works if assigned to property using bracket notation", async () => {
await setup({
@ -185,7 +187,7 @@ o.spec("bundler", async () => {
"c.js": "var cc = 2\nmodule.exports = cc",
})
o(await bundle(ns + "a.js")).equals(';(function() {\nvar x = {}\nvar bb = 1\nx["b"] = bb\nvar cc = 2\nx["c"] = cc\n}());')
o(await bundle(p("a.js"))).equals(';(function() {\nvar x = {}\nvar bb = 1\nx["b"] = bb\nvar cc = 2\nx["c"] = cc\n}());')
})
o("works if collision", async () => {
await setup({
@ -193,7 +195,7 @@ o.spec("bundler", async () => {
"b.js": "var b = 1\nmodule.exports = 2",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = 1\nvar b = 2\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = 1\nvar b = 2\n}());")
})
o("works if multiple aliases", async () => {
await setup({
@ -202,7 +204,7 @@ o.spec("bundler", async () => {
"c.js": "var b = {}\nmodule.exports = b",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = {}\nb.x = 1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b = {}\nb.x = 1\n}());")
})
o("works if multiple collision", async () => {
await setup({
@ -212,7 +214,7 @@ o.spec("bundler", async () => {
"d.js": "var a = 3\nmodule.exports = a",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar b = a\nvar a0 = 2\nvar c = a0\nvar a1 = 3\nvar d = a1\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar b = a\nvar a0 = 2\nvar c = a0\nvar a1 = 3\nvar d = a1\n}());")
})
o("works if included multiple times", async () => {
await setup({
@ -221,7 +223,7 @@ o.spec("bundler", async () => {
"c.js": 'var a = require("./a").toString()\nvar b = require("./b")',
})
o(await bundle(ns + "c.js")).equals(";(function() {\nvar _0 = 123\nvar a = _0.toString()\nvar a0 = _0.toString()\nvar b = a0\n}());")
o(await bundle(p("c.js"))).equals(";(function() {\nvar _0 = 123\nvar a = _0.toString()\nvar a0 = _0.toString()\nvar b = a0\n}());")
})
o("works if included multiple times reverse", async () => {
await setup({
@ -230,7 +232,7 @@ o.spec("bundler", async () => {
"c.js": 'var b = require("./b")\nvar a = require("./a").toString()',
})
o(await bundle(ns + "c.js")).equals(";(function() {\nvar _0 = 123\nvar a0 = _0.toString()\nvar b = a0\nvar a = _0.toString()\n}());")
o(await bundle(p("c.js"))).equals(";(function() {\nvar _0 = 123\nvar a0 = _0.toString()\nvar b = a0\nvar a = _0.toString()\n}());")
})
o("reuses binding if possible", async () => {
await setup({
@ -240,7 +242,7 @@ o.spec("bundler", async () => {
"d.js": "module.exports = 1",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar d = 1\nvar b = function() {return d + 1}\nvar c = function() {return d + 2}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar d = 1\nvar b = function() {return d + 1}\nvar c = function() {return d + 2}\n}());")
})
o("disambiguates conflicts if imported collides with itself", async () => {
await setup({
@ -248,7 +250,7 @@ o.spec("bundler", async () => {
"b.js": "var b = 1\nmodule.exports = function() {return b}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = 1\nvar b = function() {return b0}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = 1\nvar b = function() {return b0}\n}());")
})
o("disambiguates conflicts if imported collides with something else", async () => {
await setup({
@ -256,7 +258,7 @@ o.spec("bundler", async () => {
"b.js": "var a = 2\nmodule.exports = function() {return a}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar a0 = 2\nvar b = function() {return a0}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar a0 = 2\nvar b = function() {return a0}\n}());")
})
o("disambiguates conflicts if imported collides with function declaration", async () => {
await setup({
@ -264,7 +266,7 @@ o.spec("bundler", async () => {
"b.js": "var a = 2\nmodule.exports = function() {return a}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nfunction a() {}\nvar a0 = 2\nvar b = function() {return a0}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nfunction a() {}\nvar a0 = 2\nvar b = function() {return a0}\n}());")
})
o("disambiguates conflicts if imported collides with another module's private", async () => {
await setup({
@ -273,7 +275,7 @@ o.spec("bundler", async () => {
"c.js": "var a = 2\nmodule.exports = function() {return a}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar b = function() {return a}\nvar a0 = 2\nvar c = function() {return a0}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar b = function() {return a}\nvar a0 = 2\nvar c = function() {return a0}\n}());")
})
o("does not mess up strings", async () => {
await setup({
@ -281,7 +283,7 @@ o.spec("bundler", async () => {
"b.js": 'var b = "b b b \\" b"\nmodule.exports = function() {return b}',
})
o(await bundle(ns + "a.js")).equals(';(function() {\nvar b0 = "b b b \\\" b"\nvar b = function() {return b0}\n}());')
o(await bundle(p("a.js"))).equals(';(function() {\nvar b0 = "b b b \\\" b"\nvar b = function() {return b0}\n}());')
})
o("does not mess up properties", async () => {
await setup({
@ -289,6 +291,6 @@ o.spec("bundler", async () => {
"b.js": "var b = {b: 1}\nmodule.exports = function() {return b.b}",
})
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = {b: 1}\nvar b = function() {return b0.b}\n}());")
o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = {b: 1}\nvar b = function() {return b0.b}\n}());")
})
})

View file

@ -1,21 +0,0 @@
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.

View file

@ -1,6 +0,0 @@
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.

View file

@ -1,22 +0,0 @@
# Change log for stream
- [Upcoming](#upcoming)
- [v2.0.0](#v200)
- [v1.1.0](#v110)
### Upcoming...
### 2.0.0
_2019-02-07_
- when a stream conditionally returns HALT, dependant stream will also end ([#2200](https://github.com/MithrilJS/mithril.js/pull/2200), [#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
- Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` ([#1944](https://github.com/MithrilJS/mithril.js/issues/1944))
- renamed HALT to SKIP ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- rewrote implementation ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- Removed `valueOf` & `toString` methods ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150))
- fixed `stream.end` propagation ([#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
### 1.1.0
_2017-07-13_
- 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))

View file

@ -1,13 +0,0 @@
{
"name": "mithril-stream",
"version": "2.0.0",
"description": "Streaming data, mithril-style",
"main": "stream.js",
"directories": {
"test": "tests"
},
"keywords": [ "stream", "reactive", "data" ],
"author": "Leo Horie <lhorie@hotmail.com>",
"license": "MIT",
"repository": "MithrilJS/mithril.js"
}

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var stream = require("../stream")
o.spec("scan", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var stream = require("../stream")
o.spec("scanMerge", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var Stream = require("../stream")
o.spec("stream", function() {

View file

@ -495,6 +495,37 @@ module.exports = function(options) {
set: valueSetter,
enumerable: true,
})
Object.defineProperty(element, "valueAsDate", {
get: function() {
if (this.getAttribute("type") !== "date") return null
return new Date(value).getTime()
},
set: function(v) {
if (this.getAttribute("type") !== "date") throw new Error("invalid state")
var time = new Date(v).getTime()
return valueSetter(isNaN(time) ? "" : new Date(time).toUTCString())
},
enumerable: true,
})
Object.defineProperty(element, "valueAsNumber", {
get: function() {
switch (this.getAttribute("type")) {
case "date": return new Date(value).getTime()
case "number": return new Date(value).getTime()
default: return NaN
}
},
set: function(v) {
v = Number(v)
if (!isNaN(v) && !isFinite(v)) throw new TypeError("infinite value")
switch (this.getAttribute("type")) {
case "date": return valueSetter(isNaN(v) ? "" : new Date(v).toUTCString())
case "number": return valueSetter(String(value))
default: throw new Error("invalid state")
}
},
enumerable: true,
})
// we currently emulate the non-ie behavior, but emulating ie may be more useful (throw when an invalid type is set)
var typeSetter = spy(function(v) {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var browserMock = require("../../test-utils/browserMock")
var callAsync = require("../../test-utils/callAsync")
o.spec("browserMock", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var callAsync = require("../../test-utils/callAsync")
o.spec("callAsync", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var components = require("../../test-utils/components")
o.spec("test-utils/components", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var domMock = require("../../test-utils/domMock")
o.spec("domMock", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var parseURL = require("../../test-utils/parseURL")
o.spec("parseURL", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var pushStateMock = require("../../test-utils/pushStateMock")
var callAsync = require("../../test-utils/callAsync")
o.spec("pushStateMock", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var throttleMocker = require("../../test-utils/throttleMock")
o.spec("throttleMock", function() {

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var xhrMock = require("../../test-utils/xhrMock")
var parseQueryString = require("../../querystring/parse")

View file

@ -1,12 +1,13 @@
"use strict"
var o = require("../ospec/ospec")
var o = require("ospec")
var browserMock = require("../test-utils/browserMock")
var components = require("../test-utils/components")
o.spec("api", function() {
var FRAME_BUDGET = Math.floor(1000 / 60)
var mock = browserMock(), root
mock.setTimeout = setTimeout
if (typeof global !== "undefined") {
global.window = mock
global.requestAnimationFrame = mock.requestAnimationFrame

View file

@ -1,6 +1,6 @@
"use strict"
var o = require("../../ospec/ospec")
var o = require("ospec")
var censor = require("../../util/censor")
o.spec("censor", function() {