diff --git a/src/language-html/ast.js b/src/language-html/ast.js
index ced49dcf9..fe7d38c80 100644
--- a/src/language-html/ast.js
+++ b/src/language-html/ast.js
@@ -72,6 +72,18 @@ class Node {
return fn(newNode || this);
}
+ walk(fn) {
+ for (const NODES_KEY in NODES_KEYS) {
+ const nodes = this[NODES_KEY];
+ if (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ nodes[i].walk(fn);
+ }
+ }
+ }
+ fn(this);
+ }
+
/**
* @param {Object} [overrides]
*/
@@ -79,6 +91,13 @@ class Node {
return new Node(overrides ? { ...this, ...overrides } : this);
}
+ /**
+ * @param {Array} [children]
+ */
+ setChildren(children) {
+ this._setNodes("children", children);
+ }
+
get firstChild() {
// @ts-ignore
return isNonEmptyArray(this.children) ? this.children[0] : null;
diff --git a/src/language-html/print-preprocess.js b/src/language-html/print-preprocess.js
index 06a048e10..66545bba9 100644
--- a/src/language-html/print-preprocess.js
+++ b/src/language-html/print-preprocess.js
@@ -31,14 +31,15 @@ const PREPROCESS_PIPELINE = [
];
function preprocess(ast, options) {
+ const res = ast.map((node) => node);
for (const fn of PREPROCESS_PIPELINE) {
- ast = fn(ast, options);
+ fn(res, options);
}
- return ast;
+ return res;
}
function removeIgnorableFirstLf(ast /*, options */) {
- return ast.map((node) => {
+ ast.walk((node) => {
if (
node.type === "element" &&
node.tagDefinition.ignoreFirstLf &&
@@ -47,14 +48,12 @@ function removeIgnorableFirstLf(ast /*, options */) {
node.children[0].value[0] === "\n"
) {
const [text, ...rest] = node.children;
- return node.clone({
- children:
- text.value.length === 1
- ? rest
- : [text.clone({ value: text.value.slice(1) }), ...rest],
- });
+ node.setChildren(
+ text.value.length === 1
+ ? rest
+ : [text.clone({ value: text.value.slice(1) }), ...rest]
+ );
}
- return node;
});
}
@@ -72,7 +71,7 @@ function mergeIeConditonalStartEndCommentIntoElementOpeningTag(
node.firstChild &&
node.firstChild.type === "ieConditionalEndComment" &&
node.firstChild.sourceSpan.start.offset === node.startSourceSpan.end.offset;
- return ast.map((node) => {
+ ast.walk((node) => {
if (node.children) {
const isTargetResults = node.children.map(isTarget);
if (isTargetResults.some(Boolean)) {
@@ -114,15 +113,14 @@ function mergeIeConditonalStartEndCommentIntoElementOpeningTag(
newChildren.push(child);
}
- return node.clone({ children: newChildren });
+ node.setChildren(newChildren);
}
}
- return node;
});
}
function mergeNodeIntoText(ast, shouldMerge, getValue) {
- return ast.map((node) => {
+ ast.walk((node) => {
if (node.children) {
const shouldMergeResults = node.children.map(shouldMerge);
if (shouldMergeResults.some(Boolean)) {
@@ -159,11 +157,9 @@ function mergeNodeIntoText(ast, shouldMerge, getValue) {
})
);
}
- return node.clone({ children: newChildren });
+ node.setChildren(newChildren);
}
}
-
- return node;
});
}
@@ -192,7 +188,7 @@ function mergeSimpleElementIntoText(ast /*, options */) {
node.prev.type === "text" &&
node.next &&
node.next.type === "text";
- return ast.map((node) => {
+ ast.walk((node) => {
if (node.children) {
const isSimpleElementResults = node.children.map(isSimpleElement);
if (isSimpleElementResults.some(Boolean)) {
@@ -223,22 +219,21 @@ function mergeSimpleElementIntoText(ast /*, options */) {
newChildren.push(child);
}
}
- return node.clone({ children: newChildren });
+ node.setChildren(newChildren);
}
}
- return node;
});
}
function extractInterpolation(ast, options) {
if (options.parser === "html") {
- return ast;
+ return;
}
const interpolationRegex = /{{(.+?)}}/gs;
- return ast.map((node) => {
+ ast.walk((node) => {
if (!canHaveInterpolation(node)) {
- return node;
+ return;
}
const newChildren = [];
@@ -292,7 +287,7 @@ function extractInterpolation(ast, options) {
}
}
- return node.clone({ children: newChildren });
+ node.setChildren(newChildren);
});
}
@@ -305,9 +300,9 @@ function extractInterpolation(ast, options) {
*/
const WHITESPACE_NODE = { type: "whitespace" };
function extractWhitespaces(ast /*, options*/) {
- return ast.map((node) => {
+ ast.walk((node) => {
if (!node.children) {
- return node;
+ return;
}
if (
@@ -316,19 +311,16 @@ function extractWhitespaces(ast /*, options*/) {
node.children[0].type === "text" &&
htmlTrim(node.children[0].value).length === 0)
) {
- return node.clone({
- children: [],
- hasDanglingSpaces: node.children.length > 0,
- });
+ node.hasDanglingSpaces = node.children.length > 0;
+ node.children = [];
+ return;
}
const isWhitespaceSensitive = isWhitespaceSensitiveNode(node);
const isIndentationSensitive = isIndentationSensitiveNode(node);
- return node.clone({
- isWhitespaceSensitive,
- isIndentationSensitive,
- children: node.children
+ node.setChildren(
+ node.children
// extract whitespace nodes
.flatMap((child) => {
if (child.type !== "text" || isWhitespaceSensitive) {
@@ -374,13 +366,15 @@ function extractWhitespaces(ast /*, options*/) {
};
})
// filter whitespace nodes
- .filter(Boolean),
- });
+ .filter(Boolean)
+ );
+ node.isWhitespaceSensitive = isWhitespaceSensitive;
+ node.isIndentationSensitive = isIndentationSensitive;
});
}
function addIsSelfClosing(ast /*, options */) {
- return ast.map((node) =>
+ ast.walk((node) =>
Object.assign(node, {
isSelfClosing:
!node.children ||
@@ -393,7 +387,7 @@ function addIsSelfClosing(ast /*, options */) {
}
function addHasHtmComponentClosingTag(ast, options) {
- return ast.map((node) =>
+ ast.walk((node) =>
node.type !== "element"
? node
: Object.assign(node, {
@@ -410,7 +404,7 @@ function addHasHtmComponentClosingTag(ast, options) {
}
function addCssDisplay(ast, options) {
- return ast.map((node) =>
+ ast.walk((node) =>
Object.assign(node, { cssDisplay: getNodeCssStyleDisplay(node, options) })
);
}
@@ -421,19 +415,18 @@ function addCssDisplay(ast, options) {
* - add `isDanglingSpaceSensitive` field for parent nodes
*/
function addIsSpaceSensitive(ast, options) {
- return ast.map((node) => {
+ ast.walk((node) => {
if (!node.children) {
- return node;
+ return;
}
if (node.children.length === 0) {
- return node.clone({
- isDanglingSpaceSensitive: isDanglingSpaceSensitiveNode(node),
- });
+ node.isDanglingSpaceSensitive = isDanglingSpaceSensitiveNode(node);
+ return;
}
- return node.clone({
- children: node.children
+ node.setChildren(
+ node.children
.map((child) => ({
...child,
isLeadingSpaceSensitive: isLeadingSpaceSensitiveNode(child, options),
@@ -454,8 +447,8 @@ function addIsSpaceSensitive(ast, options) {
? child.isTrailingSpaceSensitive
: children[index + 1].isLeadingSpaceSensitive &&
child.isTrailingSpaceSensitive,
- })),
- });
+ }))
+ );
});
}