Class: Rigor::ModuleGraph::CLI::RigorRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/module_graph/cli.rb

Overview

Encapsulates the actual ‘rigor check –format json` shell-out and the diagnostic → Edge / Node transformation. Reused by both `Collect` (write JSONL) and `View` (render HTML).

Instance Method Summary collapse

Constructor Details

#initialize(rigor_cmd: ENV.fetch("RIGOR_CMD", "rigor"), cache: false) ⇒ RigorRunner

Returns a new instance of RigorRunner.



161
162
163
164
# File 'lib/rigor/module_graph/cli.rb', line 161

def initialize(rigor_cmd: ENV.fetch("RIGOR_CMD", "rigor"), cache: false)
  @rigor_cmd = rigor_cmd
  @cache = cache
end

Instance Method Details

#analyse(paths) ⇒ Object

Returns both edges and nodes from one rigor invocation.



172
173
174
175
# File 'lib/rigor/module_graph/cli.rb', line 172

def analyse(paths)
  diagnostics = run_rigor(paths)
  [diagnostics_to_edges(diagnostics), diagnostics_to_nodes(diagnostics)]
end

#diagnostics_to_edges(diagnostics) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rigor/module_graph/cli.rb', line 202

def diagnostics_to_edges(diagnostics)
  diagnostics.filter_map do |row|
    next unless row["rule"] == EDGE_RULE
    next unless row["source_family"] == SOURCE_FAMILY

    payload = JSON.parse(row.fetch("message"))
    Edge.build(
      from: payload.fetch("from"),
      to: payload.fetch("to"),
      kind: payload.fetch("kind"),
      path: row["path"],
      line: row["line"],
      column: row["column"],
      confidence: payload.fetch("confidence", "syntax"),
      raw: payload["raw"]
    )
  rescue JSON::ParserError, KeyError
    nil
  end
end

#diagnostics_to_nodes(diagnostics) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/rigor/module_graph/cli.rb', line 223

def diagnostics_to_nodes(diagnostics)
  diagnostics.filter_map do |row|
    next unless row["rule"] == NODE_RULE
    next unless row["source_family"] == SOURCE_FAMILY

    payload = JSON.parse(row.fetch("message"))
    Node.build(
      kind: payload.fetch("kind"),
      name: payload.fetch("name"),
      owner: payload["owner"],
      path: row["path"],
      line: row["line"],
      column: row["column"],
      visibility: payload["visibility"],
      access: payload["access"]
    )
  rescue JSON::ParserError, KeyError
    nil
  end
end

#edges_for(paths) ⇒ Object



166
167
168
169
# File 'lib/rigor/module_graph/cli.rb', line 166

def edges_for(paths)
  diagnostics = run_rigor(paths)
  diagnostics_to_edges(diagnostics)
end

#run_rigor(paths) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rigor/module_graph/cli.rb', line 177

def run_rigor(paths)
  cmd = [@rigor_cmd, "check", "--format", "json"]
  cmd << (@cache ? "--cache" : "--no-cache")
  cmd << "--no-stats"
  cmd.concat(paths) unless paths.empty?

  stdout_str, stderr_str, status = Open3.capture3(*cmd)
  unless status.success?
    # `rigor check` exits non-zero when it finds any error
    # diagnostic — our edges live inside that same output,
    # so we still parse the JSON. We only escalate when no
    # JSON was emitted at all (e.g. binary missing).
    if stdout_str.empty?
      raise CollectError, "rigor exited #{status.exitstatus} with no output\n#{stderr_str}"
    end
  end
  payload = JSON.parse(stdout_str)
  payload.fetch("diagnostics", [])
rescue Errno::ENOENT
  raise CollectError, "rigor binary not found: #{cmd.first.inspect}. " \
                      "Install rigortype or set RIGOR_CMD."
rescue JSON::ParserError => e
  raise CollectError, "rigor produced invalid JSON: #{e.message}\n#{stdout_str}"
end