mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Expose shared.js helper code for custom rule authors (fixes #134).
This commit is contained in:
parent
f614f3e1ce
commit
7e980401b8
52 changed files with 283 additions and 184 deletions
|
@ -53,6 +53,8 @@ A rule is implemented as an `Object` with four required properties:
|
||||||
- `context` is an optional `String` with relevant text surrounding the error location.
|
- `context` is an optional `String` with relevant text surrounding the error location.
|
||||||
- `range` is an optional `Array` with two `Number` values identifying the 1-based column and length of the error.
|
- `range` is an optional `Array` with two `Number` values identifying the 1-based column and length of the error.
|
||||||
|
|
||||||
|
The collection of helper functions shared by the built-in rules is available for use by custom rules in the [markdownlint-rule-helpers package](https://www.npmjs.com/package/markdownlint-rule-helpers).
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
- [Simple rules used by the project's test cases](../test/rules)
|
- [Simple rules used by the project's test cases](../test/rules)
|
||||||
|
|
21
helpers/LICENSE
Normal file
21
helpers/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015-2019 David Anson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
50
helpers/README.md
Normal file
50
helpers/README.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# markdownlint-rule-helpers
|
||||||
|
|
||||||
|
> A collection of `markdownlint` helper functions for custom rules
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The [Markdown](https://en.wikipedia.org/wiki/Markdown) linter
|
||||||
|
[`markdownlint`](https://github.com/DavidAnson/markdownlint) offers a variety of built-in validation
|
||||||
|
[rules](https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md) and supports the
|
||||||
|
creation of [custom rules](https://github.com/DavidAnson/markdownlint/blob/master/doc/CustomRules.md).
|
||||||
|
The internal rules share various helper functions; this package exposes those for reuse by custom rules.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
_Undocumented_ - This package exports the internal functions as-is. The APIs were not originally meant
|
||||||
|
to be public, are not officially supported, and may change from release to release. There are brief
|
||||||
|
descriptive comments above each function, but no [JSDoc](https://en.m.wikipedia.org/wiki/JSDoc)
|
||||||
|
annotations. That said, some of what's here will be useful to custom rule authors and may avoid
|
||||||
|
duplicating code.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { forEachLine, getLineMetadata } = require("markdownlint-rule-helpers");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"names": [ "every-n-lines" ],
|
||||||
|
"description": "Rule that reports an error every N lines",
|
||||||
|
"tags": [ "test" ],
|
||||||
|
"function": (params, onError) => {
|
||||||
|
const n = params.config.n || 2;
|
||||||
|
forEachLine(getLineMetadata(params), (line, lineIndex) => {
|
||||||
|
const lineNumber = lineIndex + 1;
|
||||||
|
if ((lineNumber % n) === 0) {
|
||||||
|
onError({
|
||||||
|
"lineNumber": lineNumber,
|
||||||
|
"detail": "Line number " + lineNumber
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See also: [`markdownlint` built-in rule implementations](https://github.com/DavidAnson/markdownlint/tree/master/lib).
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
_None_ - The entire body of code is tested to 100% coverage by the core `markdownlint` project,
|
||||||
|
so there are no additional tests here.
|
18
helpers/package.json
Normal file
18
helpers/package.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "markdownlint-rule-helpers",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "A collection of markdownlint helper functions for custom rules",
|
||||||
|
"main": "helpers.js",
|
||||||
|
"author": "David Anson (https://dlaa.me/)",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://github.com/DavidAnson/markdownlint",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/DavidAnson/markdownlint.git"
|
||||||
|
},
|
||||||
|
"bugs": "https://github.com/DavidAnson/markdownlint/issues",
|
||||||
|
"keywords": [
|
||||||
|
"markdownlint",
|
||||||
|
"markdownlint-rule"
|
||||||
|
]
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ const path = require("path");
|
||||||
const { URL } = require("url");
|
const { URL } = require("url");
|
||||||
const markdownIt = require("markdown-it");
|
const markdownIt = require("markdown-it");
|
||||||
const rules = require("./rules");
|
const rules = require("./rules");
|
||||||
const shared = require("./shared");
|
const helpers = require("../helpers");
|
||||||
const cache = require("./cache");
|
const cache = require("./cache");
|
||||||
|
|
||||||
const deprecatedRuleNames = [ "MD002" ];
|
const deprecatedRuleNames = [ "MD002" ];
|
||||||
|
@ -31,7 +31,7 @@ function validateRuleList(ruleList) {
|
||||||
const value = rule[property];
|
const value = rule[property];
|
||||||
if (!result &&
|
if (!result &&
|
||||||
(!value || !Array.isArray(value) || (value.length === 0) ||
|
(!value || !Array.isArray(value) || (value.length === 0) ||
|
||||||
!value.every(shared.isString) || value.some(shared.isEmptyString))) {
|
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
||||||
result = newError(property);
|
result = newError(property);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -134,7 +134,7 @@ function removeFrontMatter(content, frontMatter) {
|
||||||
if (frontMatterMatch && !frontMatterMatch.index) {
|
if (frontMatterMatch && !frontMatterMatch.index) {
|
||||||
const contentMatched = frontMatterMatch[0];
|
const contentMatched = frontMatterMatch[0];
|
||||||
content = content.slice(contentMatched.length);
|
content = content.slice(contentMatched.length);
|
||||||
frontMatterLines = contentMatched.split(shared.newLineRe);
|
frontMatterLines = contentMatched.split(helpers.newLineRe);
|
||||||
if (frontMatterLines.length &&
|
if (frontMatterLines.length &&
|
||||||
(frontMatterLines[frontMatterLines.length - 1] === "")) {
|
(frontMatterLines[frontMatterLines.length - 1] === "")) {
|
||||||
frontMatterLines.length--;
|
frontMatterLines.length--;
|
||||||
|
@ -269,12 +269,12 @@ function getEnabledRulesPerLineNumber(
|
||||||
const enabledRulesPerLineNumber = new Array(1 + frontMatterLines.length);
|
const enabledRulesPerLineNumber = new Array(1 + frontMatterLines.length);
|
||||||
lines.forEach(function forLine(line) {
|
lines.forEach(function forLine(line) {
|
||||||
if (!noInlineConfig) {
|
if (!noInlineConfig) {
|
||||||
let match = shared.inlineCommentRe.exec(line);
|
let match = helpers.inlineCommentRe.exec(line);
|
||||||
if (match) {
|
if (match) {
|
||||||
enabledRules = shared.clone(enabledRules);
|
enabledRules = helpers.clone(enabledRules);
|
||||||
while (match) {
|
while (match) {
|
||||||
forMatch(match);
|
forMatch(match);
|
||||||
match = shared.inlineCommentRe.exec(line);
|
match = helpers.inlineCommentRe.exec(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,10 +310,10 @@ function lintContent(
|
||||||
const removeFrontMatterResult = removeFrontMatter(content, frontMatter);
|
const removeFrontMatterResult = removeFrontMatter(content, frontMatter);
|
||||||
const frontMatterLines = removeFrontMatterResult.frontMatterLines;
|
const frontMatterLines = removeFrontMatterResult.frontMatterLines;
|
||||||
// Ignore the content of HTML comments
|
// Ignore the content of HTML comments
|
||||||
content = shared.clearHtmlCommentText(removeFrontMatterResult.content);
|
content = helpers.clearHtmlCommentText(removeFrontMatterResult.content);
|
||||||
// Parse content into tokens and lines
|
// Parse content into tokens and lines
|
||||||
const tokens = md.parse(content, {});
|
const tokens = md.parse(content, {});
|
||||||
const lines = content.split(shared.newLineRe);
|
const lines = content.split(helpers.newLineRe);
|
||||||
annotateTokens(tokens, lines);
|
annotateTokens(tokens, lines);
|
||||||
const aliasToRuleNames = mapAliasToRuleNames(ruleList);
|
const aliasToRuleNames = mapAliasToRuleNames(ruleList);
|
||||||
const effectiveConfig =
|
const effectiveConfig =
|
||||||
|
@ -328,8 +328,8 @@ function lintContent(
|
||||||
lines,
|
lines,
|
||||||
frontMatterLines
|
frontMatterLines
|
||||||
};
|
};
|
||||||
cache.lineMetadata(shared.getLineMetadata(params));
|
cache.lineMetadata(helpers.getLineMetadata(params));
|
||||||
cache.flattenedLists(shared.flattenLists(params));
|
cache.flattenedLists(helpers.flattenLists(params));
|
||||||
// Function to run for each rule
|
// Function to run for each rule
|
||||||
const result = (resultVersion === 0) ? {} : [];
|
const result = (resultVersion === 0) ? {} : [];
|
||||||
function forRule(rule) {
|
function forRule(rule) {
|
||||||
|
@ -345,22 +345,22 @@ function lintContent(
|
||||||
function onError(errorInfo) {
|
function onError(errorInfo) {
|
||||||
if (!errorInfo ||
|
if (!errorInfo ||
|
||||||
!errorInfo.lineNumber ||
|
!errorInfo.lineNumber ||
|
||||||
!shared.isNumber(errorInfo.lineNumber)) {
|
!helpers.isNumber(errorInfo.lineNumber)) {
|
||||||
throwError("lineNumber");
|
throwError("lineNumber");
|
||||||
}
|
}
|
||||||
if (errorInfo.detail &&
|
if (errorInfo.detail &&
|
||||||
!shared.isString(errorInfo.detail)) {
|
!helpers.isString(errorInfo.detail)) {
|
||||||
throwError("detail");
|
throwError("detail");
|
||||||
}
|
}
|
||||||
if (errorInfo.context &&
|
if (errorInfo.context &&
|
||||||
!shared.isString(errorInfo.context)) {
|
!helpers.isString(errorInfo.context)) {
|
||||||
throwError("context");
|
throwError("context");
|
||||||
}
|
}
|
||||||
if (errorInfo.range &&
|
if (errorInfo.range &&
|
||||||
(!Array.isArray(errorInfo.range) ||
|
(!Array.isArray(errorInfo.range) ||
|
||||||
(errorInfo.range.length !== 2) ||
|
(errorInfo.range.length !== 2) ||
|
||||||
!shared.isNumber(errorInfo.range[0]) ||
|
!helpers.isNumber(errorInfo.range[0]) ||
|
||||||
!shared.isNumber(errorInfo.range[1]))) {
|
!helpers.isNumber(errorInfo.range[1]))) {
|
||||||
throwError("range");
|
throwError("range");
|
||||||
}
|
}
|
||||||
errors.push({
|
errors.push({
|
||||||
|
@ -440,9 +440,9 @@ function lintFile(
|
||||||
}
|
}
|
||||||
// Make a/synchronous call to read file
|
// Make a/synchronous call to read file
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
lintContentWrapper(null, fs.readFileSync(file, shared.utf8Encoding));
|
lintContentWrapper(null, fs.readFileSync(file, helpers.utf8Encoding));
|
||||||
} else {
|
} else {
|
||||||
fs.readFile(file, shared.utf8Encoding, lintContentWrapper);
|
fs.readFile(file, helpers.utf8Encoding, lintContentWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ function lintInput(options, synchronous, callback) {
|
||||||
const stringsKeys = Object.keys(strings);
|
const stringsKeys = Object.keys(strings);
|
||||||
const config = options.config || { "default": true };
|
const config = options.config || { "default": true };
|
||||||
const frontMatter = (options.frontMatter === undefined) ?
|
const frontMatter = (options.frontMatter === undefined) ?
|
||||||
shared.frontMatterRe : options.frontMatter;
|
helpers.frontMatterRe : options.frontMatter;
|
||||||
const noInlineConfig = !!options.noInlineConfig;
|
const noInlineConfig = !!options.noInlineConfig;
|
||||||
const resultVersion = (options.resultVersion === undefined) ?
|
const resultVersion = (options.resultVersion === undefined) ?
|
||||||
2 : options.resultVersion;
|
2 : options.resultVersion;
|
||||||
|
@ -590,7 +590,7 @@ function readConfig(file, parsers, callback) {
|
||||||
parsers = null;
|
parsers = null;
|
||||||
}
|
}
|
||||||
// Read file
|
// Read file
|
||||||
fs.readFile(file, shared.utf8Encoding, (err, content) => {
|
fs.readFile(file, helpers.utf8Encoding, (err, content) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
@ -608,7 +608,7 @@ function readConfig(file, parsers, callback) {
|
||||||
if (errr) {
|
if (errr) {
|
||||||
return callback(errr);
|
return callback(errr);
|
||||||
}
|
}
|
||||||
return callback(null, shared.assign(extendsConfig, config));
|
return callback(null, helpers.assign(extendsConfig, config));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return callback(null, config);
|
return callback(null, config);
|
||||||
|
@ -624,7 +624,7 @@ function readConfig(file, parsers, callback) {
|
||||||
*/
|
*/
|
||||||
function readConfigSync(file, parsers) {
|
function readConfigSync(file, parsers) {
|
||||||
// Read file
|
// Read file
|
||||||
const content = fs.readFileSync(file, shared.utf8Encoding);
|
const content = fs.readFileSync(file, helpers.utf8Encoding);
|
||||||
// Try to parse file
|
// Try to parse file
|
||||||
const { config, message } = parseConfiguration(file, content, parsers);
|
const { config, message } = parseConfiguration(file, content, parsers);
|
||||||
if (!config) {
|
if (!config) {
|
||||||
|
@ -634,7 +634,7 @@ function readConfigSync(file, parsers) {
|
||||||
const configExtends = config.extends;
|
const configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
return shared.assign(
|
return helpers.assign(
|
||||||
readConfigSync(path.resolve(path.dirname(file), configExtends), parsers),
|
readConfigSync(path.resolve(path.dirname(file), configExtends), parsers),
|
||||||
config);
|
config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorDetailIf, filterTokens } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD001", "heading-increment", "header-increment" ],
|
"names": [ "MD001", "heading-increment", "header-increment" ],
|
||||||
|
@ -10,10 +10,10 @@ module.exports = {
|
||||||
"tags": [ "headings", "headers" ],
|
"tags": [ "headings", "headers" ],
|
||||||
"function": function MD001(params, onError) {
|
"function": function MD001(params, onError) {
|
||||||
let prevLevel = 0;
|
let prevLevel = 0;
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
const level = parseInt(token.tag.slice(1), 10);
|
const level = parseInt(token.tag.slice(1), 10);
|
||||||
if (prevLevel && (level > prevLevel)) {
|
if (prevLevel && (level > prevLevel)) {
|
||||||
shared.addErrorDetailIf(onError, token.lineNumber,
|
addErrorDetailIf(onError, token.lineNumber,
|
||||||
"h" + (prevLevel + 1), "h" + level);
|
"h" + (prevLevel + 1), "h" + level);
|
||||||
}
|
}
|
||||||
prevLevel = level;
|
prevLevel = level;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorDetailIf } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD002", "first-heading-h1", "first-header-h1" ],
|
"names": [ "MD002", "first-heading-h1", "first-header-h1" ],
|
||||||
|
@ -13,7 +13,7 @@ module.exports = {
|
||||||
const tag = "h" + level;
|
const tag = "h" + level;
|
||||||
params.tokens.every(function forToken(token) {
|
params.tokens.every(function forToken(token) {
|
||||||
if (token.type === "heading_open") {
|
if (token.type === "heading_open") {
|
||||||
shared.addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
|
addErrorDetailIf(onError, token.lineNumber, tag, token.tag);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorDetailIf, filterTokens, headingStyleFor } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD003", "heading-style", "header-style" ],
|
"names": [ "MD003", "heading-style", "header-style" ],
|
||||||
|
@ -10,8 +11,8 @@ module.exports = {
|
||||||
"tags": [ "headings", "headers" ],
|
"tags": [ "headings", "headers" ],
|
||||||
"function": function MD003(params, onError) {
|
"function": function MD003(params, onError) {
|
||||||
let style = params.config.style || "consistent";
|
let style = params.config.style || "consistent";
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
const styleForToken = shared.headingStyleFor(token);
|
const styleForToken = headingStyleFor(token);
|
||||||
if (style === "consistent") {
|
if (style === "consistent") {
|
||||||
style = styleForToken;
|
style = styleForToken;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +33,7 @@ module.exports = {
|
||||||
} else if (style === "setext_with_atx_closed") {
|
} else if (style === "setext_with_atx_closed") {
|
||||||
expected = h12 ? "setext" : "atx_closed";
|
expected = h12 ? "setext" : "atx_closed";
|
||||||
}
|
}
|
||||||
shared.addErrorDetailIf(onError, token.lineNumber,
|
addErrorDetailIf(onError, token.lineNumber,
|
||||||
expected, styleForToken);
|
expected, styleForToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, listItemMarkerRe,
|
const { addErrorDetailIf, listItemMarkerRe,
|
||||||
rangeFromRegExp } = require("./shared");
|
rangeFromRegExp } = require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
// Returns the unordered list style for a list item token
|
// Returns the unordered list style for a list item token
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addError, addErrorDetailIf, indentFor, listItemMarkerRe,
|
const { addError, addErrorDetailIf, indentFor, listItemMarkerRe,
|
||||||
orderedListItemMarkerRe, rangeFromRegExp } = require("./shared");
|
orderedListItemMarkerRe, rangeFromRegExp } = require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
||||||
require("./shared");
|
require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
||||||
require("./shared");
|
require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addError, filterTokens, forEachLine, includesSorted, rangeFromRegExp,
|
const { addError, filterTokens, forEachLine, includesSorted, rangeFromRegExp,
|
||||||
trimRight } = require("./shared");
|
trimRight } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
const trailingSpaceRe = /\s+$/;
|
const trailingSpaceRe = /\s+$/;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addError, forEachLine, rangeFromRegExp } = require("./shared");
|
const { addError, forEachLine, rangeFromRegExp } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
const tabRe = /\t+/;
|
const tabRe = /\t+/;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addError, forEachInlineChild, rangeFromRegExp } = require("../helpers");
|
||||||
|
|
||||||
const reversedLinkRe = /\([^)]+\)\[[^\]^][^\]]*]/;
|
const reversedLinkRe = /\([^)]+\)\[[^\]^][^\]]*]/;
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ module.exports = {
|
||||||
"description": "Reversed link syntax",
|
"description": "Reversed link syntax",
|
||||||
"tags": [ "links" ],
|
"tags": [ "links" ],
|
||||||
"function": function MD011(params, onError) {
|
"function": function MD011(params, onError) {
|
||||||
shared.forEachInlineChild(params, "text", function forToken(token) {
|
forEachInlineChild(params, "text", function forToken(token) {
|
||||||
const match = reversedLinkRe.exec(token.content);
|
const match = reversedLinkRe.exec(token.content);
|
||||||
if (match) {
|
if (match) {
|
||||||
shared.addError(onError, token.lineNumber, match[0], null,
|
addError(onError, token.lineNumber, match[0], null,
|
||||||
shared.rangeFromRegExp(token.line, reversedLinkRe));
|
rangeFromRegExp(token.line, reversedLinkRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, forEachLine } = require("./shared");
|
const { addErrorDetailIf, forEachLine } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
|
const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine,
|
||||||
includesSorted, rangeFromRegExp } = require("./shared");
|
includesSorted, rangeFromRegExp } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
const longLineRePrefix = "^(.{";
|
const longLineRePrefix = "^(.{";
|
||||||
|
|
13
lib/md014.js
13
lib/md014.js
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, newLineRe, rangeFromRegExp } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const dollarCommandRe = /^(\s*)(\$\s)/;
|
const dollarCommandRe = /^(\s*)(\$\s)/;
|
||||||
|
|
||||||
|
@ -12,15 +13,15 @@ module.exports = {
|
||||||
"tags": [ "code" ],
|
"tags": [ "code" ],
|
||||||
"function": function MD014(params, onError) {
|
"function": function MD014(params, onError) {
|
||||||
[ "code_block", "fence" ].forEach(function forType(type) {
|
[ "code_block", "fence" ].forEach(function forType(type) {
|
||||||
shared.filterTokens(params, type, function forToken(token) {
|
filterTokens(params, type, function forToken(token) {
|
||||||
let allBlank = true;
|
let allBlank = true;
|
||||||
if (token.content && token.content.split(shared.newLineRe)
|
if (token.content && token.content.split(newLineRe)
|
||||||
.every(function forLine(line) {
|
.every(function forLine(line) {
|
||||||
return !line || (allBlank = false) || dollarCommandRe.test(line);
|
return !line || (allBlank = false) || dollarCommandRe.test(line);
|
||||||
}) && !allBlank) {
|
}) && !allBlank) {
|
||||||
shared.addErrorContext(onError, token.lineNumber,
|
addErrorContext(onError, token.lineNumber,
|
||||||
token.content.split(shared.newLineRe)[0].trim(), null, null,
|
token.content.split(newLineRe)[0].trim(), null, null,
|
||||||
shared.rangeFromRegExp(token.line, dollarCommandRe));
|
rangeFromRegExp(token.line, dollarCommandRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorContext, atxHeadingSpaceRe, forEachLine,
|
const { addErrorContext, atxHeadingSpaceRe, forEachLine,
|
||||||
rangeFromRegExp } = require("./shared");
|
rangeFromRegExp } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
11
lib/md019.js
11
lib/md019.js
|
@ -2,19 +2,20 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, atxHeadingSpaceRe, filterTokens, headingStyleFor,
|
||||||
|
rangeFromRegExp } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD019", "no-multiple-space-atx" ],
|
"names": [ "MD019", "no-multiple-space-atx" ],
|
||||||
"description": "Multiple spaces after hash on atx style heading",
|
"description": "Multiple spaces after hash on atx style heading",
|
||||||
"tags": [ "headings", "headers", "atx", "spaces" ],
|
"tags": [ "headings", "headers", "atx", "spaces" ],
|
||||||
"function": function MD019(params, onError) {
|
"function": function MD019(params, onError) {
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
if ((shared.headingStyleFor(token) === "atx") &&
|
if ((headingStyleFor(token) === "atx") &&
|
||||||
/^#+\s\s/.test(token.line)) {
|
/^#+\s\s/.test(token.line)) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line.trim(),
|
addErrorContext(onError, token.lineNumber, token.line.trim(),
|
||||||
null, null,
|
null, null,
|
||||||
shared.rangeFromRegExp(token.line, shared.atxHeadingSpaceRe));
|
rangeFromRegExp(token.line, atxHeadingSpaceRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorContext, forEachLine, rangeFromRegExp } = require("./shared");
|
const { addErrorContext, forEachLine, rangeFromRegExp } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
const atxClosedHeadingNoSpaceRe = /(?:^#+[^#\s])|(?:[^#\s]#+\s*$)/;
|
const atxClosedHeadingNoSpaceRe = /(?:^#+[^#\s])|(?:[^#\s]#+\s*$)/;
|
||||||
|
|
11
lib/md021.js
11
lib/md021.js
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, headingStyleFor, rangeFromRegExp } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const atxClosedHeadingSpaceRe = /(?:^#+\s\s+?\S)|(?:\S\s\s+?#+\s*$)/;
|
const atxClosedHeadingSpaceRe = /(?:^#+\s\s+?\S)|(?:\S\s\s+?#+\s*$)/;
|
||||||
|
|
||||||
|
@ -11,14 +12,14 @@ module.exports = {
|
||||||
"description": "Multiple spaces inside hashes on closed atx style heading",
|
"description": "Multiple spaces inside hashes on closed atx style heading",
|
||||||
"tags": [ "headings", "headers", "atx_closed", "spaces" ],
|
"tags": [ "headings", "headers", "atx_closed", "spaces" ],
|
||||||
"function": function MD021(params, onError) {
|
"function": function MD021(params, onError) {
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
if (shared.headingStyleFor(token) === "atx_closed") {
|
if (headingStyleFor(token) === "atx_closed") {
|
||||||
const left = /^#+\s\s/.test(token.line);
|
const left = /^#+\s\s/.test(token.line);
|
||||||
const right = /\s\s#+$/.test(token.line);
|
const right = /\s\s#+$/.test(token.line);
|
||||||
if (left || right) {
|
if (left || right) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line.trim(),
|
addErrorContext(onError, token.lineNumber, token.line.trim(),
|
||||||
left, right,
|
left, right,
|
||||||
shared.rangeFromRegExp(token.line, atxClosedHeadingSpaceRe));
|
rangeFromRegExp(token.line, atxClosedHeadingSpaceRe));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorDetailIf, filterTokens, isBlankLine } = require("../helpers");
|
||||||
const { addErrorDetailIf, filterTokens, isBlankLine } = shared;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ],
|
"names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ],
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, rangeFromRegExp } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/;
|
const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/;
|
||||||
|
|
||||||
|
@ -11,10 +12,10 @@ module.exports = {
|
||||||
"description": "Headings must start at the beginning of the line",
|
"description": "Headings must start at the beginning of the line",
|
||||||
"tags": [ "headings", "headers", "spaces" ],
|
"tags": [ "headings", "headers", "spaces" ],
|
||||||
"function": function MD023(params, onError) {
|
"function": function MD023(params, onError) {
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
if (spaceBeforeHeadingRe.test(token.line)) {
|
if (spaceBeforeHeadingRe.test(token.line)) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line, null,
|
addErrorContext(onError, token.lineNumber, token.line, null,
|
||||||
null, shared.rangeFromRegExp(token.line, spaceBeforeHeadingRe));
|
null, rangeFromRegExp(token.line, spaceBeforeHeadingRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, forEachHeading } = require("../helpers");
|
||||||
const { addErrorContext, forEachHeading } = shared;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD024", "no-duplicate-heading", "no-duplicate-header" ],
|
"names": [ "MD024", "no-duplicate-heading", "no-duplicate-header" ],
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, frontMatterHasTitle } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD025", "single-title", "single-h1" ],
|
"names": [ "MD025", "single-title", "single-h1" ],
|
||||||
|
@ -12,15 +13,15 @@ module.exports = {
|
||||||
const level = params.config.level || 1;
|
const level = params.config.level || 1;
|
||||||
const tag = "h" + level;
|
const tag = "h" + level;
|
||||||
const foundFrontMatterTitle =
|
const foundFrontMatterTitle =
|
||||||
shared.frontMatterHasTitle(
|
frontMatterHasTitle(
|
||||||
params.frontMatterLines,
|
params.frontMatterLines,
|
||||||
params.config.front_matter_title
|
params.config.front_matter_title
|
||||||
);
|
);
|
||||||
let hasTopLevelHeading = false;
|
let hasTopLevelHeading = false;
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
filterTokens(params, "heading_open", function forToken(token) {
|
||||||
if (token.tag === tag) {
|
if (token.tag === tag) {
|
||||||
if (hasTopLevelHeading || foundFrontMatterTitle) {
|
if (hasTopLevelHeading || foundFrontMatterTitle) {
|
||||||
shared.addErrorContext(onError, token.lineNumber,
|
addErrorContext(onError, token.lineNumber,
|
||||||
token.line.trim());
|
token.line.trim());
|
||||||
} else if (token.lineNumber === 1) {
|
} else if (token.lineNumber === 1) {
|
||||||
hasTopLevelHeading = true;
|
hasTopLevelHeading = true;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addError, forEachHeading, rangeFromRegExp } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD026", "no-trailing-punctuation" ],
|
"names": [ "MD026", "no-trailing-punctuation" ],
|
||||||
|
@ -11,12 +11,12 @@ module.exports = {
|
||||||
"function": function MD026(params, onError) {
|
"function": function MD026(params, onError) {
|
||||||
const punctuation = params.config.punctuation || ".,;:!?";
|
const punctuation = params.config.punctuation || ".,;:!?";
|
||||||
const trailingPunctuationRe = new RegExp("[" + punctuation + "]$");
|
const trailingPunctuationRe = new RegExp("[" + punctuation + "]$");
|
||||||
shared.forEachHeading(params, function forHeading(heading, content) {
|
forEachHeading(params, function forHeading(heading, content) {
|
||||||
const match = trailingPunctuationRe.exec(content);
|
const match = trailingPunctuationRe.exec(content);
|
||||||
if (match) {
|
if (match) {
|
||||||
shared.addError(onError, heading.lineNumber,
|
addError(onError, heading.lineNumber,
|
||||||
"Punctuation: '" + match[0] + "'", null,
|
"Punctuation: '" + match[0] + "'", null,
|
||||||
shared.rangeFromRegExp(heading.line, trailingPunctuationRe));
|
rangeFromRegExp(heading.line, trailingPunctuationRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
12
lib/md027.js
12
lib/md027.js
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, newLineRe, rangeFromRegExp } = require("../helpers");
|
||||||
|
|
||||||
const spaceAfterBlockQuote = /^\s*(?:>\s+)+\S/;
|
const spaceAfterBlockQuote = /^\s*(?:>\s+)+\S/;
|
||||||
|
|
||||||
|
@ -27,15 +27,15 @@ module.exports = {
|
||||||
/^(\s*>)+\s\s+>/.test(token.line) :
|
/^(\s*>)+\s\s+>/.test(token.line) :
|
||||||
/^(\s*>)+\s\s/.test(token.line);
|
/^(\s*>)+\s\s/.test(token.line);
|
||||||
if (multipleSpaces) {
|
if (multipleSpaces) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line, null,
|
addErrorContext(onError, token.lineNumber, token.line, null,
|
||||||
null, shared.rangeFromRegExp(token.line, spaceAfterBlockQuote));
|
null, rangeFromRegExp(token.line, spaceAfterBlockQuote));
|
||||||
}
|
}
|
||||||
token.content.split(shared.newLineRe)
|
token.content.split(newLineRe)
|
||||||
.forEach(function forLine(line, offset) {
|
.forEach(function forLine(line, offset) {
|
||||||
if (/^\s/.test(line)) {
|
if (/^\s/.test(line)) {
|
||||||
shared.addErrorContext(onError, token.lineNumber + offset,
|
addErrorContext(onError, token.lineNumber + offset,
|
||||||
"> " + line, null, null,
|
"> " + line, null, null,
|
||||||
shared.rangeFromRegExp(line, spaceAfterBlockQuote));
|
rangeFromRegExp(line, spaceAfterBlockQuote));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addError } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD028", "no-blanks-blockquote" ],
|
"names": [ "MD028", "no-blanks-blockquote" ],
|
||||||
|
@ -13,7 +13,7 @@ module.exports = {
|
||||||
params.tokens.forEach(function forToken(token) {
|
params.tokens.forEach(function forToken(token) {
|
||||||
if ((token.type === "blockquote_open") &&
|
if ((token.type === "blockquote_open") &&
|
||||||
(prevToken.type === "blockquote_close")) {
|
(prevToken.type === "blockquote_close")) {
|
||||||
shared.addError(onError, token.lineNumber - 1);
|
addError(onError, token.lineNumber - 1);
|
||||||
}
|
}
|
||||||
prevToken = token;
|
prevToken = token;
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, listItemMarkerRe, orderedListItemMarkerRe,
|
const { addErrorDetailIf, listItemMarkerRe, orderedListItemMarkerRe,
|
||||||
rangeFromRegExp } = require("./shared");
|
rangeFromRegExp } = require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
const listStyleExamples = {
|
const listStyleExamples = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } =
|
||||||
require("./shared");
|
require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorContext, forEachLine, isBlankLine } = require("./shared");
|
const { addErrorContext, forEachLine, isBlankLine } = require("../helpers");
|
||||||
const { lineMetadata } = require("./cache");
|
const { lineMetadata } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { addErrorContext, isBlankLine } = require("./shared");
|
const { addErrorContext, isBlankLine } = require("../helpers");
|
||||||
const { flattenedLists } = require("./cache");
|
const { flattenedLists } = require("./cache");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addError, filterTokens, forEachInlineChild, newLineRe,
|
||||||
const {
|
rangeFromRegExp } = require("../helpers");
|
||||||
addError, filterTokens, forEachInlineChild, newLineRe, rangeFromRegExp
|
|
||||||
} = shared;
|
|
||||||
|
|
||||||
const htmlRe = /<[^>]*>/;
|
const htmlRe = /<[^>]*>/;
|
||||||
|
|
||||||
|
|
11
lib/md034.js
11
lib/md034.js
|
@ -2,14 +2,15 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, bareUrlRe, filterTokens, rangeFromRegExp } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD034", "no-bare-urls" ],
|
"names": [ "MD034", "no-bare-urls" ],
|
||||||
"description": "Bare URL used",
|
"description": "Bare URL used",
|
||||||
"tags": [ "links", "url" ],
|
"tags": [ "links", "url" ],
|
||||||
"function": function MD034(params, onError) {
|
"function": function MD034(params, onError) {
|
||||||
shared.filterTokens(params, "inline", function forToken(token) {
|
filterTokens(params, "inline", function forToken(token) {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
token.children.forEach(function forChild(child) {
|
token.children.forEach(function forChild(child) {
|
||||||
let match = null;
|
let match = null;
|
||||||
|
@ -19,9 +20,9 @@ module.exports = {
|
||||||
inLink = false;
|
inLink = false;
|
||||||
} else if ((child.type === "text") &&
|
} else if ((child.type === "text") &&
|
||||||
!inLink &&
|
!inLink &&
|
||||||
(match = shared.bareUrlRe.exec(child.content))) {
|
(match = bareUrlRe.exec(child.content))) {
|
||||||
shared.addErrorContext(onError, child.lineNumber, match[0], null,
|
addErrorContext(onError, child.lineNumber, match[0], null,
|
||||||
null, shared.rangeFromRegExp(child.line, shared.bareUrlRe));
|
null, rangeFromRegExp(child.line, bareUrlRe));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorDetailIf, filterTokens } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD035", "hr-style" ],
|
"names": [ "MD035", "hr-style" ],
|
||||||
|
@ -10,12 +10,12 @@ module.exports = {
|
||||||
"tags": [ "hr" ],
|
"tags": [ "hr" ],
|
||||||
"function": function MD035(params, onError) {
|
"function": function MD035(params, onError) {
|
||||||
let style = params.config.style || "consistent";
|
let style = params.config.style || "consistent";
|
||||||
shared.filterTokens(params, "hr", function forToken(token) {
|
filterTokens(params, "hr", function forToken(token) {
|
||||||
const lineTrim = token.line.trim();
|
const lineTrim = token.line.trim();
|
||||||
if (style === "consistent") {
|
if (style === "consistent") {
|
||||||
style = lineTrim;
|
style = lineTrim;
|
||||||
}
|
}
|
||||||
shared.addErrorDetailIf(onError, token.lineNumber, style, lineTrim);
|
addErrorDetailIf(onError, token.lineNumber, style, lineTrim);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD036", "no-emphasis-as-heading", "no-emphasis-as-header" ],
|
"names": [ "MD036", "no-emphasis-as-heading", "no-emphasis-as-header" ],
|
||||||
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
(children[0].type === "em_open")) &&
|
(children[0].type === "em_open")) &&
|
||||||
(children[1].type === "text") &&
|
(children[1].type === "text") &&
|
||||||
!re.test(children[1].content)) {
|
!re.test(children[1].content)) {
|
||||||
shared.addErrorContext(onError, t.lineNumber,
|
addErrorContext(onError, t.lineNumber,
|
||||||
children[1].content);
|
children[1].content);
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, forEachInlineChild } = require("../helpers");
|
||||||
const { addErrorContext, forEachInlineChild } = shared;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD037", "no-space-in-emphasis" ],
|
"names": [ "MD037", "no-space-in-emphasis" ],
|
||||||
|
|
11
lib/md038.js
11
lib/md038.js
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const startRe = /^\s([^`]|$)/;
|
const startRe = /^\s([^`]|$)/;
|
||||||
const endRe = /[^`]\s$/;
|
const endRe = /[^`]\s$/;
|
||||||
|
@ -12,16 +13,16 @@ module.exports = {
|
||||||
"description": "Spaces inside code span elements",
|
"description": "Spaces inside code span elements",
|
||||||
"tags": [ "whitespace", "code" ],
|
"tags": [ "whitespace", "code" ],
|
||||||
"function": function MD038(params, onError) {
|
"function": function MD038(params, onError) {
|
||||||
shared.filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
if (token.children.some((child) => child.type === "code_inline")) {
|
if (token.children.some((child) => child.type === "code_inline")) {
|
||||||
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
const tokenLines = params.lines.slice(token.map[0], token.map[1]);
|
||||||
shared.forEachInlineCodeSpan(
|
forEachInlineCodeSpan(
|
||||||
tokenLines.join("\n"),
|
tokenLines.join("\n"),
|
||||||
(code, lineIndex, columnIndex, tickCount) => {
|
(code, lineIndex, columnIndex, tickCount) => {
|
||||||
let rangeIndex = columnIndex - tickCount;
|
let rangeIndex = columnIndex - tickCount;
|
||||||
let rangeLength = code.length + (2 * tickCount);
|
let rangeLength = code.length + (2 * tickCount);
|
||||||
let rangeLineOffset = 0;
|
let rangeLineOffset = 0;
|
||||||
const codeLines = code.split(shared.newLineRe);
|
const codeLines = code.split(newLineRe);
|
||||||
const left = startRe.test(code);
|
const left = startRe.test(code);
|
||||||
const right = !left && endRe.test(code);
|
const right = !left && endRe.test(code);
|
||||||
if (right && (codeLines.length > 1)) {
|
if (right && (codeLines.length > 1)) {
|
||||||
|
@ -34,7 +35,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
const context = tokenLines[lineIndex + rangeLineOffset]
|
const context = tokenLines[lineIndex + rangeLineOffset]
|
||||||
.substring(rangeIndex, rangeIndex + rangeLength);
|
.substring(rangeIndex, rangeIndex + rangeLength);
|
||||||
shared.addErrorContext(
|
addErrorContext(
|
||||||
onError, token.lineNumber + lineIndex + rangeLineOffset,
|
onError, token.lineNumber + lineIndex + rangeLineOffset,
|
||||||
context, left, right, [ rangeIndex + 1, rangeLength ]);
|
context, left, right, [ rangeIndex + 1, rangeLength ]);
|
||||||
}
|
}
|
||||||
|
|
13
lib/md039.js
13
lib/md039.js
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, rangeFromRegExp, trimLeft, trimRight } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=\(\S*\))/;
|
const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=\(\S*\))/;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ module.exports = {
|
||||||
"description": "Spaces inside link text",
|
"description": "Spaces inside link text",
|
||||||
"tags": [ "whitespace", "links" ],
|
"tags": [ "whitespace", "links" ],
|
||||||
"function": function MD039(params, onError) {
|
"function": function MD039(params, onError) {
|
||||||
shared.filterTokens(params, "inline", function forToken(token) {
|
filterTokens(params, "inline", function forToken(token) {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
token.children.forEach(function forChild(child) {
|
token.children.forEach(function forChild(child) {
|
||||||
|
@ -20,12 +21,12 @@ module.exports = {
|
||||||
linkText = "";
|
linkText = "";
|
||||||
} else if (child.type === "link_close") {
|
} else if (child.type === "link_close") {
|
||||||
inLink = false;
|
inLink = false;
|
||||||
const left = shared.trimLeft(linkText).length !== linkText.length;
|
const left = trimLeft(linkText).length !== linkText.length;
|
||||||
const right = shared.trimRight(linkText).length !== linkText.length;
|
const right = trimRight(linkText).length !== linkText.length;
|
||||||
if (left || right) {
|
if (left || right) {
|
||||||
shared.addErrorContext(onError, token.lineNumber,
|
addErrorContext(onError, token.lineNumber,
|
||||||
"[" + linkText + "]", left, right,
|
"[" + linkText + "]", left, right,
|
||||||
shared.rangeFromRegExp(token.line, spaceInLinkRe));
|
rangeFromRegExp(token.line, spaceInLinkRe));
|
||||||
}
|
}
|
||||||
} else if (inLink) {
|
} else if (inLink) {
|
||||||
linkText += child.content;
|
linkText += child.content;
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD040", "fenced-code-language" ],
|
"names": [ "MD040", "fenced-code-language" ],
|
||||||
"description": "Fenced code blocks should have a language specified",
|
"description": "Fenced code blocks should have a language specified",
|
||||||
"tags": [ "code", "language" ],
|
"tags": [ "code", "language" ],
|
||||||
"function": function MD040(params, onError) {
|
"function": function MD040(params, onError) {
|
||||||
shared.filterTokens(params, "fence", function forToken(token) {
|
filterTokens(params, "fence", function forToken(token) {
|
||||||
if (!token.info.trim()) {
|
if (!token.info.trim()) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line);
|
addErrorContext(onError, token.lineNumber, token.line);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, frontMatterHasTitle } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD041", "first-line-heading", "first-line-h1" ],
|
"names": [ "MD041", "first-line-heading", "first-line-h1" ],
|
||||||
|
@ -12,7 +12,7 @@ module.exports = {
|
||||||
const level = params.config.level || 1;
|
const level = params.config.level || 1;
|
||||||
const tag = "h" + level;
|
const tag = "h" + level;
|
||||||
const foundFrontMatterTitle =
|
const foundFrontMatterTitle =
|
||||||
shared.frontMatterHasTitle(
|
frontMatterHasTitle(
|
||||||
params.frontMatterLines,
|
params.frontMatterLines,
|
||||||
params.config.front_matter_title
|
params.config.front_matter_title
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,7 @@ module.exports = {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((token.type !== "heading_open") || (token.tag !== tag)) {
|
if ((token.type !== "heading_open") || (token.tag !== tag)) {
|
||||||
shared.addErrorContext(onError, token.lineNumber, token.line);
|
addErrorContext(onError, token.lineNumber, token.line);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, filterTokens, rangeFromRegExp } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
const emptyLinkRe = /\[[^\]]*](?:\((?:#?|(?:<>))\))/;
|
const emptyLinkRe = /\[[^\]]*](?:\((?:#?|(?:<>))\))/;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ module.exports = {
|
||||||
"description": "No empty links",
|
"description": "No empty links",
|
||||||
"tags": [ "links" ],
|
"tags": [ "links" ],
|
||||||
"function": function MD042(params, onError) {
|
"function": function MD042(params, onError) {
|
||||||
shared.filterTokens(params, "inline", function forToken(token) {
|
filterTokens(params, "inline", function forToken(token) {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
let emptyLink = false;
|
let emptyLink = false;
|
||||||
|
@ -27,9 +28,9 @@ module.exports = {
|
||||||
} else if (child.type === "link_close") {
|
} else if (child.type === "link_close") {
|
||||||
inLink = false;
|
inLink = false;
|
||||||
if (emptyLink) {
|
if (emptyLink) {
|
||||||
shared.addErrorContext(onError, child.lineNumber,
|
addErrorContext(onError, child.lineNumber,
|
||||||
"[" + linkText + "]()", null, null,
|
"[" + linkText + "]()", null, null,
|
||||||
shared.rangeFromRegExp(child.line, emptyLinkRe));
|
rangeFromRegExp(child.line, emptyLinkRe));
|
||||||
}
|
}
|
||||||
} else if (inLink) {
|
} else if (inLink) {
|
||||||
linkText += child.content;
|
linkText += child.content;
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addErrorContext, addErrorDetailIf, forEachHeading } =
|
||||||
|
require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD043", "required-headings", "required-headers" ],
|
"names": [ "MD043", "required-headings", "required-headers" ],
|
||||||
|
@ -18,7 +19,7 @@ module.exports = {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let optional = false;
|
let optional = false;
|
||||||
let errorCount = 0;
|
let errorCount = 0;
|
||||||
shared.forEachHeading(params, function forHeading(heading, content) {
|
forEachHeading(params, function forHeading(heading, content) {
|
||||||
if (!errorCount) {
|
if (!errorCount) {
|
||||||
const actual = levels[heading.tag] + " " + content;
|
const actual = levels[heading.tag] + " " + content;
|
||||||
const expected = requiredHeadings[i++] || "[None]";
|
const expected = requiredHeadings[i++] || "[None]";
|
||||||
|
@ -29,14 +30,14 @@ module.exports = {
|
||||||
} else if (optional) {
|
} else if (optional) {
|
||||||
i--;
|
i--;
|
||||||
} else {
|
} else {
|
||||||
shared.addErrorDetailIf(onError, heading.lineNumber,
|
addErrorDetailIf(onError, heading.lineNumber,
|
||||||
expected, actual);
|
expected, actual);
|
||||||
errorCount++;
|
errorCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if ((i < requiredHeadings.length) && !errorCount) {
|
if ((i < requiredHeadings.length) && !errorCount) {
|
||||||
shared.addErrorContext(onError, params.lines.length,
|
addErrorContext(onError, params.lines.length,
|
||||||
requiredHeadings[i]);
|
requiredHeadings[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
|
||||||
const { addErrorDetailIf, bareUrlRe, escapeForRegExp, filterTokens,
|
const { addErrorDetailIf, bareUrlRe, escapeForRegExp, filterTokens,
|
||||||
forEachInlineChild, newLineRe } = shared;
|
forEachInlineChild, newLineRe } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD044", "proper-names" ],
|
"names": [ "MD044", "proper-names" ],
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const shared = require("./shared");
|
const { addError, forEachInlineChild } = require("../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD045", "no-alt-text" ],
|
"names": [ "MD045", "no-alt-text" ],
|
||||||
"description": "Images should have alternate text (alt text)",
|
"description": "Images should have alternate text (alt text)",
|
||||||
"tags": [ "accessibility", "images" ],
|
"tags": [ "accessibility", "images" ],
|
||||||
"function": function MD045(params, onError) {
|
"function": function MD045(params, onError) {
|
||||||
shared.forEachInlineChild(params, "image", function forToken(token) {
|
forEachInlineChild(params, "image", function forToken(token) {
|
||||||
if (token.content === "") {
|
if (token.content === "") {
|
||||||
shared.addError(onError, token.lineNumber);
|
addError(onError, token.lineNumber);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"test-cover": "istanbul cover node_modules/nodeunit/bin/nodeunit test/markdownlint-test.js",
|
"test-cover": "istanbul cover node_modules/nodeunit/bin/nodeunit test/markdownlint-test.js",
|
||||||
"test-extra": "nodeunit test/markdownlint-test-extra.js",
|
"test-extra": "nodeunit test/markdownlint-test-extra.js",
|
||||||
"debug": "node debug node_modules/nodeunit/bin/nodeunit",
|
"debug": "node debug node_modules/nodeunit/bin/nodeunit",
|
||||||
"lint": "eslint lib test schema && eslint --env browser --global markdownit --global markdownlint --rule \"no-unused-vars: 0, no-extend-native: 0, max-statements: 0, no-console: 0, no-var: 0\" demo && eslint --rule \"no-console: 0, no-invalid-this: 0, no-shadow: 0, object-property-newline: 0\" example",
|
"lint": "eslint lib helpers test schema && eslint --env browser --global markdownit --global markdownlint --rule \"no-unused-vars: 0, no-extend-native: 0, max-statements: 0, no-console: 0, no-var: 0\" demo && eslint --rule \"no-console: 0, no-invalid-this: 0, no-shadow: 0, object-property-newline: 0\" example",
|
||||||
"build-config-schema": "node schema/build-config-schema.js",
|
"build-config-schema": "node schema/build-config-schema.js",
|
||||||
"build-demo": "cpy node_modules/markdown-it/dist/markdown-it.min.js demo && cd demo && rimraf markdownlint-browser.* && cpy file-header.js . --rename=markdownlint-browser.js && tsc --allowJs --resolveJsonModule --outDir ../lib-es3 ../lib/markdownlint.js && browserify ../lib-es3/lib/markdownlint.js --standalone markdownlint >> markdownlint-browser.js && uglifyjs markdownlint-browser.js --compress --mangle --comments --output markdownlint-browser.min.js",
|
"build-demo": "cpy node_modules/markdown-it/dist/markdown-it.min.js demo && cd demo && rimraf markdownlint-browser.* && cpy file-header.js . --rename=markdownlint-browser.js && tsc --allowJs --resolveJsonModule --outDir ../lib-es3 ../lib/markdownlint.js && browserify ../lib-es3/lib/markdownlint.js --standalone markdownlint >> markdownlint-browser.js && uglifyjs markdownlint-browser.js --compress --mangle --comments --output markdownlint-browser.min.js",
|
||||||
"build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
|
"build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
|
||||||
|
|
|
@ -4,7 +4,7 @@ const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
const markdownlint = require("../lib/markdownlint");
|
const markdownlint = require("../lib/markdownlint");
|
||||||
const shared = require("../lib/shared");
|
const { newLineRe, utf8Encoding } = require("../helpers");
|
||||||
|
|
||||||
module.exports.typeTestFiles = function typeTestFiles(test) {
|
module.exports.typeTestFiles = function typeTestFiles(test) {
|
||||||
// Simulates typing each test file to validate handling of partial input
|
// Simulates typing each test file to validate handling of partial input
|
||||||
|
@ -15,7 +15,7 @@ module.exports.typeTestFiles = function typeTestFiles(test) {
|
||||||
},
|
},
|
||||||
"resultVersion": 0
|
"resultVersion": 0
|
||||||
});
|
});
|
||||||
const contentLineCount = content.split(shared.newLineRe).length;
|
const contentLineCount = content.split(newLineRe).length;
|
||||||
Object.keys(results.content).forEach(function forKey(ruleName) {
|
Object.keys(results.content).forEach(function forKey(ruleName) {
|
||||||
results.content[ruleName].forEach(function forLine(line) {
|
results.content[ruleName].forEach(function forLine(line) {
|
||||||
test.ok((line >= 1) && (line <= contentLineCount),
|
test.ok((line >= 1) && (line <= contentLineCount),
|
||||||
|
@ -28,7 +28,7 @@ module.exports.typeTestFiles = function typeTestFiles(test) {
|
||||||
files.forEach(function forFile(file) {
|
files.forEach(function forFile(file) {
|
||||||
if (/\.md$/.test(file)) {
|
if (/\.md$/.test(file)) {
|
||||||
let content = fs.readFileSync(
|
let content = fs.readFileSync(
|
||||||
path.join("./test", file), shared.utf8Encoding);
|
path.join("./test", file), utf8Encoding);
|
||||||
while (content) {
|
while (content) {
|
||||||
validate(file, content);
|
validate(file, content);
|
||||||
content = content.slice(0, -1);
|
content = content.slice(0, -1);
|
||||||
|
|
|
@ -11,7 +11,7 @@ const pluginSup = require("markdown-it-sup");
|
||||||
const tv4 = require("tv4");
|
const tv4 = require("tv4");
|
||||||
const packageJson = require("../package.json");
|
const packageJson = require("../package.json");
|
||||||
const markdownlint = require("../lib/markdownlint");
|
const markdownlint = require("../lib/markdownlint");
|
||||||
const shared = require("../lib/shared");
|
const helpers = require("../helpers");
|
||||||
const rules = require("../lib/rules");
|
const rules = require("../lib/rules");
|
||||||
const customRules = require("./rules/rules.js");
|
const customRules = require("./rules/rules.js");
|
||||||
const defaultConfig = require("./markdownlint-test-default-config.json");
|
const defaultConfig = require("./markdownlint-test-default-config.json");
|
||||||
|
@ -39,7 +39,7 @@ function createTestForFile(file) {
|
||||||
const actualPromise = promisify(fs.stat, configFile)
|
const actualPromise = promisify(fs.stat, configFile)
|
||||||
.then(
|
.then(
|
||||||
function configFileExists() {
|
function configFileExists() {
|
||||||
return promisify(fs.readFile, configFile, shared.utf8Encoding)
|
return promisify(fs.readFile, configFile, helpers.utf8Encoding)
|
||||||
.then(JSON.parse);
|
.then(JSON.parse);
|
||||||
},
|
},
|
||||||
function noConfigFile() {
|
function noConfigFile() {
|
||||||
|
@ -48,7 +48,7 @@ function createTestForFile(file) {
|
||||||
.then(
|
.then(
|
||||||
function lintWithConfig(config) {
|
function lintWithConfig(config) {
|
||||||
const mergedConfig =
|
const mergedConfig =
|
||||||
shared.assign(shared.clone(defaultConfig), config);
|
helpers.assign(helpers.clone(defaultConfig), config);
|
||||||
return promisify(markdownlint, {
|
return promisify(markdownlint, {
|
||||||
"files": [ file ],
|
"files": [ file ],
|
||||||
"config": mergedConfig,
|
"config": mergedConfig,
|
||||||
|
@ -56,7 +56,7 @@ function createTestForFile(file) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const expectedPromise = detailedResults ?
|
const expectedPromise = detailedResults ?
|
||||||
promisify(fs.readFile, resultsFile, shared.utf8Encoding)
|
promisify(fs.readFile, resultsFile, helpers.utf8Encoding)
|
||||||
.then(
|
.then(
|
||||||
function fileContents(contents) {
|
function fileContents(contents) {
|
||||||
const errorObjects = JSON.parse(contents);
|
const errorObjects = JSON.parse(contents);
|
||||||
|
@ -68,10 +68,10 @@ function createTestForFile(file) {
|
||||||
});
|
});
|
||||||
return errorObjects;
|
return errorObjects;
|
||||||
}) :
|
}) :
|
||||||
promisify(fs.readFile, file, shared.utf8Encoding)
|
promisify(fs.readFile, file, helpers.utf8Encoding)
|
||||||
.then(
|
.then(
|
||||||
function fileContents(contents) {
|
function fileContents(contents) {
|
||||||
const lines = contents.split(shared.newLineRe);
|
const lines = contents.split(helpers.newLineRe);
|
||||||
const results = {};
|
const results = {};
|
||||||
lines.forEach(function forLine(line, lineNum) {
|
lines.forEach(function forLine(line, lineNum) {
|
||||||
const regex = /\{(MD\d+)(?::(\d+))?\}/g;
|
const regex = /\{(MD\d+)(?::(\d+))?\}/g;
|
||||||
|
@ -114,7 +114,8 @@ module.exports.projectFiles = function projectFiles(test) {
|
||||||
const options = {
|
const options = {
|
||||||
"files": [
|
"files": [
|
||||||
"README.md",
|
"README.md",
|
||||||
"CONTRIBUTING.md"
|
"CONTRIBUTING.md",
|
||||||
|
"helpers/README.md"
|
||||||
],
|
],
|
||||||
"noInlineConfig": true,
|
"noInlineConfig": true,
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -126,7 +127,8 @@ module.exports.projectFiles = function projectFiles(test) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const expected = {
|
const expected = {
|
||||||
"README.md": [],
|
"README.md": [],
|
||||||
"CONTRIBUTING.md": []
|
"CONTRIBUTING.md": [],
|
||||||
|
"helpers/README.md": []
|
||||||
};
|
};
|
||||||
test.deepEqual(actual, expected, "Issue(s) with project files.");
|
test.deepEqual(actual, expected, "Issue(s) with project files.");
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1098,7 +1100,7 @@ module.exports.readme = function readme(test) {
|
||||||
tagToRules[tag] = tagRules;
|
tagToRules[tag] = tagRules;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
fs.readFile("README.md", shared.utf8Encoding,
|
fs.readFile("README.md", helpers.utf8Encoding,
|
||||||
function readFile(err, contents) {
|
function readFile(err, contents) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const rulesLeft = rules.slice();
|
const rulesLeft = rules.slice();
|
||||||
|
@ -1156,7 +1158,7 @@ module.exports.readme = function readme(test) {
|
||||||
|
|
||||||
module.exports.doc = function doc(test) {
|
module.exports.doc = function doc(test) {
|
||||||
test.expect(312);
|
test.expect(312);
|
||||||
fs.readFile("doc/Rules.md", shared.utf8Encoding,
|
fs.readFile("doc/Rules.md", helpers.utf8Encoding,
|
||||||
function readFile(err, contents) {
|
function readFile(err, contents) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const rulesLeft = rules.slice();
|
const rulesLeft = rules.slice();
|
||||||
|
@ -1323,7 +1325,7 @@ function clearHtmlCommentTextValid(test) {
|
||||||
"<!--",
|
"<!--",
|
||||||
" \\"
|
" \\"
|
||||||
];
|
];
|
||||||
const actual = shared.clearHtmlCommentText(validComments.join("\n"));
|
const actual = helpers.clearHtmlCommentText(validComments.join("\n"));
|
||||||
const expected = validResult.join("\n");
|
const expected = validResult.join("\n");
|
||||||
test.equal(actual, expected);
|
test.equal(actual, expected);
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1350,7 +1352,7 @@ function clearHtmlCommentTextInvalid(test) {
|
||||||
"<!--text--->",
|
"<!--text--->",
|
||||||
"<!--te--xt-->"
|
"<!--te--xt-->"
|
||||||
];
|
];
|
||||||
const actual = shared.clearHtmlCommentText(invalidComments.join("\n"));
|
const actual = helpers.clearHtmlCommentText(invalidComments.join("\n"));
|
||||||
const expected = invalidComments.join("\n");
|
const expected = invalidComments.join("\n");
|
||||||
test.equal(actual, expected);
|
test.equal(actual, expected);
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1371,7 +1373,7 @@ function clearHtmlCommentTextNonGreedy(test) {
|
||||||
"<!-- --> -->",
|
"<!-- --> -->",
|
||||||
"<!----> -->"
|
"<!----> -->"
|
||||||
];
|
];
|
||||||
const actual = shared.clearHtmlCommentText(nonGreedyComments.join("\n"));
|
const actual = helpers.clearHtmlCommentText(nonGreedyComments.join("\n"));
|
||||||
const expected = nonGreedyResult.join("\n");
|
const expected = nonGreedyResult.join("\n");
|
||||||
test.equal(actual, expected);
|
test.equal(actual, expected);
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1394,7 +1396,7 @@ function clearHtmlCommentTextEmbedded(test) {
|
||||||
"text<!-- markdownlint-disable MD010 -->text",
|
"text<!-- markdownlint-disable MD010 -->text",
|
||||||
"text<!-- -->text"
|
"text<!-- -->text"
|
||||||
];
|
];
|
||||||
const actual = shared.clearHtmlCommentText(embeddedComments.join("\n"));
|
const actual = helpers.clearHtmlCommentText(embeddedComments.join("\n"));
|
||||||
const expected = embeddedResult.join("\n");
|
const expected = embeddedResult.join("\n");
|
||||||
test.equal(actual, expected);
|
test.equal(actual, expected);
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1421,7 +1423,7 @@ module.exports.isBlankLine = function isBlankLine(test) {
|
||||||
"> <!--text-->",
|
"> <!--text-->",
|
||||||
">><!--text-->"
|
">><!--text-->"
|
||||||
];
|
];
|
||||||
blankLines.forEach((line) => test.ok(shared.isBlankLine(line), line));
|
blankLines.forEach((line) => test.ok(helpers.isBlankLine(line), line));
|
||||||
const nonBlankLines = [
|
const nonBlankLines = [
|
||||||
"text",
|
"text",
|
||||||
" text ",
|
" text ",
|
||||||
|
@ -1432,7 +1434,7 @@ module.exports.isBlankLine = function isBlankLine(test) {
|
||||||
"<!--",
|
"<!--",
|
||||||
"-->"
|
"-->"
|
||||||
];
|
];
|
||||||
nonBlankLines.forEach((line) => test.ok(!shared.isBlankLine(line), line));
|
nonBlankLines.forEach((line) => test.ok(!helpers.isBlankLine(line), line));
|
||||||
test.done();
|
test.done();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1449,7 +1451,7 @@ module.exports.includesSorted = function includesSorted(test) {
|
||||||
];
|
];
|
||||||
inputs.forEach((input) => {
|
inputs.forEach((input) => {
|
||||||
for (let i = 0; i <= 21; i++) {
|
for (let i = 0; i <= 21; i++) {
|
||||||
test.equal(shared.includesSorted(input, i), input.includes(i));
|
test.equal(helpers.includesSorted(input, i), input.includes(i));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1475,9 +1477,9 @@ module.exports.trimLeftRight = function trimLeftRight(test) {
|
||||||
];
|
];
|
||||||
test.expect(inputs.length * 2);
|
test.expect(inputs.length * 2);
|
||||||
inputs.forEach(function forInput(input) {
|
inputs.forEach(function forInput(input) {
|
||||||
test.equal(shared.trimLeft(input), input.trimLeft(),
|
test.equal(helpers.trimLeft(input), input.trimLeft(),
|
||||||
"trimLeft incorrect for '" + input + "'");
|
"trimLeft incorrect for '" + input + "'");
|
||||||
test.equal(shared.trimRight(input), input.trimRight(),
|
test.equal(helpers.trimRight(input), input.trimRight(),
|
||||||
"trimRight incorrect for '" + input + "'");
|
"trimRight incorrect for '" + input + "'");
|
||||||
});
|
});
|
||||||
test.done();
|
test.done();
|
||||||
|
@ -1571,7 +1573,7 @@ module.exports.forEachInlineCodeSpan = function forEachInlineCodeSpan(test) {
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
testCases.forEach((testCase) => {
|
||||||
const [ input, expecteds ] = testCase;
|
const [ input, expecteds ] = testCase;
|
||||||
shared.forEachInlineCodeSpan(input, (code, line, column, ticks) => {
|
helpers.forEachInlineCodeSpan(input, (code, line, column, ticks) => {
|
||||||
const [ expectedCode, expectedLine, expectedColumn, expectedTicks ] =
|
const [ expectedCode, expectedLine, expectedColumn, expectedTicks ] =
|
||||||
expecteds.shift();
|
expecteds.shift();
|
||||||
test.equal(code, expectedCode, input);
|
test.equal(code, expectedCode, input);
|
||||||
|
@ -1611,9 +1613,9 @@ module.exports.configMultiple = function configMultiple(test) {
|
||||||
markdownlint.readConfig("./test/config/config-grandparent.json",
|
markdownlint.readConfig("./test/config/config-grandparent.json",
|
||||||
function callback(err, actual) {
|
function callback(err, actual) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -1689,9 +1691,9 @@ module.exports.configMultipleYaml = function configMultipleYaml(test) {
|
||||||
[ require("js-yaml").safeLoad ],
|
[ require("js-yaml").safeLoad ],
|
||||||
function callback(err, actual) {
|
function callback(err, actual) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -1707,9 +1709,9 @@ module.exports.configMultipleHybrid = function configMultipleHybrid(test) {
|
||||||
[ JSON.parse, require("toml").parse, require("js-yaml").safeLoad ],
|
[ JSON.parse, require("toml").parse, require("js-yaml").safeLoad ],
|
||||||
function callback(err, actual) {
|
function callback(err, actual) {
|
||||||
test.ifError(err);
|
test.ifError(err);
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -1756,9 +1758,9 @@ module.exports.configMultipleSync = function configMultipleSync(test) {
|
||||||
test.expect(1);
|
test.expect(1);
|
||||||
const actual =
|
const actual =
|
||||||
markdownlint.readConfigSync("./test/config/config-grandparent.json");
|
markdownlint.readConfigSync("./test/config/config-grandparent.json");
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -1837,9 +1839,9 @@ module.exports.configMultipleYamlSync = function configMultipleYamlSync(test) {
|
||||||
test.expect(1);
|
test.expect(1);
|
||||||
const actual = markdownlint.readConfigSync(
|
const actual = markdownlint.readConfigSync(
|
||||||
"./test/config/config-grandparent.yaml", [ require("js-yaml").safeLoad ]);
|
"./test/config/config-grandparent.yaml", [ require("js-yaml").safeLoad ]);
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -1853,9 +1855,9 @@ function configMultipleHybridSync(test) {
|
||||||
const actual = markdownlint.readConfigSync(
|
const actual = markdownlint.readConfigSync(
|
||||||
"./test/config/config-grandparent-hybrid.yaml",
|
"./test/config/config-grandparent-hybrid.yaml",
|
||||||
[ JSON.parse, require("toml").parse, require("js-yaml").safeLoad ]);
|
[ JSON.parse, require("toml").parse, require("js-yaml").safeLoad ]);
|
||||||
const expected = shared.assign(
|
const expected = helpers.assign(
|
||||||
shared.assign(
|
helpers.assign(
|
||||||
shared.assign({}, require("./config/config-child.json")),
|
helpers.assign({}, require("./config/config-child.json")),
|
||||||
require("./config/config-parent.json")),
|
require("./config/config-parent.json")),
|
||||||
require("./config/config-grandparent.json"));
|
require("./config/config-grandparent.json"));
|
||||||
delete expected.extends;
|
delete expected.extends;
|
||||||
|
@ -2266,7 +2268,7 @@ module.exports.customRulesBadProperty = function customRulesBadProperty(test) {
|
||||||
].forEach(function forProperty(property) {
|
].forEach(function forProperty(property) {
|
||||||
const propertyName = property[0];
|
const propertyName = property[0];
|
||||||
property[1].forEach(function forPropertyValue(propertyValue) {
|
property[1].forEach(function forPropertyValue(propertyValue) {
|
||||||
const badRule = shared.clone(customRules.anyBlockquote);
|
const badRule = helpers.clone(customRules.anyBlockquote);
|
||||||
badRule[propertyName] = propertyValue;
|
badRule[propertyName] = propertyValue;
|
||||||
const options = {
|
const options = {
|
||||||
"customRules": [ badRule ]
|
"customRules": [ badRule ]
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { URL } = require("url");
|
const { URL } = require("url");
|
||||||
|
const { filterTokens } = require("../../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "any-blockquote" ],
|
"names": [ "any-blockquote" ],
|
||||||
|
@ -12,10 +13,8 @@ module.exports = {
|
||||||
"/blob/master/test/rules/any-blockquote.js"
|
"/blob/master/test/rules/any-blockquote.js"
|
||||||
),
|
),
|
||||||
"tags": [ "test" ],
|
"tags": [ "test" ],
|
||||||
"function": function rule(params, onError) {
|
"function": (params, onError) => {
|
||||||
params.tokens.filter(function filterToken(token) {
|
filterTokens(params, "blockquote_open", (blockquote) => {
|
||||||
return token.type === "blockquote_open";
|
|
||||||
}).forEach(function forToken(blockquote) {
|
|
||||||
const lines = blockquote.map[1] - blockquote.map[0];
|
const lines = blockquote.map[1] - blockquote.map[0];
|
||||||
onError({
|
onError({
|
||||||
"lineNumber": blockquote.lineNumber,
|
"lineNumber": blockquote.lineNumber,
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const { forEachLine, getLineMetadata } = require("../../helpers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "every-n-lines" ],
|
"names": [ "every-n-lines" ],
|
||||||
"description": "Rule that reports an error every N lines",
|
"description": "Rule that reports an error every N lines",
|
||||||
"tags": [ "test" ],
|
"tags": [ "test" ],
|
||||||
"function": function rule(params, onError) {
|
"function": (params, onError) => {
|
||||||
const n = params.config.n || 2;
|
const n = params.config.n || 2;
|
||||||
params.lines.forEach(function forLine(line, lineIndex) {
|
forEachLine(getLineMetadata(params), (line, lineIndex) => {
|
||||||
const lineNumber = lineIndex + 1;
|
const lineNumber = lineIndex + 1;
|
||||||
if ((lineNumber % n) === 0) {
|
if ((lineNumber % n) === 0) {
|
||||||
onError({
|
onError({
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue