Skip to content

Instantly share code, notes, and snippets.

@JorianWoltjer
Created December 1, 2024 21:04
Show Gist options
  • Save JorianWoltjer/3b3ee6d0f70e776bb94c3eac7d9c3ad2 to your computer and use it in GitHub Desktop.
Save JorianWoltjer/3b3ee6d0f70e776bb94c3eac7d9c3ad2 to your computer and use it in GitHub Desktop.
Convert an HTML/XML snippet to JavaScript `createDocument` and `setAttribute` recursively
import { JSDOM } from 'jsdom';
const dom = new JSDOM(`
<h1 id="title">Hello, World!</h1>
<p>This is a paragraph.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
`);
const { Node } = dom.window;
function getUniqueName(name, existingNames) {
if (!existingNames.has(name)) {
existingNames.add(name);
return name;
}
let i = 2;
while (existingNames.has(`${name}${i}`)) {
i++;
}
const varName = `${name}${i}`;
existingNames.add(varName);
return varName;
}
function getCode(node, indent = 0, existingNames = new Set()) {
const padding = " ".repeat(indent);
let code = "";
if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent.trim();
let varName;
if (text) {
varName = getUniqueName("text", existingNames);
code += `${padding}const ${varName} = document.createTextNode(${JSON.stringify(node.textContent)});\n`;
}
return { code, varName };
}
const tagName = node.tagName.toLowerCase();
const varName = getUniqueName(tagName.match(/(\w+)$/)[1], existingNames);
code += `${padding}const ${varName} = document.createElement(${JSON.stringify(tagName)});\n`;
for (const { name, value } of node.attributes) {
code += `${padding}${varName}.setAttribute(${JSON.stringify(name)}, ${JSON.stringify(value)});\n`;
}
let listOfChilds = Array.from(node.childNodes).map((child) => getCode(child, indent + 1, existingNames));
listOfChilds = listOfChilds.filter((child) => child.code !== "");
if (listOfChilds.length > 0) {
code += `${padding}{\n`;
for (const { code: childCode, varName: childVarName } of listOfChilds) {
code += childCode;
code += `${padding} ${varName}.appendChild(${childVarName});\n`;
}
code += `${padding}}\n`;
listOfChilds.forEach(({ varName }) => existingNames.delete(varName));
}
return { code, varName };
}
for (const node of dom.window.document.body.childNodes) {
console.log(getCode(node).code.trim());
}
@JorianWoltjer
Copy link
Author

JorianWoltjer commented Dec 1, 2024

Setup:

npm i jsdom

Example output:

const h1 = document.createElement("h1");
h1.setAttribute("id", "title");
{
  const text = document.createTextNode("Hello, World!");
  h1.appendChild(text);
}

const p = document.createElement("p");
{
  const text = document.createTextNode("This is a paragraph.");
  p.appendChild(text);
}

const ul = document.createElement("ul");
{
  const li = document.createElement("li");
  {
    const text = document.createTextNode("Item 1");
    li.appendChild(text);
  }
  ul.appendChild(li);
  const li2 = document.createElement("li");
  {
    const text = document.createTextNode("Item 2");
    li2.appendChild(text);
  }
  ul.appendChild(li2);
  const li3 = document.createElement("li");
  {
    const text = document.createTextNode("Item 3");
    li3.appendChild(text);
  }
  ul.appendChild(li3);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment