markdownlint/lib/md055.js

73 lines
2.9 KiB
JavaScript
Raw Normal View History

// @ts-check
"use strict";
const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs");
const whitespaceTypes = new Set([ "linePrefix", "whitespace" ]);
const ignoreWhitespace = (tokens) => tokens.filter(
(token) => !whitespaceTypes.has(token.type)
);
const firstOrNothing = (items) => items[0];
const lastOrNothing = (items) => items[items.length - 1];
const makeRange = (start, end) => [ start, end - start + 1 ];
module.exports = {
"names": [ "MD055", "table-pipe-style" ],
"description": "Table pipe style",
"tags": [ "table" ],
"function": function MD055(params, onError) {
const style = String(params.config.style || "consistent");
let expectedStyle = style;
let expectedLeadingPipe =
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "trailing_only"));
let expectedTrailingPipe =
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "leading_only"));
const tables = filterByTypes(params.parsers.micromark.tokens, [ "table" ]);
for (const table of tables) {
const rows = filterByTypes(table.children, [ "tableDelimiterRow", "tableRow" ]);
for (const row of rows) {
// The following uses of first/lastOrNothing lack fallback handling
// because it seems not to be possible (i.e., 0% coverage)
const firstCell = firstOrNothing(row.children);
const leadingToken = firstOrNothing(ignoreWhitespace(firstCell.children));
const actualLeadingPipe = (leadingToken.type === "tableCellDivider");
const lastCell = lastOrNothing(row.children);
const trailingToken = lastOrNothing(ignoreWhitespace(lastCell.children));
const actualTrailingPipe = (trailingToken.type === "tableCellDivider");
const actualStyle = actualLeadingPipe ?
(actualTrailingPipe ? "leading_and_trailing" : "leading_only") :
(actualTrailingPipe ? "trailing_only" : "no_leading_or_trailing");
if (expectedStyle === "consistent") {
expectedStyle = actualStyle;
expectedLeadingPipe = actualLeadingPipe;
expectedTrailingPipe = actualTrailingPipe;
}
if (actualLeadingPipe !== expectedLeadingPipe) {
addErrorDetailIf(
onError,
firstCell.startLine,
expectedStyle,
actualStyle,
`${expectedLeadingPipe ? "Missing" : "Unexpected"} leading pipe`,
undefined,
makeRange(row.startColumn, firstCell.startColumn)
);
}
if (actualTrailingPipe !== expectedTrailingPipe) {
addErrorDetailIf(
onError,
lastCell.endLine,
expectedStyle,
actualStyle,
`${expectedTrailingPipe ? "Missing" : "Unexpected"} trailing pipe`,
undefined,
makeRange(lastCell.endColumn - 1, row.endColumn - 1)
);
}
}
}
}
}