ordit 0.1.2 ā†’ 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdefa2e20e2bd7fa34e8c898fc6e54e934a35e6c9dc3eb5e9ce9f22bf0403b87
4
- data.tar.gz: 704929dfdbee426f4d358512b18d217f2ddf1521f8e376cdb839993066b229a6
3
+ metadata.gz: d5ebf59e6ecec8bf7ff9c2e8f90923426694c8b9a0fb50ed0ac969e5e881fe5c
4
+ data.tar.gz: 6fdbb94c19ea9cfec2596571b04f6e58993af1dd83b5194023b2bcb435bce6b2
5
5
  SHA512:
6
- metadata.gz: 980a3d0f8ba5d373577b55594350962f784775de06f2c0b288271929a71a68998799fc60b1611293a68ce15102168923377d0dccde9699f2348775c5cf4dc180
7
- data.tar.gz: 3e83e18491bb40508a8f65a8210b29e1c31e94c4e87c67c64c033ed5a3682768c39cae36c794363d37a8d2bdb3f3a457e161a52001584e0b1eabd8349891a0cc
6
+ metadata.gz: e1815e1b1fe8e70814d121d485785b5dcc21a435e9d70cccb75156e914508cc2d7f8cc03c991f0dbe47136745e7f26e955b4384f8c4d74234598c4945485bcb1
7
+ data.tar.gz: b22613d4aaa8f7f405bcf3249ac24ab43c80be89847dd6d1709dd92d9cb840309e223ccfa31edf6075faee7e4d8d7c95bb62a2a69223e6a8f35097b37ba86862
data/CHANGELOG.md CHANGED
@@ -1,10 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.3] - 2024-16-12
4
+
5
+ - more refactor, clean up, make more logical
6
+
3
7
  ## [0.1.2] - 2024-12-12
4
8
 
5
9
  - refactor, clean up
6
10
 
7
-
8
11
  ## [0.1.1] - 2024-12-12
9
12
 
10
13
  - Fix namespace issue in rake task
data/README.md CHANGED
@@ -28,27 +28,21 @@ rails ordit:stimulus
28
28
  This will show:
29
29
  - Controllers that are defined but never used
30
30
  - Controllers that are used but don't have corresponding files
31
- - Active controllers and where they're being used
32
31
  - Summary statistics
33
32
 
34
33
  Example output:
35
34
  ```
36
35
  šŸ“Š Stimulus Controller Audit
37
36
 
38
- āŒ Defined but unused controllers:
39
- unused_feature
40
- ā””ā”€ app/javascript/controllers/unused_feature_controller.js
37
+ āŒ Controllers not defined in any views:
38
+ unused-feature
39
+ users--edit-password
41
40
 
42
41
  āš ļø Used but undefined controllers:
43
- missing_controller
44
- ā””ā”€ app/views/products/show.html.erb (lines: 15, 23)
45
-
46
- āœ… Active controllers:
47
- products
48
- ā””ā”€ Defined in: app/javascript/controllers/products_controller.js
49
- ā””ā”€ Used in:
50
- ā””ā”€ app/views/products/index.html.erb (lines: 10, 45)
51
- ā””ā”€ app/components/product_card/component.html.erb (lines: 3)
42
+ missing-controller
43
+ ā””ā”€ šŸ“ app/views/products/show.html.erb
44
+ šŸ“ app/views/users/edit.html.erb
45
+
52
46
  ```
53
47
 
54
48
  ### Scan for Specific Controller Usage
@@ -56,13 +50,19 @@ Example output:
56
50
  Find all uses of a specific controller:
57
51
 
58
52
  ```bash
59
- rails ordit:scan[controller_name]
53
+ rails ordit:scan[toggle]
54
+ rails ordit:scan[users--name] # For namespaced controllers
60
55
  ```
61
56
 
