aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vue/src/compiler/parser/html-parser.js
diff options
context:
space:
mode:
authorruki <waruqi@gmail.com>2018-11-08 00:38:48 +0800
committerruki <waruqi@gmail.com>2018-11-07 21:53:09 +0800
commit26105034da4fcce7ac883c899d781f016559310d (patch)
treec459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/vue/src/compiler/parser/html-parser.js
parent2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff)
downloadxmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz
xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip
switch to vuepress
Diffstat (limited to 'node_modules/vue/src/compiler/parser/html-parser.js')
-rw-r--r--node_modules/vue/src/compiler/parser/html-parser.js310
1 files changed, 310 insertions, 0 deletions
diff --git a/node_modules/vue/src/compiler/parser/html-parser.js b/node_modules/vue/src/compiler/parser/html-parser.js
new file mode 100644
index 00000000..e2203613
--- /dev/null
+++ b/node_modules/vue/src/compiler/parser/html-parser.js
@@ -0,0 +1,310 @@
+/**
+ * Not type-checking this file because it's mostly vendor code.
+ */
+
+/*!
+ * HTML Parser By John Resig (ejohn.org)
+ * Modified by Juriy "kangax" Zaytsev
+ * Original code by Erik Arvidsson, Mozilla Public License
+ * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
+ */
+
+import { makeMap, no } from 'shared/util'
+import { isNonPhrasingTag } from 'web/compiler/util'
+
+// Regular Expressions for parsing tags and attributes
+const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
+// could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName
+// but for Vue templates we can enforce a simple charset
+const ncname = '[a-zA-Z_][\\w\\-\\.]*'
+const qnameCapture = `((?:${ncname}\\:)?${ncname})`
+const startTagOpen = new RegExp(`^<${qnameCapture}`)
+const startTagClose = /^\s*(\/?)>/
+const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
+const doctype = /^<!DOCTYPE [^>]+>/i
+// #7298: escape - to avoid being pased as HTML comment when inlined in page
+const comment = /^<!\--/
+const conditionalComment = /^<!\[/
+
+let IS_REGEX_CAPTURING_BROKEN = false
+'x'.replace(/x(.)?/g, function (m, g) {
+ IS_REGEX_CAPTURING_BROKEN = g === ''
+})
+
+// Special Elements (can contain anything)
+export const isPlainTextElement = makeMap('script,style,textarea', true)
+const reCache = {}
+
+const decodingMap = {
+ '&lt;': '<',
+ '&gt;': '>',
+ '&quot;': '"',
+ '&amp;': '&',
+ '&#10;': '\n',
+ '&#9;': '\t'
+}
+const encodedAttr = /&(?:lt|gt|quot|amp);/g
+const encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10|#9);/g
+
+// #5992
+const isIgnoreNewlineTag = makeMap('pre,textarea', true)
+const shouldIgnoreFirstNewline = (tag, html) => tag && isIgnoreNewlineTag(tag) && html[0] === '\n'
+
+function decodeAttr (value, shouldDecodeNewlines) {
+ const re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr
+ return value.replace(re, match => decodingMap[match])
+}
+
+export function parseHTML (html, options) {
+ const stack = []
+ const expectHTML = options.expectHTML
+ const isUnaryTag = options.isUnaryTag || no
+ const canBeLeftOpenTag = options.canBeLeftOpenTag || no
+ let index = 0
+ let last, lastTag
+ while (html) {
+ last = html
+ // Make sure we're not in a plaintext content element like script/style
+ if (!lastTag || !isPlainTextElement(lastTag)) {
+ let textEnd = html.indexOf('<')
+ if (textEnd === 0) {
+ // Comment:
+ if (comment.test(html)) {
+ const commentEnd = html.indexOf('-->')
+
+ if (commentEnd >= 0) {
+ if (options.shouldKeepComment) {
+ options.comment(html.substring(4, commentEnd))
+ }
+ advance(commentEnd + 3)
+ continue
+ }
+ }
+
+ // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
+ if (conditionalComment.test(html)) {
+ const conditionalEnd = html.indexOf(']>')
+
+ if (conditionalEnd >= 0) {
+ advance(conditionalEnd + 2)
+ continue
+ }
+ }
+
+ // Doctype:
+ const doctypeMatch = html.match(doctype)
+ if (doctypeMatch) {
+ advance(doctypeMatch[0].length)
+ continue
+ }
+
+ // End tag:
+ const endTagMatch = html.match(endTag)
+ if (endTagMatch) {
+ const curIndex = index
+ advance(endTagMatch[0].length)
+ parseEndTag(endTagMatch[1], curIndex, index)
+ continue
+ }
+
+ // Start tag:
+ const startTagMatch = parseStartTag()
+ if (startTagMatch) {
+ handleStartTag(startTagMatch)
+ if (shouldIgnoreFirstNewline(lastTag, html)) {
+ advance(1)
+ }
+ continue
+ }
+ }
+
+ let text, rest, next
+ if (textEnd >= 0) {
+ rest = html.slice(textEnd)
+ while (
+ !endTag.test(rest) &&
+ !startTagOpen.test(rest) &&
+ !comment.test(rest) &&
+ !conditionalComment.test(rest)
+ ) {
+ // < in plain text, be forgiving and treat it as text
+ next = rest.indexOf('<', 1)
+ if (next < 0) break
+ textEnd += next
+ rest = html.slice(textEnd)
+ }
+ text = html.substring(0, textEnd)
+ advance(textEnd)
+ }
+
+ if (textEnd < 0) {
+ text = html
+ html = ''
+ }
+
+ if (options.chars && text) {
+ options.chars(text)
+ }
+ } else {
+ let endTagLength = 0
+ const stackedTag = lastTag.toLowerCase()
+ const reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'))
+ const rest = html.replace(reStackedTag, function (all, text, endTag) {
+ endTagLength = endTag.length
+ if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {
+ text = text
+ .replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298
+ .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1')
+ }
+ if (shouldIgnoreFirstNewline(stackedTag, text)) {
+ text = text.slice(1)
+ }
+ if (options.chars) {
+ options.chars(text)
+ }
+ return ''
+ })
+ index += html.length - rest.length
+ html = rest
+ parseEndTag(stackedTag, index - endTagLength, index)
+ }
+
+ if (html === last) {
+ options.chars && options.chars(html)
+ if (process.env.NODE_ENV !== 'production' && !stack.length && options.warn) {
+ options.warn(`Mal-formatted tag at end of template: "${html}"`)
+ }
+ break
+ }
+ }
+
+ // Clean up any remaining tags
+ parseEndTag()
+
+ function advance (n) {
+ index += n
+ html = html.substring(n)
+ }
+
+ function parseStartTag () {
+ const start = html.match(startTagOpen)
+ if (start) {
+ const match = {
+ tagName: start[1],
+ attrs: [],
+ start: index
+ }
+ advance(start[0].length)
+ let end, attr
+ while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
+ advance(attr[0].length)
+ match.attrs.push(attr)
+ }
+ if (end) {
+ match.unarySlash = end[1]
+ advance(end[0].length)
+ match.end = index
+ return match
+ }
+ }
+ }
+
+ function handleStartTag (match) {
+ const tagName = match.tagName
+ const unarySlash = match.unarySlash
+
+ if (expectHTML) {
+ if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
+ parseEndTag(lastTag)
+ }
+ if (canBeLeftOpenTag(tagName) && lastTag === tagName) {
+ parseEndTag(tagName)
+ }
+ }
+
+ const unary = isUnaryTag(tagName) || !!unarySlash
+
+ const l = match.attrs.length
+ const attrs = new Array(l)
+ for (let i = 0; i < l; i++) {
+ const args = match.attrs[i]
+ // hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
+ if (IS_REGEX_CAPTURING_BROKEN && args[0].indexOf('""') === -1) {
+ if (args[3] === '') { delete args[3] }
+ if (args[4] === '') { delete args[4] }
+ if (args[5] === '') { delete args[5] }
+ }
+ const value = args[3] || args[4] || args[5] || ''
+ const shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'
+ ? options.shouldDecodeNewlinesForHref
+ : options.shouldDecodeNewlines
+ attrs[i] = {
+ name: args[1],
+ value: decodeAttr(value, shouldDecodeNewlines)
+ }
+ }
+
+ if (!unary) {
+ stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs })
+ lastTag = tagName
+ }
+
+ if (options.start) {
+ options.start(tagName, attrs, unary, match.start, match.end)
+ }
+ }
+
+ function parseEndTag (tagName, start, end) {
+ let pos, lowerCasedTagName
+ if (start == null) start = index
+ if (end == null) end = index
+
+ if (tagName) {
+ lowerCasedTagName = tagName.toLowerCase()
+ }
+
+ // Find the closest opened tag of the same type
+ if (tagName) {
+ for (pos = stack.length - 1; pos >= 0; pos--) {
+ if (stack[pos].lowerCasedTag === lowerCasedTagName) {
+ break
+ }
+ }
+ } else {
+ // If no tag name is provided, clean shop
+ pos = 0
+ }
+
+ if (pos >= 0) {
+ // Close all the open elements, up the stack
+ for (let i = stack.length - 1; i >= pos; i--) {
+ if (process.env.NODE_ENV !== 'production' &&
+ (i > pos || !tagName) &&
+ options.warn
+ ) {
+ options.warn(
+ `tag <${stack[i].tag}> has no matching end tag.`
+ )
+ }
+ if (options.end) {
+ options.end(stack[i].tag, start, end)
+ }
+ }
+
+ // Remove the open elements from the stack
+ stack.length = pos
+ lastTag = pos && stack[pos - 1].tag
+ } else if (lowerCasedTagName === 'br') {
+ if (options.start) {
+ options.start(tagName, [], true, start, end)
+ }
+ } else if (lowerCasedTagName === 'p') {
+ if (options.start) {
+ options.start(tagName, [], false, start, end)
+ }
+ if (options.end) {
+ options.end(tagName, start, end)
+ }
+ }
+ }
+}