decidim-dev 0.31.4 → 0.32.0.rc1

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -12
  3. data/app/models/decidim/dev/dummy_resource.rb +4 -1
  4. data/app/models/decidim/dev/nested_dummy_resource.rb +1 -0
  5. data/config/locales/ar.yml +1 -2
  6. data/config/locales/bg.yml +1 -2
  7. data/config/locales/ca-IT.yml +1 -2
  8. data/config/locales/ca.yml +1 -2
  9. data/config/locales/cs.yml +1 -2
  10. data/config/locales/de.yml +1 -2
  11. data/config/locales/el.yml +1 -2
  12. data/config/locales/es-MX.yml +1 -2
  13. data/config/locales/es-PY.yml +1 -2
  14. data/config/locales/es.yml +1 -2
  15. data/config/locales/eu.yml +1 -2
  16. data/config/locales/fi-plain.yml +1 -2
  17. data/config/locales/fi.yml +1 -2
  18. data/config/locales/fr-CA.yml +1 -2
  19. data/config/locales/fr.yml +1 -2
  20. data/config/locales/ga-IE.yml +0 -1
  21. data/config/locales/gl.yml +1 -2
  22. data/config/locales/hu.yml +1 -2
  23. data/config/locales/id-ID.yml +1 -2
  24. data/config/locales/is-IS.yml +1 -2
  25. data/config/locales/it.yml +1 -2
  26. data/config/locales/ja.yml +1 -2
  27. data/config/locales/lt.yml +1 -2
  28. data/config/locales/lv.yml +1 -2
  29. data/config/locales/nl.yml +1 -2
  30. data/config/locales/no.yml +1 -2
  31. data/config/locales/pl.yml +1 -2
  32. data/config/locales/pt-BR.yml +1 -2
  33. data/config/locales/pt.yml +1 -2
  34. data/config/locales/ro-RO.yml +1 -2
  35. data/config/locales/ru.yml +1 -2
  36. data/config/locales/sk.yml +1 -2
  37. data/config/locales/sl.yml +0 -1
  38. data/config/locales/sv.yml +1 -2
  39. data/config/locales/tr-TR.yml +1 -2
  40. data/config/locales/uk.yml +0 -1
  41. data/config/locales/zh-CN.yml +1 -2
  42. data/config/locales/zh-TW.yml +1 -2
  43. data/config/rubocop/decidim-linters/configuration.yml +8 -0
  44. data/config/rubocop/rails/disabled.yml +6 -0
  45. data/config/rubocop/rspec/configuration.yml +5 -0
  46. data/config/rubocop/ruby/configuration.yml +2 -3
  47. data/config/rubocop/ruby/disabled.yml +9 -0
  48. data/config/rubocop/yard/configuration.yml +1 -0
  49. data/decidim-dev.gemspec +21 -23
  50. data/lib/decidim/dev/assets/assemblies.json +1 -21
  51. data/lib/decidim/dev/assets/assemblies_with_null.json +1 -2
  52. data/lib/decidim/dev/assets/participatory_processes.json +1 -4
  53. data/lib/decidim/dev/assets/participatory_processes_with_null.json +1 -1
  54. data/lib/decidim/dev/dummy_translator.rb +1 -1
  55. data/lib/decidim/dev/rubocop/cop/decidim/message_antipattern.rb +76 -0
  56. data/lib/decidim/dev/test/rspec_support/active_job.rb +5 -0
  57. data/lib/decidim/dev/test/rspec_support/component_context.rb +1 -1
  58. data/lib/decidim/dev/test/rspec_support/helpers.rb +9 -3
  59. data/lib/decidim/dev/test/rspec_support/tom_select.rb +7 -4
  60. data/lib/decidim/dev/version.rb +1 -1
  61. data/lib/decidim/dev.rb +0 -1
  62. data/lib/erb_lint/linters/admin_page_title_linter.rb +46 -0
  63. data/lib/erb_lint/linters/partial_path_linter.rb +101 -0
  64. data/rubocop-decidim.yml +2 -0
  65. metadata +134 -64
  66. /data/lib/decidim/dev/assets/{import_participatory_space_private_users.csv → import_members.csv} +0 -0
  67. /data/lib/decidim/dev/assets/{import_participatory_space_private_users_invalid_col_sep.csv → import_members_invalid_col_sep.csv} +0 -0
  68. /data/lib/decidim/dev/assets/{import_participatory_space_private_users_iso8859-1.csv → import_members_iso8859-1.csv} +0 -0
  69. /data/lib/decidim/dev/assets/{import_participatory_space_private_users_nok.csv → import_members_nok.csv} +0 -0
  70. /data/lib/decidim/dev/assets/{import_participatory_space_private_users_with_bom.csv → import_members_with_bom.csv} +0 -0
data/decidim-dev.gemspec CHANGED
@@ -2,12 +2,9 @@
2
2
 
3
3
  $LOAD_PATH.push File.expand_path("lib", __dir__)
4
4
 
5
- # Maintain your gem's version:
6
- require "decidim/dev/version"
7
-
8
- # Describe your gem and declare its dependencies:
9
5
  Gem::Specification.new do |s|
10
- s.version = Decidim::Dev.version
6
+ version = "0.32.0.rc1"
7
+ s.version = version
11
8
  s.authors = ["Josep Jaume Rey Peroy", "Marc Riera Casals", "Oriol Gual Oliva"]
12
9
  s.email = ["josepjaume@gmail.com", "mrc2407@gmail.com", "oriolgual@gmail.com"]
13
10
  s.license = "AGPL-3.0-or-later"
@@ -19,7 +16,7 @@ Gem::Specification.new do |s|
19
16
  "homepage_uri" => "https://decidim.org",
20
17
  "source_code_uri" => "https://github.com/decidim/decidim"
21
18
  }
22
- s.required_ruby_version = "~> 3.3.0"
19
+ s.required_ruby_version = "~> 3.4.0"
23
20
 
24
21
  s.name = "decidim-dev"
25
22
  s.summary = "Decidim dev tools"
@@ -33,42 +30,43 @@ Gem::Specification.new do |s|
33
30
  end
34
31
 
35
32
  s.add_dependency "capybara", "~> 3.39"
36
- s.add_dependency "decidim-admin", Decidim::Dev.version
37
- s.add_dependency "decidim-api", Decidim::Dev.version
38
- s.add_dependency "decidim-comments", Decidim::Dev.version
39
- s.add_dependency "decidim-core", Decidim::Dev.version
40
- s.add_dependency "decidim-generators", Decidim::Dev.version
41
- s.add_dependency "decidim-verifications", Decidim::Dev.version
33
+ s.add_dependency "decidim-admin", version
34
+ s.add_dependency "decidim-api", version
35
+ s.add_dependency "decidim-comments", version
36
+ s.add_dependency "decidim-core", version
37
+ s.add_dependency "decidim-generators", version
38
+ s.add_dependency "decidim-verifications", version
42
39
  s.add_dependency "factory_bot_rails", "~> 6.2"
43
40
  s.add_dependency "faker", "~> 3.2"
44
41
 
45
- s.add_dependency "bullet", "~> 8.0.0"
46
- s.add_dependency "byebug", "~> 11.0"
47
- s.add_dependency "erb_lint", "~> 0.8.0"
42
+ s.add_dependency "bullet", "~> 8.1.0"
43
+ s.add_dependency "byebug", ">= 11", "< 14"
44
+ s.add_dependency "erb_lint", ">= 0.8", "< 0.10"
48
45
  s.add_dependency "i18n-tasks", "~> 1.0"
49
46
  s.add_dependency "nokogiri", "~> 1.16", ">= 1.16.2"
