rigor-module-graph 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cea3ca68d705ecbe0f3534c5b3374e7e1dfd0f01edb6a0b9e64ed4c775cb166d
4
- data.tar.gz: 70d09cd49d66f118948f2ec142d4f7a6c068a6ce098cddf97b3dd7d997a507d9
3
+ metadata.gz: 0ed5f8fe6226376ad089b013b8ad16cecc453da2202cbaf6b3a590e6b64d0c85
4
+ data.tar.gz: 47bdbc75a44a9887a58246783fcc3f57b5f1ad119b3c336c6673e72799678fe2
5
5
  SHA512:
6
- metadata.gz: 5fec0afc7142600d308187afb293484818e545e63d5e21c08221412e0bcbca98db5cbf6e1e30c3b45ad46a30459779dcfe816459b9009494c5fbd4d0265a0dea
7
- data.tar.gz: 1795a811ff1b184945dc55fb6a5451d09f895b85b778d1d98145f5fae2ad5f5aa0822dbafed51fad143ae3c32a8b75a5f3beec55cefdd3e9164658aa6e25e019
6
+ metadata.gz: ae0a36d5c2107420b5a3577a2030c5417789f52ed0732f5d67669ac31444e73131135273d067e7f3fb6dfd7cafde845a7ef5183f4abd414bfae8ff446688d68d
7
+ data.tar.gz: 43ad7597db1d1fd945159afb81ee36339450b2ffa487bd94d21fc0da8ed0ae044af02a5b6c482044b510ee1ce0df56c2e215f72707307c8aef803ff0a9eab42e
data/CHANGELOG.md CHANGED
@@ -17,6 +17,83 @@ Categories:
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.1.3] — 2026-06-20
21
+
22
+ The first release that pairs the published gem with the
23
+ [interactive viewer](docs/how-it-works.md) the README has been
24
+ showcasing, plus the supply-chain hardening that justifies
25
+ shipping a vendored third-party JS file inside the gem.
26
+
27
+ ### Added
28
+
29
+ - **Interactive `view --output html` viewer.** Replaces the
30
+ static Mermaid embed with a [Cytoscape.js](https://js.cytoscape.org/)-based
31
+ page that renders 5k+ nodes, filters live by `kind` /
32
+ `confidence`, supports a name-substring search, and copies
33
+ `path:line` to the clipboard on node click. The Cytoscape
34
+ library is vendored into the gem at a sha256-pinned version
35
+ (`lib/rigor/module_graph/templates/vendor/cytoscape.min.js`);
36
+ no CDN, no npm, no Dependabot auto-bump.
37
+ See [`docs/plan.md`](docs/plan.md) "2D interactive viewer"
38
+ for the supply-chain rationale.
39
+ - `--path-mode {relative,absolute,none}` flag on `view` —
40
+ controls how node paths reach the viewer's click-through
41
+ metadata. `none` strips paths from the HTML artefact, which
42
+ is the right setting when sharing the file outside the
43
+ project (PR comment, gist, …).
44
+ - `--open-with vscode` flag on `view` — flips the node-click
45
+ action from clipboard copy to `vscode://file/<path>:<line>`
46
+ so the editor jumps straight to the source location.
47
+ - `bundle exec rake vendor:verify` task — recomputes sha256
48
+ for every file in `vendor/CHECKSUMS` and fails on mismatch.
49
+ Wired into pre-commit on any staged file under
50
+ `lib/**/templates/vendor/**`.
51
+ - `.github/dependabot.yml` — weekly Bundler + GitHub Actions
52
+ bumps; `vendor/**` is explicitly excluded so vendored
53
+ third-party JS never auto-updates.
54
+ - `bundle exec rake vendor:audit` — 4-source cross-check
55
+ (local sha256 / npm tarball `dist.integrity` /
56
+ tarball-internal copy / GitHub raw / every CDN). Reads
57
+ `lib/rigor/module_graph/templates/vendor/MANIFEST.yml` for
58
+ the provenance metadata. Use on bump PRs; not part of the
59
+ regular CI pipeline (network-using).
60
+ - CI now runs `rake vendor:verify` independently of
61
+ pre-commit so an unaudited bump can't land on `main` even
62
+ if local hooks were skipped.
63
+ - CI now regenerates `examples/billing/` via `script/
64
+ check_billing_drift.rb` and fails on drift between the
65
+ freshly-built artefacts and the committed copies.
66
+ Normalises the graphviz version banner so the runner's
67
+ apt-shipped version doesn't trigger a false positive.
68
+ - New `docs/security.md` consolidates the supply-chain story
69
+ (Bundler / Dependabot cooldown, vendored-JS sha256 +
70
+ 4-source audit, action SHA pinning, OIDC trusted
71
+ publishing).
72
+
73
+ ### Changed
74
+
75
+ - **`view --output html` semantics.** The flag now produces
76
+ the interactive viewer. The previous static Mermaid HTML
77
+ moves behind `--output mermaid-html` (still loads Mermaid
78
+ from a CDN, kept for back-compat).
79
+ - CI workflows read Ruby from `.ruby-version` instead of
80
+ pinning `"4.0.0"` inline, so future `.ruby-version` bumps
81
+ no longer need a `.github/workflows/` chase.
82
+ - RDoc dependency bumped from `~> 6.0` to `~> 7.0` (resolves
83
+ to 7.2.0). `gemspec.rdoc_options` corrected to `--markup
84
+ markdown` to match `.rdoc_options` and the Rakefile, fixing
85
+ the silent inconsistency left when the README rendering
86
+ fix landed in [0.1.2]. No code change; `rake rdoc` emits no
87
+ warnings under 7.x.
88
+ - README hero leads with the Cytoscape viewer screenshot
89
+ (the default output) and the Graphviz SVG follows.
90
+ `examples/billing/preview.png` resized from 1280x860 to
91
+ 720x483 so it fits the RDoc darkfish content pane on the
92
+ GitHub Pages site without overflow.
93
+ - README Documentation index re-ordered along the natural
94
+ reading flow: how-it-works → security → limitation →
95
+ development → plan.
96
+
20
97
  ## [0.1.2] — 2026-06-20
21
98
 
22
99
  First release that exercises the full automated pipeline end
@@ -173,7 +250,8 @@ spike through Phase 5 (UML class diagram).
173
250
  baseline and YJIT, and trailed baseline on Stats and
174
251
  CycleDetector — recommendation stays YJIT.
175
252
 
176
- [Unreleased]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.2...HEAD
253
+ [Unreleased]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.3...HEAD
254
+ [0.1.3]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.2...v0.1.3
177
255
  [0.1.2]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.1...v0.1.2
178
256
  [0.1.1]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.0...v0.1.1
179
257
  [0.1.0]: https://github.com/nozomemein/rigor-module-graph/releases/tag/v0.1.0
data/README.md CHANGED
@@ -11,10 +11,25 @@ to Packwerk/Graphwerk: where those look at package boundaries, this
11
11
  looks at the Ruby nominal graph — inheritance, `include`/`prepend`/
12
12
  `extend`, and (later) constant references.
13
13
 
14
- ![billing example](examples/billing/graph.svg)
14
+ **Two ways to look at the same graph.** Static SVG via
15
+ Graphviz for committing into PRs and docs; interactive HTML
16
+ via Cytoscape.js for actually exploring a 1000+-node Rails
17
+ codebase. Both rendered from the same `edges.jsonl` —
18
+ no second analysis pass.
15
19
 
16
- The screenshot above is from `examples/billing/`. Open
17
- `examples/billing/index.html` for the live Mermaid version.
20
+ ### Cytoscape (`--output html`, the default)
21
+
22
+ ![billing graph via Cytoscape](examples/billing/preview.png)
23
+
24
+ ### Graphviz (`--output svg`)
25
+
26
+ ![billing graph via Graphviz](examples/billing/graph.svg)
27
+
28
+ Both screenshots are from `examples/billing/`. Open
29
+ `examples/billing/index.html` directly to try the
30
+ interactive version — pan, zoom, filter by `kind` /
31
+ `confidence`, search by name, click a node to copy
32
+ `path:line`.
18
33
 
19
34
  ## Install
20
35
 
@@ -85,27 +100,45 @@ defaults to a sensible Rails-shaped value.
85
100
 
86
101
  ### `view` — one-shot HTML / SVG / Mermaid
87
102
 
103
+ The default `html` output is an interactive
104
+ [Cytoscape.js](https://js.cytoscape.org/)-based viewer:
105
+ filter checkboxes for `kind` and `confidence`, live name
106
+ search, `fit` button, and node-click → copy `path:line` to
107
+ the clipboard. The Cytoscape library is vendored into the gem
108
+ at a sha256-pinned version, so the generated HTML opens
109
+ offline with no network round-trip.
110
+
88
111
  ```sh
89
112
  # Don't open the browser (just write the HTML)
90
113
  rigor-module-graph view --no-open
91
114
 
92
- # Pick a different output format html (default) opens a viewer
93
- # in the browser; everything else streams to stdout unless `-o`
94
- # is given.
115
+ # Pick a different output format. `html` is the interactive
116
+ # viewer; `mermaid-html` is the legacy static-Mermaid embed
117
+ # (loads Mermaid from a CDN, kept for back-compat). Everything
118
+ # else streams to stdout unless `-o` is given.
119
+ rigor-module-graph view --no-open --output mermaid-html > graph.html
95
120
  rigor-module-graph view --no-open --output mermaid > graph.mmd
96
121
  rigor-module-graph view --no-open --output dot > graph.dot
97
122
  rigor-module-graph view --no-open --output svg > graph.svg
98
123
  rigor-module-graph view --no-open --output class-diagram > class.mmd
99
124
  rigor-module-graph view --output svg -o graph.svg
100
125
 
101
- # Focus on what's around one or a few constants (Mermaid can't
102
- # render 1000+-node graphs cleanly this is the escape hatch)
126
+ # Click on a node opens the file in VSCode rather than copying
127
+ # path:line to the clipboard. `--path-mode none` strips the
128
+ # path metadata entirely — useful when sharing the HTML
129
+ # artefact outside the project.
130
+ rigor-module-graph view --open-with vscode
131
+ rigor-module-graph view --path-mode none # share-safe
132
+ rigor-module-graph view --path-mode absolute # cwd-resolved
133
+
134
+ # Focus on what's around one or a few constants
103
135
  rigor-module-graph view --from Article --depth 5
104
136
  rigor-module-graph view --from Article --depth 5 --direction out
105
137
  rigor-module-graph view --from Billing::Invoice,Billing::Payment --depth 2
106
138
 
107
139
  # Pick your own collapse list (default: auto-detect top-level
108
- # namespaces with ≥ 3 members)
140
+ # namespaces with ≥ 3 members; applies to mermaid / dot / svg
141
+ # outputs — the interactive html viewer ignores it).
109
142
  rigor-module-graph view --collapse Billing,Auth
110
143
  rigor-module-graph view --no-collapse
111
144
 
@@ -245,22 +278,6 @@ Every key shown is the default. Two switches worth knowing:
245
278
  inference. Useful when the project doesn't follow Zeitwerk's
246
279
  autoload convention.
247
280
 
248
- ## Edge format
249
-
250
- Each edge in the JSONL file looks like:
251
-
252
- ```json
253
- {"from":"Billing::Invoice","to":"ApplicationRecord","kind":"inherits","path":"app/models/billing/invoice.rb","line":2,"column":3,"confidence":"syntax"}
254
- ```
255
-
256
- - `kind`: `inherits` / `include` / `prepend` / `extend` /
257
- `const_ref` (the last one is reserved for Phase 2).
258
- - `confidence`: `syntax` / `zeitwerk` / `rigor_type` /
259
- `unresolved`. MVP only emits `syntax`.
260
-
261
- The renderers dedup by `(from, to, kind, confidence)` so two
262
- `include Foo` on the same class across files collapse to one edge.
263
-
264
281
  ## Compatibility
265
282
 
266
283
  - Ruby `>= 4.0.0, < 4.1`
@@ -281,14 +298,18 @@ published to GitHub Pages on every push to `main`.
281
298
  pipeline (Prism → node rules → confidence ladder → JSONL →
282
299
  renderers), and why this is a nominal dependency graph and
283
300
  not a call graph.
301
+ - [Security](docs/security.md) — supply-chain controls
302
+ (Bundler cooldown, vendored-JS sha256 + 4-source audit,
303
+ action SHA pinning, trusted publishing) and the layered
304
+ pre-commit / CI gates that enforce them.
305
+ - [Known limitations](docs/limitation.md) — rough edges shipped
306
+ with the current release (visibility tracker gaps, the
307
+ bundled inflector, Mermaid 10.x quirks).
284
308
  - [Development guide](docs/development.md) — local setup, git
285
309
  hooks, CI / Release workflows, test suite layout.
286
310
  - [Design plan](docs/plan.md) — the decisions still
287
311
  load-bearing for the code (edge model, confidence ladder,
288
312
  output channel, owner resolution, architecture map).
289
- - [Known limitations](docs/limitation.md) — rough edges shipped
290
- with the current release (visibility tracker gaps, the
291
- bundled inflector, Mermaid 10.x quirks).
292
313
  - [Changelog](CHANGELOG.md) — per-version changes, formatted
293
314
  per [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
294
315
  with [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
@@ -18,6 +18,7 @@ require_relative "packwerk_overlay"
18
18
  require_relative "html_view"
19
19
  require_relative "status_reporter"
20
20
  require_relative "uml/class_diagram"
21
+ require_relative "viewer/html"
21
22
 
22
23
  module Rigor
23
24
  module ModuleGraph
@@ -365,9 +366,23 @@ module Rigor
365
366
  SUBTITLE_COLLAPSE_PREVIEW = 6
366
367
 
367
368
  # The supported output formats, in roughly increasing
368
- # "wrapping" order: html embeds mermaid; svg embeds dot;
369
+ # "wrapping" order. `html` is the interactive Cytoscape
370
+ # viewer (vendored, self-contained); `mermaid-html` is
371
+ # the older static-Mermaid-via-CDN page kept for
372
+ # backwards compatibility; `svg` embeds the dot layout;
369
373
  # the rest are raw text.
370
- FORMATS = %w[html mermaid dot svg class-diagram].freeze
374
+ FORMATS = %w[html mermaid-html mermaid dot svg class-diagram].freeze
375
+
376
+ # `--path-mode` controls how the click-through metadata
377
+ # `data.path` is reported on every node. See
378
+ # `Viewer::Html#path_for` for what each mode emits.
379
+ PATH_MODES = %i[relative absolute none].freeze
380
+
381
+ # `--open-with` flips the node-click action from
382
+ # clipboard copy to opening the file in an editor via
383
+ # a custom URL scheme. `vscode` is the only supported
384
+ # editor today.
385
+ OPEN_WITH = %i[vscode].freeze
371
386
 
372
387
  # Default file destination when format is html and the
373
388
  # user didn't override with -o. Non-html formats default to
@@ -394,7 +409,9 @@ module Rigor
394
409
  package: nil,
395
410
  include_methods: true,
396
411
  include_attributes: true,
397
- visibilities: %w[public protected private]
412
+ visibilities: %w[public protected private],
413
+ path_mode: :relative,
414
+ open_with: nil
398
415
  }
399
416
  end
400
417
 
@@ -461,6 +478,16 @@ module Rigor
461
478
  def render_payload(edges, nodes, collapse, groups)
462
479
  case @options[:format]
463
480
  when "html"
481
+ html = Viewer::Html.render(
482
+ edges: edges,
483
+ nodes: restrict_nodes_to_edges(nodes, edges),
484
+ title: "rigor-module-graph: #{File.basename(Dir.pwd)}",
485
+ subtitle: render_subtitle(edges, collapse, groups),
486
+ path_mode: @options[:path_mode],
487
+ open_with: @options[:open_with]
488
+ )
489
+ [html, false]
490
+ when "mermaid-html"
464
491
  mermaid = Mermaid.render(edges, collapse: collapse, groups: groups)
465
492
  html = HtmlView.render(
466
493
  title: "rigor-module-graph: #{File.basename(Dir.pwd)}",
@@ -554,7 +581,7 @@ module Rigor
554
581
  end
555
582
 
556
583
  def html?
557
- @options[:format] == "html"
584
+ %w[html mermaid-html].include?(@options[:format])
558
585
  end
559
586
 
560
587
  def build_parser
@@ -616,6 +643,7 @@ module Rigor
616
643
  opts.on("-q", "--quiet", "Suppress step-level progress on stderr") do
617
644
  @options[:quiet] = true
618
645
  end
646
+ add_viewer_options(opts)
619
647
  add_filter_options(opts, @options)
620
648
  opts.on("-h", "--help") do
621
649
  @stdout.puts opts
@@ -624,6 +652,22 @@ module Rigor
624
652
  end
625
653
  end
626
654
 
655
+ def add_viewer_options(opts)
656
+ opts.on("--path-mode MODE", PATH_MODES,
657
+ "How to report node paths in the html viewer: " \
658
+ "#{PATH_MODES.join(" / ")} (default: relative). " \
659
+ "`none` strips path metadata entirely — useful when " \
660
+ "sharing the html artefact outside the project.") do |mode|
661
+ @options[:path_mode] = mode
662
+ end
663
+ opts.on("--open-with EDITOR", OPEN_WITH,
664
+ "Make node clicks open the file in EDITOR instead of " \
665
+ "copying path:line to the clipboard. " \
666
+ "Supported: #{OPEN_WITH.join(" / ")}.") do |editor|
667
+ @options[:open_with] = editor
668
+ end
669
+ end
670
+
627
671
  # Choose collapse prefixes. Explicit `--collapse` wins;
628
672
  # otherwise we auto-pick top-level namespaces that have at
629
673
  # least AUTO_COLLAPSE_THRESHOLD distinct nodes under them,
@@ -0,0 +1,59 @@
1
+ # Vendored third-party assets — sha256 manifest.
2
+ #
3
+ # This file is the local integrity gate: `rake vendor:verify`
4
+ # re-computes sha256 for every row below and aborts on
5
+ # mismatch. Pre-commit and CI both run it. Per-file
6
+ # provenance (upstream URLs, npm `dist.integrity`, license,
7
+ # release date) lives next door in `MANIFEST.yml`; the audit
8
+ # task reads that.
9
+ #
10
+ # What this catches: bytes on disk no longer matching what we
11
+ # committed.
12
+ # What this does NOT catch on its own: bytes that were
13
+ # silently wrong at commit time (TOFU). For that, the bump
14
+ # SOP below requires `rake vendor:audit`, which cross-checks
15
+ # against four independent sources (npm tarball + npm
16
+ # `dist.integrity` + GitHub raw + every CDN listed in
17
+ # MANIFEST).
18
+ #
19
+ # ---
20
+ # Bumping a vendored asset (SOP):
21
+ #
22
+ # 1. Edit `MANIFEST.yml`: bump `release_tag`, `release_date`,
23
+ # `npm.version`, `tarball_url`, `github_raw_url`, and
24
+ # each CDN URL to the new version.
25
+ # 2. Look up the new `npm.integrity` from
26
+ # `https://registry.npmjs.org/<package>/<version>`
27
+ # (`dist.integrity` field) and paste it into
28
+ # `MANIFEST.yml`.
29
+ # 3. Download the new asset locally; replace the file under
30
+ # `vendor/`.
31
+ # 4. `shasum -a 256 vendor/<filename>` → update the sha256
32
+ # row in this file.
33
+ # 5. `bundle exec rake vendor:audit` — this fetches the new
34
+ # version from npm + GitHub + every CDN and asserts they
35
+ # all agree with the recorded sha256, and that the npm
36
+ # tarball's sha512 matches the recorded `dist.integrity`.
37
+ # Any mismatch means at least one source disagrees — do
38
+ # NOT proceed.
39
+ # 6. Update `last_audited:` in `MANIFEST.yml` to today's date.
40
+ # 7. Open a manual PR. Reviewer checks:
41
+ # - the diff touches only `vendor/<filename>`,
42
+ # `CHECKSUMS`, and `MANIFEST.yml`
43
+ # - release tag / date / license / source URLs match the
44
+ # new version
45
+ # - CI `vendor:verify` step passes
46
+ # - the audit step output was attached to the PR (paste
47
+ # `rake vendor:audit` output into the PR description)
48
+ # - `npm audit signatures cytoscape@<new>` clean (when
49
+ # npm CLI is available locally)
50
+ #
51
+ # Format: sha256 (64 hex chars) two spaces filename
52
+ # Lines starting with `#` and blank lines are ignored.
53
+ #
54
+ # ---
55
+ # cytoscape.min.js
56
+ # See MANIFEST.yml for the full provenance.
57
+ # release: v3.34.0 (2026-06-02), MIT
58
+ # npm: cytoscape@3.34.0
59
+ 9c2a3bf2592e0b14a1f7bec07c03a54f16dedf32af9cd0af155c716aa6c87bc3 cytoscape.min.js