All files / src comment.ts

96.42% Statements 54/56
96.96% Branches 32/33
100% Functions 13/13
96.36% Lines 53/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 1306x   6x       291x 291x 291x                 112x 6x   6x 1x 1x 1x   5x       112x 8x   8x 2x 1x 1x   7x       112x       6x 515x 515x 515x     158x       246x 246x   246x 246x   246x       266x       179x 179x 179x   179x                         95x       1560x       177x         179x   179x 387x 179x           387x 2322x 774x   2322x 774x 774x   2322x 387x 1x           179x 179x      
import { Properties } from './transformers';
 
export class Comment extends Properties {
	type: string;
 
	constructor(type: string, attributes: Map<string, string>) {
		attributes.set('onTarget', type);
		super(attributes);
		this.type = type;
	}
 
	public static of(
		type: string,
		style: string[] = [],
		clazz: string[] = [],
		attributes: Map<string, string> = new Map<string, string>(),
	): Comment {
		if (clazz && clazz.length > 0) {
			const classValue = attributes.get('class');
 
			if (classValue) {
				const split = classValue.split(' ');
				split.push(...clazz);
				attributes.set('class', split.join(' '));
			} else {
				attributes.set('class', clazz.join(' '));
			}
		}
 
		if (style && style.length > 0) {
			const styleValue = attributes.get('style');
 
			if (styleValue) {
				const split = styleValue.split(';').map(value => value.trim());
				split.push(...style);
				attributes.set('style', split.join('; '));
			} else {
				attributes.set('style', style.join('; '));
			}
		}
 
		return new Comment(type, attributes);
	}
}
 
export class CommentParser {
	private readCommentRegex = /<!--.*-->/;
	private parseRegex = /<!--\s*(?:\.)?(element|slide):?\s*(.*)-->/;
	private parsePropertiesRegex = /([^=]*)\s*=\s*"([^"]*)"\s*|([^=]*)\s*=\s*'([^']*)'\s*|([^ ]*)\s*/g;
 
	commentToString(comment: Comment): string {
		return `<!-- .${comment.type}: ${this.buildAttributes(comment)} -->`;
	}
 
	buildAttributes(comment: Comment): string {
		const styles = comment.getStyles();
		const classes = comment.getClasses();
 
		const stylesString = styles.length > 0 ? `style="${styles}" ` : '';
		const classesString = classes.length > 0 ? `class="${classes}" ` : '';
 
		return `${stylesString}${classesString}${comment.getAttributes()}`.trim();
	}
 
	parseLine(line: string): Comment {
		return this.lineHasComment(line) ? this.parseComment(this.readCommentStringFromLine(line)) : null;
	}
 
	parseComment(comment: string): Comment {
		try {
			const [, type, properties] = this.parseRegex.exec(comment);
			const attributes = this.parseAttributes(properties);
 
			return new Comment(type, attributes);
		} catch (ex) {
			console.log('ERROR: Cannot parse comment: ' + comment);
			return null;
		}
	}
 
	buildComment(
		type: string,
		style: string[] = [],
		clazz: string[] = [],
		attributes: Map<string, string> = new Map<string, string>(),
	): Comment {
		return Comment.of(type, style, clazz, attributes);
	}
 
	lineHasComment(line: string): boolean {
		return this.parseRegex.test(line);
	}
 
	private readCommentStringFromLine(line: string): string {
		return this.readCommentRegex.exec(line)?.[0] ?? '';
	}
 
	private parseAttributes(properties: string): Map<string, string> {
		let m;
		const attributes = new Map<string, string>();
 
		while ((m = this.parsePropertiesRegex.exec(properties)) !== null) {
			if (m.index === this.parsePropertiesRegex.lastIndex) {
				this.parsePropertiesRegex.lastIndex++;
			}
 
			let key: string;
			let value: string;
 
			m.forEach((match, groupIndex) => {
				if (groupIndex == 1 || groupIndex == 3) {
					key = match;
				}
				if (groupIndex == 2 || groupIndex == 4) {
					value = match;
					attributes.set(key, value);
				}
				if (groupIndex == 5) {
					if (match) {
						attributes.set(match, 'true');
					}
				}
			});
		}
 
		attributes.delete(undefined);
		return attributes;
	}
}