diff options
author | 2022-12-09 16:41:38 -0800 | |
---|---|---|
committer | 2022-12-09 16:41:38 -0800 | |
commit | 88538b7c2c68fe506d0a20a8f5b78e47c6c60299 (patch) | |
tree | e27cae0caf7a42ff82177d38911693fcd3720ce8 /src/js_parser.zig | |
parent | 79138c4c7cb72a5f84c9a81720a73d283d78b1be (diff) | |
download | bun-88538b7c2c68fe506d0a20a8f5b78e47c6c60299.tar.gz bun-88538b7c2c68fe506d0a20a8f5b78e47c6c60299.tar.zst bun-88538b7c2c68fe506d0a20a8f5b78e47c6c60299.zip |
Deprecate very incomplete Solid.js JSX transform
We don't have time to do a good job of this and Bun.plugin makes it possible to use Solid with Bun
Diffstat (limited to 'src/js_parser.zig')
-rw-r--r-- | src/js_parser.zig | 1138 |
1 files changed, 5 insertions, 1133 deletions
diff --git a/src/js_parser.zig b/src/js_parser.zig index 5a58ba305..b69951377 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -1030,7 +1030,6 @@ const StaticSymbolName = struct { pub const setAttribute = NewStaticSymbol("setAttribute"); pub const effect = NewStaticSymbol("effect"); pub const delegateEvents = NewStaticSymbol("delegateEvents"); - pub const Solid = NewStaticSymbol("Solid"); pub const __merge = NewStaticSymbol("__merge"); }; @@ -2323,11 +2322,11 @@ pub const Parser = struct { if (!self.options.ts and self.options.features.is_macro_runtime) return try self._parse(JSParserMacro); if (self.options.ts and self.options.jsx.parse) { - return if (self.options.jsx.runtime != .solid) try self._parse(TSXParser) else try self._parse(SolidTSXParser); + return try self._parse(TSXParser); } else if (self.options.ts) { return try self._parse(TypeScriptParser); } else if (self.options.jsx.parse) { - return if (self.options.jsx.runtime != .solid) try self._parse(JSXParser) else try self._parse(SolidJSXParser); + return try self._parse(JSXParser); } else { return try self._parse(JavaScriptParser); } @@ -3069,114 +3068,6 @@ pub const Parser = struct { } } }, - .solid => { - p.resolveGeneratedSymbol(&p.solid.wrap); - p.resolveGeneratedSymbol(&p.solid.insert); - p.resolveGeneratedSymbol(&p.solid.template); - p.resolveGeneratedSymbol(&p.solid.delegateEvents); - p.resolveGeneratedSymbol(&p.solid.createComponent); - p.resolveGeneratedSymbol(&p.solid.setAttribute); - p.resolveGeneratedSymbol(&p.solid.effect); - p.resolveGeneratedSymbol(&p.solid.namespace); - - const import_count = - @as(usize, @boolToInt(p.symbols.items[p.solid.wrap.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.insert.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.template.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.delegateEvents.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.createComponent.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.setAttribute.ref.innerIndex()].use_count_estimate > 0)) + - @as(usize, @boolToInt(p.symbols.items[p.solid.effect.ref.innerIndex()].use_count_estimate > 0)); - var import_items = try p.allocator.alloc(js_ast.ClauseItem, import_count); - - // 1. Inject the part containing template declarations and Solid's import statement - var stmts_to_inject = p.allocator.alloc(Stmt, @as(usize, @boolToInt(p.solid.template_decls.count() > 0)) + @as(usize, @boolToInt(import_count > 0 and p.options.features.auto_import_jsx))) catch unreachable; - var j: usize = 0; - const order = .{ - "createComponent", - "delegateEvents", - "effect", - "insert", - "setAttribute", - "template", - "wrap", - }; - - var stmts_remain = stmts_to_inject; - - if (stmts_to_inject.len > 0) { - var declared_symbols = p.allocator.alloc(js_ast.DeclaredSymbol, p.solid.template_decls.count()) catch unreachable; - var import_record_ids: []u32 = &[_]u32{}; - - if (p.options.features.auto_import_jsx) { - try p.named_imports.ensureUnusedCapacity(import_count); - try p.is_import_item.ensureUnusedCapacity(p.allocator, @intCast(u32, import_count)); - const import_record_id = p.addImportRecord(.stmt, logger.Loc.Empty, p.options.jsx.import_source); - - inline for (order) |field_name| { - const ref = @field(p.solid, field_name).ref; - if (p.symbols.items[ref.innerIndex()].use_count_estimate > 0) { - import_items[j] = js_ast.ClauseItem{ - .alias = field_name, - .name = .{ .loc = logger.Loc.Empty, .ref = ref }, - .alias_loc = logger.Loc.Empty, - .original_name = "", - }; - - p.named_imports.putAssumeCapacity( - ref, - js_ast.NamedImport{ - .alias = p.symbols.items[ref.innerIndex()].original_name, - .alias_is_star = false, - .alias_loc = logger.Loc.Empty, - .namespace_ref = p.solid.namespace.ref, - .import_record_index = import_record_id, - }, - ); - p.is_import_item.putAssumeCapacity(ref, .{}); - j += 1; - } - } - - p.import_records.items[import_record_id].tag = .jsx_import; - stmts_remain[0] = p.s( - S.Import{ - .namespace_ref = p.solid.namespace.ref, - .star_name_loc = null, - .is_single_line = true, - .import_record_index = import_record_id, - .items = import_items, - }, - logger.Loc.Empty, - ); - stmts_remain = stmts_remain[1..]; - import_record_ids = p.allocator.alloc(u32, 1) catch unreachable; - import_record_ids[0] = import_record_id; - } - - if (p.solid.template_decls.count() > 0) { - for (p.solid.template_decls.values()) |val, i| { - declared_symbols[i] = js_ast.DeclaredSymbol{ - .ref = val.binding.data.b_identifier.ref, - .is_top_level = true, - }; - } - stmts_remain[0] = p.s( - S.Local{ - .decls = p.solid.template_decls.values(), - }, - logger.Loc.Empty, - ); - } - - before.append(js_ast.Part{ - .stmts = stmts_to_inject, - .declared_symbols = declared_symbols, - .import_record_indices = import_record_ids, - .tag = .jsx_import, - }) catch unreachable; - } - }, else => {}, } @@ -3505,340 +3396,8 @@ const JSXTransformType = enum { none, react, macro, - solid, -}; - -const SolidJS = struct { - namespace: GeneratedSymbol = undefined, - wrap: GeneratedSymbol = undefined, - insert: GeneratedSymbol = undefined, - template: GeneratedSymbol = undefined, - delegateEvents: GeneratedSymbol = undefined, - createComponent: GeneratedSymbol = undefined, - setAttribute: GeneratedSymbol = undefined, - effect: GeneratedSymbol = undefined, - - events_to_delegate: Event.Bitset = .{}, - template_decls: std.ArrayHashMapUnmanaged(u32, G.Decl, bun.ArrayIdentityContext, false) = .{}, - is_in_jsx_component: bool = false, - - stack: Stack = .{}, - - pub const ExpressionTransform = union(enum) { - class: void, - nativeEvent: void, - nativeEventCaptured: void, - style: void, - setAttribute: void, - event: Event, - - pub fn which(key: []const u8) ExpressionTransform { - const len = key.len; - if (len < 3) - return .{ .setAttribute = {} }; - - if (strings.hasPrefixComptime(key, "on:")) { - return .{ .nativeEvent = {} }; - } - - if (strings.hasPrefixComptime(key, "oncapture:")) { - return .{ .nativeEventCaptured = {} }; - } - - if (Event.map.get(key)) |event| { - return .{ .event = event }; - } - - switch (key.len) { - "class".len => { - if (strings.eqlComptime(key, "class")) - return .{ .class = {} }; - - if (strings.eqlComptime(key, "style")) - return .{ .style = {} }; - - return .{ .setAttribute = {} }; - }, - "className".len => { - if (strings.eqlComptime(key, "className")) - return .{ .class = {} }; - return .{ .setAttribute = {} }; - }, - else => return .{ .setAttribute = {} }, - } - } - }; - - 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, - - 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 { - if (this.stack.component_body_decls.items.len <= prefilled_element_names.len) { - return prefilled_element_names[this.stack.component_body_decls.items.len]; - } - return std.fmt.allocPrint(allocator, "_el${d}", .{this.stack.component_body_decls.items.len}) catch unreachable; - } - - pub fn generateTemplateName(this: *SolidJS, allocator: std.mem.Allocator) string { - if (this.template_decls.count() <= prefilled_template_names.len) { - return prefilled_template_names[this.template_decls.count()]; - } - return std.fmt.allocPrint(allocator, "_tmpl${d}", .{this.template_decls.count()}) catch unreachable; - } - - pub fn generateElement(solid: *SolidJS, p: anytype, template_expression: Expr, value_loc: logger.Loc) !E.Identifier { - var name = solid.generateElementName(p.allocator); - - var prev_scope = p.current_scope; - p.current_scope = &solid.stack.temporary_scope; - const ref = p.declareSymbolMaybeGenerated(.import, value_loc, name, true) catch unreachable; - p.current_scope = prev_scope; - const element = .{ .ref = ref }; - var decl_value: Expr = undefined; - var decls = &solid.stack.component_body_decls; - - switch (decls.items.len) { - 0 => { - decl_value = p.e( - E.Call{ - .target = p.e( - E.Dot{ - .name = "cloneNode", - .name_loc = value_loc, - .target = template_expression, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }, - template_expression.loc, - ), - .args = ExprNodeList.init(true_args), - .can_be_unwrapped_if_unused = true, - }, - value_loc, - ); - p.recordUsage(template_expression.data.e_identifier.ref); - }, - 1 => { - const ident = E.Identifier{ .ref = decls.items[decls.items.len - 1].binding.data.b_identifier.ref }; - decl_value = p.e( - E.Dot{ - .target = .{ - .data = .{ .e_identifier = ident }, - .loc = value_loc, - }, - .name = "firstChild", - .name_loc = template_expression.loc, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }, - value_loc, - ); - p.recordUsage(ident.ref); - }, - else => { - const ident = E.Identifier{ .ref = decls.items[decls.items.len - 1].binding.data.b_identifier.ref }; - decl_value = p.e(E.Dot{ - .target = .{ - .data = .{ .e_identifier = ident }, - .loc = value_loc, - }, - .name_loc = template_expression.loc, - .name = "nextSibling", - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }, value_loc); - p.recordUsage(ident.ref); - }, - } - try decls.append( - p.allocator, - G.Decl{ .binding = p.b(B.Identifier{ .ref = ref }, template_expression.loc), .value = decl_value }, - ); - return element; - } - - pub const Event = enum { - beforeinput, - click, - dblclick, - contextmenu, - focusin, - focusout, - input, - keydown, - keyup, - mousedown, - mousemove, - mouseout, - mouseover, - mouseup, - pointerdown, - pointermove, - pointerout, - pointerover, - pointerup, - touchend, - touchmove, - touchstart, - - pub const setter_names = std.enums.EnumArray(Event, string).init( - .{ - .beforeinput = "$$beforeinput", - .click = "$$click", - .dblclick = "$$dblclick", - .contextmenu = "$$contextmenu", - .focusin = "$$focusin", - .focusout = "$$focusout", - .input = "$$input", - .keydown = "$$keydown", - .keyup = "$$keyup", - .mousedown = "$$mousedown", - .mousemove = "$$mousemove", - .mouseout = "$$mouseout", - .mouseover = "$$mouseover", - .mouseup = "$$mouseup", - .pointerdown = "$$pointerdown", - .pointermove = "$$pointermove", - .pointerout = "$$pointerout", - .pointerover = "$$pointerover", - .pointerup = "$$pointerup", - .touchend = "$$touchend", - .touchmove = "$$touchmove", - .touchstart = "$$touchstart", - }, - ); - - pub inline fn setter(this: Event) string { - return setter_names.get(this); - } - - pub const map = ComptimeStringMap( - Event, - .{ - .{ "onbeforeinput", Event.beforeinput }, - .{ "onclick", Event.click }, - .{ "ondblclick", Event.dblclick }, - .{ "oncontextmenu", Event.contextmenu }, - .{ "onfocusin", Event.focusin }, - .{ "onfocusout", Event.focusout }, - .{ "oninput", Event.input }, - .{ "onkeydown", Event.keydown }, - .{ "onkeyup", Event.keyup }, - .{ "onmousedown", Event.mousedown }, - .{ "onmousemove", Event.mousemove }, - .{ "onmouseout", Event.mouseout }, - .{ "onmouseover", Event.mouseover }, - .{ "onmouseup", Event.mouseup }, - .{ "onpointerdown", Event.pointerdown }, - .{ "onpointermove", Event.pointermove }, - .{ "onpointerout", Event.pointerout }, - .{ "onpointerover", Event.pointerover }, - .{ "onpointerup", Event.pointerup }, - .{ "ontouchend", Event.touchend }, - .{ "ontouchmove", Event.touchmove }, - .{ "ontouchstart", Event.touchstart }, - .{ "onbeforeinput", Event.beforeinput }, - .{ "onClick", Event.click }, - .{ "onDblclick", Event.dblclick }, - .{ "onContextMenu", Event.contextmenu }, - .{ "onFocusIn", Event.focusin }, - .{ "onFocusOut", Event.focusout }, - .{ "onInput", Event.input }, - .{ "onKeydown", Event.keydown }, - .{ "onKeyup", Event.keyup }, - .{ "onMouseDown", Event.mousedown }, - .{ "onMouseMove", Event.mousemove }, - .{ "onMouseOut", Event.mouseout }, - .{ "onMouseOver", Event.mouseover }, - .{ "onMouseUp", Event.mouseup }, - .{ "onPointerDown", Event.pointerdown }, - .{ "onPointerMove", Event.pointermove }, - .{ "onPointerOut", Event.pointerout }, - .{ "onPointerOver", Event.pointerover }, - .{ "onPointerUp", Event.pointerup }, - .{ "onTouchEnd", Event.touchend }, - .{ "onTouchMove", Event.touchmove }, - .{ "onTouchStart", Event.touchstart }, - }, - ); - - pub const Bitset = std.enums.EnumSet(Event); - }; - - 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 { - if (jsx != .solid) - return void; - - return SolidJS; -} const ParserFeatures = struct { typescript: bool = false, jsx: JSXTransformType = JSXTransformType.none, @@ -4052,8 +3611,6 @@ fn NewParser_( // only applicable when is_react_fast_refresh_enabled jsx_refresh_runtime: GeneratedSymbol = GeneratedSymbol{ .ref = Ref.None, .primary = Ref.None, .backup = Ref.None }, - solid: GetSolidJSSymbols(jsx_transform_type) = if (jsx_transform_type == JSXTransformType.solid) SolidJS{} else void{}, - bun_jsx_ref: Ref = Ref.None, // Imports (both ES6 and CommonJS) are tracked at the top level @@ -5053,18 +4610,7 @@ fn NewParser_( p.jsx_automatic = p.declareGeneratedSymbol(.other, "ImportSource") catch unreachable; } }, - .solid => { - p.solid.insert = p.declareGeneratedSymbol(.other, "insert") catch unreachable; - p.solid.template = p.declareGeneratedSymbol(.other, "template") catch unreachable; - p.solid.wrap = p.declareGeneratedSymbol(.other, "wrap") catch unreachable; - p.solid.namespace = p.declareGeneratedSymbol(.other, "Solid") catch unreachable; - p.solid.delegateEvents = p.declareGeneratedSymbol(.other, "delegateEvents") catch unreachable; - p.solid.createComponent = p.declareGeneratedSymbol(.other, "createComponent") catch unreachable; - p.solid.setAttribute = p.declareGeneratedSymbol(.other, "setAttribute") catch unreachable; - p.solid.effect = p.declareGeneratedSymbol(.other, "effect") catch unreachable; - p.solid.stack.current_template_string = MutableString.initEmpty(p.allocator); - p.solid.stack.buffered_writer = p.solid.stack.current_template_string.bufferedWriter(); - }, + .macro => { p.bun_jsx_ref = p.declareSymbol(.other, logger.Loc.Empty, "bunJSX") catch unreachable; BunJSX.bun_jsx_identifier = E.Identifier{ @@ -12315,14 +11861,6 @@ fn NewParser_( value = p.e(E.Boolean{ .value = true }, logger.Loc{ .start = key_range.loc.start + key_range.len }); } else { value = try p.parseJSXPropValueIdentifier(&previous_string_with_backslash_loc); - if (comptime jsx_transform_type == .solid) { - switch (value.knownPrimitive()) { - .unknown => { - flags.insert(.has_any_dynamic); - }, - else => {}, - } - } } try props.append(G.Property{ .key = prop_name, .value = value }); @@ -12374,15 +11912,6 @@ fn NewParser_( return error.SyntaxError; }; - if (comptime jsx_transform_type == .solid) { - switch (expr.knownPrimitive()) { - .unknown => { - flags.insert(.has_any_dynamic); - }, - else => {}, - } - } - try props.append(G.Property{ .value = expr, .key = key, .kind = .normal }); }, // This implements @@ -12483,18 +12012,7 @@ fn NewParser_( // The expression is optional, and may be absent if (p.lexer.token != .t_close_brace) { - if (comptime jsx_transform_type == .solid) { - const child = try p.parseExpr(.lowest); - switch (child.knownPrimitive()) { - .unknown => { - flags.insert(.has_any_dynamic); - }, - else => {}, - } - try children.append(child); - } else { - try children.append(try p.parseExpr(.lowest)); - } + try children.append(try p.parseExpr(.lowest)); } // Use ExpectJSXElementChild() so we parse child strings @@ -12506,44 +12024,8 @@ fn NewParser_( if (p.lexer.token != .t_slash) { // This is a child element - if (comptime jsx_transform_type == .solid) { - const child = try p.parseJSXElement(less_than_loc); - - // if (!flags.contains(.has_dynamic_children)) { - // if (@as(Expr.Tag, child.data) == .e_jsx_element) { - // if (child.data.e_jsx_element.flags.contains(.has_dynamic_children) or child.data.e_jsx_element.flags.contains(.has_dynamic_prop)) { - // flags.insert(.has_dynamic_children); - - // } - // } else { - // switch (child.knownPrimitive()) { - // .unknown => { - // flags.insert(.has_dynamic_children); - // }, - // else => {}, - // } - // } - // } - - if (!flags.contains(.has_any_dynamic)) { - if (@as(Expr.Tag, child.data) == .e_jsx_element) { - if (child.data.e_jsx_element.flags.contains(.has_any_dynamic)) { - flags.insert(.has_any_dynamic); - } - } else { - switch (child.knownPrimitive()) { - .unknown => { - flags.insert(.has_any_dynamic); - }, - else => {}, - } - } - } - children.append(child) catch unreachable; - } else { - children.append(try p.parseJSXElement(less_than_loc)) catch unreachable; - } + children.append(try p.parseJSXElement(less_than_loc)) catch unreachable; // The call to parseJSXElement() above doesn't consume the last // TGreaterThan because the caller knows what Next() function to call. @@ -13100,613 +12582,6 @@ fn NewParser_( var writer = WriterType.initWriter(p, &BunJSX.bun_jsx_identifier); return writer.writeFunctionCall(e_.*); }, - .solid => { - // The rules: - // 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 - // 3. The first element in a a group of elements becomes .cloneNode(true) - // Subsequent elements call .nextSibling on the previous element. - // 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") - var global_solid = &p.solid; - var symbols = global_solid; - - var solid = &global_solid.stack; - - const old_is_in_jsx_component = global_solid.is_in_jsx_component; - global_solid.is_in_jsx_component = true; - defer global_solid.is_in_jsx_component = old_is_in_jsx_component; - - if (!old_is_in_jsx_component) { - solid.current_template_string.reset(); - solid.buffered_writer.pos = 0; - solid.component_body.clearRetainingCapacity(); - solid.component_body_decls.clearRetainingCapacity(); - - // prepend an empty statement - // this will later become an S.Local for the decls - solid.component_body.append(p.allocator, p.s(S.Empty{}, expr.loc)) catch unreachable; - - solid.last_element_id = E.Identifier{}; - solid.prev_scope = p.current_scope; - solid.temporary_scope.reset(); - solid.node_count = 0; - solid.temporary_scope.kind = .function_body; - solid.temporary_scope.parent = p.current_scope; - - solid.last_template_id.ref = Ref.None; - } - - var writer = &solid.buffered_writer; - - // The JSX tag used - const tag: Expr = tagger: { - if (e_.tag) |_tag| { - break :tagger p.visitExpr(_tag); - } else { - break :tagger p.e(E.Array{}, expr.loc); - } - }; - - const jsx_props = e_.properties.slice(); - - var template_expression = Expr{ .loc = expr.loc, .data = .{ .e_identifier = solid.last_template_id } }; - var element: ?E.Identifier = null; - var needs_end_bracket = false; - var children = e_.children.slice(); - defer { - if (old_is_in_jsx_component) { - if (element) |el| { - solid.last_element_id = el; - } - } - } - switch (tag.data) { - .e_string => { - // write the template - _ = writer.writeAll("<") catch unreachable; - _ = writer.writeString(tag.data.e_string) catch unreachable; - needs_end_bracket = true; - - for (jsx_props) |*property, i| { - if (property.kind != .spread) { - property.key = p.visitExpr(e_.properties.ptr[i].key.?); - } - - if (property.value != null) { - property.value = p.visitExpr(e_.properties.ptr[i].value.?); - - if (property.kind != .spread) { - var key = property.key.?.data.e_string; - - const transform: SolidJS.ExpressionTransform = - if (key.isUTF8()) - SolidJS.ExpressionTransform.which(key.slice(p.allocator)) - else - SolidJS.ExpressionTransform{ .setAttribute = {} }; - - const primitive = @as(Expr.Tag, property.value.?.data); - const is_dynamic = switch (primitive) { - .e_string, .e_number, .e_boolean, .e_null, .e_undefined => false, - else => true, - }; - do_transform: { - var out: Expr = p.e(E.Missing{}, expr.loc); - var needs_wrap = false; - if (is_dynamic) { - if (template_expression.data.e_identifier.ref.isNull()) { - var new_template_name = global_solid.generateTemplateName(p.allocator); - // declare the template in the module scope - solid.prev_scope = p.current_scope; - p.current_scope = p.module_scope; - solid.last_template_id = .{ - .ref = p.declareSymbolMaybeGenerated(.other, expr.loc, new_template_name, true) catch unreachable, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }; - p.current_scope = solid.prev_scope.?; - template_expression = .{ .loc = expr.loc, .data = .{ .e_identifier = solid.last_template_id } }; - } - - if (element == null) { - element = global_solid.generateElement( - p, - template_expression, - property.value.?.loc, - ) catch unreachable; - } - } - - if (!is_dynamic and (transform == .class or transform == .style or transform == .setAttribute)) { - switch (transform) { - .class => { - switch (property.value.?.data) { - .e_string => |str| { - if (str.len() == 0) break :do_transform; - _ = writer.writeAll(" class=\"") catch unreachable; - _ = writer.writeHTMLAttributeValueString(str) catch unreachable; - _ = writer.writeAll("\"") catch unreachable; - }, - .e_number => |num| { - writer.writer().print(" class={d}", .{num.value}) catch unreachable; - }, - else => {}, - } - }, - .setAttribute => { - _ = writer.writeAll(" ") catch unreachable; - _ = writer.writeString(property.key.?.data.e_string) catch unreachable; - - switch (property.value.?.data) { - .e_string => |str| { - if (str.len() == 0) break :do_transform; - _ = writer.writeAll("=\"") catch unreachable; - _ = writer.writeHTMLAttributeValueString(str) catch unreachable; - _ = writer.writeAll("\"") catch unreachable; - }, - .e_number => |num| { - writer.writer().print("={d}", .{num.value}) catch unreachable; - }, - else => {}, - } - }, - .style => {}, - else => unreachable, - } - } else { - switch (transform) { - .nativeEvent, .nativeEventCaptured => { - var args = p.allocator.alloc(Expr, 2 + @as(usize, @boolToInt(transform == .nativeEventCaptured))) catch unreachable; - - // on:MyEvent => MyEvent - property.key.?.data.e_string.data = property.key.?.data.e_string.data[3..]; - - args[0] = property.key.?; - args[1] = property.value.?; - - if (transform == .nativeEventCaptured) { - args[2] = p.e(E.Boolean{ .value = true }, property.key.?.loc); - } - // $element.addEventListener("MyEvent", (e) => { ... }); - out = p.e( - E.Call{ - .target = p.e( - E.Dot{ - .target = p.e( - element.?, - expr.loc, - ), - .name = "addEventListener", - .name_loc = property.key.?.loc, - }, - property.key.?.loc, - ), - .args = ExprNodeList.init(args), - }, - property.key.?.loc, - ); - - p.recordUsage(element.?.ref); - }, - .style => {}, - .class, .setAttribute => { - var args = p.allocator.alloc(Expr, 4) catch unreachable; - args[0] = p.e(element.?, expr.loc); - args[1] = property.key.?; - args[2] = property.value.?; - - // setAttribute(template_expression, key, value); - out = p.e( - E.Call{ - .target = p.e( - E.Identifier{ - .ref = symbols.setAttribute.ref, - .can_be_removed_if_unused = false, - .call_can_be_unwrapped_if_unused = false, - }, - property.value.?.loc, - ), - .args = ExprNodeList.init(args[0..3]), - }, - property.key.?.loc, - ); - - p.recordUsage(symbols.setAttribute.ref); - if (args[2].data == .e_identifier or args[2].data == .e_import_identifier) { - if (args[2].data == .e_identifier) p.recordUsage(args[2].data.e_identifier.ref); - if (args[2].data == .e_import_identifier) p.recordUsage(args[2].data.e_import_identifier.ref); - } else { - needs_wrap = true; - } - }, - .event => |event| { - out = p.e( - E.Binary{ - .left = p.e(E.Dot{ - .target = p.e(element.?, property.key.?.loc), - .name = event.setter(), - .name_loc = property.key.?.loc, - }, property.key.?.loc), - .op = js_ast.Op.Code.bin_assign, - .right = property.value.?, - }, - property.key.?.loc, - ); - needs_wrap = switch (property.value.?.data) { - .e_arrow, .e_function => false, - else => true, - }; - global_solid.events_to_delegate.insert(event); - }, - } - - var stmt: Stmt = undefined; - - if (needs_wrap) { - var stmts = p.allocator.alloc(Stmt, 1) catch unreachable; - stmts[0] = p.s(S.Return{ .value = out }, property.value.?.loc); - var args = p.allocator.alloc(Expr, 1) catch unreachable; - args[0] = p.e( - E.Arrow{ - .args = &[_]G.Arg{}, - .body = G.FnBody{ - .stmts = stmts, - .loc = out.loc, - }, - }, - property.value.?.loc, - ); - stmt = p.s(S.SExpr{ - .value = p.e( - E.Call{ - .target = p.e( - E.Identifier{ - .ref = symbols.effect.ref, - }, - property.value.?.loc, - ), - .args = ExprNodeList.init(args), - }, - property.value.?.loc, - ), - }, property.value.?.loc); - p.recordUsage(symbols.effect.ref); - } else { - stmt = p.s(S.SExpr{ - .value = out, - }, property.value.?.loc); - } - - solid.component_body.append(p.allocator, stmt) catch unreachable; - } - } - } - } - - if (property.initializer != null) { - property.initializer = p.visitExpr(e_.properties.ptr[i].initializer.?); - } - } - - const start_node_count = solid.node_count; - for (children) |*el, k| { - if (needs_end_bracket and el.data == .e_jsx_element) { - _ = writer.writeAll(">") catch unreachable; - solid.node_count += 1; - - needs_end_bracket = false; - } - - const child = p.visitExpr(el.*); - switch (child.data) { - // skip it - .e_missing => {}, - - // we need to serialize it to HTML - // it's probably a text node - .e_string => |str| { - if (str.len() > 0) { - if (needs_end_bracket) { - _ = writer.writeAll(">") catch unreachable; - solid.node_count += 1; - needs_end_bracket = false; - } - writer.writeHTMLAttributeValueString(str) catch unreachable; - } - }, - .e_number => |str| { - if (needs_end_bracket) { - _ = writer.writeAll(">") catch unreachable; - needs_end_bracket = false; - } - writer.writer().print("{d}", .{str.value}) catch unreachable; - }, - - // debug assertion that we don't get here - .e_jsx_element => unreachable, - - else => { - if (template_expression.data.e_identifier.ref.isNull()) { - var new_template_name = global_solid.generateTemplateName(p.allocator); - // declare the template in the module scope - p.current_scope = p.module_scope; - solid.last_template_id = .{ - .ref = p.declareSymbolMaybeGenerated(.other, expr.loc, new_template_name, true) catch unreachable, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }; - p.current_scope = solid.prev_scope.?; - template_expression = .{ .loc = expr.loc, .data = .{ .e_identifier = solid.last_template_id } }; - } - p.recordUsage(symbols.insert.ref); - p.recordUsage(template_expression.data.e_identifier.ref); - var args = p.allocator.alloc(Expr, 3) catch unreachable; - args[0..3].* = .{ - template_expression, - child, - if (k != children.len - 1 and !solid.last_element_id.ref.eql(Ref.None)) - p.e(solid.last_element_id, expr.loc) - else - p.e(E.Null{}, expr.loc), - }; - solid.node_count += 1; - solid.component_body.append( - p.allocator, - p.s( - S.SExpr{ - .value = p.e( - E.Call{ - .target = p.e(E.ImportIdentifier{ .ref = symbols.insert.ref }, child.loc), - .args = ExprNodeList.init(args), - }, - child.loc, - ), - }, - child.loc, - ), - ) catch unreachable; - }, - } - } - - if (start_node_count != solid.node_count) { - solid.node_count += 1; - _ = writer.writeAll("</") catch unreachable; - _ = writer.writeString(tag.data.e_string) catch unreachable; - _ = writer.writeAll(">") catch unreachable; - } else if (needs_end_bracket) { - _ = writer.writeAll("/>") catch unreachable; - } - - // this is the root of a template tag, we just finished - // <div> - // /* some stuff in here */ - // </div> - // ^ - // we are here! - if (!old_is_in_jsx_component) { - if (p.is_control_flow_dead) { - solid.node_count = 0; - return p.e(E.Missing{}, expr.loc); - } - - var hash: u64 = 0; - // 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 == 0 and writer.context.list.items.len == 0) {} else if (writer.pos < writer.buffer.len and writer.context.list.items.len == 0) { - hash = std.hash.Wyhash.hash(0, writer.buffer[0..writer.pos]); - } else { - var hasher = std.hash.Wyhash.init(0); - hasher.update(writer.context.list.items); - hasher.update(writer.buffer[0..writer.pos]); - hash = hasher.final(); - } - - var gpe = global_solid.template_decls.getOrPut(p.allocator, @truncate(u32, hash)) catch unreachable; - - if (template_expression.data.e_identifier.ref.isNull()) { - var new_template_name = global_solid.generateTemplateName(p.allocator); - // declare the template in the module scope - p.current_scope = p.module_scope; - solid.last_template_id = .{ - .ref = p.declareSymbolMaybeGenerated(.other, expr.loc, new_template_name, true) catch unreachable, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }; - p.current_scope = solid.prev_scope.?; - template_expression = .{ .loc = expr.loc, .data = .{ .e_identifier = solid.last_template_id } }; - } - - if (!gpe.found_existing) { - var args = p.allocator.alloc(Expr, 2) catch unreachable; - - if (writer.pos == 0 and writer.context.list.items.len == 0) { - args[0] = p.e(E.String.init(""), expr.loc); - } else 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 { - const total = writer.context.list.items.len + writer.pos; - var buffer = p.allocator.alloc(u8, total) catch unreachable; - @memcpy(buffer.ptr, writer.context.list.items.ptr, writer.context.list.items.len); - @memcpy(buffer.ptr + writer.context.list.items.len, &writer.buffer, writer.buffer.len); - args[0] = p.e(E.String.init(buffer), expr.loc); - } - - args[1] = p.e(E.Number{ .value = @intToFloat(f64, solid.node_count) }, expr.loc); - solid.node_count = 0; - - gpe.value_ptr.* = G.Decl{ - .binding = p.b(B.Identifier{ .ref = template_expression.data.e_identifier.ref }, template_expression.loc), - .value = p.e( - E.Call{ - .args = ExprNodeList.init(args), - .target = p.e( - E.ImportIdentifier{ - .ref = symbols.template.ref, - }, - expr.loc, - ), - .can_be_unwrapped_if_unused = true, - }, - template_expression.loc, - ), - }; - } else { - // link the template to the existing decl - // this will cause the printer to use the existing template - p.symbols.items[template_expression.data.e_identifier.ref.innerIndex()].link = gpe.value_ptr.binding.data.b_identifier.ref; - } - p.recordUsage(symbols.template.ref); - - // 1 means it was actually static - // that means we can just turn it into a single $template.cloneNode(true) - if (solid.component_body.items.len == 1) { - return p.e(E.Call{ - .target = p.e( - E.Dot{ - .name = "cloneNode", - .name_loc = expr.loc, - .target = template_expression, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }, - template_expression.loc, - ), - .args = ExprNodeList.init(true_args), - .can_be_unwrapped_if_unused = true, - }, expr.loc); - } - if (solid.component_body_decls.items.len == 0) { - solid.component_body_decls.ensureTotalCapacityPrecise(p.allocator, 1) catch unreachable; - solid.component_body_decls.appendAssumeCapacity(G.Decl{ - .binding = p.b(B.Identifier{ .ref = solid.last_template_id.ref }, expr.loc), - .value = p.e(E.Call{ - .target = p.e( - E.Dot{ - .name = "cloneNode", - .name_loc = expr.loc, - .target = template_expression, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = true, - }, - template_expression.loc, - ), - .args = ExprNodeList.init(true_args), - .can_be_unwrapped_if_unused = true, - }, expr.loc), - }); - } - - // we need to wrap the template in a function - const ret = p.e(E.Identifier{ .ref = solid.component_body_decls.items[0].binding.data.b_identifier.ref }, expr.loc); - solid.component_body.items[0] = p.s(S.Local{ .decls = solid.component_body_decls.toOwnedSlice(p.allocator) }, expr.loc); - solid.component_body.append(p.allocator, p.s(S.Return{ .value = ret }, expr.loc)) catch unreachable; - return p.e( - E.Arrow{ .args = &[_]G.Arg{}, .body = G.FnBody{ .stmts = solid.component_body.toOwnedSlice(p.allocator), .loc = expr.loc } }, - expr.loc, - ); - // we don't need to return anything because it's a static element that will live in the template - } else { - return p.e(E.Missing{}, expr.loc); - } - }, - .e_dot, .e_import_identifier, .e_identifier => { - var out_props = p.allocator.alloc(G.Property, jsx_props.len + @as(usize, @boolToInt(e_.key != null)) + @as(usize, @boolToInt(e_.children.len > 0))) catch unreachable; - var out_props_i: usize = 0; - for (jsx_props) |property, i| { - if (property.kind != .spread) { - e_.properties.ptr[i].key = p.visitExpr(e_.properties.ptr[i].key.?); - } - - if (property.value != null) { - e_.properties.ptr[i].value = p.visitExpr(e_.properties.ptr[i].value.?); - } - - if (property.initializer != null) { - e_.properties.ptr[i].initializer = p.visitExpr(e_.properties.ptr[i].initializer.?); - } - - if (property.kind != .spread) { - const kind = if (property.value.?.data == .e_arrow or property.value.?.data == .e_function) - G.Property.Kind.get - else - G.Property.Kind.normal; - - out_props[out_props_i] = G.Property{ - .key = property.key, - .value = if (kind != .get) - property.value.? - else - property.value.?.wrapInArrow(p.allocator) catch unreachable, - - .kind = kind, - }; - out_props_i += 1; - } - } - - if (e_.key) |k| { - const key = p.visitExpr(k); - if (key.data != .e_missing) { - const kind = if (key.data == .e_arrow or key.data == .e_function) - Property.Kind.get - else - Property.Kind.normal; - - out_props[out_props_i] = G.Property{ - .key = p.e(Prefill.String.Key, k.loc), - .value = key, - .kind = kind, - }; - out_props_i += 1; - } - } - - var out_child_i: usize = 0; - for (children) |child, j| { - children[j] = p.visitExpr(child); - if (children[j].data != .e_missing) { - children[out_child_i] = children[j]; - out_child_i += 1; - } - } - - if (out_child_i > 0) { - const kind = Property.Kind.get; - - out_props[out_props_i] = G.Property{ - .key = p.e(Prefill.String.Children, expr.loc), - .value = p.e(E.Array{ .items = ExprNodeList.init(children[0..out_child_i]) }, expr.loc), - .kind = kind, - }; - out_props_i += 1; - } - - var args = p.allocator.alloc(Expr, 2) catch unreachable; - args[0] = tag; - args[1] = p.e(E.Object{ - .properties = G.Property.List.init(out_props[0..out_props_i]), - }, expr.loc); - p.recordUsage(symbols.createComponent.ref); - return p.e( - E.Call{ - .target = p.e(E.ImportIdentifier{ .ref = symbols.createComponent.ref }, expr.loc), - .args = ExprNodeList.init(args), - .close_paren_loc = e_.close_tag_loc, - }, - expr.loc, - ); - }, - .e_array => {}, - else => unreachable, - } - }, .react => { const tag: Expr = tagger: { if (e_.tag) |_tag| { @@ -19273,9 +18148,6 @@ const JavaScriptParser = NewParser(.{}); const JSXParser = NewParser(.{ .jsx = .react }); const TSXParser = NewParser(.{ .jsx = .react, .typescript = true }); const TypeScriptParser = NewParser(.{ .typescript = true }); -const SolidJSXParser = NewParser(.{ .jsx = .solid }); -const SolidTSXParser = NewParser(.{ .jsx = .solid, .typescript = true }); - const JSParserMacro = NewParser(.{ .jsx = .macro, }); |