2018-03-13 18:24:47 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A processor that can run arbitrary checking rules against properties of documents
|
|
|
|
|
|
|
|
* The configuration for the processor is via the `docTypeRules`.
|
|
|
|
* This is a hash of docTypes to rulesets.
|
|
|
|
* Each rules set is a hash of properties to rule functions.
|
|
|
|
*
|
|
|
|
* The processor will run each rule function against each matching property of each matching doc.
|
|
|
|
*
|
|
|
|
* An example rule might look like:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* function noMarkdownHeadings(doc, prop, value) {
|
|
|
|
* const match = /^\s?#+\s+.*$/m.exec(value);
|
|
|
|
* if (match) {
|
|
|
|
* return `Headings not allowed in "${prop}" property. Found "${match[0]}"`;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
module.exports = function checkContentRules(log, createDocMessage) {
|
|
|
|
return {
|
|
|
|
/**
|
|
|
|
* {
|
|
|
|
* [docType]: {
|
|
|
|
* [property]: Array<(doc: Document, property: string, value: any) => string|undefined>
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
docTypeRules: {},
|
|
|
|
failOnContentErrors: false,
|
|
|
|
$runAfter: ['tags-extracted'],
|
2018-05-16 12:48:33 -04:00
|
|
|
$runBefore: [],
|
2018-03-13 18:24:47 -04:00
|
|
|
$process(docs) {
|
2018-06-06 07:22:25 -04:00
|
|
|
const logMessage = this.failOnContentErrors ? log.error.bind(log) : log.warn.bind(log);
|
2018-03-13 18:24:47 -04:00
|
|
|
const errors = [];
|
|
|
|
docs.forEach(doc => {
|
2019-04-02 17:24:29 -04:00
|
|
|
// Ignore private exports (and members of a private export).
|
|
|
|
if (doc.id && doc.id.indexOf('ɵ') !== -1) return;
|
2018-03-13 18:24:47 -04:00
|
|
|
const docErrors = [];
|
|
|
|
const rules = this.docTypeRules[doc.docType] || {};
|
|
|
|
if (rules) {
|
|
|
|
Object.keys(rules).forEach(property => {
|
|
|
|
const ruleFns = rules[property];
|
|
|
|
ruleFns.forEach(ruleFn => {
|
|
|
|
const error = ruleFn(doc, property, doc[property]);
|
|
|
|
if (error) {
|
|
|
|
docErrors.push(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (docErrors.length) {
|
|
|
|
errors.push({ doc, errors: docErrors });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (errors.length) {
|
2018-06-06 07:22:25 -04:00
|
|
|
logMessage('Content contains errors');
|
2018-03-13 18:24:47 -04:00
|
|
|
errors.forEach(docError => {
|
|
|
|
const errors = docError.errors.join('\n ');
|
2018-06-06 07:22:25 -04:00
|
|
|
logMessage(createDocMessage(errors + '\n ', docError.doc));
|
2018-03-13 18:24:47 -04:00
|
|
|
});
|
|
|
|
if (this.failOnContentErrors) {
|
|
|
|
throw new Error('Stopping due to content errors.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|