src/language-html/preprocess.js
function extractWhitespaces(ast /*, options*/) {
  const TYPE_WHITESPACE = "whitespace";
  return ast.map(node => {
    if (!node.children) {
      return node;
    }

    if (
      node.children.length === 0 ||
      (node.children.length === 1 &&
        node.children[0].type === "text" &&
        node.children[0].value.trim().length === 0)
    ) {
      return node.clone({
        children: [],
        hasDanglingSpaces: node.children.length !== 0
      });
    }

    const isWhitespaceSensitive = isWhitespaceSensitiveNode(node);
    const isIndentationSensitive = isIndentationSensitiveNode(node);

    return node.clone({
      isWhitespaceSensitive,
      isIndentationSensitive,
      children: node.children
        // extract whitespace nodes
        .reduce((newChildren, child) => {
          if (child.type !== "text" || isWhitespaceSensitive) {
            return newChildren.concat(child);
          }

          const localChildren = [];

          const [, leadingSpaces, text, trailingSpaces] = child.value.match(
            /^(\s*)([\s\S]*?)(\s*)$/
          );

          if (leadingSpaces) {
            localChildren.push({ type: TYPE_WHITESPACE });
          }

          const ParseSourceSpan = child.sourceSpan.constructor;

          if (text) {
            localChildren.push({
              type: "text",
              value: text,
              sourceSpan: new ParseSourceSpan(
                child.sourceSpan.start.moveBy(leadingSpaces.length),
                child.sourceSpan.end.moveBy(-trailingSpaces.length)
              )
            });
          }

          if (trailingSpaces) {
            localChildren.push({ type: TYPE_WHITESPACE });
          }

          return newChildren.concat(localChildren);
        }, [])
        // set hasLeadingSpaces/hasTrailingSpaces and filter whitespace nodes
        .reduce((newChildren, child, i, children) => {
          if (child.type === TYPE_WHITESPACE) {
            return newChildren;
          }

          const hasLeadingSpaces =
            i !== 0 && children[i - 1].type === TYPE_WHITESPACE;
          const hasTrailingSpaces =
            i !== children.length - 1 &&
            children[i + 1].type === TYPE_WHITESPACE;

          return newChildren.concat(
            Object.assign({}, child, {
              hasLeadingSpaces,
              hasTrailingSpaces
            })
          );
        }, [])
    });
  });
}
function extractWhitespaces(ast /*, options*/) {
  const TYPE_WHITESPACE = "whitespace";
  return ast.map(node => {
    if (!node.children) {
      return node;
    }

    if (
      node.children.length === 0 ||
      (node.children.length === 1 &&
        node.children[0].type === "text" &&
        node.children[0].value.trim().length === 0)
    ) {
      return node.clone({
        children: [],
        hasDanglingSpaces: node.children.length !== 0
      });
    }

    const isWhitespaceSensitive = isWhitespaceSensitiveNode(node);
    const isIndentationSensitive = isIndentationSensitiveNode(node);

    return node.clone({
      isWhitespaceSensitive,
      isIndentationSensitive,
      children: node.children
        // extract whitespace nodes
        .reduce((newChildren, child) => {
          if (child.type !== "text" || isWhitespaceSensitive) {
            return newChildren.concat(child);
          }

          const localChildren = [];

          const [, leadingSpaces, text, trailingSpaces] = child.value.match(
            /^(\s*)([\s\S]*?)(\s*)$/
          );

          if (leadingSpaces) {
            localChildren.push({ type: TYPE_WHITESPACE });
          }

          const ParseSourceSpan = child.sourceSpan.constructor;

          if (text) {
            localChildren.push({
              type: "text",
              value: text,
              sourceSpan: new ParseSourceSpan(
                child.sourceSpan.start.moveBy(leadingSpaces.length),
                child.sourceSpan.end.moveBy(-trailingSpaces.length)
              )
            });
          }

          if (trailingSpaces) {
            localChildren.push({ type: TYPE_WHITESPACE });
          }

          return newChildren.concat(localChildren);
        }, [])
        // set hasLeadingSpaces/hasTrailingSpaces and filter whitespace nodes
        .reduce((newChildren, child, i, children) => {
          if (child.type === TYPE_WHITESPACE) {
            return newChildren;
          }

          const hasLeadingSpaces =
            i !== 0 && children[i - 1].type === TYPE_WHITESPACE;
          const hasTrailingSpaces =
            i !== children.length - 1 &&
            children[i + 1].type === TYPE_WHITESPACE;

          return newChildren.concat(
            Object.assign({}, child, {
              hasLeadingSpaces,
              hasTrailingSpaces
            })
          );
        }, [])
    });
  });
}
function extractWhitespaces ( ast /*, options*/ ) { const TYPE_WHITESPACE = "whitespace" ; return ast . map ( node => { if ( ! node . children ) { return node ; } if ( node . children . length === 0 || ( node . children . length === 1 && node . children [ 0 ] . type === "text" && node . children [ 0 ] . value . trim ( ) . length === 0 ) ) { return node . clone ( { children : [ ] , hasDanglingSpaces : node . children . length !== 0 } ) ; } const isWhitespaceSensitive = isWhitespaceSensitiveNode ( node ) ; const isIndentationSensitive = isIndentationSensitiveNode ( node ) ; return node . clone ( { isWhitespaceSensitive , isIndentationSensitive , children : node . children // extract whitespace nodes . reduce ( ( newChildren , child ) => { if ( child . type !== "text" || isWhitespaceSensitive ) { return newChildren . concat ( child ) ; } const localChildren = [ ] ; const [ , leadingSpaces , text , trailingSpaces ] = child . value . match ( / ^(\s*)([\s\S]*?)(\s*)$ / ) ; if ( leadingSpaces ) { localChildren . push ( { type : TYPE_WHITESPACE } ) ; } const ParseSourceSpan = child . sourceSpan . constructor ; if ( text ) { localChildren . push ( { type : "text" , value : text , sourceSpan : new ParseSourceSpan ( child . sourceSpan . start . moveBy ( leadingSpaces . length ) , child . sourceSpan . end . moveBy ( - trailingSpaces . length ) ) } ) ; } if ( trailingSpaces ) { localChildren . push ( { type : TYPE_WHITESPACE } ) ; } return newChildren . concat ( localChildren ) ; } , [ ] ) // set hasLeadingSpaces/hasTrailingSpaces and filter whitespace nodes . reduce ( ( newChildren , child , i , children ) => { if ( child . type === TYPE_WHITESPACE ) { return newChildren ; } const hasLeadingSpaces = i !== 0 && children [ i - 1 ] . type === TYPE_WHITESPACE ; const hasTrailingSpaces = i !== children . length - 1 && children [ i + 1 ] . type === TYPE_WHITESPACE ; return newChildren . concat ( Object . assign ( { } , child , { hasLeadingSpaces , hasTrailingSpaces } ) ) ; } , [ ] ) } ) ; } ) ; }
- add `hasLeadingSpaces` field
- add `hasTrailingSpaces` field
- add `hasDanglingSpaces` field for parent nodes
- add `isWhitespaceSensitive`, `isIndentationSensitive` field for text nodes
- remove insensitive whitespaces
- add hasLeadingSpaces field - add hasTrailingSpaces field - add hasDanglingSpaces field for parent nodes - add isWhitespaceSensitive isIndentationSensitive field for text nodes - remove insensitive whitespaces