simple_english 0.6.0-x86_64-linux

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +212 -0
  4. data/THIRD_PARTY_NOTICES.md +72 -0
  5. data/bin/se +6 -0
  6. data/docs/RULES.md +496 -0
  7. data/lib/simple_english/cli.rb +183 -0
  8. data/lib/simple_english/client/daemon.rb +233 -0
  9. data/lib/simple_english/client/language_tool.rb +95 -0
  10. data/lib/simple_english/daemon/engine.rb +40 -0
  11. data/lib/simple_english/daemon/http.rb +82 -0
  12. data/lib/simple_english/daemon/server.rb +285 -0
  13. data/lib/simple_english/lint/annotated_text.rb +117 -0
  14. data/lib/simple_english/lint/counts.rb +40 -0
  15. data/lib/simple_english/lint/extractor.rb +60 -0
  16. data/lib/simple_english/lint/finding.rb +24 -0
  17. data/lib/simple_english/lint/lint_plan.rb +22 -0
  18. data/lib/simple_english/lint/markdown.rb +121 -0
  19. data/lib/simple_english/lint/paragraph.rb +10 -0
  20. data/lib/simple_english/lint/plain_text.rb +30 -0
  21. data/lib/simple_english/lint/result.rb +18 -0
  22. data/lib/simple_english/lint/segment.rb +11 -0
  23. data/lib/simple_english/lint/span.rb +8 -0
  24. data/lib/simple_english/lint/suppressions.rb +37 -0
  25. data/lib/simple_english/model_context_protocol.rb +134 -0
  26. data/lib/simple_english/setup/config.rb +63 -0
  27. data/lib/simple_english/setup/fingerprint.rb +38 -0
  28. data/lib/simple_english/setup/install.rb +40 -0
  29. data/lib/simple_english/setup/languagetool.rb +23 -0
  30. data/lib/simple_english/version.rb +5 -0
  31. data/lib/simple_english.rb +60 -0
  32. data/libexec/simple_english/languagetool-server +4 -0
  33. data/libexec/simple_english/languagetool-server.sbom.json +9044 -0
  34. data/licenses/LGPL-2.1.txt +501 -0
  35. data/licenses/OpenJDK-LICENSE.txt +347 -0
  36. data/licenses/languagetool-resource-en/12dicts-readme.html +738 -0
  37. data/licenses/languagetool-resource-en/agid-readme.txt +340 -0
  38. data/licenses/languagetool-resource-en/pos-readme.txt +115 -0
  39. data/rules/simple-english.xml +621 -0
  40. metadata +185 -0
