This is the 18th day of my participation in the First Challenge 2022.

Previously on & Background

The previous essay describes the specific logic of the tools and methods used in the parseHTML process.

  1. advance: maintenanceindexhtml.indexRecorded in the originalhtmlProcessing position in,htmlGradually shorten into untreated parts;
  2. parseStartTag: Matches the start tag with the retagNameattrsAnd the end of the start tag>or/>, and pushedstackInformation about the current start tag;
  3. handleStartTag: Further processingparsetStartTagTo get thematchObject, transformattrsThe array;
  4. parseEndTag: Maintains when the end tag is matchedstackTo makestackThe start tag corresponding to the current end tag is out of the stack;

Again and again, parseHTML uses < as a flag in the while(HTML) loop to separate templates into comments, conditional comments, document declarations, plain text, opening tags, closing tags, Then call options.comment, options.chars, options.start, and options.end to process the corresponding content types and convert them into AST nodes of fixed types.

This composition will focus on the methods passed in from options. I have not talked about this part before, because when I look at the source code, various methods are called back and forth, plus JS is an expert in callback methods, it makes people feel confused. This is because opitons are the callback method passed in when parseHTML is called from within the parse method.

Although I advocate looking at the source code in accordance with the order of the execution of the serial organization of small composition, but also to the scene, here is obviously not applicable to this method. Even so, I’ll do it the old-fashioned way — review calls and arguments first, and then cover method positions, arguments, and functions.

Second, the options.com ment

Method location: the callback method passed in when parseHTML is called within the parse method as follows:

export function parse (template: string, options: CompilerOptions) :ASTElement | void {
  / /...

  parseHTML(template, {
    warn,
    / /...
    outputSourceRange: options.outputSourceRange,

    comment (text: string, start, end) {
     
    }
  })

  // Returns the generated AST object
  return root
}
Copy the code

Method parameters:

  1. text, comment text
  2. start: indicates the starting index position
  3. end: Indicates the end index position

Methods:

  1. According to thecurrentParentExistence determines whether the current comment node is the same as the root node. Comments that are the same as the root node are ignored.currentParentIf no, it is level with root node.
  2. currentParentIf it exists, it is createdASTNode, and put itpushcurrentParentIn theThe children in the;
export function parse (template: string, options: CompilerOptions) :ASTElement | void {
  / /...

  parseHTML(template, {
    warn,
    / /...
    outputSourceRange: options.outputSourceRange,

    comment (text: string, start, end) {
        // Prohibit adding any nodes as siblings of root. Comments are allowed, but are ignored when creating the AST
        if (currentParent) {
        
          // This is the ast node of the comment, isComment: true, and the comment content is text
          const child: ASTText = {
            type: 3,
            text,
            isComment: true
          }
          if(process.env.NODE_ENV ! = ='production' && options.outputSourceRange) {
            // Start index and end index of ast node in non-production environment
            child.start = start
            child.end = end
          }
          // Put the current comment node into the children of the node
          currentParent.children.push(child)
        }
    }
  })

  // Returns the generated AST object
  return root
}
Copy the code

Third, the options. Chars

Method location: the callback method passed in when parseHTML is called within the parse method as follows:

export function parse (template: string, options: CompilerOptions) :ASTElement | void {
  / /...
parseHTML(template, {
  // ...
  shouldKeepComment: options.comments,

  chars (text: string, start: number, end: number) {
  
  }
})
  // Returns the generated AST object
  return root
}
Copy the code

Method parameters:

  1. textThe textstring
  2. start, the starting index position
  3. endTo end the index position

Methods:

  1. If the current text does notcurrentParent, indicating that the text has no parent element, ignores and prompts inrootText outside the element
  2. The next step is case by casetextCondition: Whether inpreTags, whether to compress newlines and other operations
  3. After the second steptextNot empty, no longerpreIn, compress successive Spaces and then create textastNode object, if present in text VueTemplate binding syntax{{xxx}}This,asttype2, plain textastThe object’stype3
  4. Will generate the text aboveast pushchildren
export function parse (template: string, options: CompilerOptions) :ASTElement | void {
 
  parseHTML(template, {
    // 
    chars (text: string, start: number, end: number) {
      // currentParent does not exist, indicating that the text has no parent element and is outside the root element
      if(! currentParent) {if(process.env.NODE_ENV ! = ='production') {
           // Prompts text outside the root element
        }
        return
      }
      // IE textarea placeholder bug

      // Get an array of all the children of the current parent element
      const children = currentParent.children

      // Process text,
      // Remove whitespace characters or if the whitespaceOptions option exists, text is assigned to an empty string or space
      if (inPre || text.trim()) {
        // The text inside the pre tag or after trim is not empty
        text = isTextTag(currentParent) ? text : decodeHTMLCached(text)
      } else if(! children.length) {// If this line goes here,
        Text.trim () is empty, and the current parent element has no child node
        // The text value is null
        text = ' '
      } else if (whitespaceOption) {
        / / compression
        if (whitespaceOption === 'condense') {
          // in condense mode, remove the whitespace node if it contains
          // line break, otherwise condense to a single space
          // In compression mode, remove blank nodes containing newlines, otherwise compress to a space
          text = lineBreakRE.test(text) ? ' ' : ' '
        } else {
          text = ' ' / / space}}else {
        text = preserveWhitespace ? ' ' : ' '
      }

      // After the previous processing, text is not empty
      if (text) {
        if(! inPre && whitespaceOption ==='condense') {
          // Does not exist on the Pre label and condense multiple Spaces into a single condense configuration item
          // condense consecutive whitespaces into single space
          text = text.replace(whitespaceRE, ' ')}let res

        // Generate ast objects based on text
        letchild: ? ASTNodeif(! inVPre && text ! = =' ' && (res = parseText(text, delimiters))) {
          // There are expressions in the text, i.e. {{}} Vue's data binding syntax
          child = {
            type: 2.expression: res.expression,
            tokens: res.tokens,
            text
          }
        } else if(text ! = =' '| |! children.length || children[children.length -1].text ! = =' ') {
          // Plain text node
          child = {
            type: 3,
            text
          }
        }

        // Add child to the parent element's children.
        // Push into the currentParent.children array
        if (child) {
          if(process.env.NODE_ENV ! = ='production' && options.outputSourceRange) {
            child.start = start
            child.end = end
          }
          children.push(child)
        }
      }
    },

  // Returns the generated AST object
  return root
}
Copy the code

Four,

Options.com ment, options.chars; options.chars; options.chars; options.chars;

Options.com ment is used to process comments. The method ignores the comment node at the root level, and then creates an AST node for the comment content and adds it to the currentParent. Children array.

Options. chars processes characters and determines whether to compress them according to the configured character options. Then, ast nodes of different types are created based on whether Vue’s dynamic binding syntax {{xx}} exists

Then there are the two most important methods, options.start and options.end. These two methods are the most important ones, so they will be presented in separate sections.