view_component 2.83.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/view_component/preview_actions.rb +5 -1
  3. data/app/controllers/view_components_system_test_controller.rb +24 -1
  4. data/app/helpers/preview_helper.rb +22 -4
  5. data/app/views/view_components/_preview_source.html.erb +2 -2
  6. data/docs/CHANGELOG.md +807 -1
  7. data/lib/rails/generators/abstract_generator.rb +9 -1
  8. data/lib/rails/generators/component/component_generator.rb +2 -1
  9. data/lib/rails/generators/component/templates/component.rb.tt +3 -2
  10. data/lib/rails/generators/erb/component_generator.rb +1 -1
  11. data/lib/rails/generators/locale/component_generator.rb +3 -3
  12. data/lib/rails/generators/preview/templates/component_preview.rb.tt +2 -0
  13. data/lib/rails/generators/rspec/component_generator.rb +15 -3
  14. data/lib/rails/generators/rspec/templates/component_spec.rb.tt +1 -1
  15. data/lib/rails/generators/stimulus/component_generator.rb +8 -3
  16. data/lib/rails/generators/stimulus/templates/component_controller.ts.tt +9 -0
  17. data/lib/rails/generators/test_unit/templates/component_test.rb.tt +1 -1
  18. data/lib/view_component/base.rb +169 -164
  19. data/lib/view_component/capture_compatibility.rb +44 -0
  20. data/lib/view_component/collection.rb +20 -8
  21. data/lib/view_component/compiler.rb +166 -207
  22. data/lib/view_component/config.rb +63 -14
  23. data/lib/view_component/deprecation.rb +1 -1
  24. data/lib/view_component/docs_builder_component.html.erb +5 -1
  25. data/lib/view_component/docs_builder_component.rb +28 -9
  26. data/lib/view_component/engine.rb +58 -28
  27. data/lib/view_component/errors.rb +240 -0
  28. data/lib/view_component/inline_template.rb +55 -0
  29. data/lib/view_component/instrumentation.rb +10 -2
  30. data/lib/view_component/preview.rb +7 -8
  31. data/lib/view_component/rails/tasks/view_component.rake +11 -2
  32. data/lib/view_component/slot.rb +119 -1
  33. data/lib/view_component/slotable.rb +394 -94
  34. data/lib/view_component/slotable_default.rb +20 -0
  35. data/lib/view_component/system_test_helpers.rb +5 -5
  36. data/lib/view_component/template.rb +134 -0
  37. data/lib/view_component/test_helpers.rb +138 -59
  38. data/lib/view_component/translatable.rb +45 -26
  39. data/lib/view_component/use_helpers.rb +42 -0
  40. data/lib/view_component/version.rb +4 -3
  41. data/lib/view_component/with_content_helper.rb +3 -8
  42. data/lib/view_component.rb +3 -12
  43. metadata +277 -38
  44. data/lib/view_component/content_areas.rb +0 -56
  45. data/lib/view_component/polymorphic_slots.rb +0 -103
  46. data/lib/view_component/preview_template_error.rb +0 -6
  47. data/lib/view_component/slot_v2.rb +0 -98
  48. data/lib/view_component/slotable_v2.rb +0 -391
  49. data/lib/view_component/template_error.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27bcac094fd171c4eb5c5ef2319372747f0efd62ca643fefdc2b544fd6efbd73
4
- data.tar.gz: 49d93b90f2cf504ded99a6cfe0db780ec178131800a35eff210488da62aae673
3
+ metadata.gz: 24be9824d2f5208831e8de57930415019c781a1245224659efb9258372dcafbc
4
+ data.tar.gz: 33182c814b14959c85370e274619a3da70ea19906dd40c8d0be0cd12c9f16a2b
5
5
  SHA512:
6
- metadata.gz: 89a7f4702ccfc60f9128a99a3ff0ab5b35237fc0aaba860c01e705754330d557b3c380de369cd63db430f3d42d2cb2370a0677eee07ae73a61118921ec715994
7
- data.tar.gz: 99c1af02c38bba37dc3f44b70818eadae73e307c4d05dd321585fb8cbdfed667367e34255fbbae11b9197fca731704e53a76b38abcfac93e45378c48a798cb43
6
+ metadata.gz: 0d856adb4c86acc808277c7fcc17291b41328b932b53991db003dccab6e23f2a02177e200065e78d3004f8233df98b0926202138b8b536f67c8f848f876231e2
7
+ data.tar.gz: a7c6b583fd6eaf4bdb20cdc9d7ca86ed0a5e818e90d1099c5fd799d2127122c058d5d58285251ea0713aeb73d719cabad8ab971e994e0f658767235089953dfd
@@ -11,6 +11,10 @@ module ViewComponent
11
11
  before_action :require_local!, unless: :show_previews?
12
12
 
13
13
  content_security_policy(false) if respond_to?(:content_security_policy)
14
+
15
+ # Including helpers here ensures that we're loading the
16
+ # latest version of helpers if code-reloading is enabled
17
+ helper :all if include_all_helpers
14
18
  end
15
19
 
16
20
  def index
@@ -55,7 +59,7 @@ module ViewComponent
55
59
  def find_preview