50
- s.add_dependency "parallel_tests", "~> 4.2"
51
- s.add_dependency "puma", "~> 6.5"
47
+ s.add_dependency "parallel_tests", ">= 4.2", "< 6.0"
48
+ s.add_dependency "puma", ">= 6.5", "< 8.0"
52
49
  s.add_dependency "rails-controller-testing", "~> 1.0"
53
50
  s.add_dependency "rspec", "~> 3.12"
54
51
  s.add_dependency "rspec-cells", "~> 0.3.7"
55
52
  s.add_dependency "rspec-html-matchers", "~> 0.10"
56
53
  s.add_dependency "rspec_junit_formatter", "~> 0.6.0"
57
- s.add_dependency "rspec-rails", "~> 6.0"
54
+ s.add_dependency "rspec-rails", ">= 6", "< 9"
58
55
  s.add_dependency "rspec-retry", "~> 0.6.2"
59
- s.add_dependency "rubocop", "~> 1.78.0"
56
+ s.add_dependency "rubocop", ">= 1.78", "< 1.87"
60
57
  s.add_dependency "rubocop-capybara", "~> 2.22.0", ">= 2.22.1"
61
- s.add_dependency "rubocop-factory_bot", "~> 2.27.0"
58
+ s.add_dependency "rubocop-factory_bot", ">= 2.27", "< 2.29"
62
59
  s.add_dependency "rubocop-faker", "~> 1.3", ">= 1.3.0"
63
60
  s.add_dependency "rubocop-graphql", "~> 1.5", ">= 1.5.6"
64
61
  s.add_dependency "rubocop-performance", "~> 1.25", ">= 1.25.0"
65
- s.add_dependency "rubocop-rails", "~> 2.32.0", ">= 2.32.0"
62
+ s.add_dependency "rubocop-rails", ">= 2.32", "< 2.35"
66
63
  s.add_dependency "rubocop-rspec", "~> 3.0", ">= 3.6.0"
67
- s.add_dependency "rubocop-rspec_rails", "~> 2.31.0"
64
+ s.add_dependency "rubocop-rspec_rails", ">= 2.31", "< 2.33"
68
65
  s.add_dependency "rubocop-rubycw", "~> 0.2.0"
66
+ s.add_dependency "rubocop-yard", ">= 1.0", "< 1.2"
69
67
  s.add_dependency "selenium-webdriver", "~> 4.9"
70
68
  s.add_dependency "simplecov", "~> 0.22.0"
71
- s.add_dependency "simplecov-cobertura", "~> 2.1.0"
69
+ s.add_dependency "simplecov-cobertura", "~> 3.1.0"
72
70
  s.add_dependency "spring", "~> 4.0"
73
71
  s.add_dependency "spring-watcher-listen", "~> 2.0"
74
72
  s.add_dependency "w3c_rspec_validators", "~> 0.3.0"
@@ -47,6 +47,7 @@
47
47
  "es": "Incidunt provident doloremque."
48
48
  },
49
49
  "decidim_scope_id": null,
50
+ "access_mode": "open",
50
51
  "paticipatory_scope": {
51
52
  "ca": "Assumenda.",
52
53
  "en": "Quidem.",
@@ -58,7 +59,6 @@
58
59
  "es": "Et molestiae."
59
60
  },
60
61
  "scopes_enabled": true,
61
- "private_space": false,
62
62
  "reference": "PhD-ASSE-2020-01-1",
63
63
  "purpose_of_action": {
64
64
  "ca": "<p>Velit a qui. Debitis rem occaecati. Id minus est.</p>",
@@ -90,7 +90,6 @@
90
90
  "en": "<p>Optio ducimus velit. Facilis omnis asperiores. Corporis ipsa non.</p>",
91
91
  "es": "<p>Est dolorum et. Quo sed ut. Corporis quos sit.</p>"
92
92
  },
