Home / Function/ parse() — vue Function Reference

parse() — vue Function Reference

Architecture documentation for the parse() function in index.ts from the vue codebase.

Entity Profile

Dependency Diagram

graph TD
  bbf88914_62b5_839d_3cfb_85a00fd1d67b["parse()"]
  16b5f9ed_1e09_eff8_5797_7cb90fc86d37["compileScript()"]
  16b5f9ed_1e09_eff8_5797_7cb90fc86d37 -->|calls| bbf88914_62b5_839d_3cfb_85a00fd1d67b
  6fdcd133_a6e0_85e7_3ef7_7feb272a29b3["createCompiler()"]
  6fdcd133_a6e0_85e7_3ef7_7feb272a29b3 -->|calls| bbf88914_62b5_839d_3cfb_85a00fd1d67b
  5e33e1e0_159e_45ee_a1cd_33a5b88f58de["createCompiler()"]
  5e33e1e0_159e_45ee_a1cd_33a5b88f58de -->|calls| bbf88914_62b5_839d_3cfb_85a00fd1d67b
  bbfd8571_7a74_3b7b_5f81_e28a05cb7a25["pluckModuleFunction()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| bbfd8571_7a74_3b7b_5f81_e28a05cb7a25
  31f9edc3_10e5_9556_86c6_7c900b922f60["processElement()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 31f9edc3_10e5_9556_86c6_7c900b922f60
  a43ff6ef_b3eb_ea6c_cf0e_7fea2e444821["addIfCondition()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| a43ff6ef_b3eb_ea6c_cf0e_7fea2e444821
  f819e82d_0c73_4842_095d_5d0adae6ddd9["processIfConditions()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| f819e82d_0c73_4842_095d_5d0adae6ddd9
  ca00eea8_e506_fbea_a89a_cf39796a3659["parseHTML()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| ca00eea8_e506_fbea_a89a_cf39796a3659
  11dc788f_ce22_083e_424f_60522906c402["guardIESVGBug()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 11dc788f_ce22_083e_424f_60522906c402
  61cd312b_0f3f_8048_b42c_85f0f4766ca8["createASTElement()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 61cd312b_0f3f_8048_b42c_85f0f4766ca8
  455aed7a_836d_f1a4_959e_22c383e240af["isForbiddenTag()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 455aed7a_836d_f1a4_959e_22c383e240af
  ee7e00b8_f132_f08a_234f_c191d1d2abdd["isServerRendering()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| ee7e00b8_f132_f08a_234f_c191d1d2abdd
  4988d0ac_656f_889f_8348_32957dd0c8f3["processPre()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 4988d0ac_656f_889f_8348_32957dd0c8f3
  79eab9d4_f5a9_4294_0fbd_1f3886c7069f["processRawAttrs()"]
  bbf88914_62b5_839d_3cfb_85a00fd1d67b -->|calls| 79eab9d4_f5a9_4294_0fbd_1f3886c7069f
  style bbf88914_62b5_839d_3cfb_85a00fd1d67b fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

src/compiler/parser/index.ts lines 86–422

export function parse(template: string, options: CompilerOptions): ASTElement {
  warn = options.warn || baseWarn

  platformIsPreTag = options.isPreTag || no
  platformMustUseProp = options.mustUseProp || no
  platformGetTagNamespace = options.getTagNamespace || no
  const isReservedTag = options.isReservedTag || no
  maybeComponent = (el: ASTElement) =>
    !!(
      el.component ||
      el.attrsMap[':is'] ||
      el.attrsMap['v-bind:is'] ||
      !(el.attrsMap.is ? isReservedTag(el.attrsMap.is) : isReservedTag(el.tag))
    )
  transforms = pluckModuleFunction(options.modules, 'transformNode')
  preTransforms = pluckModuleFunction(options.modules, 'preTransformNode')
  postTransforms = pluckModuleFunction(options.modules, 'postTransformNode')

  delimiters = options.delimiters

  const stack: any[] = []
  const preserveWhitespace = options.preserveWhitespace !== false
  const whitespaceOption = options.whitespace
  let root
  let currentParent
  let inVPre = false
  let inPre = false
  let warned = false

  function warnOnce(msg, range) {
    if (!warned) {
      warned = true
      warn(msg, range)
    }
  }

  function closeElement(element) {
    trimEndingWhitespace(element)
    if (!inVPre && !element.processed) {
      element = processElement(element, options)
    }
    // tree management
    if (!stack.length && element !== root) {
      // allow root elements with v-if, v-else-if and v-else
      if (root.if && (element.elseif || element.else)) {
        if (__DEV__) {
          checkRootConstraints(element)
        }
        addIfCondition(root, {
          exp: element.elseif,
          block: element
        })
      } else if (__DEV__) {
        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.`,
          { start: element.start }
        )
      }
    }
    if (currentParent && !element.forbidden) {
      if (element.elseif || element.else) {
        processIfConditions(element, currentParent)
      } else {
        if (element.slotScope) {
          // scoped slot
          // keep it in the children list so that v-else(-if) conditions can
          // find it as the prev node.
          const name = element.slotTarget || '"default"'
          ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[
            name
          ] = element
        }
        currentParent.children.push(element)
        element.parent = currentParent
      }
    }

    // final children cleanup
    // filter out scoped slots
    element.children = element.children.filter(c => !c.slotScope)
    // remove trailing whitespace node again
    trimEndingWhitespace(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)
    }
  }

  function trimEndingWhitespace(el) {
    // remove trailing whitespace node
    if (!inPre) {
      let lastNode
      while (
        (lastNode = el.children[el.children.length - 1]) &&
        lastNode.type === 3 &&
        lastNode.text === ' '
      ) {
        el.children.pop()
      }
    }
  }

  function checkRootConstraints(el) {
    if (el.tag === 'slot' || el.tag === 'template') {
      warnOnce(
        `Cannot use <${el.tag}> as component root element because it may ` +
          'contain multiple nodes.',
        { start: el.start }
      )
    }
    if (el.attrsMap.hasOwnProperty('v-for')) {
      warnOnce(
        'Cannot use v-for on stateful component root element because ' +
          'it renders multiple elements.',
        el.rawAttrsMap['v-for']
      )
    }
  }

  parseHTML(template, {
    warn,
    expectHTML: options.expectHTML,
    isUnaryTag: options.isUnaryTag,
    canBeLeftOpenTag: options.canBeLeftOpenTag,
    shouldDecodeNewlines: options.shouldDecodeNewlines,
    shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
    shouldKeepComment: options.comments,
    outputSourceRange: options.outputSourceRange,
    start(tag, attrs, unary, start, end) {
      // 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 (__DEV__) {
        if (options.outputSourceRange) {
          element.start = start
          element.end = end
          element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
            cumulated[attr.name] = attr
            return cumulated
          }, {})
        }
        attrs.forEach(attr => {
          if (invalidAttributeRE.test(attr.name)) {
            warn(
              `Invalid dynamic argument expression: attribute names cannot contain ` +
                `spaces, quotes, <, >, / or =.`,
              options.outputSourceRange
                ? {
                    start: attr.start! + attr.name.indexOf(`[`),
                    end: attr.start! + attr.name.length
                  }
                : undefined
            )
          }
        })
      }

      if (isForbiddenTag(element) && !isServerRendering()) {
        element.forbidden = true
        __DEV__ &&
          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.',
            { start: element.start }
          )
      }

      // 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)
      }

      if (!root) {
        root = element
        if (__DEV__) {
          checkRootConstraints(root)
        }
      }

      if (!unary) {
        currentParent = element
        stack.push(element)
      } else {
        closeElement(element)
      }
    },

    end(tag, start, end) {
      const element = stack[stack.length - 1]
      // pop stack
      stack.length -= 1
      currentParent = stack[stack.length - 1]
      if (__DEV__ && options.outputSourceRange) {
        element.end = end
      }
      closeElement(element)
    },

    chars(text: string, start?: number, end?: number) {
      if (!currentParent) {
        if (__DEV__) {
          if (text === template) {
            warnOnce(
              'Component template requires a root element, rather than just text.',
              { start }
            )
          } else if ((text = text.trim())) {
            warnOnce(`text "${text}" outside root element will be ignored.`, {
              start
            })
          }
        }
        return
      }
      // IE textarea placeholder bug
      /* istanbul ignore if */
      if (
        isIE &&
        currentParent.tag === 'textarea' &&
        currentParent.attrsMap.placeholder === text
      ) {
        return
      }
      const children = currentParent.children
      if (inPre || text.trim()) {
        text = isTextTag(currentParent)
          ? text
          : (decodeHTMLCached(text) as string)
      } else if (!children.length) {
        // remove the whitespace-only node right after an opening tag
        text = ''
      } else if (whitespaceOption) {
        if (whitespaceOption === 'condense') {
          // in condense mode, remove the whitespace node if it contains
          // line break, otherwise condense to a single space
          text = lineBreakRE.test(text) ? '' : ' '
        } else {
          text = ' '
        }
      } else {
        text = preserveWhitespace ? ' ' : ''
      }
      if (text) {
        if (!inPre && whitespaceOption === 'condense') {
          // condense consecutive whitespaces into single space
          text = text.replace(whitespaceRE, ' ')
        }
        let res
        let child: ASTNode | undefined
        if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) {
          child = {
            type: 2,
            expression: res.expression,
            tokens: res.tokens,
            text
          }
        } else if (
          text !== ' ' ||
          !children.length ||
          children[children.length - 1].text !== ' '
        ) {
          child = {
            type: 3,
            text
          }
        }
        if (child) {
          if (__DEV__ && options.outputSourceRange) {
            child.start = start
            child.end = end
          }
          children.push(child)
        }
      }
    },
    comment(text: string, start, end) {
      // adding anything as a sibling to the root node is forbidden
      // comments should still be allowed, but ignored
      if (currentParent) {
        const child: ASTText = {
          type: 3,
          text,
          isComment: true
        }
        if (__DEV__ && options.outputSourceRange) {
          child.start = start
          child.end = end
        }
        currentParent.children.push(child)
      }
    }
  })
  return root
}

Domain

Subdomains

Frequently Asked Questions

What does parse() do?
parse() is a function in the vue codebase.
What does parse() call?
parse() calls 16 function(s): addIfCondition, createASTElement, guardIESVGBug, isForbiddenTag, isServerRendering, isTextTag, parseHTML, parseText, and 8 more.
What calls parse()?
parse() is called by 3 function(s): compileScript, createCompiler, createCompiler.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free