Add fenced code block style rule (#224) (fixes #223).

This commit is contained in:
Marius Lichtblau 2019-10-08 21:10:02 -07:00 committed by David Anson
parent fd06a50ee5
commit e9b3cc4c18
17 changed files with 232 additions and 25 deletions

View file

@ -90,6 +90,7 @@ playground for learning and exploring.
* **[MD045](doc/Rules.md#md045)** *no-alt-text* - Images should have alternate text (alt text)
* **[MD046](doc/Rules.md#md046)** *code-block-style* - Code block style
* **[MD047](doc/Rules.md#md047)** *single-trailing-newline* - Files should end with a single newline character
* **[MD048](doc/Rules.md#md048)** *code-fence-style* - Code fence style
See [Rules.md](doc/Rules.md) for more details.
@ -109,7 +110,7 @@ Tags group related rules and can be used to enable/disable multiple rules at onc
* **blank_lines** - MD012, MD022, MD031, MD032, MD047
* **blockquote** - MD027, MD028
* **bullet** - MD004, MD005, MD006, MD007, MD032
* **code** - MD014, MD031, MD038, MD040, MD046
* **code** - MD014, MD031, MD038, MD040, MD046, MD048
* **emphasis** - MD036, MD037
* **hard_tab** - MD010
* **headers** - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023,

View file

@ -1601,3 +1601,41 @@ To fix the violation, add a newline character to the end of the file:
This file ends with a newline.
[EOF]
```
<a name="md048"></a>
## MD048 - Code fence style
Tags: code
Aliases: code-fence-style
Parameters: style ("consistent", "tilde", "backtick"; default "consistent")
This rule is triggered when the symbols used in the document for fenced code blocks do not match the configured code fence style:
````markdown
```ruby
# Fenced code
```
~~~ruby
# Fenced code
~~~
````
To fix this issue, use the configured code fence style throughout the
document:
````markdown
```ruby
# Fenced code
```
```ruby
# Fenced code
```
````
The configured list style can be a specific symbol to use (backtick, tilde), or
can require that usage be consistent within the document.

38
lib/md048.js Normal file
View file

@ -0,0 +1,38 @@
// @ts-check
"use strict";
const { addErrorDetailIf } = require("../helpers");
function fencedCodeBlockStyleFor(markup) {
switch (markup[0]) {
case "~":
return "tilde";
default:
return "backtick";
}
}
module.exports = {
"names": [ "MD048", "code-fence-style" ],
"description": "Code fence style",
"tags": [ "code" ],
"function": function MD048(params, onError) {
const style = params.config.style || "consistent";
let expectedStyle = style;
params.tokens
.filter((token) => token.type === "fence")
.forEach((fenceToken) => {
const { lineNumber, markup } = fenceToken;
if (expectedStyle === "consistent") {
expectedStyle = fencedCodeBlockStyleFor(markup);
}
addErrorDetailIf(
onError,
lineNumber,
expectedStyle,
fencedCodeBlockStyleFor(markup)
);
});
}
};

View file

@ -50,7 +50,8 @@ const rules = [
require("./md044"),
require("./md045"),
require("./md046"),
require("./md047")
require("./md047"),
require("./md048")
];
rules.forEach((rule) => {
const name = rule.names[0].toLowerCase();

View file

@ -334,6 +334,20 @@ rules.forEach(function forRule(rule) {
}
};
break;
case "MD048":
scheme.properties = {
"style": {
"description": "Code fence syle",
"type": "string",
"enum": [
"consistent",
"backtick",
"tilde"
],
"default": "consistent"
}
};
break;
default:
custom = false;
break;

View file

@ -1339,6 +1339,48 @@
"type": "boolean",
"default": true
},
"MD048": {
"description": "MD048/code-fence-style - Code fence style",
"type": [
"boolean",
"object"
],
"default": true,
"properties": {
"style": {
"description": "Code fence syle",
"type": "string",
"enum": [
"consistent",
"backtick",
"tilde"
],
"default": "consistent"
}
},
"additionalProperties": false
},
"code-fence-style": {
"description": "MD048/code-fence-style - Code fence style",
"type": [
"boolean",
"object"
],
"default": true,
"properties": {
"style": {
"description": "Code fence syle",
"type": "string",
"enum": [
"consistent",
"backtick",
"tilde"
],
"default": "consistent"
}
},
"additionalProperties": false
},
"headings": {
"description": "headings - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043",
"type": "boolean",
@ -1390,7 +1432,7 @@
"default": true
},
"code": {
"description": "code - MD014, MD031, MD038, MD040, MD046",
"description": "code - MD014, MD031, MD038, MD040, MD046, MD048",
"type": "boolean",
"default": true
},

View file

@ -74,6 +74,10 @@ Code `with ` space {MD038}
code fence without language {MD040:73} {MD046:73}
```
~~~js
code fence with different style {MD048:77} {MD046:77}
~~~
[empty link]() {MD042}
markdownLint {MD044}

View file

@ -0,0 +1,6 @@
{
"default": true,
"MD048": {
"style": "backtick"
}
}

View file

@ -0,0 +1,19 @@
```text
This is a code block
```
~~~text
This is {MD048:5} a code block
~~~
```text
~~~
This is fine
~~~
```
~~~text
```
This is not {MD048:15}
```
~~~

View file

@ -0,0 +1,6 @@
{
"default": true,
"MD048": {
"style": "tilde"
}
}

View file

@ -0,0 +1,19 @@
```text
This is {MD048:1} a code block
```
~~~text
This is a code block
~~~
```text
~~~
This is not fine {MD048:9}
~~~
```
~~~text
```
This is
```
~~~

View file

@ -24,4 +24,8 @@ Fenced code
Indented code
~~~text
Fenced code
~~~
Missing newline character

View file

@ -24,4 +24,8 @@ Fenced code
Indented code
~~~text
Fenced code
~~~
Missing newline character

View file

@ -45,7 +45,7 @@
"errorRange": [25, 13]
},
{
"lineNumber": 27,
"lineNumber": 31,
"ruleNames": [ "MD043", "required-headings", "required-headers" ],
"ruleDescription": "Required heading structure",
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md043",
@ -99,12 +99,21 @@
"errorRange": null
},
{
"lineNumber": 27,
"lineNumber": 31,
"ruleNames": [ "MD047", "single-trailing-newline" ],
"ruleDescription": "Files should end with a single newline character",
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md047",
"errorDetail": null,
"errorContext": null,
"errorRange": [ 25, 1 ]
},
{
"lineNumber": 27,
"ruleNames": [ "MD048", "code-fence-style" ],
"ruleDescription": "Code fence style",
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md048",
"errorDetail": "Expected: backtick; Actual: tilde",
"errorContext": null,
"errorRange": null
}
]

View file

@ -24,4 +24,4 @@ None of the above should trigger any heading related rules.
Code block without a language specifier
```
{MD040:23}
{MD040:23} {MD048:13}

View file

@ -4,7 +4,7 @@ text {MD031:4}
```fence
code {MD031:6}
```
text {MD031:8}
text {MD031:8} {MD048:8}
~~~fence
code
~~~
@ -14,7 +14,7 @@ text {MD031:10} {MD031:12}
code
~~~
```
text {MD031:16} {MD031:18}
text {MD031:16} {MD031:18} {MD048:18}
~~~fence
```fence
code
@ -28,7 +28,7 @@ code
~~~
```
text {MD031:30} {MD031:32}
text {MD031:30} {MD031:32} {MD048:32}
~~~fence
```fence
@ -41,7 +41,7 @@ text {MD031:38} {MD031:40}
code
~~~
```
text {MD031:43} {MD031:45}
text {MD031:43} {MD031:45} {MD048:45}
~~~fence
code
```
@ -52,7 +52,7 @@ text {MD031:48} {MD031:50}
code
```
````
text {MD031:54} {MD031:56}
text {MD031:54} {MD031:56} {MD048:56}
~~~~fence
~~~fence
code
@ -64,7 +64,7 @@ text {MD031:60} {MD031:62}
code
```
`````
text {MD031:66} {MD031:68}
text {MD031:66} {MD031:68} {MD048:68}
~~~~fence
~~~fence
code

View file

@ -1124,7 +1124,7 @@ module.exports.styleAll = function styleAll(test) {
"MD019": [ 27 ],
"MD020": [ 29 ],
"MD021": [ 31 ],
"MD022": [ 82 ],
"MD022": [ 86 ],
"MD023": [ 40 ],
"MD024": [ 35 ],
"MD026": [ 40 ],
@ -1143,10 +1143,11 @@ module.exports.styleAll = function styleAll(test) {
"MD039": [ 71 ],
"MD040": [ 73 ],
"MD041": [ 1 ],
"MD042": [ 77 ],
"MD045": [ 81 ],
"MD046": [ 49, 73 ],
"MD047": [ 84 ]
"MD042": [ 81 ],
"MD045": [ 85 ],
"MD046": [ 49, 73, 77 ],
"MD047": [ 88 ],
"MD048": [ 77 ]
}
};
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -1175,7 +1176,7 @@ module.exports.styleRelaxed = function styleRelaxed(test) {
"MD019": [ 27 ],
"MD020": [ 29 ],
"MD021": [ 31 ],
"MD022": [ 82 ],
"MD022": [ 86 ],
"MD023": [ 40 ],
"MD024": [ 35 ],
"MD026": [ 40 ],
@ -1184,10 +1185,11 @@ module.exports.styleRelaxed = function styleRelaxed(test) {
"MD032": [ 7, 8, 51 ],
"MD035": [ 61 ],
"MD036": [ 65 ],
"MD042": [ 77 ],
"MD045": [ 81 ],
"MD046": [ 49, 73 ],
"MD047": [ 84 ]
"MD042": [ 81 ],
"MD045": [ 85 ],
"MD046": [ 49, 73, 77 ],
"MD047": [ 88 ],
"MD048": [ 77 ]
}
};
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
@ -1430,7 +1432,7 @@ module.exports.missingStringValue = function missingStringValue(test) {
};
module.exports.readme = function readme(test) {
test.expect(113);
test.expect(115);
const tagToRules = {};
rules.forEach(function forRule(rule) {
rule.tags.forEach(function forTag(tag) {
@ -1499,7 +1501,7 @@ module.exports.readme = function readme(test) {
};
module.exports.doc = function doc(test) {
test.expect(328);
test.expect(336);
fs.readFile("doc/Rules.md", helpers.utf8Encoding,
function readFile(err, contents) {
test.ifError(err);
@ -2787,7 +2789,7 @@ module.exports.configBadHybridSync = function configBadHybridSync(test) {
module.exports.allBuiltInRulesHaveValidUrl =
function allBuiltInRulesHaveValidUrl(test) {
test.expect(129);
test.expect(132);
rules.forEach(function forRule(rule) {
test.ok(rule.information);
test.ok(Object.getPrototypeOf(rule.information) === URL.prototype);