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:
Sosuke Suzukiandfisker Cheung authored and GitHub committed 2022-04-08 23:36:23 +09:00
1 parent cb997ca7ab
commit f8ce0e303b
2 files changed
+51 -50

No files matched your search

+51 -49
View File
@@ -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,
};
-1
View File
@@ -8,7 +8,6 @@ const ignoredProperties = new Set([
"endSourceSpan",
"nameSpan",
"valueSpan",
"parent",
]);
function clean(ast, newNode) {