data/docs/RULES.md ADDED
@@ -0,0 +1,496 @@
1
+ # Rules
2
+
3
+ Generated by `bin/render-rules`. Do not edit by hand. The source
4
+ of truth is `rules/simple-english.xml` and
5
+ `lib/simple_english/lint/counts.rb`.
6
+
7
+ ## Pattern rules
8
+
9
+ ### SE_NO_CONTRACTIONS: No contractions
10
+
11
+ Write the words in full. No contractions.
12
+
13
+ - Wrong: You don't need this file.
14
+ - Right: You do not need this file.
15
+
16
+ ### SE_NO_SEMICOLON: No semicolons
17
+
18
+ Write two sentences, or name the relation.
19
+
20
+ - Wrong: Start the tool; then read the log.
21
+ - Right: Start the tool. Then read the log.
22
+
23
+ ### SE_NO_EMDASH: No em-dashes
24
+
25
+ Write two sentences, or use a comma.
26
+
27
+ - Wrong: The tool is fast—it also works.
28
+ - Right: The tool is fast. It also works.
29
+
30
+ ### SE_MODAL_RESTRICTED: Only can, will, must
31
+
32
+ Use can, will, or must. State the requirement exactly.
33
+
34
+ - Wrong: You should restart the service.
35
+ - Right: You must restart the service.
36
+
37
+ ### SE_ACTIVE_VOICE: Active voice
38
+
39
+ Use the active voice. Say who does the action.
40
+
41
+ - Wrong: The log was written by the worker.
42
+ - Right: The worker wrote the log.
43
+
44
+ ### SE_PRESENT_PERFECT: Simple tenses only
45
+
46
+ Use the simple past. Say when it happened.
47
+
48
+ - Wrong: The job has completed.
49
+ - Right: The job completed.
50
+
51
+ ### SE_ING_AFTER_COMMA: No -ing after a comma
52
+
53
+ Start a new sentence instead of the -ing phrase.
54
+
55
+ - Wrong: The tool runs, making it easy.
56
+ - Right: The tool runs. It is easy.
57
+
58
+ ### SE_KEEP_THAT: make sure that
59
+
60
+ Write "make sure that".
61
+
62
+ - Wrong: Make sure the file exists.
63
+ - Right: Make sure that the file exists.
64
+
65
+ ### SE_CONDITION_FIRST: Condition before command
66
+
67
+ Put the condition first: "If the build fails, read the log."
68
+
69
+ - Wrong: Read the log if the build fails.
70
+ - Right: If the build fails, read the log.
71
+
72
+ ### SE_SLOP_LEVERAGE: use, not leverage
73
+
74
+ Write use.
75
+
76
+ - Wrong: Utilize the registry file.
77
+ - Right: Use the registry file.
78
+
79
+ ### SE_SLOP_IN_ORDER_TO: to, not in order to
80
+
81
+ Write to.
82
+
83
+ - Wrong: Run the tool in order to build the file.
84
+ - Right: Run the tool to build the file.
85
+
86
+ ### SE_SLOP_PRIOR_TO: before, not prior to
87
+
88
+ Write before.
89
+
90
+ - Wrong: Read the file prior to the upgrade.
91
+ - Right: Read the file before the upgrade.
92
+
93
+ ### SE_SLOP_ENSURE: make sure that, not ensure
94
+
95
+ Write make sure that.
96
+
97
+ - Wrong: Ensure the file exists.
98
+ - Right: Make sure that the file exists.
99
+
100
+ ### SE_SLOP_FUNCTIONALITY: function, not functionality
101
+
102
+ Write function or feature.
103
+
104
+ - Wrong: Add the functionality first.
105
+ - Right: Add the function first.
106
+
107
+ ### SE_SLOP_ENABLES_YOU: you can, not enables you to
108
+
109
+ Write you can.
110
+
111
+ - Wrong: The tool enables you to build the file.
112
+ - Right: You can build the file with the tool.
113
+
114
+ ### SE_SLOP_FACILITATE: help, not facilitate
115
+
116
+ Write help or make possible.
117
+
118
+ - Wrong: The tool facilitates the build.
119
+ - Right: The tool helps the build.
120
+
121
+ ### SE_SLOP_DELVE: read, not delve into
122
+
123
+ Write read or examine.
124
+
125
+ - Wrong: Delve into the config file.
126
+ - Right: Read the config file.
127
+
128
+ ### SE_SLOP_WHEN_IT_COMES: for, not when it comes to
129
+
130
+ Write for.
131
+
132
+ - Wrong: When it comes to builds, use the tool.
133
+ - Right: For builds, use the tool.
134
+
135
+ ### SE_SLOP_IN_THE_EVENT: if, not in the event that
136
+
137
+ Write if.
138
+
139
+ - Wrong: In the event that the build fails, read the log.
140
+ - Right: If the build fails, read the log.
141
+
142
+ ### SE_SLOP_DUE_TO_FACT: because, not due to the fact that
143
+
144
+ Write because.
145
+
146
+ - Wrong: Due to the fact that the port is closed, the tool fails.
147
+ - Right: Because the port is not open, the tool fails.
148
+
149
+ ### SE_SLOP_AND_OR: no and/or
150
+
151
+ Pick one. Or write "X, or Y, or both".
152
+
153
+ - Wrong: Set the flag and/or the port.
154
+ - Right: Set the flag, or the port, or both.
155
+
156
+ ### SE_SLOP_LATIN: no Latin abbreviations
157
+
158
+ #### e.g.
159
+
160
+ Write "for example", or name the items.
161
+
162
+ - Wrong: Set the flag, e.g. the port.
163
+ - Right: Set the flag, for example the port.
164
+
165
+ #### i.e.
166
+
167
+ Write "that is", or name the items.
168
+
169
+ - Wrong: Set the flag, i.e. the port.
170
+ - Right: Set the flag, that is the port.
171
+
172
+ #### etc.
173
+
174
+ Name the items.
175
+
176
+ - Wrong: Set the flag, etc.
177
+ - Right: Set the flag or the port.
178
+
179
+ ### SE_SLOP_OUT_OF_BOX: by default, not out of the box
180
+
181
+ Write by default.
182
+
183
+ - Wrong: The tool works out of the box.
184
+ - Right: The tool works by default.
185
+
186
+ ### SE_SLOP_UNDER_HOOD: internally, not under the hood
187
+
188
+ Write internally.
189
+
190
+ - Wrong: Under the hood, the tool builds a file.
191
+ - Right: Internally, the tool builds a file.
192
+
193
+ ### SE_SLOP_STREAMLINE: make simpler, not streamline
194
+
195
+ Write make simpler or make faster.
196
+
197
+ - Wrong: The tool streamlines the build.
198
+ - Right: The tool makes the build simpler.
199
+
200
+ ### SE_SLOP_PLETHORA: many, not plethora
201
+
202
+ Write many.
203
+
204
+ - Wrong: The file has a plethora of rows.
205
+ - Right: The file has many rows.
206
+
207
+ ### SE_SLOP_ADDRESSES: corrects, not addresses the issue
208
+
209
+ Write corrects the fault or removes the error.
210
+
211
+ - Wrong: The tool addresses the issue.
212
+ - Right: The tool corrects the fault.
213
+
214
+ ### SE_SLOP_PIVOTAL: important, not pivotal
215
+
216
+ Write important.
217
+
218
+ - Wrong: The flag is crucial.
219
+ - Right: The flag is important.
220
+
221
+ ### SE_SLOP_TAPESTRY: no tapestry, testament, synergy
222
+
223
+ Delete it. State the fact.
224
+
225
+ - Wrong: The design is a testament to the team.
226
+ - Right: The design shows the work of the team.
227
+
228
+ ### SE_SLOP_INTERPLAY: interaction, not interplay
229
+
230
+ Write interaction, or delete it.
231
+
232
+ - Wrong: The interplay of the two tools is complex.
233
+ - Right: The interaction of the two tools is complex.
234
+
235
+ ### SE_SLOP_INTRICATE: complex, not intricate
236
+
237
+ Write complex.
238
+
239
+ - Wrong: The config is intricate.
240
+ - Right: The config is complex.
241
+
242
+ ### SE_SLOP_VIBRANT: delete vibrant, nuanced, multifaceted
243
+
244
+ Delete it, or name the parts.
245
+
246
+ - Wrong: The tool is nuanced.
247
+ - Right: The tool reads three file types.
248
+
249
+ ### SE_SLOP_REALM: area, not realm or landscape
250
+
251
+ Write area.
252
+
253
+ - Wrong: In the realm of builds, use the tool.
254
+ - Right: In the area of builds, use the tool.
255
+
256
+ ### SE_SLOP_GROUNDBREAKING: new, not groundbreaking
257
+
258
+ Write new, or delete it.
259
+
260
+ - Wrong: The tool is groundbreaking.
261
+ - Right: The tool is new.
262
+
263
+ ### SE_SLOP_TRANSFORMATIVE: say what changes, not transformative
264
+
265
+ Delete it. Say what changes.
266
+
267
+ - Wrong: The tool is transformative.
268
+ - Right: The tool cuts the build time in half.
269
+
270
+ ### SE_SLOP_REVOLUTIONIZE: change, not revolutionize
271
+
272
+ Write change.
273
+
274
+ - Wrong: The tool revolutionizes the build.
275
+ - Right: The tool changes the build.
276
+
277
+ ### SE_SLOP_SHOWCASE: show, not showcase
278
+
279
+ Write show.
280
+
281
+ - Wrong: The log showcases the error.
282
+ - Right: The log shows the error.
283
+
284
+ ### SE_SLOP_FOSTER: help, not foster
285
+
286
+ Write help, support, or let.
287
+
288
+ - Wrong: The tool fosters growth.
289
+ - Right: The tool supports growth.
290
+
291
+ ### SE_SLOP_HARNESS: use, not harness
292
+
293
+ Write use.
294
+
295
+ - Wrong: Harness the API.
296
+ - Right: Use the API.
297
+
298
+ ### SE_SLOP_ENHANCE: improve, not enhance
299
+
300
+ Write improve.
301
+
302
+ - Wrong: The tool enhances the build.
303
+ - Right: The tool improves the build.
304
+
305
+ ### SE_SLOP_ELEVATE: increase, not elevate
306
+
307
+ Write increase.
308
+
309
+ - Wrong: The tool elevates the speed.
310
+ - Right: The tool increases the speed.
311
+
312
+ ### SE_SLOP_FURTHERMORE: also, not furthermore
313
+
314
+ Write also.
315
+
316
+ - Wrong: Furthermore, the tool reads the log.
317
+ - Right: The tool also reads the log.
318
+
319
+ ### SE_SLOP_EMBARK: start, not embark
320
+
321
+ Write start or try.
322
+
323
+ - Wrong: Embark on the build.
324
+ - Right: Start the build.
325
+
326
+ ### SE_SLOP_METICULOUS: careful, not meticulous
327
+
328
+ Write careful or carefully.
329
+
330
+ - Wrong: The tool checks the file meticulously.
331
+ - Right: The tool checks the file carefully.
332
+
333
+ ### SE_SLOP_HOLISTIC: full, not holistic
334
+
335
+ Write full.
336
+
337
+ - Wrong: The tool gives a holistic view.
338
+ - Right: The tool gives a full view.
339
+
340
+ ### SE_SLOP_PARADIGM: model, not paradigm
341
+
342
+ Write model.
343
+
344
+ - Wrong: The tool changes the paradigm.
345
+ - Right: The tool changes the model.
346
+
347
+ ### SE_SLOP_BOASTS: has, not boasts
348
+
349
+ Write has.
350
+
351
+ - Wrong: The tool boasts a log.
352
+ - Right: The tool has a log.
353
+
354
+ ### SE_SLOP_NOTWITHSTANDING: but, not that being said
355
+
356
+ Write but.
357
+
358
+ - Wrong: The tool works. That being said, it is slow.
359
+ - Right: The tool works, but it is slow.
360
+
361
+ ### SE_SLOP_NOTWITHSTANDING2: but, not notwithstanding
362
+
363
+ Write but.
364
+
365
+ - Wrong: Notwithstanding the log, the tool fails.
366
+ - Right: The log exists, but the tool fails.
367
+
368
+ ### SE_SLOP_DELETE_ADVERBS: delete empty adverbs
369
+
370
+ Delete it. It carries no fact.
371
+
372
+ - Wrong: The tool works seamlessly.
373
+ - Right: The tool works.
374
+
375
+ ### SE_SLOP_JUST: delete just
376
+
377
+ Delete it. It carries no fact.
378
+
379
+ - Wrong: The tool just works.
380
+ - Right: The tool works.
381
+
382
+ ### SE_SLOP_DELETE_ADJ: delete empty adjectives
383
+
384
+ Delete it, or give the measurable property.
385
+
386
+ - Wrong: The tool is robust.
387
+ - Right: The tool retries three times, then stops.
388
+
389
+ ### SE_SLOP_WORTH_NOTING: delete it is worth noting
390
+
391
+ Delete it. State the fact.
392
+
393
+ - Wrong: It is worth noting that the tool is slow.
394
+ - Right: The tool is slow.
395
+
396
+ ### SE_SLOP_IMPORTANT_TO: delete it is important to
397
+
398
+ Delete it. State the fact.
399
+
400
+ - Wrong: It is important to read the log.
401
+ - Right: Read the log.
402
+
403
+ ### SE_SLOP_DESIGNED_TO: delete is designed to
404
+
405
+ Say what the tool does.
406
+
407
+ - Wrong: The tool is designed to read logs.
408
+ - Right: The tool reads logs.
409
+
410
+ ### SE_SLOP_AIMS_TO: delete aims to
411
+
412
+ Say what the tool does.
413
+
414
+ - Wrong: The tool aims to read logs.
415
+ - Right: The tool reads logs.
416
+
417
+ ### SE_SLOP_AS_NEEDED: state the condition, not as needed
418
+
419
+ State the condition.
420
+
421
+ - Wrong: Restart the tool as needed.
422
+ - Right: Restart the tool every day.
423
+
424
+ ### SE_SLOP_GRACEFULLY: say what it does, not gracefully handles
425
+
426
+ Say what the tool does: "retries three times, then stops".
427
+
428
+ - Wrong: The tool gracefully handles the error.
429
+ - Right: The tool retries three times, then stops.
430
+
431
+ ### SE_SLOP_IN_CONCLUSION: delete in conclusion
432
+
433
+ Delete it. State the fact.
434
+
435
+ - Wrong: In conclusion, the tool works.
436
+ - Right: The tool works.
437
+
438
+ ### SE_SLOP_IN_SUMMARY: delete in summary
439
+
440
+ Delete it. State the fact.
441
+
442
+ - Wrong: In summary, the tool works.
443
+ - Right: The tool works.
444
+
445
+ ### SE_SLOP_AT_END_OF_DAY: delete at the end of the day
446
+
447
+ Delete it. State the fact.
448
+
449
+ - Wrong: At the end of the day, the tool works.
450
+ - Right: The tool works.
451
+
452
+ ### SE_SLOP_NESTLED: give the location, not nestled
453
+
454
+ Give the location.
455
+
456
+ - Wrong: The file is nestled in the folder.
457
+ - Right: The file sits in the folder.
458
+
459
+ ### SE_SLOP_BUSTLING: busy, not bustling
460
+
461
+ Write busy.
462
+
463
+ - Wrong: The bustling market has many files.
464
+ - Right: The busy market has many files.
465
+
466
+ ### SE_SLOP_HOPE_HELPS: delete I hope this helps
467
+
468
+ Delete it.
469
+
470
+ - Wrong: I hope this helps. Read the log.
471
+ - Right: Read the log.
472
+
473
+ ### SE_SLOP_DIVE_IN: delete let's dive in
474
+
475
+ Delete it.
476
+
477
+ - Wrong: let's dive in. Read the log.
478
+ - Right: Read the log.
479
+
480
+ ## Counting rules
481
+
482
+ These rules run in Ruby on Markdown text. Code comments do not use
483
+ them. Procedural text is a list item. Descriptive text is every
484
+ other paragraph.
485
+
486
+ ### SE_SENTENCE_TOO_LONG
487
+
488
+ A sentence with more than 20 words in
489
+ procedural text, or more than 25 words
490
+ in descriptive text.
491
+
492
+ ### SE_PARAGRAPH_TOO_LONG
493
+
494
+ A paragraph with more than 6
495
+ sentences in descriptive text.
496
+
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The command-line interface: Thor commands for lint and serve, plus
4
+ # a no-op setup for older callers. bin/se is a thin runner over this,
5
+ # so the installed gem's RubyGems shim can load it.
6
+
7
+ require "thor"
8
+ require_relative "../simple_english"
9
+
10
+ module SimpleEnglish
11
+ class CLI < Thor
12
+ def self.exit_on_failure? = true
13
+
14
+ # Bare file arguments and "-" (stdin) are lint targets, not command
15
+ # names. Thor only falls back to the default task when the first
16
+ # argument is an option, so route them to lint explicitly.
17
+ def self.start(given_args = ARGV, config = {})
18
+ first = given_args.first
19
+ if first && !all_commands.key?(first) &&
20
+ (first == "-" || !first.start_with?("-"))
21
+ given_args = ["lint", *given_args]
22
+ end
23
+ # Thor's own commands (help, tree) return junk like nil or a
24
+ # Hash, not an exit status. Contract: start always returns an
25
+ # Integer so every caller (bin/se, tests) can exit on it.
26
+ status = super
27
+ status.is_a?(Integer) ? status : 0
28
+ end
29
+
30
+ # The test entry point. It keeps the old module interface.
31
+ def self.run(argv)
32
+ start(argv)
33
+ end
34
+
35
+ default_task :lint
36
+ desc "lint FILE_OR_DIR...", "Lint Markdown prose and code comments (- reads stdin)"
37
+ method_option :format, type: :string, default: "text", enum: %w[text json sarif],
38
+ banner: "text|json|sarif"
39
+ def lint(*paths)
40
+ if paths.empty?
41
+ help("lint")
42
+ return 2
43
+ end
44
+ config =
45
+ begin
46
+ SimpleEnglish::Config.load
47
+ rescue SimpleEnglish::Config::ConfigError => e
48
+ warn "error: #{e.message}"
49
+ return 2
50
+ end
51
+ results = []
52
+ self.class.expand_paths(paths).each do |path|
53
+ next if path != "-" && SimpleEnglish::Config.ignore?(config, path)
54
+ unless path == "-" || File.readable?(path)
55
+ warn "error: file not readable: #{path}"
56
+ return 2
57
+ end
58
+ text = (path == "-") ? $stdin.read : File.read(path)
59
+ findings = SimpleEnglish.lint_file(path, text)
60
+ return 2 if findings.nil? # already warned why
61
+ SimpleEnglish::Config.filter(config, path, findings).each do |finding|
62
+ results << [path, finding]
63
+ end
64
+ end
65
+ self.class.report(results, options[:format])
66
+ results.empty? ? 0 : 1
67
+ end
68
+
69
+ desc "version", "Print the gem version"
70
+ def version
71
+ puts SimpleEnglish::VERSION
72
+ 0
73
+ end
74
+
75
+ desc "mcp", "Run the MCP stdio server (one JSON-RPC message per line)"
76
+ def mcp
77
+ SimpleEnglish::ModelContextProtocol.run
78
+ 0
79
+ end
80
+
81
+ desc "serve", "Run the lint daemon in the foreground"
82
+ method_option :port, type: :numeric, default: SimpleEnglish::Client::DEFAULT_PORT,
83
+ desc: "Port to listen on"
84
+ method_option :"dev-log", type: :string, banner: "PATH",
85
+ desc: "Write daemon stderr to PATH"
86
+ method_option :detached, type: :boolean,
87
+ desc: "Replace any running se daemon and run in the background"
88
+ def serve
89
+ if options[:detached]
90
+ daemon = SimpleEnglish::Server.start_detached(port: options[:port],
91
+ install: SimpleEnglish::Install.from_env, dev_log: options[:"dev-log"])
92
+ if daemon
93
+ puts "se daemon detached, pid #{daemon["pid"]}, " \
94
+ "on http://localhost:#{options[:port]}"
95
+ return 0
96
+ end
97
+ warn "error: detached daemon did not come up. " \
98
+ "Run `#{Client.runner} serve` and read its output."
99
+ return 2
100
+ end
101
+ log = options[:"dev-log"] ? File.open(options[:"dev-log"], "w") : $stderr
102
+ SimpleEnglish::Server.start(port: options[:port],
103
+ install: SimpleEnglish::Install.from_env, log: log)
104
+ 0
105
+ rescue SimpleEnglish::Install::SetupError, SimpleEnglish::Server::ServerError,
106
+ SimpleEnglish::Config::ConfigError => e
107
+ warn "error: #{e.message}"
108
+ 2
109
+ end
110
+
111
+ desc "setup", "Do nothing; the lint engine ships with the gem"
112
+ def setup
113
+ puts "nothing to set up; the lint engine ships with the gem"
114
+ 0
115
+ end
116
+
117
+ # "-" stays as-is for stdin. Directories expand to all lintable files.
118
+ # Glob output keeps a "./" prefix when the argument is ".". Strip it so
119
+ # paths and config ignore globs always see the same form.
120
+ # These trees hold third-party prose, not the user's. The tool lints
121
+ # what the user owns. Skipped only during directory expansion. An
122
+ # explicit path always lints.
123
+ # Dir.glob never returns dotfiles, so ".git" is inert today. It
124
+ # guards a future FNM_DOTMATCH from turning git internals back on.
125
+ # .gitignore is not read. Users put ignore: globs in the config for
126
+ # build output and generated files.
127
+ SKIPPED_DIRS = [".git", "node_modules", "vendor"].freeze
128
+
129
+ def self.expand_paths(argv)
130
+ extensions = (SimpleEnglish::Extractor::EXTENSION_LANGUAGES.keys.map { |e| e.delete_prefix(".") } + ["md"]).uniq.join(",")
131
+ argv.flat_map do |path|
132
+ if File.directory?(path)
133
+ Dir.glob(File.join(path, "**/*.{#{extensions}}"))
134
+ .reject { |p| p.split(File::SEPARATOR).any? { |s| SKIPPED_DIRS.include?(s) } }
135
+ .sort
136
+ else
137
+ path
138
+ end
139
+ end.map { |path| path.delete_prefix("./") }
140
+ end
141
+
142
+ def self.report(results, format)
143
+ require "json"
144
+ case format
145
+ when "json"
146
+ puts JSON.pretty_generate(results.map do |path, finding|
147
+ {"path" => path, "line" => finding.line, "column" => finding.column,
148
+ "end_line" => finding.end_line, "end_column" => finding.end_column,
149
+ "rule" => finding.rule, "message" => finding.message}
150
+ end)
151
+ when "sarif"
152
+ puts JSON.pretty_generate(
153
+ "version" => "2.1.0",
154
+ "$schema" => "https://json.schemastore.org/sarif-2.1.0.json",
155
+ "runs" => [{
156
+ "columnKind" => "utf16CodeUnits",
157
+ "tool" => {"driver" => {"name" => "se"}},
158
+ "results" => results.map do |path, finding|
159
+ region = {"startLine" => finding.line}
160
+ if finding.column
161
+ region["startColumn"] = finding.column
162
+ if finding.end_line && finding.end_column
163
+ region["endLine"] = finding.end_line
164
+ region["endColumn"] = finding.end_column
165
+ end
166
+ end
167
+ {"ruleId" => finding.rule, "level" => "error",
168
+ "message" => {"text" => finding.message},
169
+ "locations" => [{"physicalLocation" => {
170
+ "artifactLocation" => {"uri" => path},
171
+ "region" => region
172
+ }}]}
173
+ end
174
+ }]
175
+ )
176
+ else
177
+ results.each do |path, finding|
178
+ puts finding.to_line(path)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end