We don't really care when this processor runs as long as it happens after the tags have been extracted. By not constraining its `runBefore` property we can ensure that other processors can be run before it. PR Close #24000
		
			
				
	
	
		
			71 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						|
/**
 | 
						|
 * 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'],
 | 
						|
    $runBefore: [],
 | 
						|
    $process(docs) {
 | 
						|
      const logMessage = this.failOnContentErrors ? log.error.bind(log) : log.warn.bind(log);
 | 
						|
      const errors = [];
 | 
						|
      docs.forEach(doc => {
 | 
						|
        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) {
 | 
						|
        logMessage('Content contains errors');
 | 
						|
        errors.forEach(docError => {
 | 
						|
          const errors = docError.errors.join('\n        ');
 | 
						|
          logMessage(createDocMessage(errors + '\n        ', docError.doc));
 | 
						|
        });
 | 
						|
        if (this.failOnContentErrors) {
 | 
						|
          throw new Error('Stopping due to content errors.');
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
};
 |