chore: replace eslint & prettier w/ biomejs (#21)
* chore: replace eslint & prettier w/ biomejs * fix syntax error in ci.yml workflow * ensure that build CI jobs only run if check job succeeds to save resources
This commit is contained in:
parent
d67e4c81ad
commit
e319626a1a
44 changed files with 2408 additions and 5691 deletions
158
src/render.ts
158
src/render.ts
|
|
@ -3,89 +3,87 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { Element, HTMLElement } from "./component";
|
||||
import type { Element, HTMLElement } from "./component";
|
||||
|
||||
const HTML_ESCAPES: { [char: string]: string } = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
};
|
||||
|
||||
const escapeHtml = (text: string): string =>
|
||||
text.replace(/[&<>]/g, (t) => HTML_ESCAPES[t]);
|
||||
text.replace(/[&<>]/g, (t) => HTML_ESCAPES[t]);
|
||||
|
||||
const escapeAttr = (text: string): string => text.replace(/"/g, """);
|
||||
|
||||
const renderElement = (elem: Element): string => {
|
||||
// Ignore null and true/false to support nicer JSX conditional syntax with
|
||||
// &&, ||, !! operators.
|
||||
if (elem == null || typeof elem === "boolean") {
|
||||
return "";
|
||||
}
|
||||
if (typeof elem === "number") {
|
||||
return elem.toString();
|
||||
}
|
||||
if (typeof elem === "string") {
|
||||
return escapeHtml(elem);
|
||||
}
|
||||
if (Array.isArray(elem)) {
|
||||
return elem.map((e) => renderElement(e)).join("");
|
||||
}
|
||||
// Ignore null and true/false to support nicer JSX conditional syntax with
|
||||
// &&, ||, !! operators.
|
||||
if (elem == null || typeof elem === "boolean") {
|
||||
return "";
|
||||
}
|
||||
if (typeof elem === "number") {
|
||||
return elem.toString();
|
||||
}
|
||||
if (typeof elem === "string") {
|
||||
return escapeHtml(elem);
|
||||
}
|
||||
if (Array.isArray(elem)) {
|
||||
return elem.map((e) => renderElement(e)).join("");
|
||||
}
|
||||
|
||||
let output = "";
|
||||
output += startTag(elem);
|
||||
if (elem.attributes.dangerouslySetInnerHTML != null) {
|
||||
output += elem.attributes.dangerouslySetInnerHTML;
|
||||
} else {
|
||||
for (const child of elem.children) {
|
||||
output += renderElement(child);
|
||||
}
|
||||
}
|
||||
output += endTag(elem);
|
||||
return output;
|
||||
let output = "";
|
||||
output += startTag(elem);
|
||||
if (elem.attributes.dangerouslySetInnerHTML != null) {
|
||||
output += elem.attributes.dangerouslySetInnerHTML;
|
||||
} else {
|
||||
for (const child of elem.children) {
|
||||
output += renderElement(child);
|
||||
}
|
||||
}
|
||||
output += endTag(elem);
|
||||
return output;
|
||||
};
|
||||
|
||||
const startTag = (elem: HTMLElement): string => {
|
||||
if (elem.tag === "#fragment") {
|
||||
return "";
|
||||
}
|
||||
if (elem.tag === "#fragment") {
|
||||
return "";
|
||||
}
|
||||
|
||||
let output = `<${escapeHtml(elem.tag)}`;
|
||||
let output = `<${escapeHtml(elem.tag)}`;
|
||||
|
||||
for (const [attrName, attrValue] of Object.entries(elem.attributes)) {
|
||||
// Handle boolean attributes with a false value by not outputting the
|
||||
// attribute at all.
|
||||
if (attrValue === false) {
|
||||
continue;
|
||||
}
|
||||
for (const [attrName, attrValue] of Object.entries(elem.attributes)) {
|
||||
// Handle boolean attributes with a false value by not outputting the
|
||||
// attribute at all.
|
||||
if (attrValue === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore the special attr for setting raw inner HTML.
|
||||
if (attrName === "dangerouslySetInnerHTML") {
|
||||
continue;
|
||||
}
|
||||
// Ignore the special attr for setting raw inner HTML.
|
||||
if (attrName === "dangerouslySetInnerHTML") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let normalizedAttrName = escapeHtml(attrName.toLowerCase());
|
||||
if (normalizedAttrName === "classname") {
|
||||
normalizedAttrName = "class";
|
||||
}
|
||||
if (attrValue === true) {
|
||||
output += ` ${normalizedAttrName}=""`;
|
||||
} else {
|
||||
output += ` ${normalizedAttrName}="${escapeAttr(
|
||||
attrValue.toString(),
|
||||
)}"`;
|
||||
}
|
||||
}
|
||||
let normalizedAttrName = escapeHtml(attrName.toLowerCase());
|
||||
if (normalizedAttrName === "classname") {
|
||||
normalizedAttrName = "class";
|
||||
}
|
||||
if (attrValue === true) {
|
||||
output += ` ${normalizedAttrName}=""`;
|
||||
} else {
|
||||
output += ` ${normalizedAttrName}="${escapeAttr(attrValue.toString())}"`;
|
||||
}
|
||||
}
|
||||
|
||||
output += ">";
|
||||
return output;
|
||||
output += ">";
|
||||
return output;
|
||||
};
|
||||
|
||||
const endTag = (elem: HTMLElement): string => {
|
||||
if (elem.tag === "#fragment") {
|
||||
return "";
|
||||
}
|
||||
return `</${escapeHtml(elem.tag)}>`;
|
||||
if (elem.tag === "#fragment") {
|
||||
return "";
|
||||
}
|
||||
return `</${escapeHtml(elem.tag)}>`;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -97,23 +95,23 @@ const endTag = (elem: HTMLElement): string => {
|
|||
* @return Fully rendered HTML document as a string.
|
||||
*/
|
||||
export const renderPage = (rootElem: Element): string => {
|
||||
if (rootElem == undefined) {
|
||||
throw new Error(`root page element cannot be null`);
|
||||
}
|
||||
if (typeof rootElem !== "object" || !("tag" in rootElem)) {
|
||||
throw new Error(
|
||||
`root page element must be a valid HTMLElement, got ${JSON.stringify(
|
||||
rootElem,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
if (rootElem.tag.toLowerCase() !== "html") {
|
||||
throw new Error(
|
||||
`attempted to render page with non-HTML root element ${rootElem.tag}`,
|
||||
);
|
||||
}
|
||||
if (rootElem == null) {
|
||||
throw new Error("root page element cannot be null");
|
||||
}
|
||||
if (typeof rootElem !== "object" || !("tag" in rootElem)) {
|
||||
throw new Error(
|
||||
`root page element must be a valid HTMLElement, got ${JSON.stringify(
|
||||
rootElem,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
if (rootElem.tag.toLowerCase() !== "html") {
|
||||
throw new Error(
|
||||
`attempted to render page with non-HTML root element ${rootElem.tag}`,
|
||||
);
|
||||
}
|
||||
|
||||
let output = "<!DOCTYPE html>";
|
||||
output += renderElement(rootElem);
|
||||
return output;
|
||||
let output = "<!DOCTYPE html>";
|
||||
output += renderElement(rootElem);
|
||||
return output;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue