git.iko.soy/typeable/remark-validate-links
on main help sign in
Add suggestions for similar references on failure
commitddabfe2c5f2a65605b2541bfb7c108cb1abe115a authorTitus Wormer <tituswormer@gmail.com> dateSun 26 Jul 2015, 16:03 (11 years ago) parent3f8c130
4 files changed+81−1
index.js+44−1 package.json+1 test/fixtures/suggestions.md+7 test/index.js+29
index.js+44−1
@@ -7,6 +7,7 @@
77var url = require('url');
88var fs = require('fs');
99var path = require('path');
10+var propose = require('propose');
1011var visit = require('mdast-util-visit');
1112var definitions = require('mdast-util-definitions');
1213var gh = require('github-url-to-object');
@@ -43,6 +44,34 @@ function getHash(uri) {
4344 return hash ? hash.slice(1) : null;
4445}
4546
47+function getClosest(pathname, references) {
48+ var hash = getHash(pathname);
49+ var base = getPathname(pathname);
50+ var dictionary = [];
51+ var reference;
52+ var subhash;
53+ var subbase;
54+
55+ for (reference in references) {
56+ subbase = getPathname(reference);
57+ subhash = getHash(reference);
58+
59+ if (getPathname(reference) === base) {
60+ if (subhash && hash) {
61+ dictionary.push(subhash);
62+ }
63+ } else {
64+ if (!subhash && !hash) {
65+ dictionary.push(subbase);
66+ }
67+ }
68+ }
69+
70+ return propose(hash ? hash : base, dictionary, {
71+ 'threshold': 0.7
72+ });
73+}
74+
4675/**
4776 * Utilitity to warn `warning` for each node in `nodes`,
4877 * on `file`.
@@ -76,9 +105,16 @@ function gatherReferences(file, project) {
76105 var filePath = file.filePath();
77106 var directory = file.directory;
78107 var ast = file.ast;
79− var getDefinition = definitions(ast);
108+ var getDefinition;
80109 var prefix = '';
81110
111+ /* istanbul ignore next - next release of mdast */
112+ if (!ast) {
113+ ast = file.namespace('mdast').ast;
114+ }
115+
116+ getDefinition = definitions(ast);
117+
82118 if (project.user && project.repo) {
83119 prefix = '/' + project.user + '/' + project.repo + '/blob/';
84120 }
@@ -304,6 +340,7 @@ function validate(exposed, file, project) {
304340 var hash;
305341 var pathname;
306342 var warning;
343+ var suggestion;
307344
308345 for (reference in references) {
309346 nodes = references[reference];
@@ -336,6 +373,12 @@ function validate(exposed, file, project) {
336373 warning = 'Link to unknown file: `' + reference + '`';
337374 }
338375
376+ suggestion = getClosest(reference, exposed);
377+
378+ if (suggestion) {
379+ warning += '. Did you mean `' + suggestion + '`';
380+ }
381+
339382 warnAll(file, nodes, warning);
340383 }
341384 }
package.json+1
@@ -16,6 +16,7 @@
1616 "mdast-slug": "^0.1.1",
1717 "mdast-util-definitions": "^0.1.0",
1818 "mdast-util-visit": "^0.1.1",
19+ "propose": "0.0.5",
1920 "urljoin": "^0.1.5"
2021 },
2122 "repository": {
test/fixtures/suggestions.mdnew file+7
@@ -0,0 +1,7 @@
1+# Hello
2+
3+This should suggest: [link](#helloo).
4+
5+## Files
6+
7+So should this: [k](example.md#fiiiles).
test/index.js+29
@@ -429,4 +429,33 @@ describe('mdast-validate-links', function () {
429429 done(err);
430430 });
431431 });
432+
433+ it('should suggest similar links', function (done) {
434+ var stop = intercept();
435+
436+ cli({
437+ 'files': ['suggestions.md'],
438+ 'color': false,
439+ 'detectRC': false,
440+ 'detectIgnore': false,
441+ 'plugins': [
442+ '../../../node_modules/mdast-slug',
443+ '../../../index.js'
444+ ]
445+ }, function (err) {
446+ var res = stop();
447+
448+ assert.equal(res.err, [
449+ 'suggestions.md: done.',
450+ ' 3:22 warning Link to unknown heading: ' +
451+ '`helloo`. Did you mean `hello`',
452+ ' 7:17 warning Link to unknown heading in `example.md`: ' +
453+ '`fiiiles`. Did you mean `files`',
454+ '',
455+ '✖ 2 problems (0 errors, 2 warnings)'
456+ ].join('\n'));
457+
458+ done(err);
459+ });
460+ });
432461});