mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-17 14:30:12 +01:00
Add MD042 no-empty-links "No empty links" (fixes #24).
This commit is contained in:
parent
efe9c9e73c
commit
2612a96ae8
7 changed files with 95 additions and 17 deletions
|
|
@ -163,7 +163,7 @@
|
||||||
"max-len": [2, 80, 4],
|
"max-len": [2, 80, 4],
|
||||||
"max-nested-callbacks": [2, 3],
|
"max-nested-callbacks": [2, 3],
|
||||||
"max-params": [2, 5],
|
"max-params": [2, 5],
|
||||||
"max-statements": [2, 20],
|
"max-statements": [2, 21],
|
||||||
"new-cap": 2,
|
"new-cap": 2,
|
||||||
"new-parens": 2,
|
"new-parens": 2,
|
||||||
"newline-after-var": 0,
|
"newline-after-var": 0,
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ playground for learning and exploring.
|
||||||
* **MD039** *no-space-in-links* - Spaces inside link text
|
* **MD039** *no-space-in-links* - Spaces inside link text
|
||||||
* **MD040** *fenced-code-language* - Fenced code blocks should have a language specified
|
* **MD040** *fenced-code-language* - Fenced code blocks should have a language specified
|
||||||
* **MD041** *first-line-h1* - First line in file should be a top level header
|
* **MD041** *first-line-h1* - First line in file should be a top level header
|
||||||
|
* **MD042** *no-empty-links* - No empty links
|
||||||
|
|
||||||
See [Rules.md](doc/Rules.md) for more details.
|
See [Rules.md](doc/Rules.md) for more details.
|
||||||
|
|
||||||
|
|
@ -101,7 +102,7 @@ See [Rules.md](doc/Rules.md) for more details.
|
||||||
* **indentation** - MD005, MD006, MD007, MD027
|
* **indentation** - MD005, MD006, MD007, MD027
|
||||||
* **language** - MD040
|
* **language** - MD040
|
||||||
* **line_length** - MD013
|
* **line_length** - MD013
|
||||||
* **links** - MD011, MD034, MD039
|
* **links** - MD011, MD034, MD039, MD042
|
||||||
* **ol** - MD029, MD030, MD032
|
* **ol** - MD029, MD030, MD032
|
||||||
* **spaces** - MD018, MD019, MD020, MD021, MD023
|
* **spaces** - MD018, MD019, MD020, MD021, MD023
|
||||||
* **ul** - MD004, MD005, MD006, MD007, MD030, MD032
|
* **ul** - MD004, MD005, MD006, MD007, MD030, MD032
|
||||||
|
|
|
||||||
22
doc/Rules.md
22
doc/Rules.md
|
|
@ -1004,3 +1004,25 @@ To fix this, add a header to the top of your file:
|
||||||
|
|
||||||
This is a file with a top level header
|
This is a file with a top level header
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MD042 - No empty links
|
||||||
|
|
||||||
|
Tags: links
|
||||||
|
|
||||||
|
Aliases: no-empty-links
|
||||||
|
|
||||||
|
This rule is triggered when an empty link is encountered:
|
||||||
|
|
||||||
|
[an empty link]()
|
||||||
|
|
||||||
|
To fix the violation, provide a destination for the link:
|
||||||
|
|
||||||
|
[a valid link](https://example.com/)
|
||||||
|
|
||||||
|
Empty fragments will trigger this rule:
|
||||||
|
|
||||||
|
[an empty fragment](#)
|
||||||
|
|
||||||
|
But non-empty fragments will not:
|
||||||
|
|
||||||
|
[a valid fragment](#fragment)
|
||||||
|
|
|
||||||
16
lib/rules.js
16
lib/rules.js
|
|
@ -891,5 +891,21 @@ module.exports = [
|
||||||
errors.push(1);
|
errors.push(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "MD042",
|
||||||
|
"desc": "No empty links",
|
||||||
|
"tags": [ "links" ],
|
||||||
|
"aliases": [ "no-empty-links" ],
|
||||||
|
"func": function MD034(params, errors) {
|
||||||
|
forEachInlineChild(params, "link_open", function forToken(token) {
|
||||||
|
token.attrs.forEach(function forAttr(attr) {
|
||||||
|
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
||||||
|
errors.push(token.lineNumber);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,5 @@ Code `with ` space {MD038}
|
||||||
```
|
```
|
||||||
code fence without language {MD040:73}
|
code fence without language {MD040:73}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[empty link]() {MD042}
|
||||||
|
|
|
||||||
31
test/empty-links.md
Normal file
31
test/empty-links.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Heading
|
||||||
|
|
||||||
|
## Empty links
|
||||||
|
|
||||||
|
[text]() {MD042}
|
||||||
|
|
||||||
|
[text](<>) {MD042}
|
||||||
|
|
||||||
|
[text](#) {MD042}
|
||||||
|
|
||||||
|
[text][frag] {MD042}
|
||||||
|
|
||||||
|
[frag]: #
|
||||||
|
|
||||||
|
## Non-empty links
|
||||||
|
|
||||||
|
[text](link)
|
||||||
|
|
||||||
|
[text](link "title")
|
||||||
|
|
||||||
|
[text](<link>)
|
||||||
|
|
||||||
|
[text](#frag)
|
||||||
|
|
||||||
|
[text][ref]
|
||||||
|
|
||||||
|
[ref]: link
|
||||||
|
|
||||||
|
[text]
|
||||||
|
|
||||||
|
[text]: link
|
||||||
|
|
@ -543,7 +543,8 @@ module.exports.styleAll = function styleAll(test) {
|
||||||
"MD038": [ 69 ],
|
"MD038": [ 69 ],
|
||||||
"MD039": [ 71 ],
|
"MD039": [ 71 ],
|
||||||
"MD040": [ 73 ],
|
"MD040": [ 73 ],
|
||||||
"MD041": [ 1 ]
|
"MD041": [ 1 ],
|
||||||
|
"MD042": [ 77 ]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
||||||
|
|
@ -580,7 +581,8 @@ module.exports.styleRelaxed = function styleRelaxed(test) {
|
||||||
"MD031": [ 50 ],
|
"MD031": [ 50 ],
|
||||||
"MD032": [ 51 ],
|
"MD032": [ 51 ],
|
||||||
"MD035": [ 61 ],
|
"MD035": [ 61 ],
|
||||||
"MD036": [ 65 ]
|
"MD036": [ 65 ],
|
||||||
|
"MD042": [ 77 ]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
||||||
|
|
@ -731,7 +733,7 @@ module.exports.missingStringValue = function missingStringValue(test) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.ruleNamesUpperCase = function ruleNamesUpperCase(test) {
|
module.exports.ruleNamesUpperCase = function ruleNamesUpperCase(test) {
|
||||||
test.expect(37);
|
test.expect(38);
|
||||||
rules.forEach(function forRule(rule) {
|
rules.forEach(function forRule(rule) {
|
||||||
test.equal(rule.name, rule.name.toUpperCase(), "Rule name not upper-case.");
|
test.equal(rule.name, rule.name.toUpperCase(), "Rule name not upper-case.");
|
||||||
});
|
});
|
||||||
|
|
@ -739,7 +741,7 @@ module.exports.ruleNamesUpperCase = function ruleNamesUpperCase(test) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.uniqueAliases = function uniqueAliases(test) {
|
module.exports.uniqueAliases = function uniqueAliases(test) {
|
||||||
test.expect(74);
|
test.expect(76);
|
||||||
var tags = [];
|
var tags = [];
|
||||||
rules.forEach(function forRule(rule) {
|
rules.forEach(function forRule(rule) {
|
||||||
Array.prototype.push.apply(tags, rule.tags);
|
Array.prototype.push.apply(tags, rule.tags);
|
||||||
|
|
@ -756,7 +758,7 @@ module.exports.uniqueAliases = function uniqueAliases(test) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.readme = function readme(test) {
|
module.exports.readme = function readme(test) {
|
||||||
test.expect(97);
|
test.expect(99);
|
||||||
var tagToRules = {};
|
var tagToRules = {};
|
||||||
rules.forEach(function forRule(rule) {
|
rules.forEach(function forRule(rule) {
|
||||||
rule.tags.forEach(function forTag(tag) {
|
rule.tags.forEach(function forTag(tag) {
|
||||||
|
|
@ -817,7 +819,7 @@ module.exports.readme = function readme(test) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.doc = function doc(test) {
|
module.exports.doc = function doc(test) {
|
||||||
test.expect(274);
|
test.expect(281);
|
||||||
fs.readFile("doc/Rules.md", shared.utf8Encoding,
|
fs.readFile("doc/Rules.md", shared.utf8Encoding,
|
||||||
function readFile(err, contents) {
|
function readFile(err, contents) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
|
|
@ -848,6 +850,7 @@ module.exports.doc = function doc(test) {
|
||||||
ruleHasTags = ruleHasAliases = false;
|
ruleHasTags = ruleHasAliases = false;
|
||||||
test.ok(rule,
|
test.ok(rule,
|
||||||
"Missing rule implementation for " + token.content + ".");
|
"Missing rule implementation for " + token.content + ".");
|
||||||
|
if (rule) {
|
||||||
test.equal(token.content, rule.name + " - " + rule.desc,
|
test.equal(token.content, rule.name + " - " + rule.desc,
|
||||||
"Rule mismatch.");
|
"Rule mismatch.");
|
||||||
ruleUsesParams = rule.func.toString()
|
ruleUsesParams = rule.func.toString()
|
||||||
|
|
@ -857,6 +860,7 @@ module.exports.doc = function doc(test) {
|
||||||
return use.split(".").pop();
|
return use.split(".").pop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (/^Tags: /.test(token.content) && rule) {
|
} else if (/^Tags: /.test(token.content) && rule) {
|
||||||
test.deepEqual(token.content.split(tagAliasParameterRe).slice(1),
|
test.deepEqual(token.content.split(tagAliasParameterRe).slice(1),
|
||||||
rule.tags, "Tag mismatch for rule " + rule.name + ".");
|
rule.tags, "Tag mismatch for rule " + rule.name + ".");
|
||||||
|
|
@ -882,7 +886,9 @@ module.exports.doc = function doc(test) {
|
||||||
var ruleLeft = rulesLeft.shift();
|
var ruleLeft = rulesLeft.shift();
|
||||||
test.ok(!ruleLeft,
|
test.ok(!ruleLeft,
|
||||||
"Missing rule documentation for " + (ruleLeft || {}).name + ".");
|
"Missing rule documentation for " + (ruleLeft || {}).name + ".");
|
||||||
|
if (rule) {
|
||||||
testTagsAliasesParams();
|
testTagsAliasesParams();
|
||||||
|
}
|
||||||
test.done();
|
test.done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue