ordit 0.1.2 ā†’ 0.1.4

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: 85359a41eabc4eca9dd38bf08749860a980e7eb3a4f31c4e1550243a141fa14a
4
+ data.tar.gz: c2fb171d7a685aa3180c00fa3aee02af58d265f53e35d7d1eca7ca66bd33a3a3
5
5
  SHA512:
6
- metadata.gz: 980a3d0f8ba5d373577b55594350962f784775de06f2c0b288271929a71a68998799fc60b1611293a68ce15102168923377d0dccde9699f2348775c5cf4dc180
7
- data.tar.gz: 3e83e18491bb40508a8f65a8210b29e1c31e94c4e87c67c64c033ed5a3682768c39cae36c794363d37a8d2bdb3f3a457e161a52001584e0b1eabd8349891a0cc
6
+ metadata.gz: 8366966cf1d4fed14fe17580e926d01e0f2f2450f4499b7fd724cda766cdf774cd0edd4203a418c9f7fc6445082366604cd32284372af70324988c24a91eefe8
7
+ data.tar.gz: 1d9af5057943c712b64116749d069cd8a737ae0a0338e32e8a7e11037b1b35a5701afc40a530fe82b768c22cc77196e21557cb44b312e8a16dc1948622843ab3
data/CHANGELOG.md CHANGED
@@ -1,10 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.4] - 2024-16-12
4
+
5
+ - remove scan, your editor does this already
6
+
7
+ ## [0.1.3] - 2024-16-12
8
+
9
+ - more refactor, clean up, make more logical
10
+
3
11
  ## [0.1.2] - 2024-12-12
4
12
 
5
13
  - refactor, clean up
6
14
 
7
-
8
15
  ## [0.1.1] - 2024-12-12
9
16
 
10
17
  - Fix namespace issue in rake task
data/README.md CHANGED
@@ -17,7 +17,7 @@ bundle install
17
17
 
18
18
  ## Usage
19
19
 
20
- ### Audit All Controllers
20
+ ### Audit Stimulus Controllers
21
21
 
22
22
  Run an audit to see all defined and used controllers in your application:
23
23
 
@@ -28,41 +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)
52
- ```
53
-
54
- ### Scan for Specific Controller Usage
55
-
56
- Find all uses of a specific controller:
57
-
58
- ```bash
59
- rails ordit:scan[controller_name]
60
- ```
42
+ missing-controller
43
+ ā””ā”€ šŸ“ app/views/products/show.html.erb
44
+ šŸ“ app/views/users/edit.html.erb
61
45
 
62
- Example:
63
- ```bash
64
- rails ordit:scan[products]
65
- rails ordit:scan[users--name] # For namespaced controllers
66
46
  ```
67
47
 
68
48
  ### Configuration
@@ -98,6 +78,9 @@ end
98
78
 
99
79
  # Hash rocket syntax
100
80
  <%= f.submit 'Save', data: { :controller => 'products' } %>
81
+
82
+ # Hash rocket string syntax
83
+ <%= f.submit 'Save', 'data' => { 'controller' => 'products' } %>
101
84
  ```
102
85
  - Scans ERB, HTML, and HAML files
103
86
  - Works with both JavaScript and TypeScript controller files
@@ -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,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module Ordit
6
+ class ConsoleOutput
7
+ extend Forwardable
8
+
9
+ def self.run
10
+ new.run
11
+ end
12
+
13
+ def_delegators :@results,
14
+ :files, :active_controllers, :undefined_controllers, :unused_controllers
15
+
16
+ def initialize
17
+ @results = Results.new
18
+ end
19
+
20
+ def run
21
+ print_audit
22
+ end
23
+
24
+ def print_audit
25
+ puts "\nšŸ“Š Stimulus Controller Audit\n"
26
+
27
+ if unused_controllers.any?
28
+ puts "\nāŒ Controllers not defined in any views:"
29
+ unused_controllers.sort.each do |controller|
30
+ puts " #{controller}"
31
+ end
32
+ end
33
+
34
+ if undefined_controllers.any?
35
+ puts "\nāš ļø View with defined but missing controller:"
36
+ undefined_controllers.each do |controller, files|
37
+ puts "\n #{controller}_controller"
38
+
39
+ files.each_with_index do |file, index|
40
+ puts " #{ index.zero? ? 'ā””ā”€' : ' ' } šŸ“ #{file}"
41
+ end
42
+ end
43
+ end
44
+
45
+ puts "\nšŸ“ˆ Summary:"
46
+ puts " Total controllers defined: #{files.size}"
47
+ puts " Total controllers in use: #{active_controllers.size}"
48
+ puts " Unused controllers: #{unused_controllers.size}"
49
+ puts " Undefined controllers: #{undefined_controllers.size}"
50
+ end
51
+ end
52
+ 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,23 @@
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
+ end
23
+ 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,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ordit
4
+ class Results
5
+ def initialize
6
+ end
7
+
8
+ def files
9
+ Files.all
10
+ end
11
+
12
+ def definitions
13
+ Definitions.all
14
+ end
15
+
16
+ def active_controllers = to_h[:active_controllers].sort
17
+ def undefined_controllers = to_h[:undefined_controllers]
18
+ def unused_controllers = to_h[:unused_controllers].sort
19
+
20
+ def to_h
21
+ @to_h ||= begin
22
+ base_object = {
23
+ active_controllers: [],
24
+ undefined_controllers: {},
25
+ unused_controllers: files.dup || []
26
+ }
27
+
28
+
29
+ definitions.each_with_object(base_object) do |(definition, file), result|
30
+ # Convert definition pattern to match file pattern
31
+ file_pattern = definition_to_file_pattern(definition)
32
+
33
+ # Find matching file
34
+ matching_file = files.find { |f| file_pattern == file_pattern_from_path(f) }
35
+
36
+ if matching_file
37
+ result[:active_controllers] << matching_file
38
+ result[:unused_controllers].delete(matching_file)
39
+ result[:active_controllers].sort!
40
+ else
41
+ result[:undefined_controllers][definition] ||= []
42
+ result[:undefined_controllers][definition] |= file
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def definition_to_file_pattern(definition)
51
+ # Handle nested paths (double hyphen becomes directory separator)
52
+ path_parts = definition.split("--")
53
+
54
+ # Convert each part from kebab-case to snake_case
55
+ path_parts = path_parts.map { |part| part.gsub("-", "_") }
56
+
57
+ # Join with directory separator
58
+ path_parts.join("/")
59
+ end
60
+
61
+ def file_pattern_from_path(file)
62
+ # Remove _controller.js suffix and return the pattern
63
+ file.sub(/_controller\.(js|ts)$/, "")
64
+ end
65
+ end
66
+ 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.4"
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,18 +3,6 @@
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
7
- end
8
-
9
- desc "Scan files for stimulus controller usage (e.g., rake audit:scan[products])"
10
- task :scan, [:controller] => :environment do |_, args|
11
- controller = args[:controller]
12
-
13
- if controller.nil? || controller.empty?
14
- puts "Please provide a controller name: rake ordit:scan[controller_name]"
15
- next
16
- end
17
-
18
- Ordit::Scanner.run(controller)
6
+ Ordit::ConsoleOutput.run
19
7
  end
20
8
  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.4
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-18 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