function extractWhitespaces(ast
/*, options*/
) {
  var TYPE_WHITESPACE = "whitespace";
  return ast.map(function (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
      });
    }

    var isWhitespaceSensitive = isWhitespaceSensitiveNode$1(node);
    var isIndentationSensitive = isIndentationSensitiveNode$1(node);
    return node.clone({
      children: node.children // extract whitespace nodes
      .reduce(function (newChildren, child) {
        if (child.type !== "text") {
          return newChildren.concat(child);
        }

        if (isWhitespaceSensitive) {
          return newChildren.concat(Object.assign({}, child, {
            isWhitespaceSensitive: isWhitespaceSensitive,
            isIndentationSensitive: isIndentationSensitive
          }));
        }

        var localChildren = [];

        var _child$value$match = child.value.match(/^(\s*)([\s\S]*?)(\s*)$/),
            _child$value$match2 = _slicedToArray(_child$value$match, 4),
            leadingSpaces = _child$value$match2[1],
            text = _child$value$match2[2],
            trailingSpaces = _child$value$match2[3];

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

        var 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(function (newChildren, child, i, children) {
        if (child.type === TYPE_WHITESPACE) {
          return newChildren;
        }

        var hasLeadingSpaces = i !== 0 && children[i - 1].type === TYPE_WHITESPACE;
        var hasTrailingSpaces = i !== children.length - 1 && children[i + 1].type === TYPE_WHITESPACE;
        return newChildren.concat(Object.assign({}, child, {
          hasLeadingSpaces: hasLeadingSpaces,
          hasTrailingSpaces: hasTrailingSpaces
        }));
      }, [])
    });
  });
}
- add `hasLeadingSpaces` field
- add `hasTrailingSpaces` field
- add `hasDanglingSpaces` field for parent nodes
- add `isWhitespaceSensitive`, `isIndentationSensitive` field for text nodes
- remove insensitive whitespaces