62
- Example:
63
- ```bash
64
- rails ordit:scan[products]
65
- rails ordit:scan[users--name] # For namespaced controllers
57
+ Example output:
58
+
59
+ ```
60
+ Searching for stimulus controller: 'toggle'
61
+
62
+ šŸ“ app/views/admin/new.html.erb
63
+ šŸ“ app/views/posts/edit.html.erb
64
+ šŸ“ app/views/products/show.html.erb
65
+ šŸ“ app/views/users/edit.html.erb
66
66
  ```
67
67
 
68
68
  ### Configuration
@@ -12,8 +12,7 @@ module Ordit
12
12
  base_path = Ordit.root
13
13
 
14
14
  @view_paths = [
15
- base_path.join("app/views/**/*.{html,erb,haml}").to_s,
16
- base_path.join("app/javascript/**/*.{js,jsx}").to_s,
15
+ base_path.join("app/views/**/*.{html,erb,haml,slim}").to_s,
17
16
  base_path.join("app/components/**/*.{html,erb,haml,rb}").to_s
18
17
  ]
19
18
 
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module Ordit
6
+ class ConsoleOutput
7
+ extend Forwardable
8
+
9
+ def self.run(name = nil)
10
+ new(name).run
11
+ end
12
+
13
+ def_delegators :@results,
14
+ :files, :active_controllers, :undefined_controllers, :unused_controllers
15
+
16
+ def initialize(name = nil)
17
+ @name = name
18
+ @results = Results.new(name)
19
+ end
20
+
21
+ def run
22
+ return print_find if @name
23
+
24
+ print_audit
25
+ end
26
+
27
+ def print_audit
28
+ puts "\nšŸ“Š Stimulus Controller Audit\n"
29
+
30
+ if unused_controllers.any?
31
+ puts "\nāŒ Controllers not defined in any views:"
32
+ unused_controllers.sort.each do |controller|
33
+ puts " #{controller}"
34
+ end
35
+ end
36
+
37
+ if undefined_controllers.any?
38
+ puts "\nāš ļø View with defined but missing controller:"
39
+ undefined_controllers.each do |controller, files|
40
+ puts "\n #{controller}_controller"
41
+
42
+ files.each_with_index do |file, index|
43
+ puts " #{ index.zero? ? 'ā””ā”€' : ' ' } šŸ“ #{file}"
44
+ end
45
+ end
46
+ end
47
+
48
+ puts "\nšŸ“ˆ Summary:"
49
+ puts " Total controllers defined: #{files.size}"
50
+ puts " Total controllers in use: #{active_controllers.size}"
51
+ puts " Unused controllers: #{unused_controllers.size}"
52
+ puts " Undefined controllers: #{undefined_controllers.size}"
53
+ end
54
+
55
+ def print_find
56
+ puts "\nSearching for stimulus controller: '#{@name}'\n\n"
57
+
58
+ if files.empty?
59
+ puts "No matches found."
60
+ return
61
+ end
62
+
63
+ files.each do |file|
64
+ puts "šŸ“ #{file}"
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ordit
4
+ class DefinitionMatcher
5
+ # Match data-controller in HTML attributes
6
+ HTML_PATTERN = /data-controller=["']([^"']+)["']/.freeze
7
+ # Match controller: in Ruby/ERB
8
+ RUBY_PATTERN = /controller:\s*['"]([^'"]+)['"]/.freeze
9
+ # Match 'controller' => in Ruby/ERB
10
+ HASH_ROCKET_PATTERN = /(?:['"]controller['"]|:controller)\s*=>\s*['"]([^'"]+)['"]/.freeze
11
+
12
+ ALL_REGEX = [HTML_PATTERN, RUBY_PATTERN, HASH_ROCKET_PATTERN].freeze
13
+
14
+ def self.run(str)
15
+ ALL_REGEX.each_with_object(Set.new) do |pattern, controllers|
16
+ matches = str.scan(pattern)
17
+ next if matches.empty? || matches.nil?
18
+
19
+ flattened_matches = matches.flatten.flat_map(&:split)
20
+ controllers.merge(flattened_matches)
21
+ end.to_a
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ordit
4
+ class Definitions
5
+ def self.all
6
+ Ordit.configuration.view_paths.each_with_object({}) do |path, hash|
7
+ Dir.glob(path.to_s).each do |file|
8
+ content = File.read(file)
9
+ matches = DefinitionMatcher.run(content)
10
+ next if matches.empty?
11
+
12
+ matches.each do |match|
13
+ relative_file = Pathname.new(file).relative_path_from(
14
+ Pathname.new(Ordit.root)
15
+ ).to_s
16
+ hash[match] ||= []
17
+ hash[match] |= [relative_file]
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.find(name)
24
+ Ordit.configuration.view_paths.flat_map do |path|
25
+ results = Dir.glob(path.to_s).reject do |file|
26
+ content = File.read(file)
27
+ matches = DefinitionMatcher.run(content)
28
+ matches.empty?
29
+ end
30
+
31
+ results.flat_map do |result|
32
+ Pathname.new(result).relative_path_from(Pathname.new(Ordit.root)).to_s
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ordit
4
+ class Files
5
+ def self.all
6
+ run
7
+ end
8
+
9
+ def self.run
10
+ Ordit.configuration.controller_paths.flat_map do |path_pattern|
11
+ base_dir = path_pattern.split("/*").first
12
+
13
+ Dir.glob(path_pattern).select do |file|
14
+ # Only filter by controller pattern if we're finding all files
15
+ file.match?(%r{[^/]*_?controller\.(js|ts)$})
16
+ end.map do |file|
17
+ Pathname.new(file).relative_path_from(Pathname.new(base_dir)).to_s
18
+ end
19
+ end.uniq
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ordit
4
+ class Results
5
+ def initialize(name = nil)
6
+ @name = name
7
+ end
8
+
9
+ def files
10
+ return Definitions.find(@name) if @name
11
+
12
+ Files.all
13
+ end
14
+
15
+ def definitions
16
+ Definitions.all
17
+ end
18
+
19
+ def active_controllers = to_h[:active_controllers].sort
20
+ def undefined_controllers = to_h[:undefined_controllers]
21
+ def unused_controllers = to_h[:unused_controllers].sort
22
+
23
+ def to_h
24
+ @to_h ||= begin
25
+ base_object = {
26
+ active_controllers: [],
27
+ undefined_controllers: {},
28
+ unused_controllers: files.dup || []
29
+ }
30
+
31
+
32
+ definitions.each_with_object(base_object) do |(definition, file), result|
33
+ # Convert definition pattern to match file pattern
34
+ file_pattern = definition_to_file_pattern(definition)
35
+
36
+ # Find matching file
37
+ matching_file = files.find { |f| file_pattern == file_pattern_from_path(f) }
38
+
39
+ if matching_file
40
+ result[:active_controllers] << matching_file
41
+ result[:unused_controllers].delete(matching_file)
42
+ result[:active_controllers].sort!
43
+ else
44
+ result[:undefined_controllers][definition] ||= []
45
+ result[:undefined_controllers][definition] |= file
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def definition_to_file_pattern(definition)
54
+ # Handle nested paths (double hyphen becomes directory separator)
55
+ path_parts = definition.split("--")
56
+
57
+ # Convert each part from kebab-case to snake_case
58
+ path_parts = path_parts.map { |part| part.gsub("-", "_") }
59
+
60
+ # Join with directory separator
61
+ path_parts.join("/")
62
+ end
63
+
64
+ def file_pattern_from_path(file)
65
+ # Remove _controller.js suffix and return the pattern
66
+ file.sub(/_controller\.(js|ts)$/, "")
67
+ end
68
+ end
69
+ end
data/lib/ordit/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ordit
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/ordit.rb CHANGED
@@ -4,9 +4,11 @@ require "set"
4
4
  require "pathname"
5
5
  require_relative "ordit/version"
6
6
  require_relative "ordit/configuration"
7
- require_relative "ordit/auditor"
8
- require_relative "ordit/scanner"
9
- require_relative "ordit/result_generator"
7
+ require_relative "ordit/files"
8
+ require_relative "ordit/definitions"
9
+ require_relative "ordit/definition_matcher"
10
+ require_relative "ordit/results"
11
+ require_relative "ordit/console_output"
10
12
 
11
13
  if defined?(Rails)
12
14
  require "rails"
data/lib/tasks/ordit.rake CHANGED
@@ -3,7 +3,7 @@
3
3
  namespace :ordit do
4
4
  desc "Audit Stimulus controllers usage and find orphaned controllers"
5
5
  task stimulus: :environment do
6
- Ordit::Auditor.run
6
+ Ordit::ConsoleOutput.run
7
7
  end
8
8
 
9
9
  desc "Scan files for stimulus controller usage (e.g., rake audit:scan[products])"
@@ -15,6 +15,6 @@ namespace :ordit do
15
15
  next
16
16
  end
17
17
 
18
- Ordit::Scanner.run(controller)
18
+ Ordit::ConsoleOutput.run(controller)
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ordit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-12 00:00:00.000000000 Z
11
+ date: 2024-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -50,11 +50,13 @@ files:
50
50
  - LICENSE.txt
51
51
  - README.md
52
52
  - lib/ordit.rb
53
- - lib/ordit/auditor.rb
54
53
  - lib/ordit/configuration.rb
54
+ - lib/ordit/console_output.rb
55
+ - lib/ordit/definition_matcher.rb
56
+ - lib/ordit/definitions.rb
57
+ - lib/ordit/files.rb
55
58
  - lib/ordit/railtie.rb
56
- - lib/ordit/result_generator.rb
57
- - lib/ordit/scanner.rb
59
+ - lib/ordit/results.rb
58
60
  - lib/ordit/version.rb
59
61
  - lib/tasks/ordit.rake
60
62
  homepage: https://github.com/tobyond/ordit
data/lib/ordit/auditor.rb DELETED
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ordit
4
- class Auditor
5
- def self.run
6
- new.run
7
- end
8
-
9
- def run
10
- ResultGenerator.new(
11
- defined_controllers:,
12
- used_controllers:,
13
- controller_locations:,
14
- usage_locations:
15
- )
16
- end
17
-
18
- private
19
-
20
- def config
21
- @config ||= Ordit.configuration
22
- end
23
-
24
- def defined_controllers
25
- config.controller_paths.each_with_object(Set.new) do |path, controllers|
26
- Dir.glob(path.to_s).each do |file|
27
- # Extract relative path from controllers directory
28
- full_path = Pathname.new(file)
29
- controllers_dir = full_path.each_filename.find_index("controllers")
30
-
31
- next unless controllers_dir
32
-
33
- # Get path components after 'controllers'
34
- controller_path = full_path.each_filename.to_a[(controllers_dir + 1)..]
35
- next unless controller_path[-1].include?('_controller')
36
-
37
- # Remove _controller.js from the last component
38
- controller_path[-1] = controller_path[-1].sub(/_controller\.(js|ts)$/, "")
39
- # Join with -- for namespacing and convert underscores to hyphens
40
- name = controller_path.join("--").gsub("_", "-")
41
- controllers << name
42
- end
43
- end
44
- end
45
-
46
- def used_controllers
47
- config.view_paths.each_with_object(Set.new) do |path, controllers|
48
- Dir.glob(path.to_s).each do |file|
49
- content = File.read(file)
50
- patterns.each do |pattern|
51
- content.scan(pattern) do |match|
52
- # Split in case of multiple controllers
53
- match[0].split(/\s+/).each do |controller|
54
- # Store controller names exactly as they appear in the view
55
- # (they should already have hyphens as per Stimulus conventions)
56
- controllers << controller
57
- end
58
- end
59
- end
60
- end
61
- end
62
- end
63
-
64
- def controller_locations
65
- config.controller_paths.each_with_object({}) do |path_pattern, locations|
66
- Dir.glob(path_pattern).each do |file|
67
- relative_path = Pathname.new(file).relative_path_from(Dir.pwd)
68
- controller_path = relative_path.to_s.gsub(%r{^app/javascript/controllers/|_controller\.(js|ts)$}, "")
69
- name = controller_path.gsub("/", "--")
70
- locations[name] = relative_path
71
- end
72
- end
73
- end
74
-
75
- def usage_locations
76
- config.view_paths.each_with_object(Hash.new { |h, k| h[k] = {} }) do |path_pattern, locations|
77
- Dir.glob(path_pattern).each do |file|
78
- File.readlines(file).each_with_index do |line, index|
79
- patterns.each do |pattern|
80
- line.scan(pattern) do |match|
81
- match[0].split(/\s+/).each do |controller|
82
- relative_path = Pathname.new(file).relative_path_from(Dir.pwd)
83
- locations[controller][relative_path] ||= []
84
- locations[controller][relative_path] << index + 1
85
- end
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end
92
-
93
- def patterns
94
- @patterns ||= [
95
- /data-controller=["']([^"']+)["']/, # HTML attribute syntax
96
- # Ruby 1.9+ hash syntax - covers both with and without symbol prefix
97
- /data:\s*{(?:[^}]*\s)?(?::)?controller:\s*["']([^"']+)["']/,
98
- # Hash rocket syntax - covers both with and without symbol prefix
99
- /data:\s*{(?:[^}]*\s)?(?::)?controller\s*=>\s*["']([^"']+)["']/
100
- ]
101
- end
102
- end
103
- end
@@ -1,67 +0,0 @@
1
- module Ordit
2
- class ResultGenerator
3
- attr_reader :defined_controllers, :used_controllers,
4
- :controller_locations, :usage_locations
5
-
6
- def initialize(defined_controllers:, used_controllers:,
7
- controller_locations:, usage_locations:)
8
- @defined_controllers = defined_controllers
9
- @used_controllers = used_controllers
10
- @controller_locations = controller_locations
11
- @usage_locations = usage_locations
12
- end
13
-
14
- def unused_controllers
15
- defined_controllers - used_controllers
16
- end
17
-
18
- def undefined_controllers
19
- used_controllers - defined_controllers
20
- end
21
-
22
- def active_controllers
23
- defined_controllers & used_controllers
24
- end
25
-
26
- def to_console
27
- puts "\nšŸ“Š Stimulus Controller Audit\n"
28
-
29
- if unused_controllers.any?
30
- puts "\nāŒ Defined but unused controllers:"
31
- unused_controllers.sort.each do |controller|
32
- puts " #{controller}"
33
- puts " ā””ā”€ #{controller_locations[controller]}"
34
- end
35
- end
36
-
37
- if undefined_controllers.any?
38
- puts "\nāš ļø Used but undefined controllers:"
39
- undefined_controllers.sort.each do |controller|
40
- puts " #{controller}"
41
- usage_locations[controller].each do |file, lines|
42
- puts " ā””ā”€ #{file} (lines: #{lines.join(", ")})"
43
- end
44
- end
45
- end
46
-
47
- if active_controllers.any?
48
- puts "\nāœ… Active controllers:"
49
- active_controllers.sort.each do |controller|
50
- puts " #{controller}"
51
- puts " ā””ā”€ Defined in: #{controller_locations[controller]}"
52
- puts " ā””ā”€ Used in:"
53
- usage_locations[controller].each do |file, lines|
54
- puts " ā””ā”€ #{file} (lines: #{lines.join(", ")})"
55
- end
56
- end
57
- end
58
-
59
- puts "\nšŸ“ˆ Summary:"
60
- puts " Total controllers defined: #{defined_controllers.size}"
61
- puts " Total controllers in use: #{used_controllers.size}"
62
- puts " Unused controllers: #{unused_controllers.size}"
63
- puts " Undefined controllers: #{undefined_controllers.size}"
64
- puts " Properly paired: #{active_controllers.size}"
65
- end
66
- end
67
- end
data/lib/ordit/scanner.rb DELETED
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ordit
4
- class Scanner
5
- def self.run(controller)
6
- new(controller).run
7
- end
8
-
9
- attr_reader :controller
10
-
11
- def initialize(controller)
12
- @controller = controller
13
- end
14
-
15
- def run
16
- print
17
- end
18
-
19
- def results
20
- config.view_paths.each_with_object([]) do |path, matches|
21
- Dir.glob(path.to_s).each do |file|
22
- content = File.readlines(file)
23
- content.each_with_index do |line, index|
24
- next unless patterns.any? { |pattern| line.match?(pattern) }
25
-
26
- matches << {
27
- file: Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd)),
28
- line_number: index + 1,
29
- content: line.strip
30
- }
31
- end
32
- end
33
- end
34
- end
35
-
36
- private
37
-
38
- def config
39
- @config ||= Ordit.configuration
40
- end
41
-
42
- def patterns
43
- @patterns ||= [
44
- /data-controller=["'](?:[^"']*\s)?#{Regexp.escape(controller)}(?:\s[^"']*)?["']/, # HTML attribute
45
- /data:\s*{\s*(?:controller:|:controller\s*=>)\s*["'](?:[^"']*\s)?#{Regexp.escape(controller)}(?:\s[^"']*)?["']/ # Both hash syntaxes
46
- ]
47
- end
48
-
49
- def print
50
- puts "\nSearching for stimulus controller: '#{controller}'\n\n"
51
-
52
- if results.empty?
53
- puts "No matches found."
54
- return
55
- end
56
-
57
- current_file = nil
58
- results.each do |match|
59
- if current_file != match[:file]
60
- puts "šŸ“ #{match[:file]}"
61
- current_file = match[:file]
62
- end
63
- puts " Line #{match[:line_number]}:"
64
- puts " #{match[:content]}\n\n"
65
- end
66
- end
67
- end
68
- end