build(aio): create noMarkdownHeadings content rule (#22759)
This content rule can check what markdown headings appear in content properties. PR Close #22759
This commit is contained in:

committed by
Igor Minar

parent
e0ae74d40e
commit
7a8c58162c
50
aio/tools/transforms/angular-api-package/content-rules/noMarkdownHeadings.js
vendored
Normal file
50
aio/tools/transforms/angular-api-package/content-rules/noMarkdownHeadings.js
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 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 ');
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
const createNoMarkdownHeadings = require('./noMarkdownHeadings');
|
||||||
|
|
||||||
|
describe('createNoMarkdownHeadings rule', () => {
|
||||||
|
|
||||||
|
const noMarkdownHeadings = createNoMarkdownHeadings();
|
||||||
|
|
||||||
|
it('should return `undefined` if there is no heading in a value', () => {
|
||||||
|
expect(noMarkdownHeadings({}, 'description', 'some ## text'))
|
||||||
|
.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error message if there is a markdown heading in a single line value', () => {
|
||||||
|
expect(noMarkdownHeadings({}, 'description', '# heading 1'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "# heading 1".');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error message if there is a markdown heading in a multiline value', () => {
|
||||||
|
expect(noMarkdownHeadings({}, 'description', 'some text\n# heading 1'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "# heading 1".');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cope with up to 3 spaces before the heading marker', () => {
|
||||||
|
expect(noMarkdownHeadings({}, 'description', ' # heading 1'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: " # heading 1".');
|
||||||
|
expect(noMarkdownHeadings({}, 'description', ' # heading 1'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: " # heading 1".');
|
||||||
|
expect(noMarkdownHeadings({}, 'description', ' # heading 1'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: " # heading 1".');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error message for each heading found', () => {
|
||||||
|
expect(noMarkdownHeadings({}, 'description', '# heading 1\nsome text\n## heading 2\nmore text\n### heading 3'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "# heading 1", "## heading 2" and "### heading 3".');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('(specified heading levels)', () => {
|
||||||
|
it('should take heading levels into account', () => {
|
||||||
|
const noTopLevelHeadings = createNoMarkdownHeadings(1);
|
||||||
|
expect(noTopLevelHeadings({}, 'description', '# top level'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "# top level".');
|
||||||
|
expect(noTopLevelHeadings({}, 'description', '## second level'))
|
||||||
|
.toBeUndefined();
|
||||||
|
expect(noTopLevelHeadings({}, 'description', '### third level'))
|
||||||
|
.toBeUndefined();
|
||||||
|
expect(noTopLevelHeadings({}, 'description', '#### fourth level'))
|
||||||
|
.toBeUndefined();
|
||||||
|
|
||||||
|
const allowLevel3Headings = createNoMarkdownHeadings(1, 2, '4,');
|
||||||
|
expect(allowLevel3Headings({}, 'description', '# top level'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "# top level".');
|
||||||
|
expect(allowLevel3Headings({}, 'description', '## second level'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "## second level".');
|
||||||
|
expect(allowLevel3Headings({}, 'description', '### third level'))
|
||||||
|
.toBeUndefined();
|
||||||
|
expect(allowLevel3Headings({}, 'description', '#### fourth level'))
|
||||||
|
.toEqual('Invalid headings found in "description" property: "#### fourth level".');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user