rubocop-katalyst 3.0.1 → 3.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +3 -1
- data/config/default.yml +1 -0
- data/config/rubocop-koi.yml +17 -0
- data/lib/rubocop/cop/katalyst_cops.rb +3 -0
- data/lib/rubocop/cop/koi/table_link_heading.rb +145 -0
- data/lib/rubocop/katalyst.rb +2 -0
- metadata +5 -3
- data/package.json +0 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 408d4a24b9d76524197c2d2773434353c0a90752578516322fbf78731d13839e
|
|
4
|
+
data.tar.gz: cc011b88f7a8798268c95a79da2ed7c1a7fa0da56b323e11735ff9ca1af22cce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 44dd1cab9b0424474fbaf1829d9279d6ae43e6e9a375b6f15f66ada55c5deaa7df66b306c79a2bc6769754797d0bbbd41d6942614c1efe93806e6f96f949f56b
|
|
7
|
+
data.tar.gz: 1cf92f1bf724c885a5bbaf4773c42d2bd9a33bcdd3f3f21edf6c0353953084c286e66976aa946bd5ef61f8753b8fc0eafab8ea9d5cf5873d28e7ebda52228a8c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## [3.1.0] - 2026-08-14
|
|
2
|
+
|
|
3
|
+
- Add Koi department for custom cops specific to katalyst-koi projects,
|
|
4
|
+
configured in `config/rubocop-koi.yml` and applied to admin views via erb_lint
|
|
5
|
+
- Add Koi/TableLinkHeading cop: tables in admin index/archived views and row
|
|
6
|
+
partials should link to the record once, from the column that identifies
|
|
7
|
+
it. A single record link must be marked `heading: true` (autocorrectable);
|
|
8
|
+
additional links should use `text`, or `heading: false` when intentional
|
|
9
|
+
- Run tests and linting in CI via `bin/ci`
|
|
10
|
+
- Remove prettier/yarn from this repository and stop shipping `package.json`
|
|
11
|
+
in the gem — nothing consumed it, and downstream `PrettierTask` installs
|
|
12
|
+
prettier in the host project itself
|
|
13
|
+
|
|
1
14
|
## [3.0.0] - 2026-05-21
|
|
2
15
|
|
|
3
16
|
- Update Ruby minimum version and syntax to 4.0
|
data/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# Rubocop::Katalyst
|
|
2
2
|
|
|
3
|
-
[Katalyst's](https://katalyst.com.au) style guide for Ruby and Rails, in gem form.
|
|
3
|
+
[Katalyst's](https://katalyst.com.au) style guide for Ruby and Rails, in gem form. This is a repository for our configuration of the standard cops with Rails, Rake, Performance and RSpec extensions, plus our own custom cops.
|
|
4
4
|
|
|
5
5
|
Cops are broken down by department; a file corresponding to each department can be found in the `config` directory, as well as the `default.yml` file which contains any global configuration and loads the cops. The `.rubocop.yml` file contains the configuration for this particular project as a guide for use in non-Rails environments.
|
|
6
6
|
|
|
7
|
+
Custom cops in the `Koi` department apply to projects built on [katalyst-koi](https://github.com/katalyst/koi). They target admin views, which plain RuboCop does not inspect — they take effect when RuboCop runs through [erb_lint](https://github.com/Shopify/erb_lint) (`rake erb_lint`), which lints the Ruby inside ERB templates. If your `.erb_lint.yml` restricts the RuboCop linter with an `only:` list, add the `Koi` cops to that list.
|
|
8
|
+
|
|
7
9
|
## Installation
|
|
8
10
|
|
|
9
11
|
Add this line to your application's Gemfile:
|
data/config/default.yml
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Custom cops for projects built on Koi (katalyst-koi).
|
|
2
|
+
#
|
|
3
|
+
# These cops target admin views, which are only linted when RuboCop runs
|
|
4
|
+
# through erb_lint, so they take effect via `rake erb_lint`.
|
|
5
|
+
Koi:
|
|
6
|
+
Enabled: true
|
|
7
|
+
|
|
8
|
+
Koi/TableLinkHeading:
|
|
9
|
+
Description: "Tables should have a single record link, rendered as the row heading."
|
|
10
|
+
Enabled: true
|
|
11
|
+
Safe: true
|
|
12
|
+
SafeAutoCorrect: false
|
|
13
|
+
VersionAdded: "3.1"
|
|
14
|
+
Include:
|
|
15
|
+
- "**/app/views/admin/**/index.html.erb"
|
|
16
|
+
- "**/app/views/admin/**/archived.html.erb"
|
|
17
|
+
- "**/app/views/admin/**/*.html+row.erb"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Koi
|
|
6
|
+
# Koi admin tables should link to each record exactly once, from the
|
|
7
|
+
# column that identifies the record, and that link should render as a
|
|
8
|
+
# row heading (`th`) for accessibility.
|
|
9
|
+
#
|
|
10
|
+
# When a table renders a single record link, mark it as the row heading
|
|
11
|
+
# with `heading: true` (autocorrectable). When a table renders more
|
|
12
|
+
# than one record link, the extra columns should use `text` instead;
|
|
13
|
+
# `heading: false` documents an intentional exception. Links that
|
|
14
|
+
# override `url:` are not record links, so they are ignored, as are
|
|
15
|
+
# links that forward options (`**options`).
|
|
16
|
+
#
|
|
17
|
+
# erb_lint feeds RuboCop one ERB tag at a time, so the fragment being
|
|
18
|
+
# inspected is not enough context to count links. When linting a view,
|
|
19
|
+
# this cop reads the whole file from disk and counts record links
|
|
20
|
+
# across all of its ERB tags. Outside a view file it counts links in
|
|
21
|
+
# the current source. Counting is per file, so a view that renders two
|
|
22
|
+
# tables is treated as one.
|
|
23
|
+
#
|
|
24
|
+
# This cop only takes effect through erb_lint: plain `rubocop` does not
|
|
25
|
+
# inspect `.erb` files, and the `Include` configuration restricts it to
|
|
26
|
+
# Koi admin views.
|
|
27
|
+
#
|
|
28
|
+
# @example
|
|
29
|
+
# # bad
|
|
30
|
+
# row.link(:name)
|
|
31
|
+
#
|
|
32
|
+
# # good
|
|
33
|
+
# row.link(:name, heading: true)
|
|
34
|
+
#
|
|
35
|
+
# # good - not a record link
|
|
36
|
+
# row.link(:name, url: :edit_admin_page_path)
|
|
37
|
+
#
|
|
38
|
+
# # good - intentional extra link
|
|
39
|
+
# row.link(:name, heading: true)
|
|
40
|
+
# row.link(:homepage, heading: false)
|
|
41
|
+
class TableLinkHeading < Base
|
|
42
|
+
extend AutoCorrector
|
|
43
|
+
|
|
44
|
+
MSG_HEADING = "The record link should be the row heading; add `heading: true`."
|
|
45
|
+
MSG_EXTRA = "Tables should link to the record once, from the column that identifies it. " \
|
|
46
|
+
"Use `text` instead, or `heading: false` to keep an intentional extra link."
|
|
47
|
+
|
|
48
|
+
RESTRICT_ON_SEND = %i[link].freeze
|
|
49
|
+
|
|
50
|
+
# How erb_lint trims trailing block expressions from ERB tags, copied
|
|
51
|
+
# from Rails: action_view/template/handlers/erb/erubi.rb
|
|
52
|
+
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
|
53
|
+
|
|
54
|
+
ERB_TAG = /<%(?:(?!%>).)*%>/m
|
|
55
|
+
|
|
56
|
+
# @!method row_link?(node)
|
|
57
|
+
def_node_matcher :row_link?, <<~PATTERN
|
|
58
|
+
(send {(send nil? :row) (lvar :row)} :link _ ...)
|
|
59
|
+
PATTERN
|
|
60
|
+
|
|
61
|
+
def on_new_investigation
|
|
62
|
+
super
|
|
63
|
+
@record_link_count = nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def on_send(node)
|
|
67
|
+
return unless row_link?(node)
|
|
68
|
+
|
|
69
|
+
options = options(node)
|
|
70
|
+
return if options && explicit_options?(options)
|
|
71
|
+
|
|
72
|
+
anchor = node.arguments.reject(&:block_pass_type?).last
|
|
73
|
+
return unless anchor
|
|
74
|
+
|
|
75
|
+
if record_link_count > 1
|
|
76
|
+
add_offense(node, message: MSG_EXTRA)
|
|
77
|
+
else
|
|
78
|
+
add_offense(node, message: MSG_HEADING) do |corrector|
|
|
79
|
+
corrector.insert_after(anchor, ", heading: true")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def options(node)
|
|
87
|
+
arg = node.arguments.reject(&:block_pass_type?).last
|
|
88
|
+
arg if arg&.hash_type?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Skip if heading is already set, options are forwarded (splat), or
|
|
92
|
+
# the link is not a record link (url override).
|
|
93
|
+
def explicit_options?(options)
|
|
94
|
+
options.children.any?(&:kwsplat_type?) ||
|
|
95
|
+
options.pairs.any? { |pair| pair.key.sym_type? && %i[heading url].include?(pair.key.value) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# A `row.link` renders a record link unless it overrides `url:`.
|
|
99
|
+
# Links that forward options are indeterminate, so they don't count.
|
|
100
|
+
def record_link?(node)
|
|
101
|
+
return false unless row_link?(node)
|
|
102
|
+
|
|
103
|
+
options = options(node)
|
|
104
|
+
return true if options.nil?
|
|
105
|
+
|
|
106
|
+
options.children.none?(&:kwsplat_type?) &&
|
|
107
|
+
options.pairs.none? { |pair| pair.key.sym_type? && pair.key.value == :url }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def record_link_count
|
|
111
|
+
@record_link_count ||= if (source = view_source)
|
|
112
|
+
count_record_links_in_erb(source)
|
|
113
|
+
else
|
|
114
|
+
count_record_links(processed_source.ast)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def view_source
|
|
119
|
+
path = processed_source.file_path
|
|
120
|
+
|
|
121
|
+
File.read(path) if path&.end_with?(".erb") && File.file?(path)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def count_record_links_in_erb(source)
|
|
125
|
+
source.scan(ERB_TAG).sum do |tag|
|
|
126
|
+
next 0 if tag.start_with?("<%#")
|
|
127
|
+
|
|
128
|
+
code = tag.sub(/\A<%[=-]*/, "").sub(/-?%>\z/, "").sub(BLOCK_EXPR, "")
|
|
129
|
+
count_record_links(parse_fragment(code))
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def count_record_links(ast)
|
|
134
|
+
return 0 if ast.nil?
|
|
135
|
+
|
|
136
|
+
ast.each_node(:send).count { |node| record_link?(node) }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def parse_fragment(code)
|
|
140
|
+
ProcessedSource.new(code, processed_source.ruby_version).ast
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
data/lib/rubocop/katalyst.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-katalyst
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Katalyst Interactive
|
|
@@ -148,6 +148,7 @@ files:
|
|
|
148
148
|
- config/default.yml
|
|
149
149
|
- config/rubocop-bundler.yml
|
|
150
150
|
- config/rubocop-gemspec.yml
|
|
151
|
+
- config/rubocop-koi.yml
|
|
151
152
|
- config/rubocop-layout.yml
|
|
152
153
|
- config/rubocop-lint.yml
|
|
153
154
|
- config/rubocop-metrics.yml
|
|
@@ -158,12 +159,13 @@ files:
|
|
|
158
159
|
- config/rubocop-rspec.yml
|
|
159
160
|
- config/rubocop-security.yml
|
|
160
161
|
- config/rubocop-style.yml
|
|
162
|
+
- lib/rubocop/cop/katalyst_cops.rb
|
|
163
|
+
- lib/rubocop/cop/koi/table_link_heading.rb
|
|
161
164
|
- lib/rubocop/katalyst.rb
|
|
162
165
|
- lib/rubocop/katalyst/erb_lint_task.rb
|
|
163
166
|
- lib/rubocop/katalyst/prettier_task.rb
|
|
164
167
|
- lib/rubocop/katalyst/rake_task.rb
|
|
165
168
|
- lib/tasks/erb_lint.rake
|
|
166
|
-
- package.json
|
|
167
169
|
homepage: https://github.com/katalyst/rubocop-katalyst
|
|
168
170
|
licenses:
|
|
169
171
|
- MIT
|
|
@@ -185,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
185
187
|
- !ruby/object:Gem::Version
|
|
186
188
|
version: '0'
|
|
187
189
|
requirements: []
|
|
188
|
-
rubygems_version: 4.0.
|
|
190
|
+
rubygems_version: 4.0.16
|
|
189
191
|
specification_version: 4
|
|
190
192
|
summary: Code standards for Katalyst
|
|
191
193
|
test_files: []
|
data/package.json
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"private": true,
|
|
3
|
-
"scripts": {
|
|
4
|
-
"lint": "prettier --check *.json app/assets/javascripts app/assets/stylesheets",
|
|
5
|
-
"autocorrect": "prettier --write *.json app/assets/javascripts app/assets/stylesheets"
|
|
6
|
-
},
|
|
7
|
-
"devDependencies": {
|
|
8
|
-
"prettier": "3.8.3"
|
|
9
|
-
}
|
|
10
|
-
}
|