remark-lint-word-case
Version:
remark-lint rule to ensure specified words are written in the correct casing.
53 lines (51 loc) • 2.04 kB
JavaScript
// src/index.ts
import { lintRule } from "unified-lint-rule";
import { visit } from "unist-util-visit";
import { location } from "vfile-location";
var RULE_ID = "word-case";
var SOURCE_ID = `remark-lint:${RULE_ID}`;
var ERRORS = {
OPTIONS_UNDEFINED: "Options must include a `words` key.",
OPTIONS_INVALID: "`words` must be a non-empty array of unique string values."
};
function wordCaseRule(tree, file, options) {
if (!options?.words) {
file.fail(ERRORS.OPTIONS_UNDEFINED, undefined, SOURCE_ID);
}
if (!Array.isArray(options.words) || options.words.length === 0 || options.words.some((word) => typeof word !== "string")) {
file.fail(ERRORS.OPTIONS_INVALID, undefined, SOURCE_ID);
}
const caseMap = new Map(options.words.map((word) => [word.toLowerCase(), word]));
const pattern = new RegExp(`\\b(${options.words.join("|")})\\b`, "gi");
const loc = location(file);
visit(tree, "text", (node) => {
if (!node.position?.start?.offset) {
return;
}
const nodeStartOffset = node.position.start.offset;
let match;
while ((match = pattern.exec(node.value)) !== null) {
const actual = match[0];
const lowercasedActual = actual.toLowerCase();
const expected = caseMap.get(lowercasedActual);
if (expected && expected !== actual) {
const wordStartIndex = match.index;
const wordStartOffset = nodeStartOffset + wordStartIndex;
const wordEndOffset = wordStartOffset + actual.length;
const start = loc.toPoint(wordStartOffset);
const end = loc.toPoint(wordEndOffset);
const message = file.message(`Incorrect word case. Expected \`${expected}\` but found \`${actual}\``, { start, end }, `${SOURCE_ID}:${RULE_ID}`);
message.expected = [expected];
message.actual = actual;
}
}
});
}
var remarkLintWordCase = lintRule(SOURCE_ID, wordCaseRule);
var src_default = remarkLintWordCase;
export {
src_default as default,
ERRORS
};
//# debugId=C716057062C8CA9F64756E2164756E21
//# sourceMappingURL=index.js.map