This commit is contained in:
Josh Goldberg 2018-06-22 16:30:55 +00:00 committed by GitHub
commit cf0e991598
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 140 additions and 43 deletions

View file

@ -16,19 +16,20 @@ npm install markdownlint --save-dev
## Overview ## Overview
The [Markdown](https://en.wikipedia.org/wiki/Markdown) markup language is The [Markdown](https://en.wikipedia.org/wiki/Markdown) markup language is
designed to be easy to read, write, and understand. It succeeds - and its designed to be easy to read, write, and understand.
flexibility is both a benefit and a drawback. Many styles are possible, so It succeeds - and its flexibility is both a benefit and a drawback.
formatting can be inconsistent. Some constructs don't work well in all Many styles are possible, so formatting can be inconsistent.
parsers and should be avoided. The [CommonMark](http://commonmark.org/) Some constructs don't work well in all parsers and should be avoided.
specification standardizes parsers - but not authors. The [CommonMark](http://commonmark.org/) specification standardizes parsers
- but not authors.
`markdownlint` is a [static analysis](https://en.wikipedia.org/wiki/Static_program_analysis) `markdownlint` is a [static analysis](https://en.wikipedia.org/wiki/Static_program_analysis)
tool for [Node.js](https://nodejs.org/) and [io.js](https://iojs.org/) with a tool for [Node.js](https://nodejs.org/) and [io.js](https://iojs.org/) with a
library of rules to enforce standards and consistency for Markdown files. It library of rules to enforce standards and consistency for Markdown files.
was inspired by - and heavily influenced by - Mark Harrison's It was inspired by - and heavily influenced by - Mark Harrison's
[markdownlint](https://github.com/markdownlint/markdownlint) for [markdownlint](https://github.com/markdownlint/markdownlint) for
[Ruby](https://www.ruby-lang.org/). The initial rules, rule documentation, and [Ruby](https://www.ruby-lang.org/).
test cases came directly from that project. The initial rules, rule documentation, and test cases came directly from that project.
### Related ### Related
@ -87,6 +88,7 @@ playground for learning and exploring.
* **[MD043](doc/Rules.md#md043)** *required-headings/required-headers* - Required heading structure * **[MD043](doc/Rules.md#md043)** *required-headings/required-headers* - Required heading structure
* **[MD044](doc/Rules.md#md044)** *proper-names* - Proper names should have the correct capitalization * **[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 alternate text (alt text) * **[MD045](doc/Rules.md#md045)** *no-alt-text* - Images should have alternate text (alt text)
* **[MD046](doc/Rules.md#md046)** *sentences-per-line* - Each sentence should be on its own line
See [Rules.md](doc/Rules.md) for more details. See [Rules.md](doc/Rules.md) for more details.
@ -116,10 +118,10 @@ Tags group related rules and can be used to enable/disable multiple rules at onc
* **images** - MD045 * **images** - MD045
* **indentation** - MD005, MD006, MD007, MD027 * **indentation** - MD005, MD006, MD007, MD027
* **language** - MD040 * **language** - MD040
* **line_length** - MD013 * **line_length** - MD013, MD046
* **links** - MD011, MD034, MD039, MD042 * **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, MD046
* **spelling** - MD044 * **spelling** - MD044
* **ul** - MD004, MD005, MD006, MD007, MD030, MD032 * **ul** - MD004, MD005, MD006, MD007, MD030, MD032
* **url** - MD034 * **url** - MD034
@ -134,9 +136,9 @@ Two kinds of text are ignored:
* [Front matter](https://jekyllrb.com/docs/frontmatter/) (see `options.frontMatter` below) * [Front matter](https://jekyllrb.com/docs/frontmatter/) (see `options.frontMatter` below)
Rules can be enabled, disabled, and configured via `options.config` (described Rules can be enabled, disabled, and configured via `options.config` (described
below) to define the expected behavior for a set of inputs. To enable or disable below) to define the expected behavior for a set of inputs.
rules within a file, add one of these markers to the appropriate place (HTML To enable or disable rules within a file, add one of these markers to the
comments don't appear in the final markup): appropriate place (HTML comments don't appear in the final markup):
* Disable all rules: `<!-- markdownlint-disable -->` * Disable all rules: `<!-- markdownlint-disable -->`
* Enable all rules: `<!-- markdownlint-enable -->` * Enable all rules: `<!-- markdownlint-enable -->`
@ -199,8 +201,8 @@ Type: `Array` of `Object`
List of custom rules to include with the default rule set for linting. List of custom rules to include with the default rule set for linting.
Each array element should define a rule. Rules are typically exported by another Each array element should define a rule.
package, but can be defined inline. Rules are typically exported by another package, but can be defined inline.
Example: Example:
@ -252,13 +254,15 @@ Configures the rules to use.
Object keys are rule names or aliases and values are the rule's configuration. Object keys are rule names or aliases and values are the rule's configuration.
The value `false` disables a rule, `true` enables its default configuration, The value `false` disables a rule, `true` enables its default configuration,
and passing an object customizes its settings. Setting the special `default` and passing an object customizes its settings.
rule to `true` or `false` includes/excludes all rules by default. Enabling or Setting the special `default` rule to `true` or `false` includes/excludes all
disabling a tag name (ex: `whitespace`) affects all rules having that tag. rules by default.
Enabling or disabling a tag name (ex: `whitespace`) affects all rules having
that tag.
The `default` rule is applied first, then keys are processed in order from top The `default` rule is applied first, then keys are processed in order from top
to bottom with later values overriding earlier ones. Keys (including rule names, to bottom with later values overriding earlier ones.
aliases, tags, and `default`) are not case-sensitive. Keys (including rule names, aliases, tags, and `default`) are not case-sensitive.
Example: Example:
@ -289,8 +293,8 @@ See the [style](style) directory for more samples.
See [markdownlint-config-schema.json](schema/markdownlint-config-schema.json) See [markdownlint-config-schema.json](schema/markdownlint-config-schema.json)
for the [JSON Schema](http://json-schema.org/) of the `options.config` object. for the [JSON Schema](http://json-schema.org/) of the `options.config` object.
For more advanced scenarios, styles can reference and extend other styles. The For more advanced scenarios, styles can reference and extend other styles.
`readConfig` and `readConfigSync` functions can be used to read such styles. The `readConfig` and `readConfigSync` functions can be used to read such styles.
For example, assuming a `base.json` configuration file: For example, assuming a `base.json` configuration file:
@ -336,8 +340,9 @@ Matches any [front matter](https://jekyllrb.com/docs/frontmatter/) found at the
beginning of a file. beginning of a file.
Some Markdown content begins with metadata; the default `RegExp` for this option Some Markdown content begins with metadata; the default `RegExp` for this option
ignores common forms of "front matter". To match differently, specify a custom ignores common forms of "front matter".
`RegExp` or use the value `null` to disable the feature. To match differently, specify a custom `RegExp` or use the value `null` to
disable the feature.
The default value: The default value:
@ -365,8 +370,8 @@ Disables the use of HTML comments like `<!-- markdownlint-disable -->` to toggle
rules within the body of Markdown content. rules within the body of Markdown content.
By default, properly-formatted inline comments can be used to create exceptions By default, properly-formatted inline comments can be used to create exceptions
for parts of a document. Setting `noInlineConfig` to `true` ignores all such for parts of a document.
comments. Setting `noInlineConfig` to `true` ignores all such comments.
##### options.resultVersion ##### options.resultVersion
@ -376,15 +381,18 @@ Specifies which version of the `result` object to return (see the "Usage" sectio
below for examples). below for examples).
Passing a `resultVersion` of `0` corresponds to the original, simple format where Passing a `resultVersion` of `0` corresponds to the original, simple format where
each error is identified by rule name and line number. This is deprecated. each error is identified by rule name and line number.
This is deprecated.
Passing a `resultVersion` of `1` corresponds to a detailed format where each error Passing a `resultVersion` of `1` corresponds to a detailed format where each error
includes information about the line number, rule name, alias, description, as well includes information about the line number, rule name, alias, description, as well
as any additional detail or context that is available. This is deprecated. as any additional detail or context that is available.
This is deprecated.
Passing a `resultVersion` of `2` corresponds to a detailed format where each error Passing a `resultVersion` of `2` corresponds to a detailed format where each error
includes information about the line number, rule names, description, as well as any includes information about the line number, rule names, description, as well as any
additional detail or context that is available. This is the default. additional detail or context that is available.
This is the default.
#### callback #### callback
@ -397,15 +405,16 @@ Standard completion callback.
Type: `Object` Type: `Object`
Call `result.toString()` for convenience or see below for an example of the Call `result.toString()` for convenience or see below for an example of the
structure of the `result` object. Passing the value `true` to `toString()` structure of the `result` object.
uses rule aliases (ex: `no-hard-tabs`) instead of names (ex: `MD010`). Passing the value `true` to `toString()` uses rule aliases (ex: `no-hard-tabs`)
instead of names (ex: `MD010`).
### Config ### Config
The `options.config` configuration object is simple and can be stored in a file The `options.config` configuration object is simple and can be stored in a file
for readability and easy reuse. The `readConfig` and `readConfigSync` functions for readability and easy reuse.
load configuration settings and support the `extends` keyword for referencing The `readConfig` and `readConfigSync` functions load configuration settings and
other files (see above). support the `extends` keyword for referencing other files (see above).
By default, configuration files are parsed as JSON (and named `.markdownlint.json`). By default, configuration files are parsed as JSON (and named `.markdownlint.json`).
Custom parsers can be provided to handle other formats like JSONC, YAML, and TOML. Custom parsers can be provided to handle other formats like JSONC, YAML, and TOML.
@ -443,11 +452,12 @@ Type: `String`
Location of configuration file to read. Location of configuration file to read.
The `file` is resolved relative to the current working directory. If an `extends` The `file` is resolved relative to the current working directory.
key is present once read, its value will be resolved as a path relative to `file` If an `extends` key is present once read, its value will be resolved as a
and loaded recursively. Settings from a file referenced by `extends` are applied path relative to `file` and loaded recursively.
first, then those of `file` are applied on top (overriding any of the same keys Settings from a file referenced by `extends` are applied first, then those of
appearing in the referenced file). `file` are applied on top (overriding any of the same keys appearing in the
referenced file).
#### parsers #### parsers
@ -456,8 +466,8 @@ Type: *Optional* `Array` of `Function` taking (`String`) and returning `Object`
Array of functions to parse configuration files. Array of functions to parse configuration files.
The contents of a configuration file are passed to each parser function until one The contents of a configuration file are passed to each parser function until one
of them returns a value (vs. throwing an exception). Consequently, strict parsers of them returns a value (vs. throwing an exception).
should come before flexible parsers. Consequently, strict parsers should come before flexible parsers.
For example: For example:

View file

@ -1461,3 +1461,18 @@ Or with reference syntax as:
Guidance for writing alternate text is available from the [W3C](https://www.w3.org/WAI/alt/), Guidance for writing alternate text is available from the [W3C](https://www.w3.org/WAI/alt/),
[Wikipedia](https://en.wikipedia.org/wiki/Alt_attribute), and [Wikipedia](https://en.wikipedia.org/wiki/Alt_attribute), and
[other locations](https://www.phase2technology.com/blog/no-more-excuses-definitive-guide-alt-text-field). [other locations](https://www.phase2technology.com/blog/no-more-excuses-definitive-guide-alt-text-field).
<a name="md046"></a>
## MD046 - Sentences Per Line
Tags: line_length, spacing
A lot of markdown commits are small corrections such as spelling or grammar fixes.
Having multiple sentences in a line increases the git commit diff size for these
smaller fixes.
It's good to follow all sentence-ending periods with an endline to reduce the chance
of conflicts.
For documentation that tends towards long sentences, this can be a good alternative
to strict line lengths.

40
lib/md046.js Normal file
View file

@ -0,0 +1,40 @@
// @ts-check
"use strict";
const shared = require("./shared");
const isAlphabetCharacter = (char) => {
const charCode = char.charCodeAt(0);
return charCode >= "A".charCodeAt(0) && charCode <= "Z".charCodeAt(0);
};
module.exports = {
"names": [ "MD046", "sentences-per-line" ],
"description": "Each sentence should be on its own line",
"tags": [ "sentences" ],
"function": function MD046(params, onError) {
let inFence = false;
shared.forEachLine(function forLine(line, lineIndex) {
if (line.substring(0, 3) === "```") {
inFence = !inFence;
return;
}
if (inFence) {
return;
}
for (let i = 0; i < line.length - 2; i += 1) {
if (line[i] === "`" && (i === 0 || line[i - 1] === "\\")) {
i = line.indexOf("`", i);
}
if (line[i] === "." && line[i + 1] === " " && isAlphabetCharacter(line[i + 2])) {
shared.addError(onError, lineIndex, null, line.substr(i, 2));
}
}
});
}
};

View file

@ -43,5 +43,6 @@ module.exports = [
require("./md042"), require("./md042"),
require("./md043"), require("./md043"),
require("./md044"), require("./md044"),
require("./md045") require("./md045"),
require("./md046")
]; ];

View file

@ -1095,6 +1095,16 @@
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
"MD046": {
"description": "MD046/sentences-per-line - Images should have alternate text (alt text)",
"type": "boolean",
"default": true
},
"sentences-per-line": {
"description": "MD046/sentences-per-line - Images should have alternate text (alt text)",
"type": "boolean",
"default": true
},
"headings": { "headings": {
"description": "headings - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043", "description": "headings - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043",
"type": "boolean", "type": "boolean",

View file

@ -0,0 +1,21 @@
One sentence.
Another sentence.
Two sentences. Two sentences.
Another sentence. Another sentence.
```
code block
```
Followup sentence. Violation.
```code block
(more code)
```.
One sentence.
Two sentences. `Two sentences`.
* list.
list.
* list. list.