lex-detect 0.1.7 → 0.2.1

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: f0a985e71fac2b9cbee47bb0f1eef3d7eb744dbbea99b573f0d90dba9ca7bc89
4
- data.tar.gz: dca63d849d77bb5aa83da69ce23146a8294666c594bb155b6f3d964d7416dccc
3
+ metadata.gz: 8e8430d894d1792494f0781c7f13c28de7da13817c40fa3a9f80cfc4c89bc9ad
4
+ data.tar.gz: 2bff9f69460165c22a025dc97912639202cca9200366e91dafbc84dc9d37bb8f
5
5
  SHA512:
6
- metadata.gz: c8718ab255658b92ce9579815b01032afc68ded3cece3d6c13eaaaa714143203303023541ffb4b24f3d275a69004f7c043492f030b775c78b371d1edce3c76ba
7
- data.tar.gz: 2695aff906451268b4733463190117c099f8c2fbb6be063003fd9ff3216db0494d0d3e265d9b8c5ebdd538b817132975dff186b37bc75f0838578b49d60e2b72
6
+ metadata.gz: b087321a87beeff9cd42417286a39477edd5608ca8190bc67877b6e55b57f6bd4f971c05b802eadf47b68967acbb40c0e74b96c25a1d970d1431adffc3f43d2a
7
+ data.tar.gz: 6f9c61761fad7069ad09110f21d23227a664a606fcc5b50737d0d05c462ce9240b60e6f91a7d3b1684845b76c92f1500e2951a512725c33880eafacbc8ac3274
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1] - 2026-03-22
4
+
5
+ ### Added
6
+ - `Formatters::Json` passthrough formatter returning detections unchanged (or as pretty-printed JSON via `.to_json`)
7
+ - `Formatters` module entry point with `Formatters.format(detections, format:)` dispatcher for `:sarif`, `:markdown`, and `:json`
8
+ - `format_results` now delegates to `Formatters.format` instead of dispatching inline
9
+ - 5 new specs for `Formatters::Json` covering passthrough identity, field preservation, JSON serialization, and empty input
10
+
11
+ ## [0.2.0] - 2026-03-22
12
+
13
+ ### Added
14
+ - SARIF 2.1.0 formatter (`Formatters::Sarif`) for GitHub Code Scanning integration
15
+ - Markdown PR comment formatter (`Formatters::MarkdownPr`) for GitHub PR annotations
16
+ - `format_results(format:, detections:)` public API method supporting `:sarif`, `:markdown`, and `:json` output formats
17
+
3
18
  ## [0.1.7] - 2026-03-22
4
19
 
5
20
  ### Fixed
data/CLAUDE.md CHANGED
@@ -10,7 +10,7 @@ Legion Extension that scans the local environment and recommends which `lex-*` e
10
10
 
11
11
  **GitHub**: https://github.com/LegionIO/lex-detect
12
12
  **License**: MIT
13
- **Version**: 0.1.4
13
+ **Version**: 0.2.0
14
14
 
15
15
  ## Architecture
16
16
 
@@ -57,7 +57,7 @@ Legion::Extensions::Detect.catalog # raw CATALOG constant
57
57
 
58
58
  ## Testing
59
59
 
60
- 40 specs across 6 spec files.
60
+ 54 specs across 9 spec files.
61
61
 
