From 26105034da4fcce7ac883c899d781f016559310d Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 8 Nov 2018 00:38:48 +0800 Subject: switch to vuepress --- node_modules/vue/src/compiler/parser/index.js | 675 ++++++++++++++++++++++++++ 1 file changed, 675 insertions(+) create mode 100644 node_modules/vue/src/compiler/parser/index.js (limited to 'node_modules/vue/src/compiler/parser/index.js') diff --git a/node_modules/vue/src/compiler/parser/index.js b/node_modules/vue/src/compiler/parser/index.js new file mode 100644 index 00000000..a603b36b --- /dev/null +++ b/node_modules/vue/src/compiler/parser/index.js @@ -0,0 +1,675 @@ +/* @flow */ + +import he from 'he' +import { parseHTML } from './html-parser' +import { parseText } from './text-parser' +import { parseFilters } from './filter-parser' +import { genAssignmentCode } from '../directives/model' +import { extend, cached, no, camelize } from 'shared/util' +import { isIE, isEdge, isServerRendering } from 'core/util/env' + +import { + addProp, + addAttr, + baseWarn, + addHandler, + addDirective, + getBindingAttr, + getAndRemoveAttr, + pluckModuleFunction +} from '../helpers' + +export const onRE = /^@|^v-on:/ +export const dirRE = /^v-|^@|^:/ +export const forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/ +export const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/ +const stripParensRE = /^\(|\)$/g + +const argRE = /:(.*)$/ +export const bindRE = /^:|^v-bind:/ +const modifierRE = /\.[^.]+/g + +const decodeHTMLCached = cached(he.decode) + +// configurable state +export let warn: any +let delimiters +let transforms +let preTransforms +let postTransforms +let platformIsPreTag +let platformMustUseProp +let platformGetTagNamespace + +type Attr = { name: string; value: string }; + +export function createASTElement ( + tag: string, + attrs: Array, + parent: ASTElement | void +): ASTElement { + return { + type: 1, + tag, + attrsList: attrs, + attrsMap: makeAttrsMap(attrs), + parent, + children: [] + } +} + +/** + * Convert HTML string to AST. + */ +export function parse ( + template: string, + options: CompilerOptions +): ASTElement | void { + warn = options.warn || baseWarn + + platformIsPreTag = options.isPreTag || no + platformMustUseProp = options.mustUseProp || no + platformGetTagNamespace = options.getTagNamespace || no + + transforms = pluckModuleFunction(options.modules, 'transformNode') + preTransforms = pluckModuleFunction(options.modules, 'preTransformNode') + postTransforms = pluckModuleFunction(options.modules, 'postTransformNode') + + delimiters = options.delimiters + + const stack = [] + const preserveWhitespace = options.preserveWhitespace !== false + let root + let currentParent + let inVPre = false + let inPre = false + let warned = false + + function warnOnce (msg) { + if (!warned) { + warned = true + warn(msg) + } + } + + function closeElement (element) { + // check pre state + if (element.pre) { + inVPre = false + } + if (platformIsPreTag(element.tag)) { + inPre = false + } + // apply post-transforms + for (let i = 0; i < postTransforms.length; i++) { + postTransforms[i](element, options) + } + } + + parseHTML(template, { + warn, + expectHTML: options.expectHTML, + isUnaryTag: options.isUnaryTag, + canBeLeftOpenTag: options.canBeLeftOpenTag, + shouldDecodeNewlines: options.shouldDecodeNewlines, + shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref, + shouldKeepComment: options.comments, + start (tag, attrs, unary) { + // check namespace. + // inherit parent ns if there is one + const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag) + + // handle IE svg bug + /* istanbul ignore if */ + if (isIE && ns === 'svg') { + attrs = guardIESVGBug(attrs) + } + + let element: ASTElement = createASTElement(tag, attrs, currentParent) + if (ns) { + element.ns = ns + } + + if (isForbiddenTag(element) && !isServerRendering()) { + element.forbidden = true + process.env.NODE_ENV !== 'production' && warn( + 'Templates should only be responsible for mapping the state to the ' + + 'UI. Avoid placing tags with side-effects in your templates, such as ' + + `<${tag}>` + ', as they will not be parsed.' + ) + } + + // apply pre-transforms + for (let i = 0; i < preTransforms.length; i++) { + element = preTransforms[i](element, options) || element + } + + if (!inVPre) { + processPre(element) + if (element.pre) { + inVPre = true + } + } + if (platformIsPreTag(element.tag)) { + inPre = true + } + if (inVPre) { + processRawAttrs(element) + } else if (!element.processed) { + // structural directives + processFor(element) + processIf(element) + processOnce(element) + // element-scope stuff + processElement(element, options) + } + + function checkRootConstraints (el) { + if (process.env.NODE_ENV !== 'production') { + if (el.tag === 'slot' || el.tag === 'template') { + warnOnce( + `Cannot use <${el.tag}> as component root element because it may ` + + 'contain multiple nodes.' + ) + } + if (el.attrsMap.hasOwnProperty('v-for')) { + warnOnce( + 'Cannot use v-for on stateful component root element because ' + + 'it renders multiple elements.' + ) + } + } + } + + // tree management + if (!root) { + root = element + checkRootConstraints(root) + } else if (!stack.length) { + // allow root elements with v-if, v-else-if and v-else + if (root.if && (element.elseif || element.else)) { + checkRootConstraints(element) + addIfCondition(root, { + exp: element.elseif, + block: element + }) + } else if (process.env.NODE_ENV !== 'production') { + warnOnce( + `Component template should contain exactly one root element. ` + + `If you are using v-if on multiple elements, ` + + `use v-else-if to chain them instead.` + ) + } + } + if (currentParent && !element.forbidden) { + if (element.elseif || element.else) { + processIfConditions(element, currentParent) + } else if (element.slotScope) { // scoped slot + currentParent.plain = false + const name = element.slotTarget || '"default"' + ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element + } else { + currentParent.children.push(element) + element.parent = currentParent + } + } + if (!unary) { + currentParent = element + stack.push(element) + } else { + closeElement(element) + } + }, + + end () { + // remove trailing whitespace + const element = stack[stack.length - 1] + const lastNode = element.children[element.children.length - 1] + if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) { + element.children.pop() + } + // pop stack + stack.length -= 1 + currentParent = stack[stack.length - 1] + closeElement(element) + }, + + chars (text: string) { + if (!currentParent) { + if (process.env.NODE_ENV !== 'production') { + if (text === template) { + warnOnce( + 'Component template requires a root element, rather than just text.' + ) + } else if ((text = text.trim())) { + warnOnce( + `text "${text}" outside root element will be ignored.` + ) + } + } + return + } + // IE textarea placeholder bug + /* istanbul ignore if */ + if (isIE && + currentParent.tag === 'textarea' && + currentParent.attrsMap.placeholder === text + ) { + return + } + const children = currentParent.children + text = inPre || text.trim() + ? isTextTag(currentParent) ? text : decodeHTMLCached(text) + // only preserve whitespace if its not right after a starting tag + : preserveWhitespace && children.length ? ' ' : '' + if (text) { + let res + if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) { + children.push({ + type: 2, + expression: res.expression, + tokens: res.tokens, + text + }) + } else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') { + children.push({ + type: 3, + text + }) + } + } + }, + comment (text: string) { + currentParent.children.push({ + type: 3, + text, + isComment: true + }) + } + }) + return root +} + +function processPre (el) { + if (getAndRemoveAttr(el, 'v-pre') != null) { + el.pre = true + } +} + +function processRawAttrs (el) { + const l = el.attrsList.length + if (l) { + const attrs = el.attrs = new Array(l) + for (let i = 0; i < l; i++) { + attrs[i] = { + name: el.attrsList[i].name, + value: JSON.stringify(el.attrsList[i].value) + } + } + } else if (!el.pre) { + // non root node in pre blocks with no attributes + el.plain = true + } +} + +export function processElement (element: ASTElement, options: CompilerOptions) { + processKey(element) + + // determine whether this is a plain element after + // removing structural attributes + element.plain = !element.key && !element.attrsList.length + + processRef(element) + processSlot(element) + processComponent(element) + for (let i = 0; i < transforms.length; i++) { + element = transforms[i](element, options) || element + } + processAttrs(element) +} + +function processKey (el) { + const exp = getBindingAttr(el, 'key') + if (exp) { + if (process.env.NODE_ENV !== 'production' && el.tag === 'template') { + warn(`