All files / src/rules element-permitted-content.ts

95.83% Statements 23/24
93.33% Branches 14/15
100% Functions 6/6
95.83% Lines 23/24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62      1x   1x           413x       413x 413x   864x 413x         451x       451x 451x   451x 451x     466x 98x 98x           368x 27x 15x           451x 502x 37x 37x   465x          
import { Rule, RuleReport, RuleParserProxy } from '../rule';
import { DOMNode } from '../dom';
import { DOMReadyEvent } from '../event';
import { Validator } from '../meta';
 
export = {
	name: 'element-permitted-content',
	init,
} as Rule;
 
function init(parser: RuleParserProxy){
	parser.on('dom:ready', validate);
}
 
function validate(event: DOMReadyEvent, report: RuleReport){
	const doc = event.document;
	doc.visitDepthFirst((node: DOMNode) => {
		/* dont verify root element, assume any element is allowed */
		if (node.parent.isRootElement()){
			return;
		}
 
		/* if parent doesn't have metadata (unknown element) skip checking permitted
		 * content */
		Iif (!node.parent.meta){
			return;
		}
 
		const parent = node.parent;
		const rules = parent.meta.permittedContent;
 
		validatePermittedContent(node);
		validatePermittedDescendant(parent);
 
		function validatePermittedContent(cur: DOMNode): void {
			if (!Validator.validatePermitted(cur, rules)){
				report(cur, `Element <${cur.tagName}> is not permitted as content in <${parent.tagName}>`);
				return;
			}
 
			/* for transparent elements all of the children must be validated against
			 * the (this elements) parent, i.e. if this node was removed from the DOM
			 * it should still be valid. */
			if (cur.meta && cur.meta.transparent){
				cur.children.forEach((child: DOMNode) => {
					validatePermittedContent(child);
				});
			}
		}
 
		function validatePermittedDescendant(cur: DOMNode): void {
			while (!cur.isRootElement()){
				if (cur.meta && node.meta && !Validator.validatePermitted(node, cur.meta.permittedDescendants)){
					report(node, `Element <${node.tagName}> is not permitted as descendant of <${cur.tagName}>`);
					return;
				}
				cur = cur.parent;
			}
		}
	});
}