62
62
  ```bash
63
63
  bundle install
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Detect
8
+ module Formatters
9
+ module Json
10
+ module_function
11
+
12
+ def format(detections)
13
+ detections
14
+ end
15
+
16
+ def to_json(detections)
17
+ ::JSON.pretty_generate(format(detections))
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Detect
6
+ module Formatters
7
+ module MarkdownPr
8
+ module_function
9
+
10
+ def format(detections)
11
+ missing = collect_missing(detections)
12
+ installed = collect_installed(detections)
13
+
14
+ lines = ["## Legion Detect Findings\n"]
15
+
16
+ if missing.any?
17
+ lines << "### Missing Extensions (#{missing.size})\n"
18
+ missing.each do |m|
19
+ lines << "- **#{m[:name]}**: `#{m[:extension]}` not installed"
20
+ lines << " Detected by: #{m[:signals].join(', ')}"
21
+ lines << " Install: `gem install #{m[:extension]}`\n"
22
+ end
23
+ end
24
+
25
+ if installed.any?
26
+ lines << "### Installed (#{installed.size})\n"
27
+ installed.each do |i|
28
+ lines << "- #{i[:name]}: `#{i[:extension]}` :white_check_mark:"
29
+ end
30
+ end
31
+
32
+ lines << "No extensions detected.\n" if missing.empty? && installed.empty?
33
+
34
+ lines << "\n---\n*Generated by legion-detect v#{VERSION}*"
35
+ lines.join("\n")
36
+ end
37
+
38
+ def collect_missing(detections)
39
+ detections.flat_map do |d|
40
+ d[:extensions].filter_map do |ext|
41
+ next if d[:installed][ext]
42
+
43
+ { name: d[:name], extension: ext, signals: d[:matched_signals] }
44
+ end
45
+ end
46
+ end
47
+
48
+ def collect_installed(detections)
49
+ detections.flat_map do |d|
50
+ d[:extensions].filter_map do |ext|
51
+ next unless d[:installed][ext]
52
+
53
+ { name: d[:name], extension: ext }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Detect
8
+ module Formatters
9
+ module Sarif
10
+ SCHEMA = 'https://json.schemastore.org/sarif-2.1.0.json'
11
+ SARIF_VERSION = '2.1.0'
12
+
13
+ SEVERITY_MAP = {
14
+ missing: 'warning',
15
+ installed: 'note'
16
+ }.freeze
17
+
18
+ module_function
19
+
20
+ def format(detections)
21
+ rules = build_rules(detections)
22
+ results = build_results(detections)
23
+
24
+ {
25
+ '$schema' => SCHEMA,
26
+ 'version' => SARIF_VERSION,
27
+ 'runs' => [{
28
+ 'tool' => {
29
+ 'driver' => {
30
+ 'name' => 'legion-detect',
31
+ 'version' => VERSION,
32
+ 'informationUri' => 'https://github.com/LegionIO/lex-detect',
33
+ 'rules' => rules
34
+ }
35
+ },
36
+ 'results' => results
37
+ }]
38
+ }
39
+ end
40
+
41
+ def to_json(detections)
42
+ ::JSON.pretty_generate(format(detections))
43
+ end
44
+
45
+ def build_rules(detections)
46
+ rules = detections.flat_map do |detection|
47
+ detection[:extensions].map do |ext|
48
+ {
49
+ 'id' => "detect/#{ext}",
50
+ 'name' => detection[:name],
51
+ 'shortDescription' => { 'text' => "#{detection[:name]} detected — #{ext} recommended" },
52
+ 'defaultConfiguration' => { 'level' => 'warning' }
53
+ }
54
+ end
55
+ end
56
+ rules.uniq { |r| r['id'] }
57
+ end
58
+
59
+ def build_results(detections)
60
+ detections.flat_map do |detection|
61
+ detection[:extensions].filter_map do |ext|
62
+ next if detection[:installed][ext]
63
+
64
+ {
65
+ 'ruleId' => "detect/#{ext}",
66
+ 'level' => 'warning',
67
+ 'message' => {
68
+ 'text' => "#{detection[:name]} detected (#{detection[:matched_signals].join(', ')}) but #{ext} is not installed"
69
+ },
70
+ 'properties' => {
71
+ 'matched_signals' => detection[:matched_signals],
72
+ 'detection_name' => detection[:name]
73
+ }
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/detect/formatters/json'
4
+ require 'legion/extensions/detect/formatters/sarif'
5
+ require 'legion/extensions/detect/formatters/markdown_pr'
6
+
7
+ module Legion
8
+ module Extensions
9
+ module Detect
10
+ module Formatters
11
+ module_function
12
+
13
+ def format(detections, format: :json)
14
+ case format.to_sym
15
+ when :sarif then Sarif.to_json(detections)
16
+ when :markdown then MarkdownPr.format(detections)
17
+ else Json.format(detections)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Detect
6
- VERSION = '0.1.7'
6
+ VERSION = '0.2.1'
7
7
  end
8
8
  end
9
9
  end
@@ -4,6 +4,7 @@ require 'legion/extensions/detect/version'
4
4
  require 'legion/extensions/detect/catalog'
5
5
  require 'legion/extensions/detect/scanner'
6
6
  require 'legion/extensions/detect/installer'
7
+ require 'legion/extensions/detect/formatters'
7
8
  require_relative 'detect/runners/task_observer'
8
9
  require_relative 'detect/runners/cancel_task'
9
10
 
@@ -41,6 +42,11 @@ module Legion
41
42
  def catalog
42
43
  CATALOG
43
44
  end
45
+
46
+ def format_results(format: :json, detections: nil)
47
+ results = detections || scan
48
+ Formatters.format(results, format: format)
49
+ end
44
50
  end
45
51
 
46
52
  require_relative 'detect/actors/full_scan' if defined?(Legion::Extensions::Actors::Once)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-detect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -31,6 +31,10 @@ files:
31
31
  - lib/legion/extensions/detect/actors/full_scan.rb
32
32
  - lib/legion/extensions/detect/actors/observer_tick.rb
33
33
  - lib/legion/extensions/detect/catalog.rb
34
+ - lib/legion/extensions/detect/formatters.rb
35
+ - lib/legion/extensions/detect/formatters/json.rb
36
+ - lib/legion/extensions/detect/formatters/markdown_pr.rb
37
+ - lib/legion/extensions/detect/formatters/sarif.rb
34
38
  - lib/legion/extensions/detect/installer.rb
35
39
  - lib/legion/extensions/detect/local_migrations/20260319000001_create_detect_results.rb
36
40
  - lib/legion/extensions/detect/local_migrations/20260320000001_create_observer_events.rb