aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-19 17:52:07 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-19 17:52:07 -0700
commit3672bb85eb9891f30295f31673038e1d9ed7dc6d (patch)
treece5327aa635426707a3a48734b42d06632359c53
parent6f741e8c1040f9565de9e4242f58527ac80f4ffd (diff)
downloadbun-3672bb85eb9891f30295f31673038e1d9ed7dc6d.tar.gz
bun-3672bb85eb9891f30295f31673038e1d9ed7dc6d.tar.zst
bun-3672bb85eb9891f30295f31673038e1d9ed7dc6d.zip
[solid] wip make nested components work
Diffstat (limited to '')
-rw-r--r--src/js_parser/js_parser.zig177
1 files changed, 97 insertions, 80 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 2cdabe46f..a5d4a74d2 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -3321,77 +3321,29 @@ const SolidJS = struct {
setAttribute: GeneratedSymbol = undefined,
effect: GeneratedSymbol = undefined,
- component_body: std.ArrayListUnmanaged(Stmt) = .{},
- component_body_decls: std.ArrayListUnmanaged(G.Decl) = .{},
- last_template_id: E.Identifier = .{},
- last_element_id: E.Identifier = .{},
- prev_had_dynamic: bool = false,
- temporary_scope: Scope = Scope{
- .kind = .function_body,
- .parent = null,
- },
- prev_scope: ?*Scope = null,
- node_count: u32 = 0,
-
+ events_to_delegate: Events.Bitset = .{},
template_decls: std.ArrayListUnmanaged(G.Decl) = .{},
- current_template_string: MutableString = .{
- .allocator = undefined,
- .list = .{},
- },
- buffered_writer: MutableString.BufferedWriter = undefined,
-
is_in_jsx_component: bool = false,
- events_to_delegate: Events.Bitset = .{},
- element_counter: u32 = 0,
+ pub const Stack = struct {
+ component_body: std.ArrayListUnmanaged(Stmt) = .{},
+ component_body_decls: std.ArrayListUnmanaged(G.Decl) = .{},
+ last_template_id: E.Identifier = .{},
+ last_element_id: E.Identifier = .{},
+ temporary_scope: Scope = Scope{
+ .kind = .function_body,
+ .parent = null,
+ },
+ prev_scope: ?*Scope = null,
+ node_count: u32 = 0,
- const prefilled_element_names = [_]string{
- "_el",
- "_el$1",
- "_el$2",
- "_el$3",
- "_el$4",
- "_el$5",
- "_el$6",
- "_el$7",
- "_el$8",
- "_el$9",
- "_el$10",
- "_el$11",
- "_el$12",
- "_el$13",
- "_el$14",
- "_el$15",
- "_el$16",
- "_el$17",
- "_el$18",
- "_el$19",
- "_el$20",
- "_el$21",
- };
- const prefilled_template_names = [_]string{
- "_tmpl",
- "_tmpl$1",
- "_tmpl$2",
- "_tmpl$3",
- "_tmpl$4",
- "_tmpl$5",
- "_tmpl$6",
- "_tmpl$7",
- "_tmpl$8",
- "_tmpl$9",
- "_tmpl$10",
- "_tmpl$11",
- "_tmpl$12",
- "_tmpl$13",
- "_tmpl$14",
- "_tmpl$15",
- "_tmpl$16",
- "_tmpl$17",
- "_tmpl$18",
- "_tmpl$19",
- "_tmpl$20",
- "_tmpl$21",
+ current_template_string: MutableString = .{
+ .allocator = undefined,
+ .list = .{},
+ },
+ buffered_writer: MutableString.BufferedWriter = undefined,
+
+ element_counter: u32 = 0,
};
pub fn generateElementName(this: *SolidJS, allocator: std.mem.Allocator) string {
@@ -3528,6 +3480,55 @@ const SolidJS = struct {
pub const Bitset = std.enums.EnumSet(Events);
};
+
+ const prefilled_element_names = [_]string{
+ "_el",
+ "_el$1",
+ "_el$2",
+ "_el$3",
+ "_el$4",
+ "_el$5",
+ "_el$6",
+ "_el$7",
+ "_el$8",
+ "_el$9",
+ "_el$10",
+ "_el$11",
+ "_el$12",
+ "_el$13",
+ "_el$14",
+ "_el$15",
+ "_el$16",
+ "_el$17",
+ "_el$18",
+ "_el$19",
+ "_el$20",
+ "_el$21",
+ };
+ const prefilled_template_names = [_]string{
+ "_tmpl",
+ "_tmpl$1",
+ "_tmpl$2",
+ "_tmpl$3",
+ "_tmpl$4",
+ "_tmpl$5",
+ "_tmpl$6",
+ "_tmpl$7",
+ "_tmpl$8",
+ "_tmpl$9",
+ "_tmpl$10",
+ "_tmpl$11",
+ "_tmpl$12",
+ "_tmpl$13",
+ "_tmpl$14",
+ "_tmpl$15",
+ "_tmpl$16",
+ "_tmpl$17",
+ "_tmpl$18",
+ "_tmpl$19",
+ "_tmpl$20",
+ "_tmpl$21",
+ };
};
fn GetSolidJSSymbols(comptime jsx: JSXTransformType) type {
@@ -12622,9 +12623,8 @@ fn NewParser_(
},
.solid => {
// The rules:
- // 1. Every JSX element with an identifier gets wrapped in a createComponent() call
- // 2. HTML string literals of static elements are generated & escaped, injected at the top of the file
- // 2a. Static elements are contiguous in the HTML, but dynamic elements get a marker string during if client-side hydration
+ // 1. HTML string literals of static JSX elements are generated & escaped, injected at the top of the file
+ // 1a. Static elements are contiguous in the HTML, but dynamic elements get a marker string during if client-side hydration
// Each element becomes a declaration in the top-level scope of the JSX expression (i.e. either the anonymous IIFE or an array)
// Those elements may be markers
// The final count of the markers is passed to the template function
@@ -12633,7 +12633,9 @@ fn NewParser_(
// The specific function differs if SSR is enabled and if client-side hydration is enabled.
// 4. Non-static JSX children are added like this:
// insert(topElement, createComponent(MyComponent, props), markerElement)
- //
+ // 5. Non-statically analyzable attributes are added like this:
+ // setAttribute(topElement, "data-foo", "bar")
+ // 6.
var solid = &p.solid;
const old_is_in_jsx_component = solid.is_in_jsx_component;
solid.is_in_jsx_component = true;
@@ -12650,7 +12652,6 @@ fn NewParser_(
solid.component_body.append(p.allocator, p.s(S.Empty{}, expr.loc)) catch unreachable;
solid.last_element_id = E.Identifier{};
- solid.prev_had_dynamic = false;
solid.prev_scope = p.current_scope;
solid.temporary_scope.reset();
solid.node_count = 0;
@@ -12662,6 +12663,7 @@ fn NewParser_(
var writer = &solid.buffered_writer;
+ // The JSX tag used
const tag: Expr = tagger: {
if (e_.tag) |_tag| {
break :tagger p.visitExpr(_tag);
@@ -12691,7 +12693,6 @@ fn NewParser_(
needs_end_bracket = true;
var wrote_anything = false;
- var had_any_dynamic_content = false;
for (jsx_props) |*property, i| {
if (property.kind != .spread) {
property.key = p.visitExpr(e_.properties.ptr[i].key.?);
@@ -12709,7 +12710,7 @@ fn NewParser_(
(key.eqlComptime("class") or key.eqlComptime("className"));
const primitive = property.value.?.knownPrimitive();
- const is_dynamic = !(primitive == .string or primitive == .number or primitive == .boolean or primitive == .@"null" or primitive == .@"undefined");
+ const is_dynamic = !primitive.isStatic();
const appears_in_template = !is_event_listener and !is_dynamic;
if (appears_in_template) {
_ = writer.writeAll(" ") catch unreachable;
@@ -12738,7 +12739,10 @@ fn NewParser_(
// TODO: should "undefined" be written?
.@"null", .@"undefined" => {},
.boolean => {
+ // existence of an HTML attribute implicitly is true
+ // so we only need to write if it's false
if (!property.value.?.data.e_boolean.value) {
+ // TODO: verify that SolidJS writes the same value
_ = writer.writeAll("=false") catch unreachable;
}
},
@@ -12758,7 +12762,6 @@ fn NewParser_(
p.current_scope = solid.prev_scope.?;
template_expression = .{ .loc = expr.loc, .data = .{ .e_identifier = solid.last_template_id } };
}
- had_any_dynamic_content = true;
if (element == null) {
element = solid.generateElement(
p,
@@ -12769,8 +12772,8 @@ fn NewParser_(
var stmt: Stmt = undefined;
if (!is_event_listener) {
- var args = p.allocator.alloc(Expr, 3) catch unreachable;
- args[0] = template_expression;
+ var args = p.allocator.alloc(Expr, 4) catch unreachable;
+ args[0] = p.e(element.?, expr.loc);
if (is_class) {
args[1] = p.e(E.String.init("className"), property.key.?.loc);
} else {
@@ -12790,7 +12793,7 @@ fn NewParser_(
},
property.value.?.loc,
),
- .args = ExprNodeList.init(args),
+ .args = ExprNodeList.init(args[0..3]),
},
property.key.?.loc,
);
@@ -12803,7 +12806,8 @@ fn NewParser_(
} else {
var stmts = p.allocator.alloc(Stmt, 1) catch unreachable;
stmts[0] = p.s(S.Return{ .value = setAttr }, property.value.?.loc);
- var arrow = p.e(
+
+ args[3] = p.e(
E.Arrow{
.args = &[_]G.Arg{},
.body = G.FnBody{
@@ -12813,7 +12817,18 @@ fn NewParser_(
},
property.value.?.loc,
);
- stmt = p.s(S.SExpr{ .value = arrow }, property.value.?.loc);
+ stmt = p.s(S.SExpr{
+ .value = p.e(
+ E.Call{
+ .target = p.e(
+ E.Identifier{
+ .ref = solid.effect.ref,
+ },
+ ),
+ .args = ExprNodeList.init(args[3..4]),
+ },
+ ),
+ }, property.value.?.loc);
}
} else {
var args = p.allocator.alloc(Expr, 2) catch unreachable;
@@ -12954,6 +12969,8 @@ fn NewParser_(
if (!old_is_in_jsx_component) {
var args = p.allocator.alloc(Expr, 2) catch unreachable;
+ // we are done, so it's time to turn our template into a string we can write
+ // note that we are writing as UTF-8 but the input may be UTF-16 or UTF-8, depending.
if (writer.pos < writer.buffer.len and writer.context.list.items.len == 0) {
args[0] = p.e(E.String.init(p.allocator.dupe(u8, writer.buffer[0..writer.pos]) catch unreachable), expr.loc);
} else if (writer.pos == 0 and writer.context.list.items.len == 0) {