mdclint
Version:
Markdown Linting
591 lines (583 loc) • 18.4 kB
JavaScript
import { l as lintSync, a as getMarkdownlintOptions } from './shared/mdclint.CxcuYGgq.mjs';
import 'node:fs';
import 'fs';
import 'path';
import 'os';
import 'crypto';
import 'node:fs/promises';
import 'node:url';
import 'node:os';
import 'node:path';
import 'node:assert';
import 'node:process';
import 'node:v8';
import 'node:util';
import 'node:module';
import 'node:events';
import 'node:stream';
import 'node:string_decoder';
const rules = {
MD001: {
name: "md001",
description: "Heading levels should only increment by one level at a time",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md001"
},
MD003: {
name: "md003",
description: "Heading style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md003"
},
MD004: {
name: "md004",
description: "Unordered list style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md004",
fixable: "code"
},
MD005: {
name: "md005",
description: "Inconsistent indentation for list items at the same level",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md005"
},
MD007: {
name: "md007",
description: "Unordered list indentation",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md007",
fixable: "whitespace"
},
MD009: {
name: "md009",
description: "Trailing spaces",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md009",
fixable: "whitespace"
},
MD010: {
name: "md010",
description: "Hard tabs",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md010",
fixable: "whitespace"
},
MD011: {
name: "md011",
description: "Reversed link syntax",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md011",
fixable: "code"
},
MD012: {
name: "md012",
description: "Multiple consecutive blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md012",
fixable: "whitespace"
},
MD013: {
name: "md013",
description: "Line length",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013"
},
MD014: {
name: "md014",
description: "Dollar signs used before commands without showing output",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md014",
fixable: "code"
},
MD018: {
name: "md018",
description: "No space after hash on atx style heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md018",
fixable: "whitespace"
},
MD019: {
name: "md019",
description: "Multiple spaces after hash on atx style heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md019",
fixable: "whitespace"
},
MD020: {
name: "md020",
description: "No space inside hashes on closed atx style heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md020",
fixable: "whitespace"
},
MD021: {
name: "md021",
description: "Multiple spaces inside hashes on closed atx style heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md021",
fixable: "whitespace"
},
MD022: {
name: "md022",
description: "Headings should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md022",
fixable: "whitespace"
},
MD023: {
name: "md023",
description: "Headings must start at the beginning of the line",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md023",
fixable: "whitespace"
},
MD024: {
name: "md024",
description: "Multiple headings with the same content",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md024"
},
MD025: {
name: "md025",
description: "Multiple top-level headings in the same document",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md025"
},
MD026: {
name: "md026",
description: "Trailing punctuation in heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md026",
fixable: "code"
},
MD027: {
name: "md027",
description: "Multiple spaces after blockquote symbol",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md027",
fixable: "whitespace"
},
MD028: {
name: "md028",
description: "Blank line inside blockquote",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md028"
},
MD029: {
name: "md029",
description: "Ordered list item prefix",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029"
},
MD030: {
name: "md030",
description: "Spaces after list markers",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md030",
fixable: "whitespace"
},
MD031: {
name: "md031",
description: "Fenced code blocks should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md031",
fixable: "whitespace"
},
MD032: {
name: "md032",
description: "Lists should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md032",
fixable: "whitespace"
},
MD033: {
name: "md033",
description: "Inline HTML",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md033"
},
MD034: {
name: "md034",
description: "Bare URL used",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md034",
fixable: "code"
},
MD035: {
name: "md035",
description: "Horizontal rule style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md035"
},
MD036: {
name: "md036",
description: "Emphasis used instead of a heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md036"
},
MD037: {
name: "md037",
description: "Spaces inside emphasis markers",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md037",
fixable: "code"
},
MD038: {
name: "md038",
description: "Spaces inside code span elements",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md038",
fixable: "code"
},
MD039: {
name: "md039",
description: "Spaces inside link text",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md039",
fixable: "code"
},
MD040: {
name: "md040",
description: "Fenced code blocks should have a language specified",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md040"
},
MD041: {
name: "md041",
description: "First line in a file should be a top-level heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md041"
},
MD042: {
name: "md042",
description: "No empty links",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md042"
},
MD043: {
name: "md043",
description: "Required heading structure",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md043"
},
MD044: {
name: "md044",
description: "Proper names should have the correct capitalization",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md044",
fixable: "code"
},
MD045: {
name: "md045",
description: "Images should have alternate text (alt text)",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md045"
},
MD046: {
name: "md046",
description: "Code block style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md046"
},
MD047: {
name: "md047",
description: "Files should end with a single newline character",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md047",
fixable: "whitespace"
},
MD048: {
name: "md048",
description: "Code fence style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md048"
},
MD049: {
name: "md049",
description: "Emphasis style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md049",
fixable: "code"
},
MD050: {
name: "md050",
description: "Strong style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md050",
fixable: "code"
},
MD051: {
name: "md051",
description: "Link fragments should be valid",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md051"
},
MD052: {
name: "md052",
description: "Reference links and images should use a label that is defined",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md052"
},
MD053: {
name: "md053",
description: "Link and image reference definitions should be needed",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md053"
},
MD054: {
name: "md054",
description: "Link and image style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md054"
},
MD055: {
name: "md055",
description: "Table pipe style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md055"
},
MD056: {
name: "md056",
description: "Table column count",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md056"
},
MD058: {
name: "md058",
description: "Tables should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md058",
fixable: "code"
},
MD059: {
name: "md059",
description: "Link text should be descriptive",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md059"
},
MD060: {
name: "md060",
description: "Table column style",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md060"
},
MDC007: {
name: "mdc007",
description: "Unordered list indentation",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md007",
fixable: "whitespace"
},
MDC018: {
name: "mdc018",
description: "No space after hash on atx style heading",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md018",
fixable: "whitespace"
},
MDC022: {
name: "mdc022",
description: "Headings should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md022",
fixable: "whitespace"
},
MDC023: {
name: "mdc023",
description: "Headings must start at the beginning of the line",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md023",
fixable: "whitespace"
},
MDC031: {
name: "mdc031",
description: "Fenced code blocks should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md031"
},
MDC032: {
name: "mdc032",
description: "Lists should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md032"
},
MDC034: {
name: "mdc034",
description: "Spaces inside code span elements",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md034",
fixable: "code"
},
MDC058: {
name: "mdc058",
description: "Tables should be surrounded by blank lines",
url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md058",
fixable: "code"
}
};
const allRulesDisabled = Object.keys(rules).reduce((o, key) => {
o[key] = false;
return o;
}, {});
const formatMessage = ({ ruleDescription, errorDetail, errorContext }) => {
let message = "";
message += ruleDescription;
if (errorDetail) {
message += ": " + errorDetail;
}
if (errorContext) {
message += ` [Context: ${errorContext}]`;
}
return message;
};
const getLocation = ({ lineNumber, errorRange }) => {
return {
start: {
line: lineNumber,
column: errorRange ? errorRange[0] : 0
},
end: {
line: lineNumber,
column: errorRange ? errorRange[0] + errorRange[1] : 0
}
};
};
const getRange = (src, err) => {
const errorLine = (err.fixInfo?.lineNumber || err.lineNumber) - 1;
const text = src.getText().split(/\r\n?|\n/g);
const charsBefore = text.slice(0, errorLine).reduce((acc, line) => line.length + 1 + acc, 0);
let start, end;
if (err.fixInfo === null) {
start = charsBefore;
end = start + text[err.lineNumber - 1].length + 1;
return [start, end];
}
if (err.lineNumber === text.length && err.fixInfo && (err.fixInfo.deleteCount || 0) < 0) {
start = src.getIndexFromLoc({
line: err.lineNumber + (err.fixInfo.deleteCount || 0),
column: 0
});
end = src.getIndexFromLoc({
line: err.lineNumber,
column: text[err.lineNumber - 1].length
});
return [start, end];
}
if (err.fixInfo && (err.fixInfo.deleteCount || 0) < 0) {
start = src.getIndexFromLoc({ line: err.lineNumber, column: 0 });
end = src.getIndexFromLoc({
line: Math.min(
src.lines.length,
err.lineNumber - (err.fixInfo.deleteCount || 0)
),
// line should not exceed number of lines in the source code
column: 0
});
return [start, end];
}
start = charsBefore + (err.fixInfo.editColumn || 1) - 1;
end = start + (err.fixInfo.deleteCount || 0);
return [start, end];
};
const md012Preprocessor = (errors) => {
const deleteLineErrors = errors.filter(
(err) => err.fixInfo && err.fixInfo.deleteCount === -1
);
const others = errors.filter((err) => !err.fixInfo || err.fixInfo.deleteCount !== -1);
const joinedErrors = [];
let line = null;
deleteLineErrors.forEach((dle) => {
if (!line) {
joinedErrors.push(dle);
line = dle.lineNumber;
} else if (dle.lineNumber === line + 1) {
joinedErrors[joinedErrors.length - 1].fixInfo.deleteCount += dle.fixInfo.deleteCount;
joinedErrors[joinedErrors.length - 1].errorDetail = dle.errorDetail;
line = dle.lineNumber;
}
});
return others.concat(joinedErrors);
};
const handleErrors = (errors, src, fixable) => {
if (errors.length && errors[0].ruleNames[0] === "MD012") {
errors = md012Preprocessor(errors);
}
return errors.map((err) => {
const error = {
loc: getLocation(err),
message: formatMessage(err),
fix: void 0
};
if (fixable && err.fixInfo) {
error.fix = function(fixer) {
const range = getRange(src, err);
if (range[0] === range[1]) {
return fixer.insertTextBeforeRange(range, err.fixInfo?.insertText || "");
}
return fixer.replaceTextRange(range, err.fixInfo?.insertText || "");
};
}
return error;
});
};
const reportErrors = (context, errors) => {
errors.forEach((err) => context.report(err));
};
function createRuleChecker(options) {
const lintOptions = {
...options,
config: allRulesDisabled
};
const check = (ruleId, src) => {
const { text: errors } = lintSync({
...lintOptions,
strings: { text: src.getText() },
config: {
...allRulesDisabled,
[ruleId]: options.config?.[ruleId.toLowerCase()] ?? options.config?.[ruleId.toUpperCase()] ?? true
}
});
return errors;
};
return function(rule) {
return {
meta: {
type: "layout",
docs: {
description: rule.description,
url: rule.url
},
schema: [],
fixable: rule.fixable
},
create: function(context) {
return {
Program() {
const src = context.sourceCode;
const errors = check(rule.name, src);
const handledErrors = handleErrors(errors, src, rule.fixable);
reportErrors(context, handledErrors);
}
};
}
};
};
}
const version = "0.1.2";
const parserMeta = {
name: "mdclint/markdown-parser",
version
};
const parser = { meta: parserMeta, parseForESLint };
async function index(opts) {
const { files, preset, ...markdownlintOptions } = opts ?? {};
const ruleNames = Object.keys(rules);
const options = await getMarkdownlintOptions(process.cwd(), {
preset,
overrides: markdownlintOptions.config
});
const config = options.config;
const rulesOptions = ruleNames.map((rule) => [rule, config[rule.toUpperCase()] ?? config[rule.toLowerCase()]]);
const rulesToCheck = rulesOptions.filter(([, options2]) => options2 !== false);
const recommendedRules = Object.fromEntries(rulesToCheck.map(([rule]) => [`mdclint/${rule.toLowerCase()}`, "error"]));
const ruleChecker = createRuleChecker(options);
return {
files: files ?? ["**/*.md"],
plugins: {
mdclint: {
configs: {
recommended: {
plugins: ["mdclint"],
rules: recommendedRules
}
},
rules: {
...Object.fromEntries(rulesToCheck.map(([ruleName, option]) => [
`${ruleName.toLowerCase()}`,
ruleChecker(rules[ruleName])
]))
}
}
},
languageOptions: {
parser
},
rules: recommendedRules
};
}
function parseForESLint(code, _options) {
const lines = code.split(/\r\n?|\n/g);
const linesCount = lines.length;
const lastLineLength = lines[linesCount - 1].length;
return {
ast: {
type: "Program",
start: 0,
end: 0,
loc: {
start: { line: 1, column: 0 },
end: { line: linesCount, column: lastLineLength }
},
range: [0, linesCount],
body: [],
comments: [],
tokens: [],
code
},
scopeManager: null,
visitorKeys: void 0
};
}
async function lint(text, fix = false) {
const options = await getMarkdownlintOptions(process.cwd(), { preset: "mdc" });
const lint2 = await import('./chunks/exports-sync.mjs').then((m) => m.lint);
const result = lint2({
strings: {
text
},
...options
});
return result;
}
export { lint, index as mdcLint };