lib/parse.js
function readOpenTag() {
		// Read tag name
		let start = getSourcePoint(),
			match = tagNameRegex.exec(source.substr(pos))
		if (!match) {
			throwSyntaxError('Invalid open tag')
		}
		let tagName = match[0].toLowerCase(),
			isVoid = voidElementsRegex.test(tagName)
		advanceTo(pos + tagName.length)

		// Keep reading content
		let selfClose = false,
			attributes = [],
			// Used to detect repeated attributes
			foundAttributeNames = []
		while (true) {
			// Match using anchored regex
			let match = tagOpenContentStartRegex.exec(source.substr(pos))
			if (!match) {
				throwSyntaxError('Invalid open tag')
			}

			advanceTo(pos + match[0].length)
			if (match[1] === '<%-') {
				throwSyntaxError('EJS unescaped tags are not allowed inside open tags')
			} else if (match[1] === '<%=') {
				throwSyntaxError('EJS escaped tags are not allowed inside open tags')
			} else if (match[1] === '<%') {
				throwSyntaxError('EJS eval tags are not allowed inside open tags')
			} else if (match[1] === '>') {
				break
			} else if (match[1] === '/>') {
				selfClose = true
				break
			} else {
				// Attribute start
				let lowerName = match[1].toLowerCase()
				if (foundAttributeNames.indexOf(lowerName) !== -1) {
					throwSyntaxError(`Repeated attribute ${match[1]} in open tag ${tagName}`)
				}
				foundAttributeNames.push(lowerName)
				attributes.push(readAttribute(lowerName))
			}
		}

		if (!isVoid && selfClose) {
			throwSyntaxError('Self-closed tags for non-void elements are not allowed')
		}

		return {
			type: 'element',
			start,
			end: getSourcePoint(),
			name: tagName,
			isVoid,
			attributes,
			children: []
		}
	}
function readOpenTag() {
		// Read tag name
		let start = getSourcePoint(),
			match = tagNameRegex.exec(source.substr(pos))
		if (!match) {
			throwSyntaxError('Invalid open tag')
		}
		let tagName = match[0].toLowerCase(),
			isVoid = voidElementsRegex.test(tagName)
		advanceTo(pos + tagName.length)

		// Keep reading content
		let selfClose = false,
			attributes = [],
			// Used to detect repeated attributes
			foundAttributeNames = []
		while (true) {
			// Match using anchored regex
			let match = tagOpenContentStartRegex.exec(source.substr(pos))
			if (!match) {
				throwSyntaxError('Invalid open tag')
			}

			advanceTo(pos + match[0].length)
			if (match[1] === '<%-') {
				throwSyntaxError('EJS unescaped tags are not allowed inside open tags')
			} else if (match[1] === '<%=') {
				throwSyntaxError('EJS escaped tags are not allowed inside open tags')
			} else if (match[1] === '<%') {
				throwSyntaxError('EJS eval tags are not allowed inside open tags')
			} else if (match[1] === '>') {
				break
			} else if (match[1] === '/>') {
				selfClose = true
				break
			} else {
				// Attribute start
				let lowerName = match[1].toLowerCase()
				if (foundAttributeNames.indexOf(lowerName) !== -1) {
					throwSyntaxError(`Repeated attribute ${match[1]} in open tag ${tagName}`)
				}
				foundAttributeNames.push(lowerName)
				attributes.push(readAttribute(lowerName))
			}
		}

		if (!isVoid && selfClose) {
			throwSyntaxError('Self-closed tags for non-void elements are not allowed')
		}

		return {
			type: 'element',
			start,
			end: getSourcePoint(),
			name: tagName,
			isVoid,
			attributes,
			children: []
		}
	}
function readOpenTag ( ) { // Read tag name let start = getSourcePoint ( ) , match = tagNameRegex . exec ( source . substr ( pos ) ) if ( ! match ) { throwSyntaxError ( 'Invalid open tag' ) } let tagName = match [ 0 ] . toLowerCase ( ) , isVoid = voidElementsRegex . test ( tagName ) advanceTo ( pos + tagName . length ) // Keep reading content let selfClose = false , attributes = [ ] , // Used to detect repeated attributes foundAttributeNames = [ ] while ( true ) { // Match using anchored regex let match = tagOpenContentStartRegex . exec ( source . substr ( pos ) ) if ( ! match ) { throwSyntaxError ( 'Invalid open tag' ) } advanceTo ( pos + match [ 0 ] . length ) if ( match [ 1 ] === '<%-' ) { throwSyntaxError ( 'EJS unescaped tags are not allowed inside open tags' ) } else if ( match [ 1 ] === '<%=' ) { throwSyntaxError ( 'EJS escaped tags are not allowed inside open tags' ) } else if ( match [ 1 ] === '<%' ) { throwSyntaxError ( 'EJS eval tags are not allowed inside open tags' ) } else if ( match [ 1 ] === '>' ) { break } else if ( match [ 1 ] === '/>' ) { selfClose = true break } else { // Attribute start let lowerName = match [ 1 ] . toLowerCase ( ) if ( foundAttributeNames . indexOf ( lowerName ) !== - 1 ) { throwSyntaxError ( ` ${ match [ 1 ] } ${ tagName } ` ) } foundAttributeNames . push ( lowerName ) attributes . push ( readAttribute ( lowerName ) ) } } if ( ! isVoid && selfClose ) { throwSyntaxError ( 'Self-closed tags for non-void elements are not allowed' ) } return { type : 'element' , start , end : getSourcePoint ( ) , name : tagName , isVoid , attributes , children : [ ] } }
Read an open tag token
@returns {Token}
Read an open tag token