From fd91956d4570f4a252313db7491a96cd35bccd37 Mon Sep 17 00:00:00 2001 From: Michael Daross Date: Mon, 8 Jan 2024 09:03:33 -0600 Subject: [PATCH 1/5] Add output_preamble to match postamble --- .DS_Store | Bin 0 -> 6148 bytes docs/CHANGELOG.md | 7 ++++- docs/api.md | 4 +++ docs/index.md | 2 ++ lib/view_component/base.rb | 26 +++++++++++++++--- .../before_and_after_render_component.rb | 15 ++++++++++ .../app/components/before_render_component.rb | 11 ++++++++ 7 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 .DS_Store create mode 100644 test/sandbox/app/components/before_and_after_render_component.rb create mode 100644 test/sandbox/app/components/before_render_component.rb diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ca2b7874ee44cef1857d5487e8c8184223131c55 GIT binary patch literal 6148 zcmeH~F$w}f3`G;&La^D=avBfd4F=H@>;(h`8(BfodXDZ-CJ2t!BJu;tpJXO1`-+{7 zi0JxuSc&u^GJ~7S(n4d3ypw~RWiQwJa2ZeM@rat$Cvn!+@Lrnz*rt#G36KB@kN^q% z5COZlVY7KvMiL+a5_l4@??Zx{=Fn2rKOG1@0zf;I-LUpq0-CG<&7q|#Dlm=dL8DcD z46(YmLsOi~p`~hV7meXV4M3`}dgXhH(h?7~0-B+w9;*1Wg-e+&OK|2Hj6Nq_|Y zjDU8VVY9|d#ohY$dRE^>)z$?L_2URHKLJSWDqg_du%B!J&7q|#Dlq;CI0gn1_$q-1 D?w=C8 literal 0 HcmV?d00001 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5f1b01e01..edb6d1747 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,11 @@ nav_order: 5 ## main +* Add `output_preamble` to match `output_postamble`, using the same safety checks. + + *Kali Donovan* + *Michael Daross* + * Update CI configuration to use `Appraisal`. *Hans Lemuet, Simon Fish* @@ -26,7 +31,7 @@ nav_order: 5 * Add support for Ruby 3.3. - *Reegan Viljoen* + *Reegan Viljoen* * Allow translations to be inherited and overridden in subclasses. diff --git a/docs/api.md b/docs/api.md index aac79b266..e2d5f3b18 100644 --- a/docs/api.md +++ b/docs/api.md @@ -78,6 +78,10 @@ that inhibits encapsulation & reuse, often making testing difficult. A proxy through which to access helpers. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult. +### `#output_preamble` → [String] + +Optional content to be returned before the rendered template. + ### `#output_postamble` → [String] Optional content to be returned after the rendered template. diff --git a/docs/index.md b/docs/index.md index 24f750a5c..809283f2e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -123,6 +123,7 @@ ViewComponent is built by over a hundred members of the community, including: cesariouy cover cpjmcquillan +crookedgrin czj dani-sc danieldiekmeier @@ -157,6 +158,7 @@ ViewComponent is built by over a hundred members of the community, including: jwshuff kaspermeyer kylefox +kdonovan leighhalliday llenk manuelpuyol diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index 1dfc641fa..aea0eff94 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -104,11 +104,16 @@ def render_in(view_context, &block) before_render if render? - # Avoid allocating new string when output_postamble is blank - if output_postamble.blank? - safe_render_template_for(@__vc_variant).to_s + # Avoid allocating new string when output_preamble and output_postamble are blank + rendered_template = safe_render_template_for(@__vc_variant).to_s + + if output_preamble.blank? && output_postamble.blank? + rendered_template else - safe_render_template_for(@__vc_variant).to_s + safe_output_postamble + preamble = output_preamble.blank? ? '' : safe_output_preamble + postamble = output_postamble.blank? ? '' : safe_output_postamble + + preamble + rendered_template + postamble end else "" @@ -156,6 +161,13 @@ def render_parent_to_string end end + # Optional content to be returned before the rendered template. + # + # @return [String] + def output_preamble + @@default_output_preamble ||= "".html_safe + end + # Optional content to be returned after the rendered template. # # @return [String] @@ -329,6 +341,12 @@ def safe_render_template_for(variant) end end + def safe_output_preamble + maybe_escape_html(output_preamble) do + Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe preamble. The preamble will be automatically escaped, but you may want to investigate.") + end + end + def safe_output_postamble maybe_escape_html(output_postamble) do Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe postamble. The postamble will be automatically escaped, but you may want to investigate.") diff --git a/test/sandbox/app/components/before_and_after_render_component.rb b/test/sandbox/app/components/before_and_after_render_component.rb new file mode 100644 index 000000000..49c6ef2a7 --- /dev/null +++ b/test/sandbox/app/components/before_and_after_render_component.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class BeforeAndAfterRenderComponent < ViewComponent::Base + def call + "Hello, ".html_safe + end + + def output_preamble + "Well, ".html_safe + end + + def output_postamble + "World!".html_safe + end +end diff --git a/test/sandbox/app/components/before_render_component.rb b/test/sandbox/app/components/before_render_component.rb new file mode 100644 index 000000000..a6e662f85 --- /dev/null +++ b/test/sandbox/app/components/before_render_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class BeforeRenderComponent < ViewComponent::Base + def call + "Hello!".html_safe + end + + def output_preamble + "Well, ".html_safe + end +end From 5cf477f6289e961bff733996dcf7010f9a49224c Mon Sep 17 00:00:00 2001 From: Michael Daross Date: Mon, 8 Jan 2024 09:11:19 -0600 Subject: [PATCH 2/5] Linter updated --- lib/view_component/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index aea0eff94..533564f8f 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -110,8 +110,8 @@ def render_in(view_context, &block) if output_preamble.blank? && output_postamble.blank? rendered_template else - preamble = output_preamble.blank? ? '' : safe_output_preamble - postamble = output_postamble.blank? ? '' : safe_output_postamble + preamble = output_preamble.blank? ? "" : safe_output_preamble + postamble = output_postamble.blank? ? "" : safe_output_postamble preamble + rendered_template + postamble end From 75de421075773cf47d8f3eb6ee825c29e63b2e1a Mon Sep 17 00:00:00 2001 From: Michael Daross Date: Mon, 8 Jan 2024 09:56:53 -0600 Subject: [PATCH 3/5] Adding unsafe_preamble and test coverage --- .../app/components/unsafe_preamble_component.rb | 11 +++++++++++ .../controllers/integration_examples_controller.rb | 4 ++++ test/sandbox/config/routes.rb | 1 + test/sandbox/test/integration_test.rb | 9 +++++++++ test/sandbox/test/rendering_test.rb | 12 ++++++++++++ 5 files changed, 37 insertions(+) create mode 100644 test/sandbox/app/components/unsafe_preamble_component.rb diff --git a/test/sandbox/app/components/unsafe_preamble_component.rb b/test/sandbox/app/components/unsafe_preamble_component.rb new file mode 100644 index 000000000..6b4e3c013 --- /dev/null +++ b/test/sandbox/app/components/unsafe_preamble_component.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class UnsafePreambleComponent < ViewComponent::Base + def call + "
some content
".html_safe + end + + def output_preamble + "" + end +end diff --git a/test/sandbox/app/controllers/integration_examples_controller.rb b/test/sandbox/app/controllers/integration_examples_controller.rb index ae654faff..c7dfad3ba 100644 --- a/test/sandbox/app/controllers/integration_examples_controller.rb +++ b/test/sandbox/app/controllers/integration_examples_controller.rb @@ -64,6 +64,10 @@ def unsafe_component render(UnsafeComponent.new) end + def unsafe_preamble_component + render(UnsafePreambleComponent.new) + end + def unsafe_postamble_component render(UnsafePostambleComponent.new) end diff --git a/test/sandbox/config/routes.rb b/test/sandbox/config/routes.rb index f671f7adb..072cf9687 100644 --- a/test/sandbox/config/routes.rb +++ b/test/sandbox/config/routes.rb @@ -30,6 +30,7 @@ get :inherited_sidecar, to: "integration_examples#inherited_sidecar" get :inherited_from_uncompilable_component, to: "integration_examples#inherited_from_uncompilable_component" get :unsafe_component, to: "integration_examples#unsafe_component" + get :unsafe_preamble_component, to: "integration_examples#unsafe_preamble_component" get :unsafe_postamble_component, to: "integration_examples#unsafe_postamble_component" post :create, to: "integration_examples#create" diff --git a/test/sandbox/test/integration_test.rb b/test/sandbox/test/integration_test.rb index 14ab6a2d6..3721b045c 100644 --- a/test/sandbox/test/integration_test.rb +++ b/test/sandbox/test/integration_test.rb @@ -733,6 +733,15 @@ def test_unsafe_component ) end + def test_unsafe_preamble_component + warnings = capture_warnings { get "/unsafe_preamble_component" } + assert_select("script", false) + assert( + warnings.any? { |warning| warning.include?("component was provided an HTML-unsafe preamble") }, + "Rendering UnsafePreambleComponent did not emit an HTML safety warning" + ) + end + def test_unsafe_postamble_component warnings = capture_warnings { get "/unsafe_postamble_component" } assert_select("script", false) diff --git a/test/sandbox/test/rendering_test.rb b/test/sandbox/test/rendering_test.rb index f0962ddb6..2889d0796 100644 --- a/test/sandbox/test/rendering_test.rb +++ b/test/sandbox/test/rendering_test.rb @@ -889,12 +889,24 @@ def test_components_share_helpers_state assert_equal 1, PartialHelper::State.calls end + def test_output_preamble + render_inline(BeforeRenderComponent.new) + + assert_text("Hello, World!") + end + def test_output_postamble render_inline(AfterRenderComponent.new) assert_text("Hello, World!") end + def test_output_preamble_and_postamble + render_inline(BeforeAndAfterRenderComponent.new) + + assert_text("Well, Hello, World!") + end + def test_compilation_in_development_mode with_compiler_mode(ViewComponent::Compiler::DEVELOPMENT_MODE) do with_new_cache do From 0ae6cc5dd3d1d0f87d3a7fa8d4476e98a861425f Mon Sep 17 00:00:00 2001 From: Michael Daross Date: Mon, 8 Jan 2024 10:00:54 -0600 Subject: [PATCH 4/5] Fixing preamble test --- test/sandbox/test/rendering_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sandbox/test/rendering_test.rb b/test/sandbox/test/rendering_test.rb index 2889d0796..f1952c64c 100644 --- a/test/sandbox/test/rendering_test.rb +++ b/test/sandbox/test/rendering_test.rb @@ -892,7 +892,7 @@ def test_components_share_helpers_state def test_output_preamble render_inline(BeforeRenderComponent.new) - assert_text("Hello, World!") + assert_text("Well, Hello!") end def test_output_postamble From 5085d9533e8ff3e23e939efb678999337c7d7163 Mon Sep 17 00:00:00 2001 From: Michael Daross Date: Mon, 8 Jan 2024 13:03:02 -0600 Subject: [PATCH 5/5] Update lib/view_component/base.rb Taking @camertron's suggestions Co-authored-by: Cameron Dutro --- lib/view_component/base.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index 533564f8f..94c5a7188 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -110,10 +110,7 @@ def render_in(view_context, &block) if output_preamble.blank? && output_postamble.blank? rendered_template else - preamble = output_preamble.blank? ? "" : safe_output_preamble - postamble = output_postamble.blank? ? "" : safe_output_postamble - - preamble + rendered_template + postamble + safe_output_preamble + rendered_template + safe_output_postamble end else ""