From 21ab0326927cc6485cfa192dee3daa2ccfba3412 Mon Sep 17 00:00:00 2001 From: Liam Rooney Date: Wed, 23 Apr 2025 23:06:40 -0700 Subject: [PATCH 1/3] fix: allow options to contain html elements --- internal/parser.go | 2 + ...ect_with_2_options_containing_element.snap | 41 +++++++++++++++++++ ...s_containing_element_with_div_sibling.snap | 41 +++++++++++++++++++ ...select_with_option_containing_element.snap | 41 +++++++++++++++++++ ...nd_button_containing_selected_content.snap | 41 +++++++++++++++++++ ...n_containing_element_with_div_sibling.snap | 41 +++++++++++++++++++ internal/printer/printer_test.go | 28 +++++++++++-- 7 files changed, 231 insertions(+), 4 deletions(-) create mode 100755 internal/printer/__printer_js__/select_with_2_options_containing_element.snap create mode 100755 internal/printer/__printer_js__/select_with_2_options_containing_element_with_div_sibling.snap create mode 100755 internal/printer/__printer_js__/select_with_option_containing_element.snap create mode 100755 internal/printer/__printer_js__/select_with_option_containing_element_and_button_containing_selected_content.snap create mode 100755 internal/printer/__printer_js__/select_with_option_containing_element_with_div_sibling.snap diff --git a/internal/parser.go b/internal/parser.go index 42d7eb0d..ba607ea8 100644 --- a/internal/parser.go +++ b/internal/parser.go @@ -2319,6 +2319,8 @@ func inSelectIM(p *parser) bool { p.resetInsertionMode() case a.Template: return inHeadIM(p) + default: + return inBodyIM(p) } case CommentToken: p.addChild(&Node{ diff --git a/internal/printer/__printer_js__/select_with_2_options_containing_element.snap b/internal/printer/__printer_js__/select_with_2_options_containing_element.snap new file mode 100755 index 00000000..25bf2885 --- /dev/null +++ b/internal/printer/__printer_js__/select_with_2_options_containing_element.snap @@ -0,0 +1,41 @@ + +[TestPrinter/select_with_2_options_containing_element - 1] +## Input + +``` + +``` + +## Output + +```js +import { + Fragment, + render as $$render, + createAstro as $$createAstro, + createComponent as $$createComponent, + renderComponent as $$renderComponent, + renderHead as $$renderHead, + maybeRenderHead as $$maybeRenderHead, + unescapeHTML as $$unescapeHTML, + renderSlot as $$renderSlot, + mergeSlots as $$mergeSlots, + addAttribute as $$addAttribute, + spreadAttributes as $$spreadAttributes, + defineStyleVars as $$defineStyleVars, + defineScriptVars as $$defineScriptVars, + renderTransition as $$renderTransition, + createTransitionScope as $$createTransitionScope, + renderScript as $$renderScript, + createMetadata as $$createMetadata +} from "http://localhost:3000/"; + +export const $$metadata = $$createMetadata(import.meta.url, { modules: [], hydratedComponents: [], clientOnlyComponents: [], hydrationDirectives: new Set([]), hoisted: [] }); + +const $$Component = $$createComponent(($$result, $$props, $$slots) => { + +return $$render`${$$maybeRenderHead($$result)}`; +}, undefined, undefined); +export default $$Component; +``` +--- diff --git a/internal/printer/__printer_js__/select_with_2_options_containing_element_with_div_sibling.snap b/internal/printer/__printer_js__/select_with_2_options_containing_element_with_div_sibling.snap new file mode 100755 index 00000000..6e404e4b --- /dev/null +++ b/internal/printer/__printer_js__/select_with_2_options_containing_element_with_div_sibling.snap @@ -0,0 +1,41 @@ + +[TestPrinter/select_with_2_options_containing_element_with_div_sibling - 1] +## Input + +``` +
Orange
+``` + +## Output + +```js +import { + Fragment, + render as $$render, + createAstro as $$createAstro, + createComponent as $$createComponent, + renderComponent as $$renderComponent, + renderHead as $$renderHead, + maybeRenderHead as $$maybeRenderHead, + unescapeHTML as $$unescapeHTML, + renderSlot as $$renderSlot, + mergeSlots as $$mergeSlots, + addAttribute as $$addAttribute, + spreadAttributes as $$spreadAttributes, + defineStyleVars as $$defineStyleVars, + defineScriptVars as $$defineScriptVars, + renderTransition as $$renderTransition, + createTransitionScope as $$createTransitionScope, + renderScript as $$renderScript, + createMetadata as $$createMetadata +} from "http://localhost:3000/"; + +export const $$metadata = $$createMetadata(import.meta.url, { modules: [], hydratedComponents: [], clientOnlyComponents: [], hydrationDirectives: new Set([]), hoisted: [] }); + +const $$Component = $$createComponent(($$result, $$props, $$slots) => { + +return $$render`${$$maybeRenderHead($$result)}
Orange
`; +}, undefined, undefined); +export default $$Component; +``` +--- diff --git a/internal/printer/__printer_js__/select_with_option_containing_element.snap b/internal/printer/__printer_js__/select_with_option_containing_element.snap new file mode 100755 index 00000000..50d4fa23 --- /dev/null +++ b/internal/printer/__printer_js__/select_with_option_containing_element.snap @@ -0,0 +1,41 @@ + +[TestPrinter/select_with_option_containing_element - 1] +## Input + +``` + +``` + +## Output + +```js +import { + Fragment, + render as $$render, + createAstro as $$createAstro, + createComponent as $$createComponent, + renderComponent as $$renderComponent, + renderHead as $$renderHead, + maybeRenderHead as $$maybeRenderHead, + unescapeHTML as $$unescapeHTML, + renderSlot as $$renderSlot, + mergeSlots as $$mergeSlots, + addAttribute as $$addAttribute, + spreadAttributes as $$spreadAttributes, + defineStyleVars as $$defineStyleVars, + defineScriptVars as $$defineScriptVars, + renderTransition as $$renderTransition, + createTransitionScope as $$createTransitionScope, + renderScript as $$renderScript, + createMetadata as $$createMetadata +} from "http://localhost:3000/"; + +export const $$metadata = $$createMetadata(import.meta.url, { modules: [], hydratedComponents: [], clientOnlyComponents: [], hydrationDirectives: new Set([]), hoisted: [] }); + +const $$Component = $$createComponent(($$result, $$props, $$slots) => { + +return $$render`${$$maybeRenderHead($$result)}`; +}, undefined, undefined); +export default $$Component; +``` +--- diff --git a/internal/printer/__printer_js__/select_with_option_containing_element_and_button_containing_selected_content.snap b/internal/printer/__printer_js__/select_with_option_containing_element_and_button_containing_selected_content.snap new file mode 100755 index 00000000..eb1d207e --- /dev/null +++ b/internal/printer/__printer_js__/select_with_option_containing_element_and_button_containing_selected_content.snap @@ -0,0 +1,41 @@ + +[TestPrinter/select_with_option_containing_element_and_button_containing_selected_content - 1] +## Input + +``` + +``` + +## Output + +```js +import { + Fragment, + render as $$render, + createAstro as $$createAstro, + createComponent as $$createComponent, + renderComponent as $$renderComponent, + renderHead as $$renderHead, + maybeRenderHead as $$maybeRenderHead, + unescapeHTML as $$unescapeHTML, + renderSlot as $$renderSlot, + mergeSlots as $$mergeSlots, + addAttribute as $$addAttribute, + spreadAttributes as $$spreadAttributes, + defineStyleVars as $$defineStyleVars, + defineScriptVars as $$defineScriptVars, + renderTransition as $$renderTransition, + createTransitionScope as $$createTransitionScope, + renderScript as $$renderScript, + createMetadata as $$createMetadata +} from "http://localhost:3000/"; + +export const $$metadata = $$createMetadata(import.meta.url, { modules: [], hydratedComponents: [], clientOnlyComponents: [], hydrationDirectives: new Set([]), hoisted: [] }); + +const $$Component = $$createComponent(($$result, $$props, $$slots) => { + +return $$render`${$$maybeRenderHead($$result)}`; +}, undefined, undefined); +export default $$Component; +``` +--- diff --git a/internal/printer/__printer_js__/select_with_option_containing_element_with_div_sibling.snap b/internal/printer/__printer_js__/select_with_option_containing_element_with_div_sibling.snap new file mode 100755 index 00000000..f8b51d8b --- /dev/null +++ b/internal/printer/__printer_js__/select_with_option_containing_element_with_div_sibling.snap @@ -0,0 +1,41 @@ + +[TestPrinter/select_with_option_containing_element_with_div_sibling - 1] +## Input + +``` +
Orange
+``` + +## Output + +```js +import { + Fragment, + render as $$render, + createAstro as $$createAstro, + createComponent as $$createComponent, + renderComponent as $$renderComponent, + renderHead as $$renderHead, + maybeRenderHead as $$maybeRenderHead, + unescapeHTML as $$unescapeHTML, + renderSlot as $$renderSlot, + mergeSlots as $$mergeSlots, + addAttribute as $$addAttribute, + spreadAttributes as $$spreadAttributes, + defineStyleVars as $$defineStyleVars, + defineScriptVars as $$defineScriptVars, + renderTransition as $$renderTransition, + createTransitionScope as $$createTransitionScope, + renderScript as $$renderScript, + createMetadata as $$createMetadata +} from "http://localhost:3000/"; + +export const $$metadata = $$createMetadata(import.meta.url, { modules: [], hydratedComponents: [], clientOnlyComponents: [], hydrationDirectives: new Set([]), hoisted: [] }); + +const $$Component = $$createComponent(($$result, $$props, $$slots) => { + +return $$render`${$$maybeRenderHead($$result)}
Orange
`; +}, undefined, undefined); +export default $$Component; +``` +--- diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index fedea94a..73d28744 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -1234,19 +1234,19 @@ import { Container, Col, Row } from 'react-bootstrap'; source: `
Default
Named
`, }, { - name: "Fragment with await", + name: "Fragment with await", source: ` { await Promise.resolve("Awaited") } `, }, { - name: "Fragment shorthand with await", + name: "Fragment shorthand with await", source: `<> { await Promise.resolve("Awaited") } `, }, { - name: "Fragment wrapping link with awaited href", + name: "Fragment wrapping link with awaited href", source: ``, }, { - name: "Component with await", + name: "Component with await", source: ` { await Promise.resolve("Awaited") } `, }, { @@ -2092,6 +2092,26 @@ const meta = { title: 'My App' }; name: "namespace is preserved when inside an expression", source: `{}`, }, + { + name: "select with option containing element", + source: ``, + }, + { + name: "select with 2 options containing element", + source: ``, + }, + { + name: "select with option containing element with div sibling", + source: `
Orange
`, + }, + { + name: "select with 2 options containing element with div sibling", + source: `
Orange
`, + }, + { + name: "select with option containing element and button containing selected content", + source: ``, + }, } for _, tt := range tests { if tt.only { From 385dcf14b3a86752c85c2633c50e0b428da74ea9 Mon Sep 17 00:00:00 2001 From: Liam Rooney Date: Thu, 24 Apr 2025 14:11:15 -0700 Subject: [PATCH 2/3] add changeset --- .changeset/large-mangos-look.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/large-mangos-look.md diff --git a/.changeset/large-mangos-look.md b/.changeset/large-mangos-look.md new file mode 100644 index 00000000..4ab42497 --- /dev/null +++ b/.changeset/large-mangos-look.md @@ -0,0 +1,5 @@ +--- +"@astrojs/compiler": patch +--- + +fix: correctly parse select elements containing HTML, preventing elements from being incorrectly nested From f7af8186f432a7b6dcb21fd76eb66f48a289640a Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Mon, 28 Apr 2025 16:04:45 +0100 Subject: [PATCH 3/3] Update .changeset/large-mangos-look.md --- .changeset/large-mangos-look.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/large-mangos-look.md b/.changeset/large-mangos-look.md index 4ab42497..65129ee9 100644 --- a/.changeset/large-mangos-look.md +++ b/.changeset/large-mangos-look.md @@ -2,4 +2,4 @@ "@astrojs/compiler": patch --- -fix: correctly parse select elements containing HTML, preventing elements from being incorrectly nested +Fixes a bug where the compiler couldn't correctly parse `select` elements, preventing elements from being incorrectly nested