Skip to content

Commit 8d623ea

Browse files
committed
Add childish dom codegen
Design: - For each HTML element there's a single function, suffixed with underscore, like `div_`, `body_`, `data_`, `main_`. The "add an underscore suffix to **every** name" idea is taken from [lucid](https://chrisdone.com/posts/lucid#naming-issues). - Functions for void elements simply take the props record. - Other functions take props record and an array of children. - If no props need to be specified, the record can be left empty: `div_ {} [ text "Foo", text "Bar" ]` The advantage is that this: - Avoids name collisions with some "standard" and reserved names (`a`, `b`, head`, `div`). However, I'm debating the usefullness of that since the module could be just use qualified and the only reserved name conflict is `data`. - This model maps to DOM tree model in a more straightforward way (each leaf is a tag with attributes and a children tree), very similar to XML/JSX. This also makes codegen simpler (no need to insert the extra `children` property into `Prop` type or do name mangling) - Makes it much easier to make and review changes. Especially switching from an element with no props (`div_ []`) to an element with a prop `div { className: "foo", children: [] }`.
1 parent 8865c54 commit 8d623ea

File tree

2 files changed

+1712
-0
lines changed

2 files changed

+1712
-0
lines changed

codegen/childish.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const props = require("react-html-attributes");
2+
3+
const voids = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
4+
5+
const types = {
6+
"allowFullScreen": "Boolean",
7+
"async": "Boolean",
8+
"autoPlay": "Boolean",
9+
"capture": "Boolean",
10+
"checked": "Boolean",
11+
"children": "Array JSX",
12+
"cols": "Number",
13+
"controls": "Boolean",
14+
"default": "Boolean",
15+
"defer": "Boolean",
16+
"disabled": "Boolean",
17+
"formNoValidate": "Boolean",
18+
"hidden": "Boolean",
19+
"itemScope": "Boolean",
20+
"loop": "Boolean",
21+
"max": "Number",
22+
"min": "Number",
23+
"multiple": "Boolean",
24+
"muted": "Boolean",
25+
"onClick": "EventHandler",
26+
"onInput": "EventHandler",
27+
"onInvalid": "EventHandler",
28+
"onSubmit": "EventHandler",
29+
"noValidate": "Boolean",
30+
"onChange": "EventHandler",
31+
"open": "Boolean",
32+
"playsInline": "Boolean",
33+
"readOnly": "Boolean",
34+
"required": "Boolean",
35+
"reversed": "Boolean",
36+
"rowSpan": "Number",
37+
"rows": "Number",
38+
"scoped": "Boolean",
39+
"seamless": "Boolean",
40+
"selected": "Boolean",
41+
"size": "Number",
42+
"span": "Number",
43+
"start": "Number"
44+
};
45+
46+
printRecord = (elProps) => elProps.length ? `
47+
( ${ elProps.map((p) =>
48+
`${p} :: ${types[p] || "String"}`).join("\n , ")
49+
}
50+
)` : "()"
51+
52+
const header =
53+
`
54+
module React.Basic.DOM.Childish
55+
( module React.Basic.DOM
56+
, module React.Basic.DOM.Childish
57+
) where
58+
59+
import Prim.Row (class Union)
60+
import React.Basic (JSX, ReactComponent, createElement, createElementKeyed)
61+
import React.Basic.DOM (text, CSS, css, mergeStyles, SharedProps, unsafeCreateDOMComponent)
62+
import React.Basic.Events (EventHandler)
63+
import Record (union)
64+
65+
createChildishElement
66+
:: forall children props
67+
. ReactComponent { children :: children | props }
68+
-> { | props }
69+
-> children
70+
-> JSX
71+
createChildishElement component props children =
72+
createElement component (union { children } props)
73+
74+
createChildishKeyedElement
75+
:: forall children props
76+
. ReactComponent { children :: children | props }
77+
-> { key :: String | props }
78+
-> children
79+
-> JSX
80+
createChildishKeyedElement component props children =
81+
createElementKeyed component (union { children } props)
82+
83+
-- | -------------------------------
84+
-- | GENERATED CODE BELOW THIS LINE!
85+
-- | -------------------------------
86+
`.trim();
87+
88+
console.log(header);
89+
console.log();
90+
91+
props.elements.html
92+
.map((e) => {
93+
const noChildren = voids.includes(e);
94+
return `
95+
type Props_${e} =${printRecord((props[e] || []).sort())}
96+
97+
${e}_
98+
:: forall attrs attrs_
99+
. Union attrs attrs_ (SharedProps Props_${e})
100+
=> Record attrs${noChildren ? "" : ` -> Array JSX`}
101+
-> JSX
102+
${e}_ = ${noChildren ? "createElement" : "createChildishElement"} (unsafeCreateDOMComponent "${e}")
103+
`;
104+
}).forEach((x) => console.log(x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n")))

0 commit comments

Comments
 (0)