Fix HTML AST JSON serializer for debugging (#12611)
* Add `JSON.stringify` replacer * Fix serializer for playground * Use `opt.parser` * Consitent style * lwc * Revert "lwc" This reverts commit 799bf357e8b30765944b29639a45b3c326bce615. Revert "Use `opt.parser`" This reverts commit 3046f52798ce740ea0ed267bf46c3221606b1fbc. Revert "Add `JSON.stringify` replacer" This reverts commit 54266cde61ea8f7cc4b3b0c9714559c93b456923. * Rewrite `Node` class * Revert changes in playground * Revert wrong changes * Update clean.js * Set `configurable: true` * Fix missing `return` * Fix: "children" and "attrs" are enumerable * Type check * Revert unnessary change Co-authored-by: fisker Cheung <lionkay@gmail.com>
This commit is contained in:
1 parent
cb997ca7ab
commit
f8ce0e303b
2 files changed
+51
-50
No files matched your search
+51
-49
@@ -8,33 +8,40 @@ const NODES_KEYS = {
|
||||
children: true,
|
||||
};
|
||||
|
||||
const NON_ENUMERABLE_PROPERTIES = new Set(["parent"]);
|
||||
|
||||
// TODO: typechecking is problematic for this class because of this issue:
|
||||
// https://github.com/microsoft/TypeScript/issues/26811
|
||||
|
||||
class Node {
|
||||
constructor(props = {}) {
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
if (key in NODES_KEYS) {
|
||||
this._setNodes(key, value);
|
||||
} else {
|
||||
this[key] = value;
|
||||
}
|
||||
constructor(nodeOrProperties = {}) {
|
||||
for (const property of new Set([
|
||||
...NON_ENUMERABLE_PROPERTIES,
|
||||
...Object.keys(nodeOrProperties),
|
||||
])) {
|
||||
this.setProperty(property, nodeOrProperties[property]);
|
||||
}
|
||||
}
|
||||
|
||||
_setNodes(key, nodes) {
|
||||
if (nodes !== this[key]) {
|
||||
this[key] = cloneAndUpdateNodes(nodes, this);
|
||||
if (key === "attrs") {
|
||||
setNonEnumerableProperty(
|
||||
this,
|
||||
"attrMap",
|
||||
Object.fromEntries(
|
||||
this[key].map((attr) => [attr.fullName, attr.value])
|
||||
)
|
||||
);
|
||||
}
|
||||
setProperty(property, value) {
|
||||
if (this[property] === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (property in NODES_KEYS) {
|
||||
value = value.map((node) => this.createChild(node));
|
||||
}
|
||||
|
||||
if (!NON_ENUMERABLE_PROPERTIES.has(property)) {
|
||||
this[property] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
Object.defineProperty(this, property, {
|
||||
value,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
map(fn) {
|
||||
@@ -50,7 +57,7 @@ class Node {
|
||||
// @ts-expect-error
|
||||
newNode = new Node({ parent: this.parent });
|
||||
}
|
||||
newNode._setNodes(NODES_KEY, mappedNodes);
|
||||
newNode.setProperty(NODES_KEY, mappedNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,15 +85,27 @@ class Node {
|
||||
fn(this);
|
||||
}
|
||||
|
||||
createChild(nodeOrProperties) {
|
||||
const node =
|
||||
nodeOrProperties instanceof Node
|
||||
? nodeOrProperties.clone()
|
||||
: new Node(nodeOrProperties);
|
||||
node.setProperty("parent", this);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} [target]
|
||||
* @param {Object} [node]
|
||||
*/
|
||||
insertChildBefore(target, node) {
|
||||
const newNode = new Node({ ...node, parent: this });
|
||||
|
||||
// @ts-expect-error
|
||||
this.children.splice(this.children.indexOf(target), 0, newNode);
|
||||
this.children.splice(
|
||||
// @ts-expect-error
|
||||
this.children.indexOf(target),
|
||||
0,
|
||||
this.createChild(node)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,23 +121,14 @@ class Node {
|
||||
* @param {Object} [node]
|
||||
*/
|
||||
replaceChild(target, node) {
|
||||
const newNode = new Node({ ...node, parent: this });
|
||||
|
||||
// @ts-expect-error
|
||||
this.children[this.children.indexOf(target)] = newNode;
|
||||
this.children[this.children.indexOf(target)] = this.createChild(node);
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new Node(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} [children]
|
||||
*/
|
||||
setChildren(children) {
|
||||
this._setNodes("children", children);
|
||||
}
|
||||
|
||||
get firstChild() {
|
||||
// @ts-expect-error
|
||||
return isNonEmptyArray(this.children) ? this.children[0] : null;
|
||||
@@ -152,10 +162,18 @@ class Node {
|
||||
// @ts-expect-error
|
||||
return this.hasExplicitNamespace ? this.fullName : this.name;
|
||||
}
|
||||
|
||||
get fullName() {
|
||||
// @ts-expect-error
|
||||
return this.namespace ? this.namespace + ":" + this.name : this.name;
|
||||
}
|
||||
|
||||
get attrMap() {
|
||||
return Object.fromEntries(
|
||||
// @ts-expect-error
|
||||
this.attrs.map((attr) => [attr.fullName, attr.value])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapNodesIfChanged(nodes, fn) {
|
||||
@@ -165,22 +183,6 @@ function mapNodesIfChanged(nodes, fn) {
|
||||
: nodes;
|
||||
}
|
||||
|
||||
function cloneAndUpdateNodes(nodes, parent) {
|
||||
const siblings = nodes.map((node) =>
|
||||
node instanceof Node ? node.clone() : new Node({ ...node, parent })
|
||||
);
|
||||
|
||||
for (const sibling of siblings) {
|
||||
sibling.parent = parent;
|
||||
}
|
||||
|
||||
return siblings;
|
||||
}
|
||||
|
||||
function setNonEnumerableProperty(obj, key, value) {
|
||||
Object.defineProperty(obj, key, { value, enumerable: false });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Node,
|
||||
};
|
||||
@@ -8,7 +8,6 @@ const ignoredProperties = new Set([
|
||||
"endSourceSpan",
|
||||
"nameSpan",
|
||||
"valueSpan",
|
||||
"parent",
|
||||
]);
|
||||
|
||||
function clean(ast, newNode) {
|
||||
|
||||
Reference in new issue
Block a user