Class: HakumiComponents::FileSizeChecker

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/hakumi_components/file_size_checker.rb

Defined Under Namespace

Classes: Finding, Rule

Constant Summary collapse

REPO_ROOT =
T.let(Pathname.new(__dir__).join("../..").expand_path, Pathname)
DEFAULT_RULES =
T.let([
  Rule.new(
    name: "Ruby component",
    pattern: "app/components/hakumi_components/**/component.rb",
    threshold: 500
  ),
  Rule.new(
    name: "Hakumi Stimulus controller",
    pattern: "app/javascript/hakumi_components/controllers/hakumi/*_controller.js",
    threshold: 700
  )
].freeze, T::Array[Rule])
EXCEPTIONS_PATH =
T.let(Pathname.new("docs/file_size_exceptions.yml"), Pathname)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root: REPO_ROOT, rules: DEFAULT_RULES, approved_exceptions: nil) ⇒ FileSizeChecker

Returns a new instance of FileSizeChecker.



108
109
110
111
112
113
# File 'lib/hakumi_components/file_size_checker.rb', line 108

def initialize(root: REPO_ROOT, rules: DEFAULT_RULES, approved_exceptions: nil)
  @root = T.let(root, Pathname)
  @rules = T.let(rules, T::Array[Rule])
  @approved_exceptions = T.let(approved_exceptions || self.class.load_approved_exceptions(root: root),
    T::Hash[String, Integer])
end

Class Method Details

.load_approved_exceptions(root: REPO_ROOT) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/hakumi_components/file_size_checker.rb', line 78

def self.load_approved_exceptions(root: REPO_ROOT)
  path = root.join(EXCEPTIONS_PATH)
  return {} unless path.exist?

  data = YAML.safe_load(path.read, aliases: false) || {}
  exceptions = T.let({}, T::Hash[String, Integer])

  T.cast(data, T::Hash[String, T.untyped]).each_value do |entries|
    next unless entries.is_a?(Hash)

    entries.each do |relative_path, config|
      next unless config.is_a?(Hash)

      baseline = config["baseline_lines"]
      next if baseline.nil?

      exceptions[relative_path.to_s] = Integer(baseline)
    end
  end

  exceptions
end

Instance Method Details

#findingsObject



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/hakumi_components/file_size_checker.rb', line 116

def findings
  @rules.flat_map do |rule|
    matching_paths(rule).filter_map do |path|
      lines = line_count(path)
      next if lines <= rule.threshold

      relative_path = relative_path_for(path)
      Finding.new(
        rule_name: rule.name,
        path: relative_path,
        lines: lines,
        threshold: rule.threshold,
        approved_limit: @approved_exceptions[relative_path]
      )
    end
  end.sort_by { |finding| [ finding.rule_name, finding.path ] }
end

#report(strict: false) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/hakumi_components/file_size_checker.rb', line 145

def report(strict: false)
  current_findings = findings

  lines = []
  lines << "File size guardrail#{strict ? ' (strict)' : ' (warning-only)'}"
  lines << ""
  lines << "Thresholds:"
  @rules.each do |rule|
    lines << "- #{rule.name}: #{rule.threshold} lines (#{rule.pattern})"
  end
  lines << ""

  if current_findings.empty?
    lines << "All tracked files are within their thresholds."
    return lines.join("\n")
  end

  approved, actionable = current_findings.partition(&:approved?)

  unless approved.empty?
    lines << "Approved exceptions:"
    approved.each do |finding|
      lines << format_finding(finding)
    end
    lines << ""
  end

  unless actionable.empty?
    lines << "Actionable overages:"
    actionable.each do |finding|
      lines << format_finding(finding)
    end
    lines << ""
  end

  unless strict
    lines << "This check is currently non-blocking. Run `bin/check-file-sizes --strict` to fail on actionable overages."
  end

  lines.join("\n").strip
end

#success?(strict: false) ⇒ Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/hakumi_components/file_size_checker.rb', line 140

def success?(strict: false)
  !strict || violations.empty?
end

#violationsObject



135
136
137
# File 'lib/hakumi_components/file_size_checker.rb', line 135

def violations
  findings.select(&:violation?)
end