56
60
  candidates = []
57
61
  params[:path].to_s.scan(%r{/|$}) { candidates << Regexp.last_match.pre_match }
58
- preview = candidates.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
62
+ preview = candidates.sort_by(&:length).reverse_each.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
59
63
 
60
64
  if preview
61
65
  @preview = ViewComponent::Preview.find(preview)
@@ -1,7 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ViewComponentsSystemTestController < ActionController::Base # :nodoc:
4
+ before_action :validate_test_env
5
+ before_action :validate_file_path
6
+
7
+ def self.temp_dir
8
+ @_tmpdir ||= FileUtils.mkdir_p("./tmp/view_components/").first
9
+ end
10
+
4
11
  def system_test_entrypoint
5
- render file: "./tmp/view_components/#{params.permit(:file)[:file]}"
12
+ render file: @path
13
+ end
14
+
15
+ private
16
+
17
+ def validate_test_env
18
+ raise ViewComponent::SystemTestControllerOnlyAllowedInTestError unless Rails.env.test?
19
+ end
20
+
21
+ # Ensure that the file path is valid and doesn't target files outside
22
+ # the expected directory (e.g. via a path traversal or symlink attack)
23
+ def validate_file_path
24
+ base_path = ::File.realpath(self.class.temp_dir)
25
+ @path = ::File.realpath(params.permit(:file)[:file], base_path)
26
+ unless @path.start_with?(base_path)
27
+ raise ViewComponent::SystemTestControllerNefariousPathError
28
+ end
6
29
  end
7
30
  end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PreviewHelper
4
+ # :nocov:
5
+ include ActionView::Helpers::AssetUrlHelper if Rails.version.to_f < 6.1
6
+ # :nocov:
7
+
4
8
  AVAILABLE_PRISM_LANGUAGES = %w[ruby erb haml]
5
9
  FALLBACK_LANGUAGE = "ruby"
6
10
 
@@ -10,6 +14,14 @@ module PreviewHelper
10
14
  render "preview_source"
11
15
  end
12
16
 
17
+ def prism_css_source_url
18
+ serve_static_preview_assets? ? asset_path("prism.css", skip_pipeline: true) : "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/themes/prism.min.css"
19
+ end
20
+
21
+ def prism_js_source_url
22
+ serve_static_preview_assets? ? asset_path("prism.min.js", skip_pipeline: true) : "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/prism.min.js"
23
+ end
24
+
13
25
  def find_template_data(lookup_context:, template_identifier:)
14
26
  template = lookup_context.find_template(template_identifier)
15
27
 
@@ -18,6 +30,7 @@ module PreviewHelper
18
30
  source: template.source,
19
31
  prism_language_name: prism_language_name_by_template(template: template)
20
32
  }
33
+ # :nocov:
21
34
  else
22
35
  # Fetch template source via finding it through preview paths
23
36
  # to accomodate source view when exclusively using templates
@@ -31,10 +44,8 @@ module PreviewHelper
31
44
  path =~ /#{template_identifier}*.(html)/
32
45
  end
33
46
 
34
- # In-case of a conflict due to multiple template files with
35
- # the same name
36
- raise "found 0 matches for templates for #{template_identifier}." if matching_templates.empty?
37
- raise "found multiple templates for #{template_identifier}." if matching_templates.size > 1
47
+ raise ViewComponent::NoMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.empty?
48
+ raise ViewComponent::MultipleMatchingTemplatesForPreviewError.new(template_identifier) if matching_templates.size > 1
38
49
 
39
50
  template_file_path = matching_templates.first
40
51
  template_source = File.read(template_file_path)
@@ -45,6 +56,7 @@ module PreviewHelper
45
56
  prism_language_name: prism_language_name
46
57
  }
47
58
  end
59
+ # :nocov:
48
60
  end
49
61
 
50
62
  private
@@ -57,6 +69,7 @@ module PreviewHelper
57
69
  language
58
70
  end
59
71
 
72
+ # :nocov:
60
73
  def prism_language_name_by_template_path(template_file_path:)
61
74
  language = template_file_path.gsub(".html", "").split(".").last
62
75
 
@@ -64,4 +77,9 @@ module PreviewHelper
64
77
 
65
78
  language
66
79
  end
80
+ # :nocov:
81
+
82
+ def serve_static_preview_assets?
83
+ ViewComponent::Base.config.show_previews && Rails.application.config.public_file_server.enabled
84
+ end
67
85
  end
@@ -1,4 +1,4 @@
1
- <link href="<%= asset_path('prism.css', skip_pipeline: true) %>" media="screen" rel="stylesheet" type="text/css">
1
+ <link href="<%= prism_css_source_url %>" media="screen" rel="stylesheet" type="text/css">
2
2
  <div class="view-component-source-example">
3
3
  <h2>Source:</h2>
4
4
  <pre class="source">
@@ -14,4 +14,4 @@
14
14
  <% end %>
15
15
  </pre>
16
16
  </div>
17
- <script type="text/javascript" src="<%= asset_path('prism.min.js', skip_pipeline: true) %>"></script>
17
+ <script type="text/javascript" src="<%= prism_js_source_url %>"></script>