git.iko.soy/typeable/remark-validate-links
on main help sign in
Add support for inspecting referenced files

* Add support for pulling in references files: This gives **validate-links** access to a references file even if it did not exist in the files given or detected by mdast. * Refactor code, tests. * Update mdast;

commit763c0d1df5739d1ce89ede34df1449628a8b5a56 authorTitus Wormer <tituswormer@gmail.com> dateSun 19 Jul 2015, 16:59 (11 years ago) parent162029c
5 files changed+381−220
index.js+243−130 package.json+1−1 readme.md+2−4 test/fixtures/example.md+2 test/index.js+133−85
index.js+243−130
@@ -8,6 +8,7 @@ var url = require('url');
88var fs = require('fs');
99var path = require('path');
1010var visit = require('mdast-util-visit');
11+var definitions = require('mdast-util-definitions');
1112var gh = require('github-url-to-object');
1213var urljoin = require('urljoin');
1314
@@ -19,110 +20,69 @@ var exists = fs.existsSync;
1920var parse = url.parse;
2021
2122/**
22− * Factory to store all markdown files, and headings.
23− *
24− * @example
25− * var gather = gatherFactory();
26− * var file = new File('# foo');
23+ * Get the `pathname` of `uri`, if applicable.
2724 *
28− * gather(file).done() // {}
29− *
30− * @return {Function}
25+ * @todo Externalise.
26+ * @param {string} uri - Reference.
27+ * @return {string?} - Pathname.
3128 */
32−function gatherFactory() {
33− var cache = {};
34− var hasHeadings = false;
35− var hasSlugs = false;
36−
37− /**
38− * Access found files and headings.
39− *
40− * @return {Object.<string, boolean>} - Map of
41− * file-paths, with `true` as their value.
42− * @throws {Error} - When headings are found, but no
43− * heading has a slug.
44− */
45− function done() {
46− if (hasHeadings && !hasSlugs) {
47− throw new Error(
48− 'Missing slugs. Use for example `mdast-slug` to generate ' +
49− 'heading IDs'
50− );
51− }
52−
53− return cache;
54− }
55−
56− /**
57− * Find headings in `file`.
58− *
59− * @property {Function} done - Access found links.
60− * @param {File} file - Virtual file.
61− * @returns {Function} - Itself.
62− */
63− function gather(file) {
64− var filePath = file.filePath();
65−
66− cache[filePath] = true;
67−
68− /*
69− * Ignore files without AST or filename.
70− */
71−
72− if (filePath && file.ast) {
73− visit(file.ast, 'heading', function (node) {
74− var id = node.attributes && node.attributes.id;
75−
76− hasHeadings = true;
77−
78− if (id) {
79− cache[filePath + '#' + id] = hasSlugs = true;
80− }
81− });
82− }
29+function getPathname(uri) {
30+ return parse(uri).pathname;
31+}
8332
84− return gather;
85− }
33+/**
34+ * Get the `hash` of `uri`, if applicable.
35+ *
36+ * @todo Externalise.
37+ * @param {string} uri - Reference.
38+ * @return {string?} - Hash.
39+ */
40+function getHash(uri) {
41+ var hash = parse(uri).hash;
8642
87− gather.done = done;
43+ return hash ? hash.slice(1) : null;
44+}
8845
89− return gather;
46+/**
47+ * Utilitity to warn `warning` for each node in `nodes`,
48+ * on `file`.
49+ *
50+ * @param {File} file - Virtual file.
51+ * @param {Array.<Node>} nodes - Offending nodes.
52+ * @param {string} warning - Message.
53+ */
54+function warnAll(file, nodes, warning) {
55+ nodes.forEach(function (node) {
56+ file.warn(warning, node);
57+ });
9058}
9159
9260/**
93− * Resolve a single `file`.
61+ * Gather references: a map of file-paths references
62+ * to be one or more nodes.
9463 *
9564 * @example
96− * var file = new File('[](foo.md)')
97− *
98− * resolve(file, {
99− * 'foo.md': true
100− * }, {});
101− * // no warnings.
65+ * gatherReferences(new File(), {});
10266 *
103− * @param {File} file - Virtual file.
104− * @param {Object} cache - Found links.
105− * @param {Object} project - GitHub project, if applicable.
67+ * @param {File} file - Set of virtual files.
68+ * @param {Object.<string, string>} project - GitHub
69+ * project, with a `user` and `repo` property
70+ * (optional).
71+ * @return {Object.<string, Array.<Node>>} exposed - Map of
72+ * file-paths (and anchors) which are referenced.
10673 */
107−function resolve(file, cache, project) {
74+function gatherReferences(file, project) {
75+ var cache = {};
10876 var filePath = file.filePath();
10977 var directory = file.directory;
11078 var ast = file.ast;
111− var definitions = {};
79+ var getDefinition = definitions(ast);
11280 var prefix = '';
11381
11482 if (project.user && project.repo) {
11583 prefix = '/' + project.user + '/' + project.repo + '/blob/';
11684 }
11785
118− /*
119− * Store link definitions.
120− */
121−
122− visit(ast, 'definition', function (node) {
123− definitions[node.identifier.toUpperCase()] = node;
124− });
125−
12686 /**
12787 * Handle new links.
12888 *
@@ -143,17 +103,16 @@ function resolve(file, cache, project) {
143103 var link = node.href;
144104 var definition;
145105 var index;
106+ var uri;
146107 var pathname;
147108 var hash;
148− var uri;
149− var warning;
150109
151110 /*
152111 * Handle link-references.
153112 */
154113
155114 if (node.identifier) {
156− definition = definitions[node.identifier.toUpperCase()];
115+ definition = getDefinition(node.identifier);
157116 link = definition && definition.link;
158117 }
159118
@@ -229,60 +188,157 @@ function resolve(file, cache, project) {
229188 hash = link.slice(index + 1);
230189 }
231190
232− if (cache[pathname] !== true) {
233− /*
234− * Ignore actually existing, but not to mdast
235− * visible files (unless the link has a hash).
236− */
191+ if (!cache[pathname]) {
192+ cache[pathname] = [];
193+ }
237194
238− if (!exists(pathname) || hash) {
239− warning = 'Link to unknown file: `' + pathname + '`';
240− }
241− } else if (cache[link] !== true) {
242− warning = 'Link to unknown heading';
195+ cache[pathname].push(node);
243196
244− if (pathname !== filePath) {
245− warning += ' in `' + pathname + '`';
197+ if (hash) {
198+ if (!cache[link]) {
199+ cache[link] = [];
246200 }
247201
248− warning += ': `' + hash + '`';
249− }
250−
251− if (warning) {
252− file.warn(warning, node);
202+ cache[link].push(node);
253203 }
254204 }
255205
256206 visit(ast, 'link', onlink);
257207 visit(ast, 'linkReference', onlink);
208+
209+ return cache;
258210}
259211
260212/**
261− * Resolve all files in `set`.
213+ * Factory to store all markdown files, and headings.
262214 *
263215 * @example
264− * var set = new FileSet();
265− * set.add(new File('[](foo.md)'));
216+ * var gather = gatherExposedFactory();
217+ * var file = new File('# foo');
266218 *
267− * resolveAll(set, {
268− * 'foo.md': true
269− * }, {});
270− * // no warnings.
219+ * gather(file).done() // {}
271220 *
272− * @param {FileSet} set - Virtual file-set.
273− * @param {Object} cache - Found links.
274− * @param {Object} project - GitHub project, if applicable.
221+ * @return {Function}
222+ */
223+function gatherExposedFactory() {
224+ var cache = {};
225+ var hasHeadings = false;
226+ var hasSlugs = false;
227+
228+ /**
229+ * Access found files and headings.
230+ *
231+ * @return {Object.<string, boolean>} - Map of
232+ * file-paths, with `true` as their value.
233+ * @throws {Error} - When headings are found, but no
234+ * heading has a slug.
235+ */
236+ function done() {
237+ if (hasHeadings && !hasSlugs) {
238+ throw new Error(
239+ 'Missing slugs. Use for example `mdast-slug` to generate ' +
240+ 'heading IDs'
241+ );
242+ }
243+
244+ return cache;
245+ }
246+
247+ /**
248+ * Find headings in `file`.
249+ *
250+ * @property {Function} done - Access found links.
251+ * @param {File} file - Virtual file.
252+ * @returns {Function} - Itself.
253+ */
254+ function gather(file) {
255+ var filePath = file.filePath();
256+
257+ /*
258+ * Ignore files without AST or filename.
259+ */
260+
261+ if (filePath && file.ast) {
262+ cache[filePath] = true;
263+
264+ visit(file.ast, 'heading', function (node) {
265+ var id = node.attributes && node.attributes.id;
266+
267+ hasHeadings = true;
268+
269+ if (id) {
270+ cache[filePath + '#' + id] = hasSlugs = true;
271+ }
272+ });
273+ }
274+
275+ return gather;
276+ }
277+
278+ gather.done = done;
279+
280+ return gather;
281+}
282+
283+/**
284+ * Check if `file` references headings or files not in
285+ * `exposed`. If `project` is given, normalizes GitHub blob
286+ * URLs.
287+ *
288+ * @example
289+ * validate({'example.md': true}, new File());
290+ *
291+ * @param {Object.<string, boolean?>} exposed - Map of
292+ * file-paths (and anchors) which can be references to.
293+ * @param {File} file - Set of virtual files.
294+ * @param {Object.<string, string>} project - GitHub
295+ * project, with a `user` and `repo` property
296+ * (optional).
275297 */
276−function resolveAll(set, cache, project) {
277− set.valueOf().forEach(function (file) {
298+function validate(exposed, file, project) {
299+ var references = file.ast ? gatherReferences(file, project) : {};
300+ var filePath = file.filePath();
301+ var reference;
302+ var nodes;
303+ var real;
304+ var hash;
305+ var pathname;
306+ var warning;
307+
308+ for (reference in references) {
309+ nodes = references[reference];
310+ real = exposed[reference];
311+ hash = getHash(reference);
312+
278313 /*
279− * Ignore failed files.
314+ * Check if files without `hash` can be linked to.
315+ * Because there’s no need to inspect those files
316+ * for headings they are not added to mdast. This
317+ * is especially useful because they might be
318+ * non-markdown files. Here we check if they exist.
280319 */
281320
282− if (!file.hasFailed()) {
283− resolve(file, cache, project);
321+ if ((real === undefined || real === null) && !hash) {
322+ real = references[reference] = exists(reference);
284323 }
285− });
324+
325+ if (!real) {
326+ if (hash) {
327+ pathname = getPathname(reference);
328+ warning = 'Link to unknown heading';
329+
330+ if (pathname !== filePath) {
331+ warning += ' in `' + pathname + '`';
332+ }
333+
334+ warning += ': `' + hash + '`';
335+ } else {
336+ warning = 'Link to unknown file: `' + reference + '`';
337+ }
338+
339+ warnAll(file, nodes, warning);
340+ }
341+ }
286342}
287343
288344/**
@@ -311,11 +367,16 @@ function completerFactory(project) {
311367 * @param {function(err?)} done - Callback.
312368 */
313369 function completer(set, done) {
314− var gather = gatherFactory();
370+ var gatherExposed = gatherExposedFactory();
371+ var exposed;
315372
316− set.valueOf().forEach(gather);
373+ set.valueOf().forEach(gatherExposed);
317374
318− resolveAll(set, gather.done(), project);
375+ exposed = gatherExposed.done();
376+
377+ set.valueOf().forEach(function (file) {
378+ validate(exposed, file, project);
379+ });
319380
320381 done();
321382 }
@@ -325,6 +386,54 @@ function completerFactory(project) {
325386 return completer;
326387}
327388
389+/**
390+ * Factory to create a transformer based on the given
391+ * project and set.
392+ *
393+ * @example
394+ * transformerFactory({}, new FileSet());
395+ *
396+ * @param {Object.<string, string>} project - GitHub
397+ * project, with a `user` and `repo` property
398+ * (optional).
399+ * @param {FileSet} fileSet - Set of virtual files.
400+ * @return {function(ast, file)}
401+ */
402+function transformerFactory(project, fileSet) {
403+ /**
404+ * Transformer. Adds references files to the set.
405+ *
406+ * @example
407+ * transformer({}, new File());
408+ *
409+ * @param {*} ast - Node.
410+ * @param {File} file - Virtual file.
411+ */
412+ function transformer(ast, file) {
413+ var references = gatherReferences(file, project);
414+ var links = [];
415+ var current = getPathname(file.filePath());
416+ var link;
417+ var pathname;
418+
419+ for (link in references) {
420+ pathname = getPathname(link);
421+
422+ if (
423+ pathname !== current &&
424+ getHash(link) &&
425+ links.indexOf(pathname) === -1
426+ ) {
427+ links.push(pathname);
428+
429+ fileSet.add(pathname);
430+ }
431+ }
432+ }
433+
434+ return transformer;
435+}
436+
328437/**
329438 * Attacher.
330439 *
@@ -334,11 +443,11 @@ function completerFactory(project) {
334443 *
335444 * @param {MDAST} mdast - Processor.
336445 * @param {Object?} options - Settings.
337− * @param {FileSet?} set - Virtual file-set.
338− * @throws {Error} - When `set` is not given (when not on
446+ * @param {FileSet?} fileSet - Virtual file-set.
447+ * @throws {Error} - When `fileSet` is not given (when not on
339448 * the CLI).
340449 */
341−function attacher(mdast, options, set) {
450+function attacher(mdast, options, fileSet) {
342451 var repo = (options || {}).repository;
343452 var pack;
344453
@@ -346,7 +455,7 @@ function attacher(mdast, options, set) {
346455 * Throw when not on the CLI.
347456 */
348457
349− if (!set) {
458+ if (!fileSet) {
350459 throw new Error('mdast-validate-links only works on the CLI');
351460 }
352461
@@ -367,14 +476,18 @@ function attacher(mdast, options, set) {
367476
368477 repo = repo ? gh(repo) : {};
369478
479+ repo = {
480+ 'user': repo.user,
481+ 'repo': repo.repo
482+ };
483+
370484 /*
371485 * Attach a `completer`.
372486 */
373487
374− set.use(completerFactory({
375− 'user': repo.user,
376− 'repo': repo.repo
377− }));
488+ fileSet.use(completerFactory(repo));
489+
490+ return transformerFactory(repo, fileSet);
378491}
379492
380493/*
package.json+1−1
@@ -35,7 +35,7 @@
3535 "istanbul": "^0.3.0",
3636 "jscs": "^1.0.0",
3737 "jscs-jsdoc": "^1.0.0",
38− "mdast": "^0.27.0-rc.1",
38+ "mdast": "^0.27.0-rc.2",
3939 "mdast-github": "^0.3.0",
4040 "mdast-lint": "^0.4.0",
4141 "mdast-yaml-config": "^0.2.0",
readme.md+2−4
@@ -1,7 +1,7 @@
11# mdast-validate-links [![Build Status](https://img.shields.io/travis/wooorm/mdast-validate-links.svg?style=flat)](https://travis-ci.org/wooorm/mdast-validate-links) [![Coverage Status](https://img.shields.io/coveralls/wooorm/mdast-validate-links.svg?style=flat)](https://coveralls.io/r/wooorm/mdast-validate-links?branch=master)
22
33> Currently, this only works with the current beta version of
4−> **mdast**: [0.27.0-rc.1](https://github.com/wooorm/mdast/blob/5f3d914fd0a59fd42bd1a2852ba17e1d1f6360db/history.md).
4+> **mdast**: [0.27.0-rc.2](https://github.com/wooorm/mdast/blob/5f3d914fd0a59fd42bd1a2852ba17e1d1f6360db/history.md).
55
66[**mdast**](https://github.com/wooorm/mdast) plug-in to validate if links to
77headings and files in markdown point to existing things.
@@ -52,7 +52,7 @@ So does this: [README](readme.md#installation).
5252Then, to run **mdast-validate-links** on `example.md` and `readme.md`:
5353
5454```bash
55−mdast -u mdast-slug -u mdast-validate-links example.md readme.md
55+mdast -u mdast-slug -u mdast-validate-links example.md
5656#
5757# Yields:
5858#
@@ -61,8 +61,6 @@ mdast -u mdast-slug -u mdast-validate-links example.md readme.md
6161# 5:27 warning Link to unknown heading in `readme.md`: `foo`
6262#
6363# ✖ 2 problems (0 errors, 2 warnings)
64−#
65−# readme.md: done.
6664```
6765
6866## Programmatic
test/fixtures/example.md+2
@@ -14,6 +14,8 @@ And this [link](./examples/example.md).
1414
1515And this [link](examples/example.md).
1616
17+This is a valid external [file](../index.js).
18+
1719This is an invalid relative file [link](https://github.com/wooorm/test/blob/master/examples/world.md).
1820
1921So is this [link](https://github.com/wooorm/test/blob/foo-bar/examples/world.md).
test/index.js+133−85
@@ -18,8 +18,8 @@ var links = require('..');
1818 */
1919
2020var std = {
21− 'out': '',
22− 'err': ''
21+ 'out': [],
22+ 'err': []
2323};
2424
2525/**
@@ -33,7 +33,7 @@ function queue(type) {
3333 * Store a bound type.
3434 */
3535 return function () {
36− std[type] += [].slice.call(arguments).join('');
36+ std[type].push([].slice.call(arguments).join(''));
3737 };
3838}
3939
@@ -54,15 +54,15 @@ function intercept() {
5454 */
5555 return function () {
5656 var current = {
57− 'out': std.out.trim(),
58− 'err': std.err.trim()
57+ 'out': std.out.join('\n').trim(),
58+ 'err': std.err.join('\n').trim()
5959 };
6060
6161 stopOut();
6262 stopErr();
6363
64− std.out = '';
65− std.err = '';
64+ std.out = [];
65+ std.err = [];
6666
6767 return current;
6868 };
@@ -95,16 +95,16 @@ describe('mdast-validate-links', function () {
9595 'color': false,
9696 'detectRC': false,
9797 'detectIgnore': false,
98− 'plugins': ['./index.js']
98+ 'plugins': [
99+ '../../../index.js'
100+ ]
99101 }, function (err) {
100102 var res = stop();
101103
102− assert.equal(res.out, '');
103−
104104 assert.equal(res.err, [
105− 'example.md',
106− ' 0:0 error Missing slugs. Use for example ' +
107− '`mdast-slug` to generate heading IDs',
105+ 'example.md: done.',
106+ ' 0:0 error Missing slugs. Use for example `mdast-slug` ' +
107+ 'to generate heading IDs',
108108 '',
109109 '✖ 1 problem (1 error, 0 warnings)'
110110 ].join('\n'));
@@ -121,22 +121,26 @@ describe('mdast-validate-links', function () {
121121 'color': false,
122122 'detectRC': false,
123123 'detectIgnore': false,
124− 'plugins': ['slug', './index.js']
124+ 'plugins': [
125+ '../../../node_modules/mdast-slug',
126+ '../../../index.js'
127+ ]
125128 }, function (err) {
126129 var res = stop();
127130
128131 assert.equal(res.out, '');
129132
130133 assert.equal(res.err, [
131− 'definitions.md',
132− ' 5:12 warning Link to unknown heading: `world`',
134+ 'FOOOO: done.',
135+ ' 0:0 error No such file or directory',
133136 '',
134− '✖ 1 problem (0 errors, 1 warning)',
137+ '✖ 1 problem (1 error, 0 warnings)',
135138 '',
136− 'FOOOO',
137− ' 0:0 error No such file or directory',
138139 '',
139− '✖ 1 problem (1 error, 0 warnings)'
140+ 'definitions.md: done.',
141+ ' 5:12 warning Link to unknown heading: `world`',
142+ '',
143+ '✖ 1 problem (0 errors, 1 warning)'
140144 ].join('\n'));
141145
142146 done(err);
@@ -151,25 +155,28 @@ describe('mdast-validate-links', function () {
151155 'color': false,
152156 'detectRC': false,
153157 'detectIgnore': false,
154− 'plugins': ['slug', './index.js']
158+ 'plugins': [
159+ '../../../node_modules/mdast-slug',
160+ '../../../index.js'
161+ ]
155162 }, function (err) {
156163 var res = stop();
157164
158165 assert.equal(res.err, [
159− 'example.md',
166+ 'example.md: done.',
160167 ' 5:37 warning Link to unknown heading: `world`',
161− ' 21:10 warning Link to unknown file: `examples/world.md`',
162168 ' 23:10 warning Link to unknown file: `examples/world.md`',
163− ' 27:8 warning Link to unknown file: ' +
164− '`examples/example.md`',
165− ' 29:8 warning Link to unknown file: ' +
166− '`examples/example.md`',
167− ' 35:10 warning Link to unknown file: ' +
168− '`examples/example.md`',
169− ' 37:10 warning Link to unknown file: ' +
170− '`examples/example.md`',
171− ' 43:10 warning Link to unknown file: `examples/world.md`',
169+ ' 25:10 warning Link to unknown file: `examples/world.md`',
172170 ' 45:10 warning Link to unknown file: `examples/world.md`',
171+ ' 47:10 warning Link to unknown file: `examples/world.md`',
172+ ' 37:10 warning Link to unknown heading in ' +
173+ '`examples/example.md`: `world`',
174+ ' 39:10 warning Link to unknown heading in ' +
175+ '`examples/example.md`: `world`',
176+ ' 45:10 warning Link to unknown heading in ' +
177+ '`examples/world.md`: `hello`',
178+ ' 47:10 warning Link to unknown heading in ' +
179+ '`examples/world.md`: `hello`',
173180 '',
174181 '✖ 9 problems (0 errors, 9 warnings)'
175182 ].join('\n'));
@@ -189,34 +196,44 @@ describe('mdast-validate-links', function () {
189196 'color': false,
190197 'detectRC': false,
191198 'detectIgnore': false,
192− 'plugins': ['slug', './index.js']
199+ 'plugins': [
200+ '../../../node_modules/mdast-slug',
201+ '../../../index.js'
202+ ]
193203 }, function (err) {
194204 var res = stop();
195205
196206 assert.equal(res.out, '');
197207
198208 assert.equal(res.err, [
199− 'example.md',
209+ 'example.md: done.',
200210 ' 5:37 warning Link to unknown heading: `world`',
201− ' 21:10 warning Link to unknown file: `examples/world.md`',
202211 ' 23:10 warning Link to unknown file: `examples/world.md`',
203− ' 35:10 warning Link to unknown heading in ' +
204− '`examples/example.md`: `world`',
212+ ' 25:10 warning Link to unknown file: `examples/world.md`',
213+ ' 45:10 warning Link to unknown file: `examples/world.md`',
214+ ' 47:10 warning Link to unknown file: `examples/world.md`',
205215 ' 37:10 warning Link to unknown heading in ' +
206216 '`examples/example.md`: `world`',
207− ' 43:10 warning Link to unknown file: `examples/world.md`',
208− ' 45:10 warning Link to unknown file: `examples/world.md`',
217+ ' 39:10 warning Link to unknown heading in ' +
218+ '`examples/example.md`: `world`',
219+ ' 45:10 warning Link to unknown heading in ' +
220+ '`examples/world.md`: `hello`',
221+ ' 47:10 warning Link to unknown heading in ' +
222+ '`examples/world.md`: `hello`',
223+ '',
224+ '✖ 9 problems (0 errors, 9 warnings)',
209225 '',
210− '✖ 7 problems (0 errors, 7 warnings)',
211226 '',
212− 'examples/example.md',
227+ 'examples/example.md: done.',
213228 ' 5:37 warning Link to unknown heading: `world`',
214229 ' 19:10 warning Link to unknown file: `world.md`',
230+ ' 35:10 warning Link to unknown file: `world.md`',
215231 ' 29:10 warning Link to unknown heading in ' +
216232 '`example.md`: `world`',
217− ' 35:10 warning Link to unknown file: `world.md`',
233+ ' 35:10 warning Link to unknown heading in ' +
234+ '`world.md`: `hello`',
218235 '',
219− '✖ 4 problems (0 errors, 4 warnings)'
236+ '✖ 5 problems (0 errors, 5 warnings)'
220237 ].join('\n'));
221238
222239 done(err);
@@ -231,12 +248,15 @@ describe('mdast-validate-links', function () {
231248 'color': false,
232249 'detectRC': false,
233250 'detectIgnore': false,
234− 'plugins': ['slug', './index.js']
251+ 'plugins': [
252+ '../../../node_modules/mdast-slug',
253+ '../../../index.js'
254+ ]
235255 }, function (err) {
236256 var res = stop();
237257
238258 assert.equal(res.err, [
239− 'definitions.md',
259+ 'definitions.md: done.',
240260 ' 5:12 warning Link to unknown heading: `world`',
241261 '',
242262 '✖ 1 problem (0 errors, 1 warning)'
@@ -258,8 +278,8 @@ describe('mdast-validate-links', function () {
258278 'detectRC': false,
259279 'detectIgnore': false,
260280 'plugins': {
261− 'slug': null,
262− './index.js': {
281+ '../../../node_modules/mdast-slug': null,
282+ '../../../index.js': {
263283 'repository': 'wooorm/test'
264284 }
265285 }
@@ -269,43 +289,58 @@ describe('mdast-validate-links', function () {
269289 assert.equal(res.out, '');
270290
271291 assert.equal(res.err, [
272− 'example.md',
292+ 'example.md: done.',
273293 ' 5:37 warning Link to unknown heading: `world`',
274− ' 17:34 warning Link to unknown file: `examples/world.md`',
275− ' 19:12 warning Link to unknown file: `examples/world.md`',
276− ' 21:10 warning Link to unknown file: `examples/world.md`',
294+ ' 19:34 warning Link to unknown file: `examples/world.md`',
295+ ' 21:12 warning Link to unknown file: `examples/world.md`',
277296 ' 23:10 warning Link to unknown file: `examples/world.md`',
278− ' 35:10 warning Link to unknown heading in ' +
279− '`examples/example.md`: `world`',
297+ ' 25:10 warning Link to unknown file: `examples/world.md`',
298+ ' 45:10 warning Link to unknown file: `examples/world.md`',
299+ ' 47:10 warning Link to unknown file: `examples/world.md`',
300+ ' 49:10 warning Link to unknown file: `examples/world.md`',
301+ ' 51:10 warning Link to unknown file: `examples/world.md`',
280302 ' 37:10 warning Link to unknown heading in ' +
281303 '`examples/example.md`: `world`',
282304 ' 39:10 warning Link to unknown heading in ' +
283305 '`examples/example.md`: `world`',
284306 ' 41:10 warning Link to unknown heading in ' +
285307 '`examples/example.md`: `world`',
286− ' 43:10 warning Link to unknown file: `examples/world.md`',
287− ' 45:10 warning Link to unknown file: `examples/world.md`',
288− ' 47:10 warning Link to unknown file: `examples/world.md`',
289− ' 49:10 warning Link to unknown file: `examples/world.md`',
308+ ' 43:10 warning Link to unknown heading in ' +
309+ '`examples/example.md`: `world`',
310+ ' 45:10 warning Link to unknown heading in ' +
311+ '`examples/world.md`: `hello`',
312+ ' 47:10 warning Link to unknown heading in ' +
313+ '`examples/world.md`: `hello`',
314+ ' 49:10 warning Link to unknown heading in ' +
315+ '`examples/world.md`: `hello`',
316+ ' 51:10 warning Link to unknown heading in ' +
317+ '`examples/world.md`: `hello`',
290318 '',
291− '✖ 13 problems (0 errors, 13 warnings)',
319+ '✖ 17 problems (0 errors, 17 warnings)',
292320 '',
293− 'examples/example.md',
321+ '',
322+ 'examples/example.md: done.',
294323 ' 5:37 warning Link to unknown heading: `world`',
295324 ' 15:34 warning Link to unknown file: `world.md`',
296325 ' 17:12 warning Link to unknown file: `world.md`',
297326 ' 19:10 warning Link to unknown file: `world.md`',
327+ ' 35:10 warning Link to unknown file: `world.md`',
328+ ' 37:10 warning Link to unknown file: `world.md`',
329+ ' 39:10 warning Link to unknown file: `world.md`',
298330 ' 29:10 warning Link to unknown heading in ' +
299331 '`example.md`: `world`',
300332 ' 31:10 warning Link to unknown heading in ' +
301333 '`example.md`: `world`',
302334 ' 33:10 warning Link to unknown heading in ' +
303335 '`example.md`: `world`',
304− ' 35:10 warning Link to unknown file: `world.md`',
305− ' 37:10 warning Link to unknown file: `world.md`',
306− ' 39:10 warning Link to unknown file: `world.md`',
336+ ' 35:10 warning Link to unknown heading in ' +
337+ '`world.md`: `hello`',
338+ ' 37:10 warning Link to unknown heading in ' +
339+ '`world.md`: `hello`',
340+ ' 39:10 warning Link to unknown heading in ' +
341+ '`world.md`: `hello`',
307342 '',
308− '✖ 10 problems (0 errors, 10 warnings)'
343+ '✖ 13 problems (0 errors, 13 warnings)'
309344 ].join('\n'));
310345
311346 done(err);
@@ -327,55 +362,68 @@ describe('mdast-validate-links', function () {
327362 'color': false,
328363 'detectRC': false,
329364 'detectIgnore': false,
330− 'plugins': [
331− '../../../node_modules/mdast-slug',
332− '../../../index.js'
333− ]
365+ 'plugins': [
366+ '../../../node_modules/mdast-slug',
367+ '../../../index.js'
368+ ]
334369 }, function (err) {
335370 var res = stop();
336371
337372 fs.unlinkSync('./package.json');
338373
339− assert.equal(res.out, '');
340−
341374 assert.equal(res.err, [
342− 'example.md',
375+ 'example.md: done.',
343376 ' 5:37 warning Link to unknown heading: `world`',
344− ' 17:34 warning Link to unknown file: `examples/world.md`',
345− ' 19:12 warning Link to unknown file: `examples/world.md`',
346− ' 21:10 warning Link to unknown file: `examples/world.md`',
377+ ' 19:34 warning Link to unknown file: `examples/world.md`',
378+ ' 21:12 warning Link to unknown file: `examples/world.md`',
347379 ' 23:10 warning Link to unknown file: `examples/world.md`',
348− ' 35:10 warning Link to unknown heading in ' +
349− '`examples/example.md`: `world`',
380+ ' 25:10 warning Link to unknown file: `examples/world.md`',
381+ ' 45:10 warning Link to unknown file: `examples/world.md`',
382+ ' 47:10 warning Link to unknown file: `examples/world.md`',
383+ ' 49:10 warning Link to unknown file: `examples/world.md`',
384+ ' 51:10 warning Link to unknown file: `examples/world.md`',
350385 ' 37:10 warning Link to unknown heading in ' +
351386 '`examples/example.md`: `world`',
352387 ' 39:10 warning Link to unknown heading in ' +
353388 '`examples/example.md`: `world`',
354389 ' 41:10 warning Link to unknown heading in ' +
355390 '`examples/example.md`: `world`',
356− ' 43:10 warning Link to unknown file: `examples/world.md`',
357− ' 45:10 warning Link to unknown file: `examples/world.md`',
358− ' 47:10 warning Link to unknown file: `examples/world.md`',
359− ' 49:10 warning Link to unknown file: `examples/world.md`',
391+ ' 43:10 warning Link to unknown heading in ' +
392+ '`examples/example.md`: `world`',
393+ ' 45:10 warning Link to unknown heading in ' +
394+ '`examples/world.md`: `hello`',
395+ ' 47:10 warning Link to unknown heading in ' +
396+ '`examples/world.md`: `hello`',
397+ ' 49:10 warning Link to unknown heading in ' +
398+ '`examples/world.md`: `hello`',
399+ ' 51:10 warning Link to unknown heading in ' +
400+ '`examples/world.md`: `hello`',
360401 '',
361− '✖ 13 problems (0 errors, 13 warnings)',
402+ '✖ 17 problems (0 errors, 17 warnings)',
362403 '',
363− 'examples/example.md',
404+ '',
405+ 'examples/example.md: done.',
364406 ' 5:37 warning Link to unknown heading: `world`',
365407 ' 15:34 warning Link to unknown file: `world.md`',
366408 ' 17:12 warning Link to unknown file: `world.md`',
367409 ' 19:10 warning Link to unknown file: `world.md`',
410+ ' 35:10 warning Link to unknown file: `world.md`',
411+ ' 37:10 warning Link to unknown file: `world.md`',
412+ ' 39:10 warning Link to unknown file: `world.md`',
368413 ' 29:10 warning Link to unknown heading in ' +
369414 '`example.md`: `world`',
370415 ' 31:10 warning Link to unknown heading in ' +
371416 '`example.md`: `world`',
372417 ' 33:10 warning Link to unknown heading in ' +
373418 '`example.md`: `world`',
374− ' 35:10 warning Link to unknown file: `world.md`',
375− ' 37:10 warning Link to unknown file: `world.md`',
376− ' 39:10 warning Link to unknown file: `world.md`',
419+ ' 35:10 warning Link to unknown heading in ' +
420+ '`world.md`: `hello`',
421+ ' 37:10 warning Link to unknown heading in ' +
422+ '`world.md`: `hello`',
423+ ' 39:10 warning Link to unknown heading in ' +
424+ '`world.md`: `hello`',
377425 '',
378− '✖ 10 problems (0 errors, 10 warnings)'
426+ '✖ 13 problems (0 errors, 13 warnings)'
379427 ].join('\n'));
380428
381429 done(err);