Move to own JSX implementation
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@ -1,5 +0,0 @@
|
||||
Denreg JSX renderer
|
||||
|
||||
**deprecated**
|
||||
|
||||
**DO NOT USE**
|
@ -1,13 +1,9 @@
|
||||
{
|
||||
"name": "@denreg-jsx",
|
||||
"version": "0.0.3",
|
||||
"description": "Denreg JSX renderer",
|
||||
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
||||
"contributors": [],
|
||||
"deprecated": true,
|
||||
"files": [
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
"name": "@denreg-jsx",
|
||||
"version": "0.1.0",
|
||||
"description": "Denreg JSX renderer",
|
||||
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
||||
"contributors": [],
|
||||
"deprecated": false,
|
||||
"files": ["**/*.ts", "**/*.js", "tsconfig.json", "README.md"]
|
||||
}
|
||||
|
133
jsx/mod.ts
Normal file
133
jsx/mod.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import "./types.ts";
|
||||
|
||||
const Fragment = Symbol("fragment");
|
||||
|
||||
declare namespace JSX {
|
||||
interface Element {}
|
||||
interface IntrinsicElements {
|
||||
div: any;
|
||||
}
|
||||
}
|
||||
|
||||
export { Fragment };
|
||||
|
||||
export type Element = {
|
||||
component: Component | string;
|
||||
props: any;
|
||||
children: any[];
|
||||
};
|
||||
export type ComponentRetElm = Element | Element[];
|
||||
export type Component = (
|
||||
props: any,
|
||||
children: any
|
||||
) => ComponentRetElm | Promise<ComponentRetElm>;
|
||||
|
||||
export function h(
|
||||
component: string | Component,
|
||||
props: any,
|
||||
...children: Element[]
|
||||
): Element {
|
||||
return {
|
||||
component,
|
||||
props,
|
||||
children,
|
||||
};
|
||||
}
|
||||
|
||||
export async function renderSSR(element: Element | string): Promise<string> {
|
||||
if (typeof element === "string") return element;
|
||||
else if (typeof element.component === "string")
|
||||
return await renderHTML(element as Element);
|
||||
else if (typeof element.component === "function")
|
||||
return await renderCustom(element as Element);
|
||||
|
||||
console.warn("renderSSR: invalid element", element);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const selfClosing = new Set([
|
||||
"area",
|
||||
"base",
|
||||
"br",
|
||||
"col",
|
||||
"embed",
|
||||
"hr",
|
||||
"img",
|
||||
"input",
|
||||
"link",
|
||||
"meta",
|
||||
"param",
|
||||
"source",
|
||||
"track",
|
||||
"wbr",
|
||||
]);
|
||||
|
||||
function flatDeep(arr: any, d = Infinity): any[] {
|
||||
if (Array.isArray(arr) && d >= 0) {
|
||||
let res = [];
|
||||
for (const val of arr) {
|
||||
const v = flatDeep(val, d - 1);
|
||||
res.push(...v);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return [arr];
|
||||
}
|
||||
|
||||
function cleanChildren(children: any) {
|
||||
return flatDeep(children).filter((e) => !!e);
|
||||
}
|
||||
|
||||
async function renderHTML(element: Element) {
|
||||
if (typeof element.component !== "string")
|
||||
throw new Error("Internal consistency error");
|
||||
|
||||
console.log("Element:", element.component);
|
||||
let props = "";
|
||||
|
||||
for (const key in element.props) {
|
||||
if (key == "innerHTML") continue;
|
||||
props += `${key}="${element.props[key] || ""}" `;
|
||||
}
|
||||
|
||||
const tag = element.component;
|
||||
|
||||
if (selfClosing.has(element.component)) {
|
||||
return `<${tag} ${props}/>`;
|
||||
} else {
|
||||
let inner = "";
|
||||
if (element.props && element.props["innerHTML"]) {
|
||||
inner = element.props["innerHTML"];
|
||||
} else {
|
||||
const children = cleanChildren(element.children);
|
||||
if (tag == "body") console.log(element.children, children);
|
||||
inner = (
|
||||
await Promise.all(children.map((child) => renderSSR(child)))
|
||||
).join("");
|
||||
}
|
||||
return `<${tag} ${props}>${inner || ""}</${tag}>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function renderCustom(element: Element) {
|
||||
if (typeof element.component === "string")
|
||||
throw new Error("Internal consistency error");
|
||||
|
||||
console.log("Component:", element.component);
|
||||
const res = await Promise.resolve(
|
||||
element.component(
|
||||
{
|
||||
...element.props,
|
||||
children: element.children,
|
||||
},
|
||||
element.children
|
||||
)
|
||||
);
|
||||
|
||||
const ch = (
|
||||
await Promise.all(cleanChildren(res).map((child) => renderSSR(child)))
|
||||
).join("");
|
||||
|
||||
return ch;
|
||||
}
|
7
jsx/tsconfig.json
Normal file
7
jsx/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext", "deno.ns", "deno.unstable"],
|
||||
"jsxFactory": "h",
|
||||
"strictPropertyInitialization": false
|
||||
}
|
||||
}
|
11
jsx/types.ts
Normal file
11
jsx/types.ts
Normal file
@ -0,0 +1,11 @@
|
||||
declare namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
[elemName: string]: any;
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace JSX {
|
||||
interface ElementClass {
|
||||
render: any;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user