93
- "is_transparent": true,
94
93
  "special_features": {
95
94
  "ca": "<p>Dolor et reprehenderit. Unde soluta eum. Omnis occaecati omnis.</p>",
96
95
  "en": "<p>Et atque perspiciatis. Quas impedit corporis. Nesciunt blanditiis ipsa.</p>",
@@ -106,7 +105,6 @@
106
105
  "en": "ut",
107
106
  "es": "rerum"
108
107
  },
109
- "decidim_assemblies_type_id": 1,
110
108
  "area": {
111
109
  "id": null,
112
110
  "name": {
@@ -514,7 +512,6 @@
514
512
  "geocoding_enabled": false,
515
513
  "attachments_allowed": false,
516
514
  "resources_permissions_enabled": true,
517
- "collaborative_drafts_enabled": true,
518
515
  "participatory_texts_enabled": false,
519
516
  "amendments_enabled": false,
520
517
  "amendments_wizard_help_text": {
@@ -578,23 +575,6 @@
578
575
  "permissions": null,
579
576
  "published_at": "2020-01-22 07:55:05 UTC"
580
577
  },
581
- {
582
- "manifest_name": "sortitions",
583
- "id": 26,
584
- "name": {
585
- "ca": "Sortejos",
586
- "en": "Sortitions",
587
- "es": "Sorteos"
588
- },
589
- "participatory_space_id": 1,
590
- "participatory_space_type": "Decidim::Assembly",
591
- "settings": {
592
- "comments_enabled": true
593
- },
594
- "weight": 0,
595
- "permissions": null,
596
- "published_at": "2020-01-22 07:55:19 UTC"
597
- },
598
578
  {
599
579
  "manifest_name": "surveys",
600
580
  "id": 23,
@@ -58,7 +58,7 @@
58
58
  "es": "Et molestiae."
59
59
  },
60
60
  "scopes_enabled": true,
61
- "private_space": false,
61
+ "access_mode": "open",
62
62
  "reference": "PhD-ASSE-2020-01-1",
63
63
  "purpose_of_action": {
64
64
  "ca": "<p>Velit a qui. Debitis rem occaecati. Id minus est.</p>",
@@ -106,7 +106,6 @@
106
106
  "en": "ut",
107
107
  "es": "rerum"
108
108
  },
109
- "decidim_assemblies_type_id": 1,
110
109
  "area": {
111
110
  "id": null,
112
111
  "name": {
@@ -87,7 +87,7 @@
87
87
  "es": "South Carolina"
88
88
  }
89
89
  },
90
- "private_space": false,
90
+ "access_mode": "open",
91
91
  "promoted": true,
92
92
  "scopes_enabled": true,
93
93
  "participatory_process_steps": [
@@ -105,9 +105,6 @@
105
105
  },
106
106
  "start_date": "2019-09-02",
107
107
  "end_date": "2019-12-02",
108
- "cta_path": null,
109
- "cta_text": {
110
- },
111
108
  "active": true,
112
109
  "position": 0
113
110
  }
@@ -87,7 +87,7 @@
87
87
  "es": "South Carolina"
88
88
  }
89
89
  },
90
- "private_space": false,
90
+ "access_mode": "open",
91
91
  "promoted": true,
92
92
  "scopes_enabled": true,
93
93
  "participatory_process_steps": null,
@@ -20,7 +20,7 @@ module Decidim
20
20
  def translate
21
21
  translated_text = "#{target_locale} - #{text}"
22
22
 
