50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
/**
|
|
* A factory for creating a rule for the `checkContentRules` processor, which disallows markdown
|
|
* headings in a content property.
|
|
*
|
|
* @param {...number|string} disallowedHeadings
|
|
* Each parameter identifies heading levels that are not allowed. They can be in the form of:
|
|
*
|
|
* - a number (e.g. 1), which implies that the specified heading is not allowed
|
|
* - a range (e.g. '2,3'), which implies the range of headings that are not allowed
|
|
*
|
|
* (A range can be open ended on the upper bound by not specifying a value after the comma.)
|
|
*
|
|
* @example
|
|
* To create a rule that will only allow level 3 headings:
|
|
*
|
|
* ```
|
|
* const rule = createNoMarkdownHeadingRule(1, 2, '4,');
|
|
* ```
|
|
*
|
|
*/
|
|
module.exports = function createrNoMarkdownHeadingRule() {
|
|
const args = Array.prototype.slice.apply(arguments);
|
|
const disallowedHeadings = args.map(arg => `#{${arg}}`);
|
|
if (!disallowedHeadings.length) {
|
|
disallowedHeadings.push('#{1,}');
|
|
}
|
|
const regex = new RegExp(`^ {0,3}(${disallowedHeadings.join('|')}) +.*$`, 'mg');
|
|
return (doc, prop, value) => {
|
|
let match, matches = [];
|
|
while(match = regex.exec(value)) { // eslint-disable-line no-cond-assign
|
|
matches.push(match[0]);
|
|
}
|
|
if (matches.length) {
|
|
const list = listify(matches.map(match => `"${match}"`));
|
|
return `Invalid headings found in "${prop}" property: ${list}.`;
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
* Convert an array of strings in to a human list - e.g separated by commas and the word `and`.
|
|
* @param {string[]} values The strings to convert to a list
|
|
*/
|
|
function listify(values) {
|
|
if (values.length <= 1) return values;
|
|
const last = values[values.length - 1];
|
|
const rest = values.slice(0, values.length - 1);
|
|
return [rest.join(', '), last].join(' and ');
|
|
} |