UNPKG

mdclint

Version:

Markdown Linting

503 lines (497 loc) 15.3 kB
import { l as lintSync, g as getMarkdownlintOptions } from './shared/mdclint.C8nPUujy.mjs'; import 'c12'; import 'glob'; import 'node:fs'; import 'node:module'; import 'node:os'; import 'node:path'; import 'remark-mdc'; 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: "Code block style", 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: "Line length", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md011", fixable: "code" }, MD012: { name: "md012", description: "Multiple top-level headings in the same document", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md012", fixable: "whitespace" }, MD013: { name: "md013", description: "Multiple blank lines", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013" }, MD014: { name: "md014", description: "No empty sections", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md014", fixable: "code" }, MD018: { name: "md018", description: "No space after hash", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md018", fixable: "whitespace" }, MD019: { name: "md019", description: "No space after hash", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md019", fixable: "whitespace" }, MD020: { name: "md020", description: "No space after hash", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md020", fixable: "whitespace" }, MD021: { name: "md021", description: "Multiple headings with the same content", 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 should be surrounded by blank lines", 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 header", 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: "Multiple spaces after blockquote symbol", 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: "Spaces inside code span elements", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md034", fixable: "code" }, MD035: { name: "md035", description: "Spaces inside code span elements", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md035" }, MD036: { name: "md036", description: "Spaces inside emphasis markers", 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 emphasis markers", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md038", fixable: "code" }, MD039: { name: "md039", description: "Spaces inside emphasis markers", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md039", fixable: "code" }, MD040: { name: "md040", description: "Spaces inside emphasis markers", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md040" }, MD041: { name: "md041", description: "First line in file should be a top level heading", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md041" }, MD042: { name: "md042", description: "First line in file should be a top level heading", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md042" }, MD043: { name: "md043", description: "First line in file should be a top level heading", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md043" }, MD044: { name: "md044", description: "MD044", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md044", fixable: "code" }, MD045: { name: "md045", description: "MD045", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md045" }, MD046: { name: "md046", description: "MD046", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md046" }, MD047: { name: "md047", description: "MD047", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md047", fixable: "whitespace" }, MD048: { name: "md048", description: "MD048", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md048" }, MD049: { name: "md049", description: "MD049", url: "https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md049", fixable: "code" }, MD050: { name: "md050", description: "MD050", 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: "Link and image 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" } }; 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: err.lineNumber - (err.fixInfo.deleteCount || 0), 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) => { 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 (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); reportErrors(context, handledErrors); } }; } }; }; } async function index(opts) { const ruleNames = Object.keys(rules); const options = await getMarkdownlintOptions(process.cwd(), { preset: opts?.preset, overrides: opts?.markdownlint?.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: opts?.files ?? ["**/*.md"], plugins: { mdclint: { configs: { recommended: { plugins: ["mdclint"], rules: recommendedRules } }, rules: { ...Object.fromEntries(rulesToCheck.map(([ruleName, option]) => [ `${ruleName.toLowerCase()}`, ruleChecker(rules[ruleName]) ])) } } }, languageOptions: { parser: { parseForESLint } }, 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 }; } export { index as mdcLint };