23
- MachineTranslationSaveJob.perform_later(
23
+ Decidim::MachineTranslationSaveJob.perform_later(
24
24
  resource,
25
25
  field_name,
26
26
  target_locale,
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Decidim
8
+ class MessageAntipattern < RuboCop::Cop::Base
9
+ SINGLE_WORD_ANTI_PATTERNS = %w(
10
+ successfully
11
+ problem
12
+ error
13
+ warning
14
+ done
15
+ complete
16
+ finished
17
+ ok
18
+ okay
19
+ saved
20
+ updated
21
+ created
22
+ deleted
23
+ removed
24
+ published
25
+ unpublished
26
+ ).freeze
27
+
28
+ MSG = "Anti-pattern detected: avoid generic single-word text in have_callout/have_admin_callout/have_content. " \
29
+ "Use the full admin flash message, e.g. 'Meeting successfully published'. " \
30
+ "Exception: when used inside `within` blocks (e.g., for checking `.label` elements)."
31
+
32
+ def on_send(node)
33
+ return unless [:have_callout, :have_admin_callout, :have_content].include?(node.method_name)
34
+ return if within_block?(node)
35
+
36
+ first_argument = node.first_argument
37
+ return unless first_argument
38
+
39
+ if first_argument.nil_type?
40
+ add_offense(first_argument, message: MSG)
41
+ return
42
+ end
43
+ return unless first_argument.str_type?
44
+
45
+ text = first_argument.value
46
+ return unless antipattern_text?(text)
47
+
48
+ add_offense(first_argument, message: MSG)
49
+ end
50
+
51
+ private
52
+
53
+ def within_block?(node)
54
+ node.each_ancestor(:block).any? do |ancestor|
55
+ ancestor.send_node&.method_name == :within
56
+ end
57
+ end
58
+
59
+ def antipattern_text?(text)
60
+ return true if text.nil?
61
+ return true if text.empty?
62
+
63
+ stripped_text = text.gsub(/[[:punct:]\s]/, "")
64
+ return true if stripped_text.empty?
65
+
66
+ single_word = text.strip !~ /\s/
67
+ return false unless single_word
68
+
69
+ return true if SINGLE_WORD_ANTI_PATTERNS.include?(stripped_text.downcase)
70
+
71
+ false
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -14,6 +14,11 @@ end
14
14
  RSpec.configure do |config|
15
15
  config.include ActiveJob::TestHelper
16
16
  config.include DecidimActiveJobExtensions
17
+
18
+ config.before do
19
+ clear_enqueued_jobs
20
+ clear_performed_jobs
21
+ end
17
22
  end
18
23
 
19
24
  ActiveJob::Base.queue_adapter = :test
@@ -58,7 +58,7 @@ shared_context "with a component" do
58
58
  end
59
59
 
60
60
  def visit_component
61
- page.visit main_component_path(component)
61
+ page.visit main_component_path(component, locale: I18n.locale)
62
62
  end
63
63
  end
64
64
 
@@ -33,8 +33,8 @@ module Decidim
33
33
  end
34
34
 
35
35
  def within_language_menu(options = {})
36
- within(options[:admin] ? ".language-choose" : "footer") do
37
- find(options[:admin] ? "#admin-menu-trigger" : "#trigger-dropdown-language-chooser").click
36
+ within(options[:admin] ? ".language-choose" : "header") do
37
+ find(options[:admin] ? "#admin-menu-trigger" : "#trigger-dropdown-menu-language-chooser-desktop").click
38
38
  yield
39
39
  end
40
40
  end
@@ -53,12 +53,18 @@ module Decidim
53
53
  expect(page).to have_css(".main-bar #trigger-dropdown-account")
54
54
  end
55
55
 
56
- def have_admin_callout(text)
56
+ def have_callout(text)
57
57
  within_flash_messages do
58
58
  have_content text
59
59
  end
60
60
  end
61
61
 
62
+ # Fallback for legacy usage of this helper
63
+ # It actually works the same, as the markup is the same too
64
+ def have_admin_callout(text)
65
+ have_callout(text)
66
+ end
67
+
62
68
  def stub_get_request_with_format(rq_url, rs_format)
63
69
  stub_request(:get, rq_url)
64
70
  .with(
@@ -9,11 +9,14 @@ module Capybara
9
9
  # a better way, we could try actually interacting with the on-screen tom-select-provided UI,
10
10
  # but we are taking the easy way out for now.
11
11
  #
12
- # @param option_id can be the `id` value of an option in the select, OR for select multiple inputs,
13
- # can be an array of such IDs.
12
+ # @param select_selector [String] The CSS selector of the select element.
13
+ # @param option_id [String, Array<String>] The `id` value of an option in the select.
14
+ # For selects with the `multiple` attribute, this can be an array of such IDs.
14
15
  #
15
- # @example tom_select("#select_id", option_id: "2")
16
- # @example tom_select("#select_id", option_id: ["2", "10"]) # `multiple` input.
16
+ # @example
17
+ # tom_select("#select_id", option_id: "2")
18
+ # @example
19
+ # tom_select("#select_id", option_id: ["2", "10"]) # For a `multiple` select input.
17
20
  def tom_select(select_selector, option_id:)
18
21
  js_str = %(document.querySelector("#{select_selector}").tomselect.setValue(#{option_id.inspect}))
19
22
  execute_script(js_str)
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-dev version.
5
5
  module Dev
6
6
  def self.version
7
- "0.31.4"
7
+ "0.32.0.rc1"
8
8
  end
9
9
  end
10
10
  end
data/lib/decidim/dev.rb CHANGED
@@ -22,7 +22,6 @@ module Decidim
22
22
  # create external libraries that create test apps and test themselves against
23
23
  # them.
24
24
  module Dev
25
- include ActiveSupport::Configurable
26
25
  autoload :DummyTranslator, "decidim/dev/dummy_translator"
27
26
 
28
27
  # Public: Finds an asset.
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb_lint"
4
+ require "erb_lint/linter"
5
+ require "erb_lint/linter_config"
6
+ require "erb_lint/linter_registry"
7
+ require "erb_lint/offense"
8
+
9
+ module ERBLint
10
+ module Linters
11
+ class AdminPageTitleLinter < Linter
12
+ include LinterRegistry
13
+
14
+ TITLE_SNIPPET = '<% add_decidim_page_title(t(".title")) %>'
15
+ TITLE_SNIPPET_REGEX = /\A<%\s*add_decidim_page_title\(t\(".title".*?\)\)\s*%>/
16
+
17
+ def run(processed_source)
18
+ return unless admin_view?(processed_source.filename)
19
+
20
+ first_line = processed_source.file_content.to_s.lines.first
21
+ return if first_line&.match?(TITLE_SNIPPET_REGEX)
22
+
23
+ add_offense(
24
+ processed_source.to_source_range(0...0),
25
+ "Admin views must start with: #{TITLE_SNIPPET}"
26
+ )
27
+ end
28
+
29
+ private
30
+
31
+ def admin_view?(filename)
32
+ return false unless filename.include?("/app/views/")
33
+ return false unless filename.include?("/admin/")
34
+ return false if filename.include?("/layouts/")
35
+ return false if mailer_view?(filename)
36
+ return false unless filename.end_with?(".html.erb")
37
+
38
+ File.basename(filename).start_with?("_") == false
39
+ end
40
+
41
+ def mailer_view?(filename)
42
+ filename.include?("/mailer/") || filename =~ %r{/\w+_mailer/}
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb_lint"
4
+ require "erb_lint/linter"
5
+ require "erb_lint/linter_config"
6
+ require "erb_lint/linter_registry"
7
+ require "erb_lint/offense"
8
+
9
+ module ERBLint
10
+ module Linters
11
+ # Lint ERB partial paths.
12
+ #
13
+ # This linter ensures that partials are rendered with their full path
14
+ # relative to the views directory. For example, in app/views/posts/index.html.erb,
15
+ # it will flag `render "post"` and suggest `render "posts/post"`.
16
+ #
17
+ # It allows configuring prefixes that are exempt from this rule via
18
+ # the `allowed_prefixes` configuration option.
19
+ class PartialPath < Linter
20
+ include LinterRegistry
21
+
22
+ # Configuration schema for the PartialPath linter.
23
+ #
24
+ # @!attribute allowed_prefixes
25
+ # @return [Array<String>] List of prefixes that are allowed to be used without full path
26
+ class ConfigSchema < LinterConfig
27
+ property :allowed_prefixes, accepts: Array
28
+ end
29
+ self.config_schema = ConfigSchema
30
+
31
+ # Runs the linter on the given processed source.
32
+ #
33
+ # This method scans the source code for ERB render calls and checks if they
34
+ # are using the full path for partials. If not, it adds an offense.
35
+ #
36
+ # @param processed_source [ERBLint::ProcessedSource] The processed source to lint
37
+ # @return [void]
38
+ def run(processed_source)
39
+ file_path = processed_source.filename
40
+
41
+ return unless file_path =~ %r{app/views/(.+?)/_?([^/]+)\.html\.erb$}
42
+ return if file_path.include?("/cells/")
43
+
44
+ current_directory = Regexp.last_match(1)
45
+ source = processed_source.file_content
46
+
47
+ source.scan(/<%=\s*render\s+"([^"]+)"[^%]*%>/) do
48
+ partial_path = Regexp.last_match(1)
49
+ start_pos = Regexp.last_match.begin(1)
50
+
51
+ next if partial_path.start_with?("layouts/")
52
+ next if partial_path.start_with?("/")
53
+ next if partial_path.include?("/")
54
+
55
+ next if allowed_prefix?(partial_path)
56
+
57
+ full_path = "#{current_directory}/#{partial_path}"
58
+ range = processed_source.to_source_range(
59
+ start_pos...(start_pos + partial_path.length)
60
+ )
61
+
62
+ add_offense(
63
+ range,
64
+ "Use the full path for partials. Replace `render \"#{partial_path}\"` with `render \"#{full_path}\"`"
65
+ )
66
+ end
67
+ end
68
+
69
+ # Checks if the given path starts with any of the allowed prefixes.
70
+ #
71
+ # @param path [String] The partial path to check
72
+ # @return [Boolean] true if the path starts with an allowed prefix, false otherwise
73
+ def allowed_prefix?(path)
74
+ return false unless @config.allowed_prefixes
75
+
76
+ @config.allowed_prefixes.any? { |prefix| path.start_with?(prefix) }
77
+ end
78
+
79
+ # Generates the autocorrection lambda for the given offense.
80
+ #
81
+ # This method creates a lambda that will replace the partial path with its
82
+ # full path when the linter's autocorrect feature is used.
83
+ #
84
+ # @param processed_source [ERBLint::ProcessedSource] The processed source containing the offense
85
+ # @param offense [ERBLint::Offense] The offense to generate a correction for
86
+ # @return [Proc, nil] A lambda that performs the correction, or nil if correction is not possible
87
+ def autocorrect(processed_source, offense)
88
+ return unless processed_source.filename =~ %r{app/views/(.+?)/_?([^/]+)\.html\.erb$}
89
+ return if processed_source.filename.include?("/cells/")
90
+
91
+ current_directory = Regexp.last_match(1)
92
+
93
+ lambda do |corrector|
94
+ partial_path = offense.source_range.source
95
+ full_path = "#{current_directory}/#{partial_path}"
96
+ corrector.replace(offense.source_range, full_path)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
data/rubocop-decidim.yml CHANGED
@@ -25,4 +25,6 @@ inherit_from:
25
25
  - config/rubocop/graphql/disabled.yml
26
26
  - config/rubocop/factory_bot/configuration.yml
27
27
  - config/rubocop/factory_bot/disabled.yml
28
+ - config/rubocop/yard/configuration.yml
28
29
  - config/rubocop/disabled.yml
30
+ - config/rubocop/decidim-linters/configuration.yml