49 lines
1.2 KiB
JavaScript
49 lines
1.2 KiB
JavaScript
// @ts-check
|
|
|
|
/**
|
|
* @typedef {object} ErrorInfo
|
|
* @property {number} lineNumber
|
|
* @property {string} [context]
|
|
* @property {string} [detail]
|
|
* @property {[number, number]} [range]
|
|
*/
|
|
|
|
/**
|
|
* @typedef {object} Params
|
|
* @property {string[]} lines
|
|
*/
|
|
|
|
/** @typedef {(error: ErrorInfo) => void} OnError */
|
|
|
|
/**
|
|
* @typedef {object} Rule
|
|
* @property {string[]} names
|
|
* @property {string} description
|
|
* @property {string[]} tags
|
|
* @property {(params: Params, onError: OnError) => void} function
|
|
*/
|
|
|
|
/** @type {Rule} */
|
|
export default {
|
|
names: ["one-sentence-per-line"],
|
|
description: "Each sentence must be on its own line",
|
|
tags: ["sentences"],
|
|
function: function (params, onError) {
|
|
let inFence = false;
|
|
params.lines.forEach((line, index) => {
|
|
if (/^```/.test(line)) {
|
|
inFence = !inFence;
|
|
return;
|
|
}
|
|
if (inFence) return;
|
|
// Skip headings, blank lines, HTML, table rows
|
|
if (/^(#|\s*[|<]|>|\s*$)/.test(line)) return;
|
|
// Strip list marker before checking
|
|
const text = line.replace(/^\s*(?:[-*+]|\d+\.)\s+/, "");
|
|
if (/[.!?]\s+[A-Z]/.test(text)) {
|
|
onError({ lineNumber: index + 1, context: text.trim() });
|
|
}
|
|
});
|
|
},
|
|
};
|