diff options
author | Alan Pearce | 2017-07-02 15:30:20 +0200 |
---|---|---|
committer | Alan Pearce | 2017-07-02 15:30:20 +0200 |
commit | b7bf162e6c3bc834097e65936704e3eac59eb4bd (patch) | |
tree | 9f080d9c67d6ee17a506e5ab52761f22b649137c | |
parent | 2d931962b74fe06c1bfbc2454fa166d24e8e2f59 (diff) | |
download | homestead-b7bf162e6c3bc834097e65936704e3eac59eb4bd.tar.lz homestead-b7bf162e6c3bc834097e65936704e3eac59eb4bd.tar.zst homestead-b7bf162e6c3bc834097e65936704e3eac59eb4bd.zip |
feat: Use microformats classes
Add snapshot-based tests to ensure microformats data can be extracted correctly.
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | src/app.js | 36 | ||||
-rw-r--r-- | src/domain/posts.js | 73 | ||||
-rw-r--r-- | src/responders.js | 31 | ||||
-rw-r--r-- | src/templates/home.html | 8 | ||||
-rw-r--r-- | src/templates/post.html | 8 | ||||
-rw-r--r-- | src/templates/taxon.html | 8 | ||||
-rw-r--r-- | test/app.test.js | 227 | ||||
-rw-r--r-- | test/domain/posts.test.js | 18 | ||||
-rw-r--r-- | test/snapshots/app.test.js.md | 163 | ||||
-rw-r--r-- | test/snapshots/app.test.js.snap | bin | 0 -> 1236 bytes | |||
-rw-r--r-- | yarn.lock | 272 |
12 files changed, 518 insertions, 329 deletions
diff --git a/package.json b/package.json index 6cb7921..d324fdf 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "auto-install": "^1.7.4", - "ava": "^0.19.1", + "ava": "^0.20.0", "cheerio": "^1.0.0-rc.1", "eslint": "^4.1.1", "eslint-config-prettier": "^2.2.0", @@ -38,6 +38,7 @@ "eslint-plugin-standard": "^3.0.1", "husky": "^0.13.4", "lint-staged": "^3.6.1", + "microformat-node": "^2.0.1", "node-dev": "^3.1.3", "prettier-standard": "^5.1.0", "standard": "^10.0.2", diff --git a/src/app.js b/src/app.js index fa0d5c2..1a0c5cb 100644 --- a/src/app.js +++ b/src/app.js @@ -1,31 +1,33 @@ -'use strict' +"use strict"; -const Koa = require('koa') -const app = new Koa() +const Koa = require("koa"); +const app = new Koa(); -const helmet = require('koa-helmet') +const helmet = require("koa-helmet"); -const actions = require('./actions.js') +const actions = require("./actions.js"); -const config = require('./modules/config.js') +const config = require("./modules/config.js"); -const Router = require('koa-router') -const router = new Router() +const Router = require("koa-router"); +const router = new Router(); -app.context.getURL = router.url.bind(router) +app.context.getURL = router.url.bind(router); -const Posts = require('./domain/posts.js')(config.posts) +const Posts = require("./domain/posts.js")(config.posts, basename => + router.url("post", basename) +); -router.get('home', '/', actions.home(config, Posts.posts)) +router.get("home", "/", actions.home(config, Posts.posts)); -router.get('post', '/post/:filename', actions.post(config, Posts.posts)) +router.get("post", "/post/:filename", actions.post(config, Posts.posts)); for (let [term, items] of Posts.taxonomies) { router.get( `taxon-${term}`, `/${term}/:value`, actions.taxonGenerator(config, term, items) - ) + ); } app.use( @@ -34,10 +36,10 @@ app.use( setIf: ctx => ctx.secure } }) -) +); -app.use(router.routes()).use(router.allowedMethods()) +app.use(router.routes()).use(router.allowedMethods()); -app.use(actions.serveFiles) +app.use(actions.serveFiles); -module.exports = app +module.exports = app; diff --git a/src/domain/posts.js b/src/domain/posts.js index ea81729..fd4fb3d 100644 --- a/src/domain/posts.js +++ b/src/domain/posts.js @@ -1,81 +1,82 @@ -'use strict' +"use strict"; -const fs = require('fs') -const path = require('path') -const matter = require('gray-matter') -const markdown = require('../modules/markdown.js') -const { indentForTemplate, postIndentLevel } = require('../responders.js') +const fs = require("fs"); +const path = require("path"); +const matter = require("gray-matter"); +const markdown = require("../modules/markdown.js"); +const { indentForTemplate, postIndentLevel } = require("../responders.js"); const grayMatterOptions = { - lang: 'toml', - delims: '+++' -} + lang: "toml", + delims: "+++" +}; -function* lowercaseKeys (iterator) { +function* lowercaseKeys(iterator) { for (let [k, v] of iterator) { - yield [String(k).toLowerCase(), v] + yield [String(k).toLowerCase(), v]; } } -function canonicaliseMetadata (meta) { +function canonicaliseMetadata(meta) { if (meta.data) { - meta.data = new Map(lowercaseKeys(Object.entries(meta.data))) + meta.data = new Map(lowercaseKeys(Object.entries(meta.data))); } else { - meta.data = new Map() + meta.data = new Map(); } - return meta + return meta; } -function getTitle (file) { - return path.basename(file.path, path.extname(file.path)) +function getTitle(file) { + return path.basename(file.path, path.extname(file.path)); } -function get (filename) { - const fileMatter = matter.read(filename, grayMatterOptions) - fileMatter.basename = getTitle(fileMatter) - delete fileMatter.orig +function get(getURL, filename) { + const fileMatter = matter.read(filename, grayMatterOptions); + fileMatter.basename = getTitle(fileMatter); + delete fileMatter.orig; fileMatter.body = indentForTemplate( markdown(fileMatter.content), postIndentLevel - ) - return canonicaliseMetadata(fileMatter) + ); + fileMatter.url = getURL(fileMatter.basename); + return canonicaliseMetadata(fileMatter); } -function getFolder (folder) { +function getFolder(folder, getURL) { return new Map( fs .readdirSync(folder) .map(f => path.resolve(folder, f)) - .map(get) + .map(get.bind(this, getURL)) .map(f => [getTitle(f), f]) - ) + ); } -function taxonomise (taxonomies, posts) { - const taxons = new Map(Object.keys(taxonomies).map(t => [t, new Map()])) +function taxonomise(taxonomies, posts) { + const taxons = new Map(Object.keys(taxonomies).map(t => [t, new Map()])); for (let [, post] of posts) { for (let [singularName, pluralName] of Object.entries(taxonomies)) { if (post.data.has(pluralName)) { for (let term of post.data.get(pluralName)) { - const current = taxons.get(singularName).get(term) + const current = taxons.get(singularName).get(term); taxons .get(singularName) - .set(term, current ? current.concat(post) : [post]) + .set(term, current ? current.concat(post) : [post]); } } } } - return taxons + return taxons; } -module.exports = function (config) { - const posts = getFolder(config.folder) - const taxonomies = taxonomise(config.taxonomies, posts) +module.exports = function(config, getURL) { + const posts = getFolder(config.folder, getURL); + const taxonomies = taxonomise(config.taxonomies, posts); return { posts, taxonomies, get - } -} + }; +}; diff --git a/src/responders.js b/src/responders.js index 4049ebf..867310a 100644 --- a/src/responders.js +++ b/src/responders.js @@ -21,7 +21,7 @@ function getTemplateIndent(re, template) { } const findMain = /^(\s+)<main/m; const baseIndentLevel = getTemplateIndent(findMain, "layout"); -const findPostContent = /^(\s+)<div class="post-content/m; +const findPostContent = /^(\s+)<div class="e-content/m; const postIndentLevel = baseIndentLevel + getTemplateIndent(findPostContent, "post"); @@ -49,12 +49,15 @@ const makeTime = date => ({ _text: postDateFormatter.format(date) }); -const renderPostListItem = ctx => post => { +const renderPost = ctx => post => { return { - time: makeTime(post.data.get("date")), - a: { - href: ctx.getURL("post", post.basename), - _text: post.data.get("title") + ".dt-published": makeTime(post.data.get("date")), + ".p-name": post.data.get("title"), + ".u-url": { + href: ctx.getURL("post", post.basename) + }, + ".e-content": { + _html: post.body } }; }; @@ -62,8 +65,8 @@ const renderPostListItem = ctx => post => { function layout(config, pageTitle, pageElement) { return hyperfast(templates.layout, { title: title(config.site.author.name, pageTitle), - "body > header .p-name": config.site.author.name, - "body > header .u-photo": { + ".h-card .p-name": config.site.author.name, + ".h-card .u-photo": { alt: config.site.author.name, src: config.site.author.photo }, @@ -83,7 +86,7 @@ module.exports = { config, null, hyperfast(templates.home, { - ".post": posts.map(renderPostListItem(ctx)) + ".h-entry": posts.map(renderPost(ctx)) }) ); }, @@ -94,13 +97,7 @@ module.exports = { ctx.body = layout( config, post.data.get("title"), - hyperfast(templates.post, { - "article h1": post.data.get("title"), - "article time": makeTime(post.data.get("date")), - "article .post-content": { - _html: post.body - } - }) + hyperfast(templates.post, renderPost(ctx)(post)) ); }, @@ -111,7 +108,7 @@ module.exports = { config, Case.title(value), hyperfast(templates.taxon, { - ".post": taxonItems.map(renderPostListItem(ctx)) + ".h-entry": taxonItems.map(renderPost(ctx)) }) ); } diff --git a/src/templates/home.html b/src/templates/home.html index a3597a1..44244e5 100644 --- a/src/templates/home.html +++ b/src/templates/home.html @@ -1,6 +1,6 @@ -<ul class="posts"> - <li class="post"> - <a href="/">Test post please ignore</a> - <time></time> +<ul class="h-feed"> + <li class="h-entry"> + <a class="u-url p-name" href="/">Test post please ignore</a> + <time class="dt-published"></time> </li> </ul> diff --git a/src/templates/post.html b/src/templates/post.html index 27bcdc3..a047aa4 100644 --- a/src/templates/post.html +++ b/src/templates/post.html @@ -1,7 +1,7 @@ -<article> - <h1>post title</h1> - <time></time> - <div class="post-content"> +<article class="h-entry"> + <h1 class="p-name">post title</h1> + <time class="dt-published"></time> + <div class="e-content"> Fringilla ut morbi tincidunt augue interdum velit euismod! Interdum velit laoreet id donec ultrices tincidunt arcu, non sodales neque sodales ut etiam sit amet nisl purus, in diff --git a/src/templates/taxon.html b/src/templates/taxon.html index a3597a1..44244e5 100644 --- a/src/templates/taxon.html +++ b/src/templates/taxon.html @@ -1,6 +1,6 @@ -<ul class="posts"> - <li class="post"> - <a href="/">Test post please ignore</a> - <time></time> +<ul class="h-feed"> + <li class="h-entry"> + <a class="u-url p-name" href="/">Test post please ignore</a> + <time class="dt-published"></time> </li> </ul> diff --git a/test/app.test.js b/test/app.test.js index 6810089..69cea86 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -22,137 +22,110 @@ const toMicroformatsOptions = node => ({ textFormat: "normalised" }); -test("homepage", t => { - return request(app.listen()) - .get("/") - .expect(200) - .expect("Content-Type", "text/html; charset=utf-8") - .expect(/^<!DOCTYPE html>/) - .then(parseResponse) - .then($ => { - t.is($("head > title").text(), "John Doe", "head title is site author"); - t.is($("h1").text(), "John Doe", "h1 is site author"); - t.is($("main").length, 1, "only one <main> tag"); - t.is($("main .posts").length, 1, "contains one posts listing"); - t.is( - $(".post:first-of-type a").attr("href"), - "/post/testfile", - "first post url" - ); - t.is( - $(".post:first-of-type time").text(), - "Sunday, January 1, 2017", - "first post date" - ); - t.is( - $(".post:first-of-type time").attr("datetime"), - new Date("2017-01-01").toISOString() - ); - return $; - }) - .then(toMicroformatsOptions) - .then(options => - Promise.all([ - mf.countAsync(options).then(count => - t.deepEqual(count, { - "h-card": 1 - }) - ), - mf.getAsync(options).then(data => { - t.deepEqual(data.items, [ - { - properties: { - name: ["John Doe"], - url: ["/"], - photo: ["/static/johndoe.jpg"] - }, - type: ["h-card"] - } - ]); - }) - ]) - ); -}); +async function notFound(t, url, bodyRegex) { + const res = await request(app.listen()).get(url); + const body = res.text; + t.is(res.statusCode, 404); + t.regex(body, bodyRegex); +} +notFound.title = (providedTitle, input, expected) => + `${input} = 404 ${expected.toString()}`; + +test("homepage", async function(t) { + const res = await request(app.listen()).get("/"); + + t.is(res.statusCode, 200); + t.is(res.type, "text/html"); + t.is(res.charset, "utf-8"); + t.regex(res.text, /^<!DOCTYPE html>/); + + const $ = parseResponse(res); -test("post", t => { - return request(app.listen()) - .get("/post/testfile") - .expect(200) - .expect("Content-Type", "text/html; charset=utf-8") - .expect(/^<!DOCTYPE html>/) - .then(parseResponse) - .then($ => { - t.is( - $("head > title").text(), - "This is a test · " + "John Doe", - "head title contains post and site author" - ); - t.is( - $("article h1").text(), - "This is a test", - "article header is post title" - ); - t.is( - $("article time").text(), - "Sunday, January 1, 2017", - "first post date" - ); - t.is( - $("article time").attr("datetime"), - new Date("2017-01-01").toISOString() - ); - t.is( - $("article p").text(), - `Ut enim blandit volutpat maecenas? Volutpat blandit aliquam etiam erat \ -velit, scelerisque in dictum non, consectetur a erat nam at lectus \ -urna duis convallis convallis tellus, id interdum velit laoreet!`, - "article has text" - ); - }); + t.is($("head > title").text(), "John Doe", "head title is site author"); + t.is($("h1").text(), "John Doe", "h1 is site author"); + t.is($("main").length, 1, "only one <main> tag"); + t.is( + $(".h-entry:first-of-type time").text(), + "Sunday, January 1, 2017", + "first post date" + ); + t.is( + $(".h-entry:first-of-type time").attr("datetime"), + new Date("2017-01-01").toISOString() + ); + + const options = toMicroformatsOptions($); + const count = await mf.countAsync(options); + + t.deepEqual(count, { + "h-card": 1, + "h-feed": 1, + "h-entry": 1 + }); + + const data = await mf.getAsync(options); + + t.snapshot(data, "should contain relevant microformats data"); }); -test("post not found", t => { - return request(app.listen()) - .get("/post/non-existant") - .expect(404) - .expect(/Post not found/) - .then(() => t.pass()); +test("post", async function(t) { + const res = await request(app.listen()).get("/post/testfile"); + + t.is(res.statusCode, 200); + t.is(res.type, "text/html"); + t.is(res.charset, "utf-8"); + t.regex(res.text, /^<!DOCTYPE html>/); + + const $ = parseResponse(res); + + t.is( + $("head > title").text(), + "This is a test · " + "John Doe", + "head title contains post and site author" + ); + + const options = toMicroformatsOptions($); + + const count = await mf.countAsync(options); + + t.deepEqual(count, { + "h-card": 1, + "h-entry": 1 + }); + + const data = await mf.getAsync(options); + + t.snapshot(data, "should contain relevant microformats data"); }); -test("tags", t => { - return request(app.listen()) - .get("/tag/a") - .expect(200) - .expect("Content-Type", "text/html; charset=utf-8") - .expect(/^<!DOCTYPE html>/) - .then(parseResponse) - .then($ => { - t.is( - $("head > title").text(), - "A · John Doe", - "head title contains title-cased tag and site name" - ); - t.is( - $(".post a").text(), - "This is a test", - "post link text is post title" - ); - t.is( - $(".post:first-of-type a").attr("href"), - "/post/testfile", - "post url" - ); - t.is( - $(".post:first-of-type time").text(), - "Sunday, January 1, 2017", - "first post date" - ); - }); +test("tags", async function(t) { + const res = await request(app.listen()).get("/tag/a"); + + t.is(res.statusCode, 200); + t.is(res.type, "text/html"); + t.is(res.charset, "utf-8"); + t.regex(res.text, /^<!DOCTYPE html>/); + + const $ = parseResponse(res); + + t.is( + $("head > title").text(), + "A · John Doe", + "head title contains title-cased tag and site name" + ); + const options = toMicroformatsOptions($); + const count = await mf.countAsync(options); + + t.deepEqual(count, { + "h-card": 1, + "h-feed": 1, + "h-entry": 1 + }); + + const data = await mf.getAsync(options); + + t.snapshot(data, "should contain relevant microformats data"); }); -test("tags not found", t => - request(app.listen()) - .get("/tag/non-existant") - .expect(404) - .expect(/tag non-existant not found/) - .then(() => t.pass())); +test(notFound, "/post/non-existent", /Post not found/); +test(notFound, "/tag/non-existent", /tag non-existent not found/); diff --git a/test/domain/posts.test.js b/test/domain/posts.test.js index cc236c7..8b27698 100644 --- a/test/domain/posts.test.js +++ b/test/domain/posts.test.js @@ -1,13 +1,16 @@ const test = require("ava"); const path = require("path"); -const Posts = require("../../src/domain/posts.js")({ - folder: path.resolve(__dirname, "../testsite/posts/"), - taxonomies: { - tag: "tags", - category: "categories" - } -}); +const Posts = require("../../src/domain/posts.js")( + { + folder: path.resolve(__dirname, "../testsite/posts/"), + taxonomies: { + tag: "tags", + category: "categories" + } + }, + basename => basename +); test("get", t => { const expected = new Map( @@ -19,6 +22,7 @@ test("get", t => { }) ); const post = Posts.get( + basename => basename, path.resolve(__dirname, "../testsite/posts/testfile.md") ); t.deepEqual(post.data, expected); diff --git a/test/snapshots/app.test.js.md b/test/snapshots/app.test.js.md new file mode 100644 index 0000000..99811f9 --- /dev/null +++ b/test/snapshots/app.test.js.md @@ -0,0 +1,163 @@ +# Snapshot report for `test/app.test.js` + +The actual snapshot is saved in `app.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## homepage + +> should contain relevant microformats data + + { + items: [ + { + properties: { + name: [ + 'John Doe', + ], + photo: [ + '/static/johndoe.jpg', + ], + url: [ + '/', + ], + }, + type: [ + 'h-card', + ], + }, + { + children: [ + { + properties: { + name: [ + 'This is a test', + ], + published: [ + '2017-01-01T00:00:00.000Z', + ], + url: [ + '/post/testfile', + ], + }, + type: [ + 'h-entry', + ], + value: 'This is a test Sunday, January 1, 2017', + }, + ], + properties: { + name: [ + 'John Doe', + ], + }, + type: [ + 'h-feed', + ], + }, + ], + 'rel-urls': {}, + rels: {}, + } + +## post + +> should contain relevant microformats data + + { + items: [ + { + properties: { + name: [ + 'John Doe', + ], + photo: [ + '/static/johndoe.jpg', + ], + url: [ + '/', + ], + }, + type: [ + 'h-card', + ], + }, + { + properties: { + content: [ + { + html: '<p>Ut enim blandit volutpat maecenas? Volutpat blandit aliquam etiam erat velit, scelerisque in dictum non, consectetur a erat nam at lectus urna duis convallis convallis tellus, id interdum velit laoreet!</p>', + value: 'Ut enim blandit volutpat maecenas? Volutpat blandit aliquam etiam erat velit, scelerisque in dictum non, consectetur a erat nam at lectus urna duis convallis convallis tellus, id interdum velit laoreet!', + }, + ], + name: [ + 'This is a test', + ], + published: [ + '2017-01-01T00:00:00.000Z', + ], + }, + type: [ + 'h-entry', + ], + }, + ], + 'rel-urls': {}, + rels: {}, + } + +## tags + +> should contain relevant microformats data + + { + items: [ + { + properties: { + name: [ + 'John Doe', + ], + photo: [ + '/static/johndoe.jpg', + ], + url: [ + '/', + ], + }, + type: [ + 'h-card', + ], + }, + { + children: [ + { + properties: { + name: [ + 'This is a test', + ], + published: [ + '2017-01-01T00:00:00.000Z', + ], + url: [ + '/post/testfile', + ], + }, + type: [ + 'h-entry', + ], + value: 'This is a test Sunday, January 1, 2017', + }, + ], + properties: { + name: [ + 'A · John Doe', + ], + }, + type: [ + 'h-feed', + ], + }, + ], + 'rel-urls': {}, + rels: {}, + } diff --git a/test/snapshots/app.test.js.snap b/test/snapshots/app.test.js.snap new file mode 100644 index 0000000..bbc5c61 --- /dev/null +++ b/test/snapshots/app.test.js.snap Binary files differdiff --git a/yarn.lock b/yarn.lock index 48d071d..a43ee0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6,7 +6,7 @@ version "2.0.0" resolved "https://registry.yarnpkg.com/@ava/babel-plugin-throws-helper/-/babel-plugin-throws-helper-2.0.0.tgz#2fc1fe3c211a71071a4eca7b8f7af5842cd1ae7c" -"@ava/babel-preset-stage-4@^1.0.0": +"@ava/babel-preset-stage-4@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@ava/babel-preset-stage-4/-/babel-preset-stage-4-1.1.0.tgz#ae60be881a0babf7d35f52aba770d1f6194f76bd" dependencies: @@ -30,12 +30,19 @@ "@ava/babel-plugin-throws-helper" "^2.0.0" babel-plugin-espower "^2.3.2" -"@ava/pretty-format@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@ava/pretty-format/-/pretty-format-1.1.0.tgz#d0a57d25eb9aeab9643bdd1a030642b91c123e28" +"@ava/write-file-atomic@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ava/write-file-atomic/-/write-file-atomic-2.2.0.tgz#d625046f3495f1f5e372135f473909684b429247" dependencies: - ansi-styles "^2.2.1" - esutils "^2.0.2" + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +"@concordance/react@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@concordance/react/-/react-1.0.0.tgz#fcf3cad020e5121bfd1c61d05bc3516aac25f734" + dependencies: + arrify "^1.0.1" "@types/node@^6.0.46": version "6.0.79" @@ -105,7 +112,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.0.0: +ansi-styles@^3.0.0, ansi-styles@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.1.0.tgz#09c202d5c917ec23188caa5c9cb9179cd9547750" dependencies: @@ -259,20 +266,22 @@ ava-init@^0.2.0: read-pkg-up "^2.0.0" write-pkg "^2.0.0" -ava@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/ava/-/ava-0.19.1.tgz#43dd82435ad19b3980ffca2488f05daab940b273" +ava@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/ava/-/ava-0.20.0.tgz#bdc0dd36453d7255e9f733305ab370c248381e41" dependencies: - "@ava/babel-preset-stage-4" "^1.0.0" + "@ava/babel-preset-stage-4" "^1.1.0" "@ava/babel-preset-transform-test-files" "^3.0.0" - "@ava/pretty-format" "^1.1.0" + "@ava/write-file-atomic" "^2.2.0" + "@concordance/react" "^1.0.0" + ansi-escapes "^2.0.0" + ansi-styles "^3.1.0" arr-flatten "^1.0.1" array-union "^1.0.1" array-uniq "^1.0.2" arrify "^1.0.0" auto-bind "^1.1.0" ava-init "^0.2.0" - babel-code-frame "^6.16.0" babel-core "^6.17.0" bluebird "^3.0.0" caching-transform "^1.0.0" @@ -286,12 +295,11 @@ ava@^0.19.1: co-with-promise "^4.6.0" code-excerpt "^2.1.0" common-path-prefix "^1.0.0" + concordance "^2.0.0" convert-source-map "^1.2.0" core-assert "^0.2.0" currently-unhandled "^0.4.1" debug "^2.2.0" - diff "^3.0.1" - diff-match-patch "^1.0.0" dot-prop "^4.1.0" empower-core "^0.6.1" equal-length "^1.0.0" @@ -301,28 +309,27 @@ ava@^0.19.1: get-port "^3.0.0" globby "^6.0.0" has-flag "^2.0.0" - hullabaloo-config-manager "^1.0.0" + hullabaloo-config-manager "^1.1.0" ignore-by-default "^1.0.0" + import-local "^0.1.1" indent-string "^3.0.0" is-ci "^1.0.7" is-generator-fn "^1.0.0" is-obj "^1.0.0" is-observable "^0.2.0" is-promise "^2.1.0" - jest-diff "19.0.0" - jest-snapshot "19.0.2" js-yaml "^3.8.2" last-line-stream "^1.0.0" + lodash.clonedeepwith "^4.5.0" lodash.debounce "^4.0.3" lodash.difference "^4.3.0" lodash.flatten "^4.2.0" - lodash.isequal "^4.5.0" loud-rejection "^1.2.0" + make-dir "^1.0.0" matcher "^0.1.1" md5-hex "^2.0.0" meow "^3.7.0" - mkdirp "^0.5.1" - ms "^0.7.1" + ms "^1.0.0" multimatch "^2.1.0" observable-to-promise "^0.5.0" option-chain "^0.1.0" @@ -339,6 +346,7 @@ ava@^0.19.1: strip-bom-buf "^1.0.0" supports-color "^3.2.3" time-require "^0.1.2" + trim-off-newlines "^1.0.1" unique-temp-dir "^1.0.0" update-notifier "^2.1.0" @@ -675,9 +683,9 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.0.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" +bluebird@3.4.x, bluebird@^3.0.0: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" boolbase@~1.0.0: version "1.0.0" @@ -823,6 +831,27 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +cheerio@0.22.x: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + cheerio@^1.0.0-rc.1: version "1.0.0-rc.1" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.1.tgz#2af37339eab713ef6b72cde98cefa672b87641fe" @@ -1020,6 +1049,22 @@ concat-stream@^1.5.2, concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" +concordance@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/concordance/-/concordance-2.0.0.tgz#c3c5dbffa83c29537df202bded8fa1d6aa94e805" + dependencies: + esutils "^2.0.2" + fast-diff "^1.1.1" + function-name-support "^0.2.0" + js-string-escape "^1.0.1" + lodash.clonedeep "^4.5.0" + lodash.flattendeep "^4.4.0" + lodash.merge "^4.6.0" + md5-hex "^2.0.0" + moment "^2.18.1" + semver "^5.3.0" + well-known-symbols "^1.0.0" + configly@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/configly/-/configly-4.1.0.tgz#48a6af73cddd1e4d98d44fe264b78db2b0880bce" @@ -1339,14 +1384,6 @@ detective@4.3.2: acorn "^3.1.0" defined "^1.0.0" -diff-match-patch@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048" - -diff@^3.0.0, diff@^3.0.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" - dlv@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.0.tgz#fee1a7c43f63be75f3f679e85262da5f102764a7" @@ -2079,6 +2116,10 @@ function-bind@^1.0.2, function-bind@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" +function-name-support@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2242,7 +2283,7 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -2425,7 +2466,7 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -hullabaloo-config-manager@^1.0.0: +hullabaloo-config-manager@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz#1d9117813129ad035fd9e8477eaf066911269fe3" dependencies: @@ -2482,6 +2523,13 @@ import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" +import-local@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-0.1.1.tgz#b1179572aacdc11c6a91009fb430dbcab5f668a8" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + import-modules@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/import-modules/-/import-modules-1.1.0.tgz#748db79c5cc42bb9701efab424f894e72600e9dc" @@ -2801,74 +2849,13 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -jest-diff@19.0.0, jest-diff@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c" - dependencies: - chalk "^1.1.3" - diff "^3.0.0" - jest-matcher-utils "^19.0.0" - pretty-format "^19.0.0" - jest-docblock@^20.0.1: version "20.0.3" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.0.3.tgz#17bea984342cc33d83c50fbe1545ea0efaa44712" -jest-file-exists@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8" - -jest-matcher-utils@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d" - dependencies: - chalk "^1.1.3" - pretty-format "^19.0.0" - -jest-message-util@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416" - dependencies: - chalk "^1.1.1" - micromatch "^2.3.11" - -jest-mock@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01" - -jest-snapshot@19.0.2: - version "19.0.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b" - dependencies: - chalk "^1.1.3" - jest-diff "^19.0.0" - jest-file-exists "^19.0.0" - jest-matcher-utils "^19.0.0" - jest-util "^19.0.2" - natural-compare "^1.4.0" - pretty-format "^19.0.0" - -jest-util@^19.0.2: - version "19.0.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41" - dependencies: - chalk "^1.1.1" - graceful-fs "^4.1.6" - jest-file-exists "^19.0.0" - jest-message-util "^19.0.0" - jest-mock "^19.0.0" - jest-validate "^19.0.2" - leven "^2.0.0" - mkdirp "^0.5.1" - -jest-validate@^19.0.2: - version "19.0.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c" - dependencies: - chalk "^1.1.1" - jest-matcher-utils "^19.0.0" - leven "^2.0.0" - pretty-format "^19.0.0" +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" js-tokens@^3.0.0: version "3.0.1" @@ -3041,10 +3028,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -leven@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -3191,6 +3174,14 @@ lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + lodash.chunk@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc" @@ -3218,10 +3209,18 @@ lodash.debounce@^4.0.3: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + lodash.difference@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + lodash.flatten@^4.2.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" @@ -3230,6 +3229,10 @@ lodash.flattendeep@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -3250,18 +3253,34 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" -lodash.merge@^4.6.0: +lodash.merge@^4.4.0, lodash.merge@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" -lodash.reduce@4.6.0: +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + +lodash.reduce@4.6.0, lodash.reduce@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3417,7 +3436,20 @@ methods@^1.0.1, methods@^1.1.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.11: +microformat-node@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/microformat-node/-/microformat-node-2.0.1.tgz#0849dcfb29f4f9251a4c6523d9a873cf45b8e942" + dependencies: + bluebird "3.4.x" + cheerio "0.22.x" + ent "^2.2.0" + microformat-shiv "^2.0.0" + +microformat-shiv@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/microformat-shiv/-/microformat-shiv-2.0.3.tgz#0350dab6da2c517f8f4cef1ab287fe6beeaec725" + +micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -3473,7 +3505,11 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: dependencies: minimist "0.0.8" -ms@0.7.1, ms@^0.7.1: +moment@^2.18.1: + version "2.18.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + +ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" @@ -3481,6 +3517,10 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-1.0.0.tgz#59adcd22edc543f7b5381862d31387b1f4bc9473" + multimatch@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" @@ -4060,12 +4100,6 @@ prettier@^1.4.2, prettier@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.4.4.tgz#a8d1447b14c9bf67e6d420dcadd10fb9a4fad65a" -pretty-format@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84" - dependencies: - ansi-styles "^3.0.0" - pretty-format@^20.0.3: version "20.0.3" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-20.0.3.tgz#020e350a560a1fe1a98dc3beb6ccffb386de8b14" @@ -4407,6 +4441,12 @@ resolve-cwd@^1.0.0: dependencies: resolve-from "^2.0.0" +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" @@ -4891,6 +4931,10 @@ trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" +trim-off-newlines@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -5026,6 +5070,10 @@ verror@1.3.6: dependencies: extsprintf "1.0.2" +well-known-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-1.0.0.tgz#73c78ae81a7726a8fa598e2880801c8b16225518" + which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" |