diff --git a/README.md b/README.md index 3a257530..a4ed243e 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,13 @@ playground for learning and exploring. * **[MD042](doc/Rules.md#md042)** *no-empty-links* - No empty links * **[MD043](doc/Rules.md#md043)** *required-headers* - Required header structure * **[MD044](doc/Rules.md#md044)** *proper-names* - Proper names should have the correct capitalization +* **[MD045](doc/Rules.md#md045)** *no-alt-text* - Images should have ALT Text attribute See [Rules.md](doc/Rules.md) for more details. ## Tags +* **accessibility** - MD045 * **atx** - MD018, MD019 * **atx_closed** - MD020, MD021 * **blank_lines** - MD012, MD022, MD031, MD032 @@ -103,6 +105,7 @@ See [Rules.md](doc/Rules.md) for more details. MD024, MD025, MD026, MD036, MD041, MD043 * **hr** - MD035 * **html** - MD033 +* **images** - MD045 * **indentation** - MD005, MD006, MD007, MD027 * **language** - MD040 * **line_length** - MD013 diff --git a/doc/Rules.md b/doc/Rules.md index b73b66e8..9845b1e6 100644 --- a/doc/Rules.md +++ b/doc/Rules.md @@ -1243,3 +1243,13 @@ the proper capitalization, specify the desired letter case in the `names` array: ] Set the `code_blocks` parameter to `false` to disable this rule for code blocks. + + + +## MD045 - Images should have ALT Text attribute + +Tags: accessibility, images + +Aliases: no-alt-text + +This rule is triggered when an image is found with no alt text. This is a key concern for accessibility. [Guidance on how to write alt text for images](https://www.phase2technology.com/blog/no-more-excuses-definitive-guide-alt-text-field). diff --git a/lib/rules.js b/lib/rules.js index 613d0800..9f2f75d8 100644 --- a/lib/rules.js +++ b/lib/rules.js @@ -1219,5 +1219,23 @@ module.exports = [ } }); } + }, + { + "name": "MD045", + "desc": "Images should have ALT Text attribute", + "tags": [ "accessibility", "images" ], + "aliases": [ "no-alt-text" ], + "regexp": null, + "func": function MD045(params, errors) { + forEachInlineChild(params, "image", function forToken(token) { + if (token.content === "") { + token.attrs.forEach(function forAttr(attr) { + if (attr[0] === "alt" && attr[1] === "") { + errors.add(token.lineNumber); + } + }); + } + }); + } } ]; diff --git a/schema/markdownlint-config-schema.json b/schema/markdownlint-config-schema.json index a4c2a81c..c7ccac35 100644 --- a/schema/markdownlint-config-schema.json +++ b/schema/markdownlint-config-schema.json @@ -956,6 +956,16 @@ }, "additionalProperties": false }, + "MD045": { + "description": "MD045/no-alt-text - Images should have ALT Text attribute", + "type": "boolean", + "default": true + }, + "no-alt-text": { + "description": "MD045/no-alt-text - Images should have ALT Text attribute", + "type": "boolean", + "default": true + }, "headers": { "description": "headers - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043", "type": "boolean", @@ -1060,6 +1070,16 @@ "description": "spelling - MD044", "type": "boolean", "default": true + }, + "images": { + "description": "images - MD045", + "type": "boolean", + "default": true + }, + "accessibility": { + "description": "accessibility - MD045", + "type": "boolean", + "default": true } }, "additionalProperties": false diff --git a/test/detailed-results-MD041-MD050.md b/test/detailed-results-MD041-MD050.md index a19515d3..ad2911ce 100644 --- a/test/detailed-results-MD041-MD050.md +++ b/test/detailed-results-MD041-MD050.md @@ -15,3 +15,11 @@ name wrong twice: MarkDownLint. A [normal](link) and an [empty one]() and a [fragment](#one). + +An image without alt text ![](image.jpg) + +![](image.jpg) + +A reference image without alt text ![][reference] + +[reference]: image.jpg "title" \ No newline at end of file diff --git a/test/detailed-results-MD041-MD050.results.json b/test/detailed-results-MD041-MD050.results.json index 2a74d2a9..9558a3d9 100644 --- a/test/detailed-results-MD041-MD050.results.json +++ b/test/detailed-results-MD041-MD050.results.json @@ -45,7 +45,7 @@ "errorRange": [25, 13] }, { - "lineNumber": 18, + "lineNumber": 25, "ruleName": "MD043", "ruleAlias": "required-headers", "ruleDescription": "Required header structure", @@ -79,5 +79,32 @@ "errorDetail": "Expected: markdownlint; Actual: MarkDownLint", "errorContext": null, "errorRange": [1, 12] + }, + { + "lineNumber": 19, + "ruleName": "MD045", + "ruleAlias": "no-alt-text", + "ruleDescription": "Images should have ALT Text attribute", + "errorDetail": null, + "errorContext": null, + "errorRange": null + }, + { + "lineNumber": 21, + "ruleName": "MD045", + "ruleAlias": "no-alt-text", + "ruleDescription": "Images should have ALT Text attribute", + "errorDetail": null, + "errorContext": null, + "errorRange": null + }, + { + "lineNumber": 23, + "ruleName": "MD045", + "ruleAlias": "no-alt-text", + "ruleDescription": "Images should have ALT Text attribute", + "errorDetail": null, + "errorContext": null, + "errorRange": null } ] \ No newline at end of file diff --git a/test/markdownlint-test.js b/test/markdownlint-test.js index 917c7cb1..26689bc7 100644 --- a/test/markdownlint-test.js +++ b/test/markdownlint-test.js @@ -965,7 +965,7 @@ module.exports.missingStringValue = function missingStringValue(test) { }; module.exports.ruleNamesUpperCase = function ruleNamesUpperCase(test) { - test.expect(40); + test.expect(41); rules.forEach(function forRule(rule) { test.equal(rule.name, rule.name.toUpperCase(), "Rule name not upper-case."); }); @@ -973,7 +973,7 @@ module.exports.ruleNamesUpperCase = function ruleNamesUpperCase(test) { }; module.exports.uniqueAliases = function uniqueAliases(test) { - test.expect(80); + test.expect(82); var tags = []; rules.forEach(function forRule(rule) { Array.prototype.push.apply(tags, rule.tags); @@ -990,7 +990,7 @@ module.exports.uniqueAliases = function uniqueAliases(test) { }; module.exports.readme = function readme(test) { - test.expect(104); + test.expect(108); var tagToRules = {}; rules.forEach(function forRule(rule) { rule.tags.forEach(function forTag(tag) { @@ -1052,7 +1052,7 @@ module.exports.readme = function readme(test) { }; module.exports.doc = function doc(test) { - test.expect(303); + test.expect(310); fs.readFile("doc/Rules.md", shared.utf8Encoding, function readFile(err, contents) { test.ifError(err); diff --git a/test/no-alt-text.md b/test/no-alt-text.md new file mode 100644 index 00000000..a05e2094 --- /dev/null +++ b/test/no-alt-text.md @@ -0,0 +1,3 @@ +# This is an image link without any alt text + +![](image.jpg) {MD045} \ No newline at end of file