Skip to content

Commit

Permalink
feat: support namespaced attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister committed Oct 21, 2023
1 parent 1652f38 commit 20076b1
Showing 1 changed file with 40 additions and 15 deletions.
55 changes: 40 additions & 15 deletions src/transpiling/jsx_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fn normalize_dom_attr_name(name: &str) -> String {
"className" => "class".to_string(),
// xlink:href was removed from SVG and isn't needed
"xlinkHref" => "href".to_string(),
"xlink:href" => "href".to_string(),
_ => name.to_string(),
}
}
Expand Down Expand Up @@ -80,10 +81,12 @@ fn get_attr_name(jsx_attr: &JSXAttr) -> String {
match &jsx_attr.name {
// Case: <button class="btn">
JSXAttrName::Ident(ident) => normalize_dom_attr_name(ident.sym.as_ref()),
// Case (svg only): <a xlink:href="#">...</a>
JSXAttrName::JSXNamespacedName(_namespace_name) => {
// TODO: Only support "xlink:href", but convert it to "href"
todo!()
// Case: <a xlink:href="#">...</a>
JSXAttrName::JSXNamespacedName(namespace_name) => {
let ns = namespace_name.ns.sym.to_string();
let name = namespace_name.name.sym.to_string();
let combined = format!("{}:{}", ns, name);
normalize_dom_attr_name(&combined)
}
}
}
Expand Down Expand Up @@ -218,19 +221,18 @@ impl JsxString {
if name.chars().next().unwrap().is_ascii_uppercase() {
Expr::Ident(ident)
} else {
Expr::Lit(Lit::Str(Str {
span: DUMMY_SP,
value: name.into(),
raw: None,
}))
string_lit_expr(name)
}
}
// Case: <ctx.Provider />
JSXElementName::JSXMemberExpr(jsx_member_expr) => {
Expr::Member(jsx_member_expr_to_normal(&jsx_member_expr))
}
JSXElementName::JSXNamespacedName(_jsx_namespaced_name) => {
todo!()
JSXElementName::JSXNamespacedName(namespace_name) => {
let ns = namespace_name.ns.sym.to_string();
let name = namespace_name.name.sym.to_string();
let combined = format!("{}:{}", ns, name);
string_lit_expr(combined)
}
};

Expand Down Expand Up @@ -466,7 +468,9 @@ impl JsxString {
let ident = match el.opening.name.clone() {
// Case: <div />
JSXElementName::Ident(ident) => ident,
_ => todo!(),
_ => {
unreachable!("serialize_jsx_element_to_string_vec(JSXNamespacedName)")
}
};

let name = ident.sym.to_string();
Expand Down Expand Up @@ -1001,15 +1005,24 @@ const a = _jsxssr($$_tpl_1, _jsxattr("bar", 2));"#,
);
}

#[ignore]
#[test]
fn namespace_attr_test() {
test_transform(
JsxString::default(),
r#"const a = <a xlink:href="foo">foo</a>;"#,
r#"import { jsxssr as _jsxssr } from "react/jsx-runtime";
const $$_tpl_1 = [
'<a href="foo">foo</a>',
'<a href="foo">foo</a>'
];
const a = _jsxssr($$_tpl_1, null);"#,
);

test_transform(
JsxString::default(),
r#"const a = <a foo:bar="foo">foo</a>;"#,
r#"import { jsxssr as _jsxssr } from "react/jsx-runtime";
const $$_tpl_1 = [
'<a foo:bar="foo">foo</a>'
];
const a = _jsxssr($$_tpl_1, null);"#,
);
Expand Down Expand Up @@ -1099,6 +1112,19 @@ const a = _jsxssr($$_tpl_1, null);"#,
);
}

#[test]
fn namespace_name_test() {
// Note: This isn't really supported anywhere, but I guess why not
test_transform(
JsxString::default(),
r#"const a = <a:b>foo</a:b>;"#,
r#"import { jsx as _jsx } from "react/jsx-runtime";
const a = _jsx("a:b", {
children: "foo"
});"#,
);
}

#[test]
fn empty_jsx_child_test() {
test_transform(
Expand Down Expand Up @@ -1395,7 +1421,6 @@ const a = _jsx(ctx.Provider, {
);
}

// TODO: HTMLEscape attribute names + text children
// TODO: Fresh specific: <Head> opt out? Or maybe move Fresh users to a
// different pattern

Expand Down

0 comments on commit 20076b1

Please sign in to comment.