simplecov 0.22.0 → 1.0.2

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +1058 -508
  4. data/doc/alternate-formatters.md +0 -5
  5. data/doc/commercial-services.md +5 -5
  6. data/exe/simplecov +11 -0
  7. data/lib/minitest/simplecov_plugin.rb +13 -5
  8. data/lib/simplecov/autostart.rb +11 -0
  9. data/lib/simplecov/cli/clean.rb +47 -0
  10. data/lib/simplecov/cli/coverage.rb +93 -0
  11. data/lib/simplecov/cli/diff.rb +152 -0
  12. data/lib/simplecov/cli/dotfile.rb +105 -0
  13. data/lib/simplecov/cli/merge.rb +118 -0
  14. data/lib/simplecov/cli/open.rb +50 -0
  15. data/lib/simplecov/cli/report.rb +89 -0
  16. data/lib/simplecov/cli/run.rb +36 -0
  17. data/lib/simplecov/cli/serve.rb +149 -0
  18. data/lib/simplecov/cli/uncovered.rb +108 -0
  19. data/lib/simplecov/cli.rb +150 -0
  20. data/lib/simplecov/color.rb +79 -0
  21. data/lib/simplecov/combine/branches_combiner.rb +28 -5
  22. data/lib/simplecov/combine/files_combiner.rb +47 -1
  23. data/lib/simplecov/combine/lines_combiner.rb +19 -17
  24. data/lib/simplecov/combine/methods_combiner.rb +49 -0
  25. data/lib/simplecov/combine/results_combiner.rb +7 -5
  26. data/lib/simplecov/command_guesser.rb +46 -32
  27. data/lib/simplecov/configuration/coverage.rb +175 -0
  28. data/lib/simplecov/configuration/coverage_criteria.rb +158 -0
  29. data/lib/simplecov/configuration/filters.rb +197 -0
  30. data/lib/simplecov/configuration/formatting.rb +129 -0
  31. data/lib/simplecov/configuration/ignored_entries.rb +63 -0
  32. data/lib/simplecov/configuration/merging.rb +164 -0
  33. data/lib/simplecov/configuration/thresholds.rb +178 -0
  34. data/lib/simplecov/configuration.rb +105 -412
  35. data/lib/simplecov/coverage_statistics.rb +15 -9
  36. data/lib/simplecov/coverage_violations.rb +149 -0
  37. data/lib/simplecov/defaults.rb +29 -22
  38. data/lib/simplecov/deprecation.rb +45 -0
  39. data/lib/simplecov/directive.rb +167 -0
  40. data/lib/simplecov/exit_codes/exit_code_handling.rb +8 -2
  41. data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +19 -57
  42. data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +45 -0
  43. data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +17 -27
  44. data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +41 -0
  45. data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +38 -21
  46. data/lib/simplecov/exit_codes.rb +15 -0
  47. data/lib/simplecov/exit_handling.rb +158 -0
  48. data/lib/simplecov/file_list.rb +70 -19
  49. data/lib/simplecov/filter.rb +69 -24
  50. data/lib/simplecov/formatter/base.rb +102 -0
  51. data/lib/simplecov/formatter/html_formatter/public/application.css +1 -0
  52. data/lib/simplecov/formatter/html_formatter/public/application.js +18 -0
  53. data/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
  54. data/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
  55. data/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
  56. data/lib/simplecov/formatter/html_formatter/public/index.html +56 -0
  57. data/lib/simplecov/formatter/html_formatter.rb +85 -0
  58. data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +90 -0
  59. data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +128 -0
  60. data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +99 -0
  61. data/lib/simplecov/formatter/json_formatter.rb +89 -0
  62. data/lib/simplecov/formatter/multi_formatter.rb +11 -7
  63. data/lib/simplecov/formatter/simple_formatter.rb +11 -11
  64. data/lib/simplecov/formatter.rb +4 -0
  65. data/lib/simplecov/last_run.rb +10 -3
  66. data/lib/simplecov/lines_classifier.rb +25 -13
  67. data/lib/simplecov/load_global_config.rb +9 -4
  68. data/lib/simplecov/parallel_adapters/base.rb +61 -0
  69. data/lib/simplecov/parallel_adapters/generic.rb +44 -0
  70. data/lib/simplecov/parallel_adapters/parallel_tests.rb +93 -0
  71. data/lib/simplecov/parallel_adapters.rb +83 -0
  72. data/lib/simplecov/parallel_coordination.rb +129 -0
  73. data/lib/simplecov/process.rb +52 -12
  74. data/lib/simplecov/profiles/bundler_filter.rb +1 -1
  75. data/lib/simplecov/profiles/hidden_filter.rb +1 -1
  76. data/lib/simplecov/profiles/rails.rb +24 -10
  77. data/lib/simplecov/profiles/root_filter.rb +6 -5
  78. data/lib/simplecov/profiles/strict.rb +32 -0
  79. data/lib/simplecov/profiles/test_frameworks.rb +1 -4
  80. data/lib/simplecov/profiles.rb +32 -3
  81. data/lib/simplecov/result/missing_source_files_reporter.rb +49 -0
  82. data/lib/simplecov/result/source_file_builder.rb +51 -0
  83. data/lib/simplecov/result.rb +108 -19
  84. data/lib/simplecov/result_adapter.rb +105 -8
  85. data/lib/simplecov/result_merger/legacy_format_adapter.rb +28 -0
  86. data/lib/simplecov/result_merger/resultset_file.rb +38 -0
  87. data/lib/simplecov/result_merger/resultset_store.rb +50 -0
  88. data/lib/simplecov/result_merger.rb +59 -91
  89. data/lib/simplecov/result_processing.rb +179 -0
  90. data/lib/simplecov/simulate_coverage.rb +54 -8
  91. data/lib/simplecov/source_file/branch.rb +1 -3
  92. data/lib/simplecov/source_file/branch_builder.rb +114 -0
  93. data/lib/simplecov/source_file/builder_context.rb +28 -0
  94. data/lib/simplecov/source_file/line.rb +9 -4
  95. data/lib/simplecov/source_file/line_builder.rb +43 -0
  96. data/lib/simplecov/source_file/method.rb +52 -0
  97. data/lib/simplecov/source_file/method_builder.rb +60 -0
  98. data/lib/simplecov/source_file/ruby_data_parser.rb +88 -0
  99. data/lib/simplecov/source_file/skip_chunks.rb +75 -0
  100. data/lib/simplecov/source_file/source_loader.rb +63 -0
  101. data/lib/simplecov/source_file/statistics.rb +57 -0
  102. data/lib/simplecov/source_file.rb +66 -232
  103. data/lib/simplecov/static_coverage_extractor/condition_folding.rb +49 -0
  104. data/lib/simplecov/static_coverage_extractor/location_conventions.rb +247 -0
  105. data/lib/simplecov/static_coverage_extractor/method_collector.rb +55 -0
  106. data/lib/simplecov/static_coverage_extractor/value_position.rb +82 -0
  107. data/lib/simplecov/static_coverage_extractor/visitor.rb +196 -0
  108. data/lib/simplecov/static_coverage_extractor.rb +110 -0
  109. data/lib/simplecov/useless_results_remover.rb +16 -7
  110. data/lib/simplecov/version.rb +1 -1
  111. data/lib/simplecov-html.rb +4 -0
  112. data/lib/simplecov.rb +178 -380
  113. data/lib/simplecov_json_formatter.rb +4 -0
  114. data/schemas/coverage-v1.0.schema.json +306 -0
  115. data/schemas/coverage.schema.json +306 -0
  116. data/sig/simplecov.rbs +1638 -0
  117. metadata +94 -57
  118. data/CHANGELOG.md +0 -191
  119. data/lib/simplecov/default_formatter.rb +0 -20
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module SimpleCov
6
+ module Formatter
7
+ # @api private
8
+ #
9
+ # Shared scaffolding for formatters that write a coverage report to
10
+ # an output directory and emit a "Coverage report generated for X
11
+ # to Y" summary on stderr (it's a status message, not data).
12
+ # Subclasses override `format` to do their actual writing, and may
13
+ # override `message_prefix` (e.g. JSON prepends "JSON ").
14
+ class Base
15
+ # `output_dir` defaults to `SimpleCov.coverage_path` so the at_exit
16
+ # pipeline keeps working unchanged. Pass it explicitly to write
17
+ # somewhere else (handy for tests that don't want to clobber the
18
+ # project's `coverage/` directory).
19
+ def initialize(silent: false, output_dir: nil)
20
+ @silent = silent
21
+ @output_dir = output_dir
22
+ end
23
+
24
+ private
25
+
26
+ # Subclasses override to prepend a marker (e.g. "JSON ") to the
27
+ # summary line. Default empty for the HTML formatter, which has
28
+ # historically been the unmarked default.
29
+ def message_prefix
30
+ ""
31
+ end
32
+
33
+ def output_path
34
+ @output_dir || SimpleCov.coverage_path
35
+ end
36
+
37
+ # The path shown in the "Coverage report generated for X to Y"
38
+ # status line. Renders relative to cwd when `output_path` lives
39
+ # inside cwd (e.g. `coverage` instead of `/Users/me/proj/coverage`)
40
+ # and appends the formatter's `entry_point_filename` so the line
41
+ # points at a concrete file the user (or a terminal that
42
+ # hyperlinks paths) can act on — e.g. `coverage/index.html`
43
+ # instead of the bare directory `coverage`. Paths outside cwd
44
+ # stay absolute; a `../../../tmp/cov` display would be more
45
+ # confusing than the absolute form. See issue #197.
46
+ def displayable_output_path
47
+ directory = relative_or_absolute_output_path
48
+ entry_point = entry_point_filename
49
+ entry_point ? File.join(directory, entry_point) : directory
50
+ end
51
+
52
+ def relative_or_absolute_output_path
53
+ absolute = output_path
54
+ relative = Pathname.new(absolute).relative_path_from(Pathname.pwd).to_s
55
+ relative.start_with?("..") ? absolute : relative
56
+ rescue ArgumentError
57
+ # Pathname#relative_path_from raises across mixed absolute/
58
+ # relative inputs (and across Windows drives) — keep the
59
+ # absolute form on any unresolvable case.
60
+ output_path
61
+ end
62
+
63
+ # Subclasses override to name the report's entry-point file
64
+ # (e.g. `index.html` for HTML, `coverage.json` for JSON), which
65
+ # gets appended to the directory in the status line. Default nil
66
+ # leaves the bare directory in place for any third-party formatter
67
+ # that has no single canonical entry point.
68
+ def entry_point_filename
69
+ nil
70
+ end
71
+
72
+ # Emit one summary line per criterion that the run actually
73
+ # measured. The header line ("Coverage report generated for X
74
+ # to Y") is always first; per-criterion lines follow in the
75
+ # order of `result.coverage_statistics` (which is the same
76
+ # insertion order as `SourceFile#coverage_statistics`, which in
77
+ # turn reflects what the user enabled).
78
+ def output_message(result)
79
+ header = "#{message_prefix}Coverage report generated for #{result.command_name} to #{displayable_output_path}"
80
+ body = result.coverage_statistics.filter_map { |criterion, stat| stats_line(criterion, stat) }
81
+ [header, *body].join("\n")
82
+ end
83
+
84
+ # Returns nil for branch/method criteria that have nothing to
85
+ # measure (e.g. a file with no branches under branch coverage).
86
+ # Showing "Branch coverage: 0 / 0 (100.00%)" is noise; the older
87
+ # output specifically suppressed it.
88
+ def stats_line(criterion, stat)
89
+ return if criterion != :line && !stat.total.positive?
90
+
91
+ percent = SimpleCov.round_coverage(stat.percent)
92
+ Kernel.format(
93
+ "%<label>s coverage: %<covered>d / %<total>d (%<percent>s)",
94
+ label: criterion.to_s.capitalize,
95
+ covered: stat.covered,
96
+ total: stat.total,
97
+ percent: SimpleCov::Color.colorize_percent(percent)
98
+ )
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1 @@
1
+ *,*:before,*:after{box-sizing:border-box}*{margin:0;padding:0}html{-moz-text-size-adjust:none;-webkit-text-size-adjust:none;text-size-adjust:none}body{min-height:100vh;line-height:1.5;-webkit-font-smoothing:antialiased}img,picture,svg{display:block;max-width:100%}input,button,textarea,select{font:inherit}h1,h2,h3,h4,h5,h6{overflow-wrap:break-word;text-wrap:balance}p{overflow-wrap:break-word;text-wrap:pretty}table{border-collapse:collapse;border-spacing:0}ul,ol{list-style:none}a{text-decoration-skip-ink:auto;color:currentColor}.hide{display:none}.hljs{color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}@media(prefers-color-scheme:dark){:root:not(.light-mode) .hljs{color:#c9d1d9}:root:not(.light-mode) .hljs-doctag,:root:not(.light-mode) .hljs-keyword,:root:not(.light-mode) .hljs-meta .hljs-keyword,:root:not(.light-mode) .hljs-template-tag,:root:not(.light-mode) .hljs-template-variable,:root:not(.light-mode) .hljs-type,:root:not(.light-mode) .hljs-variable.language_{color:#ff7b72}:root:not(.light-mode) .hljs-title,:root:not(.light-mode) .hljs-title.class_,:root:not(.light-mode) .hljs-title.class_.inherited__,:root:not(.light-mode) .hljs-title.function_{color:#d2a8ff}:root:not(.light-mode) .hljs-attr,:root:not(.light-mode) .hljs-attribute,:root:not(.light-mode) .hljs-literal,:root:not(.light-mode) .hljs-meta,:root:not(.light-mode) .hljs-number,:root:not(.light-mode) .hljs-operator,:root:not(.light-mode) .hljs-variable,:root:not(.light-mode) .hljs-selector-attr,:root:not(.light-mode) .hljs-selector-class,:root:not(.light-mode) .hljs-selector-id{color:#79c0ff}:root:not(.light-mode) .hljs-regexp,:root:not(.light-mode) .hljs-string,:root:not(.light-mode) .hljs-meta .hljs-string{color:#a5d6ff}:root:not(.light-mode) .hljs-built_in,:root:not(.light-mode) .hljs-symbol{color:#ffa657}:root:not(.light-mode) .hljs-comment,:root:not(.light-mode) .hljs-code,:root:not(.light-mode) .hljs-formula{color:#8b949e}:root:not(.light-mode) .hljs-name,:root:not(.light-mode) .hljs-quote,:root:not(.light-mode) .hljs-selector-tag,:root:not(.light-mode) .hljs-selector-pseudo{color:#7ee787}:root:not(.light-mode) .hljs-subst{color:#c9d1d9}:root:not(.light-mode) .hljs-section{color:#1f6feb}}.dark-mode .hljs{color:#c9d1d9}.dark-mode .hljs-doctag,.dark-mode .hljs-keyword,.dark-mode .hljs-meta .hljs-keyword,.dark-mode .hljs-template-tag,.dark-mode .hljs-template-variable,.dark-mode .hljs-type,.dark-mode .hljs-variable.language_{color:#ff7b72}.dark-mode .hljs-title,.dark-mode .hljs-title.class_,.dark-mode .hljs-title.class_.inherited__,.dark-mode .hljs-title.function_{color:#d2a8ff}.dark-mode .hljs-attr,.dark-mode .hljs-attribute,.dark-mode .hljs-literal,.dark-mode .hljs-meta,.dark-mode .hljs-number,.dark-mode .hljs-operator,.dark-mode .hljs-variable,.dark-mode .hljs-selector-attr,.dark-mode .hljs-selector-class,.dark-mode .hljs-selector-id{color:#79c0ff}.dark-mode .hljs-regexp,.dark-mode .hljs-string,.dark-mode .hljs-meta .hljs-string{color:#a5d6ff}.dark-mode .hljs-built_in,.dark-mode .hljs-symbol{color:#ffa657}.dark-mode .hljs-comment,.dark-mode .hljs-code,.dark-mode .hljs-formula{color:#8b949e}.dark-mode .hljs-name,.dark-mode .hljs-quote,.dark-mode .hljs-selector-tag,.dark-mode .hljs-selector-pseudo{color:#7ee787}.dark-mode .hljs-subst{color:#c9d1d9}.dark-mode .hljs-section{color:#1f6feb}:root{--font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;--sp-1: 4px;--sp-2: 8px;--sp-3: 12px;--sp-4: 16px;--sp-5: 20px;--sp-6: 24px;--sp-8: 32px;--radius-sm: 8px;--radius-md: 12px;--radius-lg: 16px;--bg: #f0f1f3;--surface: #fff;--surface-alt: #f0f1f3;--text: #111;--text-secondary: #333;--text-tertiary: #444;--zebra: #f4f5f7;--border: #c0c5cc;--border-strong: #999;--accent: #0550ae;--accent-hover: #033d8b;--accent-subtle: #ddf4ff;--green: #116329;--red: #a40e26;--yellow: #7a5200;--orange: #953800;--covered-bg: #ccf5d0;--covered-line-num-bg: #9ae6a4;--missed-bg: #ffd8d5;--missed-line-num-bg: #ffb8b3;--never-bg: #fff;--never-line-num-bg: #f0f1f3;--skipped-bg: #fff0a0;--skipped-line-num-bg: #eed860;--missed-branch-bg: #ffd0a0;--missed-branch-line-num-bg: #ffb060;--missed-branch-text: #b45309;--missed-method-bg: #e8d0ff;--missed-method-line-num-bg: #d4b0ff;--missed-method-text: #7b2d8e;--source-bg: #fff;--source-border: #c0c5cc;--source-line-number: #444;--source-line-num-bg: #f0f1f3;--hits-bg: #e0e3e8;--hits-color: #333;--overlay-bg: rgba(0, 0, 0, .5);--bar-bg: #d0d7de;--bar-height: 6px}@media(prefers-color-scheme:dark){:root:not(.light-mode){--bg: #010409;--surface: #0d1117;--surface-alt: #161b22;--text: #f0f3f6;--text-secondary: #b0b8c4;--text-tertiary: #9aa5b1;--zebra: #161b22;--border: #3d444d;--border-strong: #555e68;--accent: #6cb6ff;--accent-hover: #96ccff;--accent-subtle: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--orange: #f0883e;--covered-bg: #122d1e;--covered-line-num-bg: #1e4430;--missed-bg: #351418;--missed-line-num-bg: #4e1d20;--never-bg: #0d1117;--never-line-num-bg: #161b22;--skipped-bg: #302818;--skipped-line-num-bg: #443920;--missed-branch-bg: #322218;--missed-branch-line-num-bg: #483020;--missed-branch-text: #ffb86c;--missed-method-bg: #1e1830;--missed-method-line-num-bg: #2a2044;--missed-method-text: #dcb8ff;--source-bg: #0d1117;--source-border: #3d444d;--source-line-number: #9aa5b1;--source-line-num-bg: #161b22;--hits-bg: #262c34;--hits-color: #b0b8c4;--overlay-bg: rgba(1, 4, 9, .8);--bar-bg: #3d444d}}.dark-mode{--bg: #010409;--surface: #0d1117;--surface-alt: #161b22;--text: #f0f3f6;--text-secondary: #b0b8c4;--text-tertiary: #9aa5b1;--zebra: #161b22;--border: #3d444d;--border-strong: #555e68;--accent: #6cb6ff;--accent-hover: #96ccff;--accent-subtle: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--orange: #f0883e;--covered-bg: #122d1e;--covered-line-num-bg: #1e4430;--missed-bg: #351418;--missed-line-num-bg: #4e1d20;--never-bg: #0d1117;--never-line-num-bg: #161b22;--skipped-bg: #302818;--skipped-line-num-bg: #443920;--missed-branch-bg: #322218;--missed-branch-line-num-bg: #483020;--missed-branch-text: #ffb86c;--missed-method-bg: #1e1830;--missed-method-line-num-bg: #2a2044;--missed-method-text: #dcb8ff;--source-bg: #0d1117;--source-border: #3d444d;--source-line-number: #9aa5b1;--source-line-num-bg: #161b22;--hits-bg: #262c34;--hits-color: #b0b8c4;--overlay-bg: rgba(1, 4, 9, .8);--bar-bg: #3d444d}body{font-family:var(--font-sans);font-size:18px;color:var(--text);background:var(--bg);padding:var(--sp-6)}a{color:var(--accent);text-decoration:none;transition:color .15s}a:hover{color:var(--accent-hover)}strong,b{font-weight:600}#loading{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--bg);z-index:9999}#loading-inner{width:280px;text-align:center}#loading-bar-track{width:100%;height:6px;background:var(--bar-bg);border-radius:6px;overflow:hidden}#loading-bar-fill{width:0%;height:100%;background:var(--accent);border-radius:6px;transition:width .15s ease-out}#loading-text{margin-top:var(--sp-3);font-size:18px;color:var(--text-tertiary)}#sort-overlay{position:fixed;inset:0;z-index:9998;display:flex;align-items:center;justify-content:center;background:var(--overlay-bg)}#sort-overlay-label{padding:var(--sp-2) var(--sp-4);border:1px solid var(--border);border-radius:6px;background:var(--bg);font-size:16px;color:var(--text-tertiary)}#wrapper{margin:0 auto}.tab-bar{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);margin-bottom:-1px;position:relative;z-index:1}abbr.timeago{text-decoration:none;border:none}.group_tabs{display:flex;align-self:flex-end;gap:var(--sp-1);overflow-x:auto}.group_tabs li a{display:block;padding:var(--sp-2) var(--sp-4);font-size:18px;font-weight:500;color:var(--text-secondary);background:transparent;border:1px solid transparent;border-bottom:none;border-radius:var(--radius-md) var(--radius-md) 0 0;white-space:nowrap;transition:color .15s,background .15s}.group_tabs li a:hover{color:var(--text);background:var(--surface-alt);text-decoration:none}.group_tabs li.active a{color:var(--accent);background:var(--surface);border-color:var(--border);font-weight:600}#content{background:var(--surface);border:1px solid var(--border);border-radius:0 var(--radius-lg) var(--radius-lg) var(--radius-lg);padding:var(--sp-6)}.file_list_container h2{font-size:24px;font-weight:600;color:var(--text);margin:0}.file_list_container h2 .covered_percent{font-weight:600}.summary-stats{display:flex;flex-direction:column;gap:var(--sp-1);font-size:18px;color:var(--text-secondary)}.summary-stats b{color:var(--text)}.summary-stats .missed-branch-text b,.summary-stats .missed-method-text-color b,.summary-stats .green b,.summary-stats .red b{color:inherit}.summary-stats .green{color:var(--green)}.summary-stats .red{color:var(--red)}.coverage-disabled{color:var(--text-tertiary);font-style:italic}.th-with-filter{display:flex;align-items:center;gap:var(--sp-2)}table.file_list th.cell--coverage .th-with-filter{white-space:nowrap;justify-content:flex-end}.th-with-filter .th-label{white-space:nowrap}.col-filter--name{width:100%;min-width:200px;border:1px solid var(--border);border-radius:999px;padding:var(--sp-1) var(--sp-4);font-size:14px;background:var(--surface);color:var(--text);outline:none}.col-filter--name:focus{border-color:var(--accent)}.col-filter__coverage{display:flex;gap:var(--sp-1)}.col-filter__op{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--sp-1) var(--sp-1);font-size:14px;background:var(--surface);color:var(--text);cursor:pointer}.col-filter__value{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--sp-1) var(--sp-2);font-size:14px;background:var(--surface);color:var(--text);width:60px;outline:none}.col-filter__value:focus{border-color:var(--accent)}.file_list--responsive{overflow-x:auto}table.file_list{width:100%;font-size:18px}table.file_list{border-collapse:separate;border-spacing:0}table.file_list thead th{font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--text-tertiary);background:var(--surface);padding:var(--sp-2) var(--sp-2);border-bottom:2px solid var(--border-strong);white-space:nowrap}table.file_list tbody tr{background:var(--surface);cursor:pointer}table.file_list tbody tr:nth-child(2n){background:var(--zebra)}table.file_list tbody tr:hover{background:var(--accent-subtle)}table.file_list tbody tr.keyboard-focus{background:var(--accent-subtle);outline:2px solid var(--accent);outline-offset:-2px}table.file_list tbody td{padding:var(--sp-2) var(--sp-2);border-bottom:1px solid var(--border);color:var(--text)}table.file_list td.cell--number{text-align:right;font-variant-numeric:tabular-nums;color:var(--text)}table.file_list th.cell--left,table.file_list th.cell--coverage{text-align:left}table.file_list th.cell--number{text-align:right}table.file_list th.cell--numerator{text-align:right;padding-right:0}table.file_list th.cell--denominator{text-align:left;padding-left:0}table.file_list td.strong{font-weight:600;color:var(--text)}table.file_list td.t-file__name{white-space:nowrap}a.src_link{color:var(--accent);font-weight:500;word-break:break-all}table.file_list td.cell--coverage{white-space:nowrap}.coverage-cell{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-end;gap:10px}.coverage-cell .coverage-pct{flex:0 0 4.5em;font-variant-numeric:tabular-nums}tr.t-window-hidden{display:none}tr.t-show-all td{padding:var(--sp-3);text-align:center;color:var(--text-tertiary);cursor:pointer}.coverage-cell .bar-sizer{flex:0 0 auto;width:var(--bar-sizer-width, 240px);min-width:160px;max-width:240px}table.file_list td.cell--numerator{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;padding-left:var(--sp-1);padding-right:0}table.file_list td.cell--denominator{text-align:left;font-variant-numeric:tabular-nums;white-space:nowrap;padding-left:0;padding-right:var(--sp-1)}table.file_list .totals-row td.cell--numerator{color:var(--text);padding-right:0}table.file_list .totals-row td.cell--denominator{color:var(--text);padding-left:0}.coverage-cell__fraction{font-variant-numeric:tabular-nums;color:var(--text-secondary);font-size:14px;white-space:nowrap}.coverage-bar{width:100%;height:var(--bar-height);background:var(--bar-bg);border-radius:6px;overflow:hidden}.coverage-bar__fill{height:100%;border-radius:6px}.coverage-bar__fill--green{background:var(--green)}.coverage-bar__fill--yellow{background:var(--yellow)}.coverage-bar__fill--red{background:var(--red)}.green,table.file_list td.green{color:var(--green)}.red,table.file_list td.red{color:var(--red)}.yellow,table.file_list td.yellow{color:var(--yellow)}.missed-branch-text{color:var(--missed-branch-text)}.missed-method-text-color{color:var(--missed-method-text)}dialog.source-dialog{position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;border:none;padding:0;background:var(--bg);color:var(--text);overflow:hidden}dialog.source-dialog::backdrop{background:var(--overlay-bg)}dialog.source-dialog[open]{display:flex;flex-direction:column}.source-dialog__header{display:flex;align-items:flex-start;justify-content:space-between;padding:var(--sp-4) var(--sp-6);background:var(--surface);border-bottom:1px solid var(--border);flex-shrink:0}.source-dialog__title{flex:1;min-width:0}.source-dialog__title h2{font-size:22px;font-weight:700;color:var(--text);margin-bottom:var(--sp-2);word-break:break-all}.source-legend{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);align-items:center;align-self:flex-end;flex-shrink:0;margin-left:auto;padding-left:var(--sp-6)}.source-legend__item{display:flex;align-items:center;gap:var(--sp-1);font-size:13px;color:var(--text-secondary);white-space:nowrap}.source-legend__swatch{display:inline-block;width:14px;height:14px;border-radius:3px;border:1px solid var(--border)}.source-legend__swatch--covered{background:var(--covered-bg);border-color:var(--covered-line-num-bg)}.source-legend__swatch--missed{background:var(--missed-bg);border-color:var(--missed-line-num-bg)}.source-legend__swatch--skipped{background:var(--skipped-bg);border-color:var(--skipped-line-num-bg)}.source-legend__swatch--missed-branch{background:var(--missed-branch-bg);border-color:var(--missed-branch-line-num-bg)}.source-legend__swatch--missed-method{background:var(--missed-method-bg);border-color:var(--missed-method-line-num-bg)}.source-dialog__close{appearance:none;background:none;border:1px solid var(--border);border-radius:50%;width:34px;height:34px;font-size:0;color:var(--text-secondary);cursor:pointer;position:relative;flex-shrink:0;margin-left:var(--sp-4);transition:color .15s,border-color .15s}.source-dialog__close:before,.source-dialog__close:after{content:"";position:absolute;top:50%;left:50%;width:14px;height:2px;background:currentColor;border-radius:1px}.source-dialog__close:before{transform:translate(-50%,-50%) rotate(45deg)}.source-dialog__close:after{transform:translate(-50%,-50%) rotate(-45deg)}.source-dialog__close:hover{color:var(--text);border-color:var(--border-strong)}.source-dialog__body{flex:1;overflow:auto}.source_table .header{padding:var(--sp-4) var(--sp-6);background:var(--surface)}.source_table .header h2{font-size:22px;font-weight:700;color:var(--text);margin-bottom:var(--sp-2)}table.file_list .totals-row td{padding:var(--sp-2) var(--sp-2);font-weight:600;border-bottom:2px solid var(--border-strong);background:var(--surface-alt)}.totals-row .t-file-count{font-size:18px;font-weight:700;color:var(--text)}.t-missed-method-toggle{color:var(--missed-method-text);font-weight:600;cursor:pointer;text-decoration:none}.t-missed-method-toggle:hover{text-decoration:underline;color:var(--missed-method-text)}.t-missed-method-list ul{padding-left:2em;margin-top:var(--sp-1);max-height:200px;overflow-y:auto}.t-missed-method-list li{list-style:none}.source_table pre{margin:0;padding:0;white-space:normal;color:var(--text);font-family:var(--font-mono);font-size:16px;line-height:24px;background:var(--source-bg);border:1px solid var(--source-border);border-top:none}.source_table code{color:inherit;font-family:var(--font-mono)}.source_table pre ol{margin:0;padding:0;list-style:none;counter-reset:linenumber}.source_table pre li{display:flex;counter-increment:linenumber;background:var(--never-bg)}.source_table pre li:before{content:counter(linenumber);flex-shrink:0;width:50px;padding:0 8px;text-align:right;color:var(--source-line-number);background:var(--source-line-num-bg);border-right:1px solid var(--source-border);-webkit-user-select:none;user-select:none;cursor:pointer}.source_table pre li:hover:before{color:var(--text)}.source_table pre li:hover{cursor:pointer}.source_table pre li code{order:1;flex:1;min-width:0;padding:0 12px;white-space:pre-wrap}.source_table pre .hits{order:2;flex-shrink:0;padding:0 var(--sp-2);background:var(--hits-bg);color:var(--hits-color);font-family:var(--font-mono);font-size:14px;text-align:center;line-height:24px;border-left:1px solid var(--source-border);-webkit-user-select:none;user-select:none}.source_table pre .hits:after{content:attr(data-content)}.source_table .covered{background-color:var(--covered-bg)}.source_table .missed{background-color:var(--missed-bg)}.source_table .never{background-color:var(--never-bg)}.source_table .skipped{background-color:var(--skipped-bg)}.source_table .missed-branch{background-color:var(--missed-branch-bg)}.source_table .missed-method{background-color:var(--missed-method-bg)}.source_table .covered:before{background-color:var(--covered-line-num-bg)}.source_table .missed:before{background-color:var(--missed-line-num-bg)}.source_table .never:before{background-color:var(--never-line-num-bg)}.source_table .skipped:before{background-color:var(--skipped-line-num-bg)}.source_table .missed-branch:before{background-color:var(--missed-branch-line-num-bg)}.source_table .missed-method:before{background-color:var(--missed-method-line-num-bg)}#dark-mode-toggle{appearance:none;background:var(--surface);color:var(--text-secondary);border:1px solid var(--border);border-radius:999px;padding:var(--sp-1) var(--sp-4);font-size:16px;font-family:var(--font-sans);cursor:pointer;white-space:nowrap;transition:color .15s,border-color .15s}#dark-mode-toggle:hover{color:var(--text);border-color:var(--border-strong)}#footer{color:var(--text-tertiary);font-size:16px;margin-top:var(--sp-5);text-align:center}#footer a{color:var(--text-secondary);text-decoration:underline}#footer a:hover{color:var(--text)}table.file_list thead th.sorting,table.file_list thead th.sorting_asc,table.file_list thead th.sorting_desc{cursor:pointer;position:relative;padding-right:12px}table.file_list thead th.sorting:after,table.file_list thead th.sorting_asc:after,table.file_list thead th.sorting_desc:after{position:absolute;right:2px;top:50%;transform:translateY(-50%);font-size:14px;color:var(--text-tertiary)}table.file_list thead th.sorting:after{content:"\2195"}table.file_list thead th.sorting_asc:after{content:"\2191"}table.file_list thead th.sorting_desc:after{content:"\2193"}@media print{:root,.dark-mode{--bg: #fff;--surface: #fff;--surface-alt: #f4f5f7;--text: #111;--text-secondary: #333;--text-tertiary: #444;--zebra: #f4f5f7;--border: #c0c5cc;--border-strong: #999;--accent: #0550ae;--green: #116329;--red: #a40e26;--yellow: #7a5200;--orange: #953800;--bar-bg: #d0d7de;--covered-bg: #ccf5d0;--covered-line-num-bg: #9ae6a4;--missed-bg: #ffd8d5;--missed-line-num-bg: #ffb8b3;--never-bg: #fff;--never-line-num-bg: #f0f1f3;--skipped-bg: #fff0a0;--skipped-line-num-bg: #eed860;--missed-branch-bg: #ffd0a0;--missed-branch-line-num-bg: #ffb060;--missed-branch-text: #b45309;--missed-method-bg: #e8d0ff;--missed-method-line-num-bg: #d4b0ff;--missed-method-text: #7b2d8e;--source-bg: #fff;--source-border: #c0c5cc;--source-line-number: #444;--source-line-num-bg: #f0f1f3;--hits-bg: #e0e3e8;--hits-color: #333}body{padding:0;font-size:12pt}#loading,#sort-overlay,#dark-mode-toggle,.tab-bar,.source_files,.col-filter--name,.col-filter__coverage,tr.t-show-all,table.file_list thead th.sorting:after,table.file_list thead th.sorting_asc:after,table.file_list thead th.sorting_desc:after{display:none!important}#wrapper,.file_list_container{display:block!important}body:has(.source-dialog[open]) #wrapper{display:none!important}#content{border:none;border-radius:0;padding:0}.file_list_container .group_name{display:inline!important;font-size:16pt;font-weight:700}.file_list_container .covered_percent{display:inline!important;font-weight:600}.file_list_container+.file_list_container{margin-top:24pt}dialog.source-dialog{display:none}dialog.source-dialog[open]{display:block!important;position:static;width:100%;height:auto;max-height:none;overflow:visible;background:#fff}.source-dialog__close{display:none!important}.source-dialog__header{flex-wrap:wrap;border-bottom:none;padding:0 0 8pt}.source-dialog__title{flex:0 0 100%}.source-dialog__title h2{word-break:normal;overflow-wrap:break-word}.source-legend{margin-left:0;padding-left:0;padding-top:var(--sp-2)}.source-dialog__body{overflow:visible}.source_table pre{font-size:8pt;line-height:1.4}.source_table pre li{-webkit-print-color-adjust:exact;print-color-adjust:exact}.source_table pre li:before{-webkit-print-color-adjust:exact;print-color-adjust:exact}.source_table pre .hits{-webkit-print-color-adjust:exact;print-color-adjust:exact}.coverage-bar{border:1px solid var(--border);-webkit-print-color-adjust:exact;print-color-adjust:exact}.coverage-bar__fill{-webkit-print-color-adjust:exact;print-color-adjust:exact}table.file_list tbody tr:nth-child(2n){-webkit-print-color-adjust:exact;print-color-adjust:exact}table.file_list{font-size:10pt}table.file_list thead th{font-size:9pt}table.file_list{page-break-inside:auto}table.file_list tr{page-break-inside:avoid}table.file_list thead{display:table-header-group}#footer{font-size:10pt;margin-top:12pt}#footer a:after{content:" (" attr(href) ")";font-size:9pt;color:var(--text-tertiary)}}
@@ -0,0 +1,18 @@
1
+ "use strict";(()=>{var xn=Object.create;var dt=Object.defineProperty;var An=Object.getOwnPropertyDescriptor;var Cn=Object.getOwnPropertyNames;var Rn=Object.getPrototypeOf,Nn=Object.prototype.hasOwnProperty;var On=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var In=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Cn(t))!Nn.call(e,r)&&r!==n&&dt(e,r,{get:()=>t[r],enumerable:!(s=An(t,r))||s.enumerable});return e};var Hn=(e,t,n)=>(n=e!=null?xn(Rn(e)):{},In(t||!e||!e.__esModule?dt(n,"default",{value:e,enumerable:!0}):n,e));var J=(e,t,n)=>new Promise((s,r)=>{var l=c=>{try{o(n.next(c))}catch(d){r(d)}},i=c=>{try{o(n.throw(c))}catch(d){r(d)}},o=c=>c.done?s(c.value):Promise.resolve(c.value).then(l,i);o((n=n.apply(e,t)).next())});var Bt=On((br,Dt)=>{function Tt(e){return e instanceof Map?e.clear=e.delete=e.set=function(){throw new Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=function(){throw new Error("set is read-only")}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach(t=>{let n=e[t],s=typeof n;(s==="object"||s==="function")&&!Object.isFrozen(n)&&Tt(n)}),e}var ye=class{constructor(t){t.data===void 0&&(t.data={}),this.data=t.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}};function Lt(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function G(e,...t){let n=Object.create(null);for(let s in e)n[s]=e[s];return t.forEach(function(s){for(let r in s)n[r]=s[r]}),n}var Bn="</span>",_t=e=>!!e.scope,Fn=(e,{prefix:t})=>{if(e.startsWith("language:"))return e.replace("language:","language-");if(e.includes(".")){let n=e.split(".");return[`${t}${n.shift()}`,...n.map((s,r)=>`${s}${"_".repeat(r+1)}`)].join(" ")}return`${t}${e}`},ke=class{constructor(t,n){this.buffer="",this.classPrefix=n.classPrefix,t.walk(this)}addText(t){this.buffer+=Lt(t)}openNode(t){if(!_t(t))return;let n=Fn(t.scope,{prefix:this.classPrefix});this.span(n)}closeNode(t){_t(t)&&(this.buffer+=Bn)}value(){return this.buffer}span(t){this.buffer+=`<span class="${t}">`}},vt=(e={})=>{let t={children:[]};return Object.assign(t,e),t},De=class e{constructor(){this.rootNode=vt(),this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(t){this.top.children.push(t)}openNode(t){let n=vt({scope:t});this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(t){return this.constructor._walk(t,this.rootNode)}static _walk(t,n){return typeof n=="string"?t.addText(n):n.children&&(t.openNode(n),n.children.forEach(s=>this._walk(t,s)),t.closeNode(n)),t}static _collapse(t){typeof t!="string"&&t.children&&(t.children.every(n=>typeof n=="string")?t.children=[t.children.join("")]:t.children.forEach(n=>{e._collapse(n)}))}},Be=class extends De{constructor(t){super(),this.options=t}addText(t){t!==""&&this.add(t)}startScope(t){this.openNode(t)}endScope(){this.closeNode()}__addSublanguage(t,n){let s=t.root;n&&(s.scope=`language:${n}`),this.add(s)}toHTML(){return new ke(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}};function ae(e){return e?typeof e=="string"?e:e.source:null}function xt(e){return Z("(?=",e,")")}function Pn(e){return Z("(?:",e,")*")}function qn(e){return Z("(?:",e,")?")}function Z(...e){return e.map(n=>ae(n)).join("")}function Wn(e){let t=e[e.length-1];return typeof t=="object"&&t.constructor===Object?(e.splice(e.length-1,1),t):{}}function Pe(...e){return"("+(Wn(e).capture?"":"?:")+e.map(s=>ae(s)).join("|")+")"}function At(e){return new RegExp(e.toString()+"|").exec("").length-1}function Un(e,t){let n=e&&e.exec(t);return n&&n.index===0}var jn=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function qe(e,{joinWith:t}){let n=0;return e.map(s=>{n+=1;let r=n,l=ae(s),i="";for(;l.length>0;){let o=jn.exec(l);if(!o){i+=l;break}i+=l.substring(0,o.index),l=l.substring(o.index+o[0].length),o[0][0]==="\\"&&o[1]?i+="\\"+String(Number(o[1])+r):(i+=o[0],o[0]==="("&&n++)}return i}).map(s=>`(${s})`).join(t)}var zn=/\b\B/,Ct="[a-zA-Z]\\w*",We="[a-zA-Z_]\\w*",Rt="\\b\\d+(\\.\\d+)?",Nt="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",Ot="\\b(0b[01]+)",Gn="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",Kn=(e={})=>{let t=/^#![ ]*\//;return e.binary&&(e.begin=Z(t,/.*\b/,e.binary,/\b.*/)),G({scope:"meta",begin:t,end:/$/,relevance:0,"on:begin":(n,s)=>{n.index!==0&&s.ignoreMatch()}},e)},ue={begin:"\\\\[\\s\\S]",relevance:0},Xn={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[ue]},Vn={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[ue]},Zn={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},we=function(e,t,n={}){let s=G({scope:"comment",begin:e,end:t,contains:[]},n);s.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});let r=Pe("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return s.contains.push({begin:Z(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s},Yn=we("//","$"),Qn=we("/\\*","\\*/"),Jn=we("#","$"),es={scope:"number",begin:Rt,relevance:0},ts={scope:"number",begin:Nt,relevance:0},ns={scope:"number",begin:Ot,relevance:0},ss={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[ue,{begin:/\[/,end:/\]/,relevance:0,contains:[ue]}]},rs={scope:"title",begin:Ct,relevance:0},is={scope:"title",begin:We,relevance:0},os={begin:"\\.\\s*"+We,relevance:0},ls=function(e){return Object.assign(e,{"on:begin":(t,n)=>{n.data._beginMatch=t[1]},"on:end":(t,n)=>{n.data._beginMatch!==t[1]&&n.ignoreMatch()}})},ve=Object.freeze({__proto__:null,APOS_STRING_MODE:Xn,BACKSLASH_ESCAPE:ue,BINARY_NUMBER_MODE:ns,BINARY_NUMBER_RE:Ot,COMMENT:we,C_BLOCK_COMMENT_MODE:Qn,C_LINE_COMMENT_MODE:Yn,C_NUMBER_MODE:ts,C_NUMBER_RE:Nt,END_SAME_AS_BEGIN:ls,HASH_COMMENT_MODE:Jn,IDENT_RE:Ct,MATCH_NOTHING_RE:zn,METHOD_GUARD:os,NUMBER_MODE:es,NUMBER_RE:Rt,PHRASAL_WORDS_MODE:Zn,QUOTE_STRING_MODE:Vn,REGEXP_MODE:ss,RE_STARTERS_RE:Gn,SHEBANG:Kn,TITLE_MODE:rs,UNDERSCORE_IDENT_RE:We,UNDERSCORE_TITLE_MODE:is});function cs(e,t){e.input[e.index-1]==="."&&t.ignoreMatch()}function as(e,t){e.className!==void 0&&(e.scope=e.className,delete e.className)}function us(e,t){t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=cs,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function ds(e,t){Array.isArray(e.illegal)&&(e.illegal=Pe(...e.illegal))}function fs(e,t){if(e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function gs(e,t){e.relevance===void 0&&(e.relevance=1)}var ps=(e,t)=>{if(!e.beforeMatch)return;if(e.starts)throw new Error("beforeMatch cannot be used with starts");let n=Object.assign({},e);Object.keys(e).forEach(s=>{delete e[s]}),e.keywords=n.keywords,e.begin=Z(n.beforeMatch,xt(n.begin)),e.starts={relevance:0,contains:[Object.assign(n,{endsParent:!0})]},e.relevance=0,delete n.beforeMatch},hs=["of","and","for","in","not","or","if","then","parent","list","value"],ms="keyword";function It(e,t,n=ms){let s=Object.create(null);return typeof e=="string"?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach(function(l){Object.assign(s,It(e[l],t,l))}),s;function r(l,i){t&&(i=i.map(o=>o.toLowerCase())),i.forEach(function(o){let c=o.split("|");s[c[0]]=[l,bs(c[0],c[1])]})}}function bs(e,t){return t?Number(t):Es(e)?0:1}function Es(e){return hs.includes(e.toLowerCase())}var yt={},V=e=>{console.error(e)},Mt=(e,...t)=>{console.log(`WARN: ${e}`,...t)},te=(e,t)=>{yt[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),yt[`${e}/${t}`]=!0)},Me=new Error;function Ht(e,t,{key:n}){let s=0,r=e[n],l={},i={};for(let o=1;o<=t.length;o++)i[o+s]=r[o],l[o+s]=!0,s+=At(t[o-1]);e[n]=i,e[n]._emit=l,e[n]._multi=!0}function _s(e){if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw V("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),Me;if(typeof e.beginScope!="object"||e.beginScope===null)throw V("beginScope must be object"),Me;Ht(e,e.begin,{key:"beginScope"}),e.begin=qe(e.begin,{joinWith:""})}}function vs(e){if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw V("skip, excludeEnd, returnEnd not compatible with endScope: {}"),Me;if(typeof e.endScope!="object"||e.endScope===null)throw V("endScope must be object"),Me;Ht(e,e.end,{key:"endScope"}),e.end=qe(e.end,{joinWith:""})}}function ys(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function Ms(e){ys(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),_s(e),vs(e)}function ws(e){function t(i,o){return new RegExp(ae(i),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(o?"g":""))}class n{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(o,c){c.position=this.position++,this.matchIndexes[this.matchAt]=c,this.regexes.push([c,o]),this.matchAt+=At(o)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);let o=this.regexes.map(c=>c[1]);this.matcherRe=t(qe(o,{joinWith:"|"}),!0),this.lastIndex=0}exec(o){this.matcherRe.lastIndex=this.lastIndex;let c=this.matcherRe.exec(o);if(!c)return null;let d=c.findIndex((M,w)=>w>0&&M!==void 0),p=this.matchIndexes[d];return c.splice(0,d),Object.assign(c,p)}}class s{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(o){if(this.multiRegexes[o])return this.multiRegexes[o];let c=new n;return this.rules.slice(o).forEach(([d,p])=>c.addRule(d,p)),c.compile(),this.multiRegexes[o]=c,c}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(o,c){this.rules.push([o,c]),c.type==="begin"&&this.count++}exec(o){let c=this.getMatcher(this.regexIndex);c.lastIndex=this.lastIndex;let d=c.exec(o);if(this.resumingScanAtSamePosition()&&!(d&&d.index===this.lastIndex)){let p=this.getMatcher(0);p.lastIndex=this.lastIndex+1,d=p.exec(o)}return d&&(this.regexIndex+=d.position+1,this.regexIndex===this.count&&this.considerAll()),d}}function r(i){let o=new s;return i.contains.forEach(c=>o.addRule(c.begin,{rule:c,type:"begin"})),i.terminatorEnd&&o.addRule(i.terminatorEnd,{type:"end"}),i.illegal&&o.addRule(i.illegal,{type:"illegal"}),o}function l(i,o){let c=i;if(i.isCompiled)return c;[as,fs,Ms,ps].forEach(p=>p(i,o)),e.compilerExtensions.forEach(p=>p(i,o)),i.__beforeBegin=null,[us,ds,gs].forEach(p=>p(i,o)),i.isCompiled=!0;let d=null;return typeof i.keywords=="object"&&i.keywords.$pattern&&(i.keywords=Object.assign({},i.keywords),d=i.keywords.$pattern,delete i.keywords.$pattern),d=d||/\w+/,i.keywords&&(i.keywords=It(i.keywords,e.case_insensitive)),c.keywordPatternRe=t(d,!0),o&&(i.begin||(i.begin=/\B|\b/),c.beginRe=t(c.begin),!i.end&&!i.endsWithParent&&(i.end=/\B|\b/),i.end&&(c.endRe=t(c.end)),c.terminatorEnd=ae(c.end)||"",i.endsWithParent&&o.terminatorEnd&&(c.terminatorEnd+=(i.end?"|":"")+o.terminatorEnd)),i.illegal&&(c.illegalRe=t(i.illegal)),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map(function(p){return Ss(p==="self"?i:p)})),i.contains.forEach(function(p){l(p,c)}),i.starts&&l(i.starts,o),c.matcher=r(c),c}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=G(e.classNameAliases||{}),l(e)}function $t(e){return e?e.endsWithParent||$t(e.starts):!1}function Ss(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(t){return G(e,{variants:null},t)})),e.cachedVariants?e.cachedVariants:$t(e)?G(e,{starts:e.starts?G(e.starts):null}):Object.isFrozen(e)?G(e):e}var Ts="11.11.1",Fe=class extends Error{constructor(t,n){super(t),this.name="HTMLInjectionError",this.html=n}},$e=Lt,wt=G,St=Symbol("nomatch"),Ls=7,kt=function(e){let t=Object.create(null),n=Object.create(null),s=[],r=!0,l="Could not find the language '{}', did you forget to load/include a language module?",i={disableAutodetect:!0,name:"Plain text",contains:[]},o={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:Be};function c(a){return o.noHighlightRe.test(a)}function d(a){let g=a.className+" ";g+=a.parentNode?a.parentNode.className:"";let b=o.languageDetectRe.exec(g);if(b){let v=q(b[1]);return v||(Mt(l.replace("{}",b[1])),Mt("Falling back to no-highlight mode for this block.",a)),v?b[1]:"no-highlight"}return g.split(/\s+/).find(v=>c(v)||q(v))}function p(a,g,b){let v="",S="";typeof g=="object"?(v=a,b=g.ignoreIllegals,S=g.language):(te("10.7.0","highlight(lang, code, ...args) has been deprecated."),te("10.7.0",`Please use highlight(code, options) instead.
2
+ https://github.com/highlightjs/highlight.js/issues/2277`),S=a,v=g),b===void 0&&(b=!0);let k={code:v,language:S};me("before:highlight",k);let z=k.result?k.result:M(k.language,k.code,b);return z.code=k.code,me("after:highlight",z),z}function M(a,g,b,v){let S=Object.create(null);function k(u,f){return u.keywords[f]}function z(){if(!h.keywords){T.addText(y);return}let u=0;h.keywordPatternRe.lastIndex=0;let f=h.keywordPatternRe.exec(y),m="";for(;f;){m+=y.substring(u,f.index);let _=B.case_insensitive?f[0].toLowerCase():f[0],L=k(h,_);if(L){let[W,Tn]=L;if(T.addText(m),m="",S[_]=(S[_]||0)+1,S[_]<=Ls&&(_e+=Tn),W.startsWith("_"))m+=f[0];else{let Ln=B.classNameAliases[W]||W;D(f[0],Ln)}}else m+=f[0];u=h.keywordPatternRe.lastIndex,f=h.keywordPatternRe.exec(y)}m+=y.substring(u),T.addText(m)}function be(){if(y==="")return;let u=null;if(typeof h.subLanguage=="string"){if(!t[h.subLanguage]){T.addText(y);return}u=M(h.subLanguage,y,!0,ut[h.subLanguage]),ut[h.subLanguage]=u._top}else u=A(y,h.subLanguage.length?h.subLanguage:null);h.relevance>0&&(_e+=u.relevance),T.__addSublanguage(u._emitter,u.language)}function O(){h.subLanguage!=null?be():z(),y=""}function D(u,f){u!==""&&(T.startScope(f),T.addText(u),T.endScope())}function ot(u,f){let m=1,_=f.length-1;for(;m<=_;){if(!u._emit[m]){m++;continue}let L=B.classNameAliases[u[m]]||u[m],W=f[m];L?D(W,L):(y=W,z(),y=""),m++}}function lt(u,f){return u.scope&&typeof u.scope=="string"&&T.openNode(B.classNameAliases[u.scope]||u.scope),u.beginScope&&(u.beginScope._wrap?(D(y,B.classNameAliases[u.beginScope._wrap]||u.beginScope._wrap),y=""):u.beginScope._multi&&(ot(u.beginScope,f),y="")),h=Object.create(u,{parent:{value:h}}),h}function ct(u,f,m){let _=Un(u.endRe,m);if(_){if(u["on:end"]){let L=new ye(u);u["on:end"](f,L),L.isMatchIgnored&&(_=!1)}if(_){for(;u.endsParent&&u.parent;)u=u.parent;return u}}if(u.endsWithParent)return ct(u.parent,f,m)}function vn(u){return h.matcher.regexIndex===0?(y+=u[0],1):(He=!0,0)}function yn(u){let f=u[0],m=u.rule,_=new ye(m),L=[m.__beforeBegin,m["on:begin"]];for(let W of L)if(W&&(W(u,_),_.isMatchIgnored))return vn(f);return m.skip?y+=f:(m.excludeBegin&&(y+=f),O(),!m.returnBegin&&!m.excludeBegin&&(y=f)),lt(m,u),m.returnBegin?0:f.length}function Mn(u){let f=u[0],m=g.substring(u.index),_=ct(h,u,m);if(!_)return St;let L=h;h.endScope&&h.endScope._wrap?(O(),D(f,h.endScope._wrap)):h.endScope&&h.endScope._multi?(O(),ot(h.endScope,u)):L.skip?y+=f:(L.returnEnd||L.excludeEnd||(y+=f),O(),L.excludeEnd&&(y=f));do h.scope&&T.closeNode(),!h.skip&&!h.subLanguage&&(_e+=h.relevance),h=h.parent;while(h!==_.parent);return _.starts&&lt(_.starts,u),L.returnEnd?0:f.length}function wn(){let u=[];for(let f=h;f!==B;f=f.parent)f.scope&&u.unshift(f.scope);u.forEach(f=>T.openNode(f))}let Ee={};function at(u,f){let m=f&&f[0];if(y+=u,m==null)return O(),0;if(Ee.type==="begin"&&f.type==="end"&&Ee.index===f.index&&m===""){if(y+=g.slice(f.index,f.index+1),!r){let _=new Error(`0 width match regex (${a})`);throw _.languageName=a,_.badRule=Ee.rule,_}return 1}if(Ee=f,f.type==="begin")return yn(f);if(f.type==="illegal"&&!b){let _=new Error('Illegal lexeme "'+m+'" for mode "'+(h.scope||"<unnamed>")+'"');throw _.mode=h,_}else if(f.type==="end"){let _=Mn(f);if(_!==St)return _}if(f.type==="illegal"&&m==="")return y+=`
3
+ `,1;if(Ie>1e5&&Ie>f.index*3)throw new Error("potential infinite loop, way more iterations than matches");return y+=m,m.length}let B=q(a);if(!B)throw V(l.replace("{}",a)),new Error('Unknown language: "'+a+'"');let Sn=ws(B),Oe="",h=v||Sn,ut={},T=new o.__emitter(o);wn();let y="",_e=0,X=0,Ie=0,He=!1;try{if(B.__emitTokens)B.__emitTokens(g,T);else{for(h.matcher.considerAll();;){Ie++,He?He=!1:h.matcher.considerAll(),h.matcher.lastIndex=X;let u=h.matcher.exec(g);if(!u)break;let f=g.substring(X,u.index),m=at(f,u);X=u.index+m}at(g.substring(X))}return T.finalize(),Oe=T.toHTML(),{language:a,value:Oe,relevance:_e,illegal:!1,_emitter:T,_top:h}}catch(u){if(u.message&&u.message.includes("Illegal"))return{language:a,value:$e(g),illegal:!0,relevance:0,_illegalBy:{message:u.message,index:X,context:g.slice(X-100,X+100),mode:u.mode,resultSoFar:Oe},_emitter:T};if(r)return{language:a,value:$e(g),illegal:!1,relevance:0,errorRaised:u,_emitter:T,_top:h};throw u}}function w(a){let g={value:$e(a),illegal:!1,relevance:0,_top:i,_emitter:new o.__emitter(o)};return g._emitter.addText(a),g}function A(a,g){g=g||o.languages||Object.keys(t);let b=w(a),v=g.filter(q).filter(he).map(O=>M(O,a,!1));v.unshift(b);let S=v.sort((O,D)=>{if(O.relevance!==D.relevance)return D.relevance-O.relevance;if(O.language&&D.language){if(q(O.language).supersetOf===D.language)return 1;if(q(D.language).supersetOf===O.language)return-1}return 0}),[k,z]=S,be=k;return be.secondBest=z,be}function $(a,g,b){let v=g&&n[g]||b;a.classList.add("hljs"),a.classList.add(`language-${v}`)}function C(a){let g=null,b=d(a);if(c(b))return;if(me("before:highlightElement",{el:a,language:b}),a.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",a);return}if(a.children.length>0&&(o.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(a)),o.throwUnescapedHTML))throw new Fe("One of your code blocks includes unescaped HTML.",a.innerHTML);g=a;let v=g.textContent,S=b?p(v,{language:b,ignoreIllegals:!0}):A(v);a.innerHTML=S.value,a.dataset.highlighted="yes",$(a,b,S.language),a.result={language:S.language,re:S.relevance,relevance:S.relevance},S.secondBest&&(a.secondBest={language:S.secondBest.language,relevance:S.secondBest.relevance}),me("after:highlightElement",{el:a,result:S,text:v})}function N(a){o=wt(o,a)}let le=()=>{ce(),te("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function pe(){ce(),te("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let Re=!1;function ce(){function a(){ce()}if(document.readyState==="loading"){Re||window.addEventListener("DOMContentLoaded",a,!1),Re=!0;return}document.querySelectorAll(o.cssSelector).forEach(C)}function rt(a,g){let b=null;try{b=g(e)}catch(v){if(V("Language definition for '{}' could not be registered.".replace("{}",a)),r)V(v);else throw v;b=i}b.name||(b.name=a),t[a]=b,b.rawDefinition=g.bind(null,e),b.aliases&&Ne(b.aliases,{languageName:a})}function K(a){delete t[a];for(let g of Object.keys(n))n[g]===a&&delete n[g]}function it(){return Object.keys(t)}function q(a){return a=(a||"").toLowerCase(),t[a]||t[n[a]]}function Ne(a,{languageName:g}){typeof a=="string"&&(a=[a]),a.forEach(b=>{n[b.toLowerCase()]=g})}function he(a){let g=q(a);return g&&!g.disableAutodetect}function mn(a){a["before:highlightBlock"]&&!a["before:highlightElement"]&&(a["before:highlightElement"]=g=>{a["before:highlightBlock"](Object.assign({block:g.el},g))}),a["after:highlightBlock"]&&!a["after:highlightElement"]&&(a["after:highlightElement"]=g=>{a["after:highlightBlock"](Object.assign({block:g.el},g))})}function bn(a){mn(a),s.push(a)}function En(a){let g=s.indexOf(a);g!==-1&&s.splice(g,1)}function me(a,g){let b=a;s.forEach(function(v){v[b]&&v[b](g)})}function _n(a){return te("10.7.0","highlightBlock will be removed entirely in v12.0"),te("10.7.0","Please use highlightElement now."),C(a)}Object.assign(e,{highlight:p,highlightAuto:A,highlightAll:ce,highlightElement:C,highlightBlock:_n,configure:N,initHighlighting:le,initHighlightingOnLoad:pe,registerLanguage:rt,unregisterLanguage:K,listLanguages:it,getLanguage:q,registerAliases:Ne,autoDetection:he,inherit:wt,addPlugin:bn,removePlugin:En}),e.debugMode=function(){r=!1},e.safeMode=function(){r=!0},e.versionString=Ts,e.regex={concat:Z,lookahead:xt,either:Pe,optional:qn,anyNumberOfTimes:Pn};for(let a in ve)typeof ve[a]=="object"&&Tt(ve[a]);return Object.assign(e,ve),e},ne=kt({});ne.newInstance=()=>kt({});Dt.exports=ne;ne.HighlightJS=ne;ne.default=ne});function R(e,t){return(t||document).querySelector(e)}function E(e,t){return Array.from((t||document).querySelectorAll(e))}function F(e,t,n,s){typeof n=="function"?e.addEventListener(t,n):e.addEventListener(t,function(r){let l=r.target.closest(n);l&&e.contains(l)&&s&&s.call(l,r)})}var $n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function I(e){return e.replace(/[&<>"']/g,t=>$n[t])}function ft(e){return J(this,null,function*(){let t=new TextEncoder().encode(e),n=yield crypto.subtle.digest("SHA-1",t);return Array.from(new Uint8Array(n,0,4),s=>s.toString(16).padStart(2,"0")).join("")})}var kn=90,Dn=75;function P(e){return e>=kn?"green":e>=Dn?"yellow":"red"}function x(e){return e.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function U(e){return(Math.floor(e*100)/100).toFixed(2)}function gt(e){return"g-"+e.replace(/[^a-zA-Z0-9_-]/gu,t=>`_${t.codePointAt(0).toString(16)}_`)}var pt=[[31536e3,"year"],[2592e3,"month"],[86400,"day"],[3600,"hour"],[60,"minute"],[1,"second"]];function ht(e){let t=Math.floor((Date.now()-e.getTime())/1e3);for(let[n,s]of pt){let r=Math.floor(t/n);if(r>=1)return r===1?`about 1 ${s} ago`:`${r} ${s}s ago`}return"just now"}function mt(e){let t=(Date.now()-e.getTime())/1e3;for(let[n]of pt){let s=Math.floor(t/n);if(s>=1){let r=(s+1)*n;return Math.max((r-t)*1e3+500,1e3)}}return 1e3}var bt={};function ee(e){return bt[e]}function Et(e){return J(this,null,function*(){let t=yield Promise.all(e.map(ft));e.forEach((n,s)=>{bt[n]=t[s]})})}var Ft=Hn(Bt(),1);var Ue=Ft.default;function Pt(e){let t=e.regex,n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",s=t.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),r=t.concat(s,/(::\w+)*/),i={"variable.constant":["__FILE__","__LINE__","__ENCODING__"],"variable.language":["self","super"],keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield",...["include","extend","prepend","public","private","protected","raise","throw"]],built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"],literal:["true","false","nil"]},o={className:"doctag",begin:"@[A-Za-z]+"},c={begin:"#<",end:">"},d=[e.COMMENT("#","$",{contains:[o]}),e.COMMENT("^=begin","^=end",{contains:[o],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],p={className:"subst",begin:/#\{/,end:/\}/,keywords:i},M={className:"string",contains:[e.BACKSLASH_ESCAPE,p],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?</,end:/>/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:t.concat(/<<[-~]?'?/,t.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,p]})]}]},w="[1-9](_?[0-9])*|0",A="[0-9](_?[0-9])*",$={className:"number",relevance:0,variants:[{begin:`\\b(${w})(\\.(${A}))?([eE][+-]?(${A})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},C={variants:[{match:/\(\)/},{className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,keywords:i}]},K=[M,{variants:[{match:[/class\s+/,r,/\s+<\s+/,r]},{match:[/\b(class|module)\s+/,r]}],scope:{2:"title.class",4:"title.class.inherited"},keywords:i},{match:[/(include|extend)\s+/,r],scope:{2:"title.class"},keywords:i},{relevance:0,match:[r,/\.new[. (]/],scope:{1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{relevance:0,match:s,scope:"title.class"},{match:[/def/,/\s+/,n],scope:{1:"keyword",3:"title.function"},contains:[C]},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[M,{begin:n}],relevance:0},$,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|(?!=)/,end:/\|/,excludeBegin:!0,excludeEnd:!0,relevance:0,keywords:i},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,p],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(c,d),relevance:0}].concat(c,d);p.contains=K,C.contains=K;let he=[{begin:/^\s*=>/,starts:{end:"$",contains:K}},{className:"meta.prompt",begin:"^("+"[>?]>"+"|"+"[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]"+"|"+"(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>"+")(?=[ ])",starts:{end:"$",keywords:i,contains:K}}];return d.unshift(c),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(he).concat(d).concat(K)}}function ze(e){let t=P(e),n=U(e);return`<div class="bar-sizer"><div class="coverage-bar"><div class="coverage-bar__fill coverage-bar__fill--${t}" style="width: ${n}%"></div></div></div>`}function Y(e,t,n,s,r){let l=P(e),i=U(e),o=`<div class="coverage-cell">${ze(e)}<span class="coverage-pct">${i}%</span></div>`;if(r)return`<td class="cell--coverage strong t-totals__${s}-pct ${l}">${o}</td><td class="cell--numerator strong t-totals__${s}-num">${x(t)}/</td><td class="cell--denominator strong t-totals__${s}-den">${x(n)}</td>`;let c=` data-order="${U(e)}"`;return`<td class="cell--coverage cell--${s}-pct ${l}"${c}>${o}</td><td class="cell--numerator">${x(t)}/</td><td class="cell--denominator">${x(n)}</td>`}function Se(e,t,n,s){return`<th class="cell--coverage">
4
+ <div class="th-with-filter">
5
+ <span class="th-label">${e}</span>
6
+ <div class="col-filter__coverage">
7
+ <select class="col-filter__op" data-type="${t}"><option value="lt">&lt;</option><option value="lte" selected>&le;</option><option value="eq">=</option><option value="gte">&ge;</option><option value="gt">&gt;</option></select>
8
+ <span class="col-filter__pct-wrap"><input type="number" class="col-filter__value" min="0" max="100" data-type="${t}" value="100" step="any"></span>
9
+ </div>
10
+ </div>
11
+ </th>
12
+ <th class="cell--numerator">${n}</th>
13
+ <th class="cell--denominator">${s}</th>`}function je(e){let{type:t,label:n,covered:s,total:r,enabled:l,toggle:i}=e;if(!l)return`<div class="t-${t}-summary">
14
+ ${n}: <span class="coverage-disabled">disabled</span>
15
+ </div>`;let o=r-s,c=r>0?s*100/r:100,d=P(c),p=e.suffix||"covered",M=e.missedClass||"red",w=`<div class="t-${t}-summary">
16
+ ${n}: <span class="${d}"><b>${U(c)}%</b></span><span class="coverage-cell__fraction"> ${s}/${r} ${p}</span>`;if(o>0){let A=i?`<a href="#" class="t-missed-method-toggle"><b>${o}</b> missed</a>`:`<span class="${M}"><b>${o}</b> missed</span>`;w+=`<span class="coverage-cell__fraction">,</span>
17
+ ${A}`}return w+=`
18
+ </div>`,w}function qt(e){return'<div class="summary-stats">'+je({type:"line",label:"Line coverage",covered:e.coveredLines,total:e.totalLines,enabled:!0,suffix:"relevant lines covered"})+je({type:"branch",label:"Branch coverage",covered:e.coveredBranches,total:e.totalBranches,enabled:e.branchCoverage,missedClass:"missed-branch-text"})+je({type:"method",label:"Method coverage",covered:e.coveredMethods,total:e.totalMethods,enabled:e.methodCoverage,missedClass:"missed-method-text-color",toggle:e.showMethodToggle})+"</div>"}function xs(e){let{title:t,filenames:n,stats:s,branchCoverage:r,methodCoverage:l}=e,i=gt(t),o=s.lines,c=r?s.branches:void 0,d=l?s.methods:void 0,p=[`<div class="file_list_container" id="${i}" data-total-files="${n.length}">`,`<span class="group_name hide">${I(t)}</span>`,`<span class="covered_percent hide"><span class="${P(o.percent)}">${U(o.percent)}%</span></span>`,'<div class="file_list--responsive"><table class="file_list"><thead><tr>','<th class="cell--left"><div class="th-with-filter"><span class="th-label">File Name</span><input type="search" class="col-filter col-filter--name" placeholder="Filter paths\u2026"></div></th>',Se("Line Coverage","line","Covered","Lines")];r&&p.push(Se("Branch Coverage","branch","Covered","Branches")),l&&p.push(Se("Method Coverage","method","Covered","Methods")),p.push("</tr>");let M=n.length===1?"file":"files";return p.push(`<tr class="totals-row"><td class="strong t-file-count">${x(n.length)} ${M}</td>`,Y(o.percent,o.covered,o.total,"line",!0)),c&&p.push(Y(c.percent,c.covered,c.total,"branch",!0)),d&&p.push(Y(d.percent,d.covered,d.total,"method",!0)),p.push("</tr></thead><tbody>"),p.join("")}function As(e){let{filename:t,coverage:n,branchCoverage:s,methodCoverage:r}=e,l=ee(t),i=[`data-covered-lines="${n.covered_lines}"`,`data-relevant-lines="${n.total_lines}"`];s&&i.push(`data-covered-branches="${n.covered_branches||0}"`,`data-total-branches="${n.total_branches||0}"`),r&&i.push(`data-covered-methods="${n.covered_methods||0}"`,`data-total-methods="${n.total_methods||0}"`);let o=[`<tr class="t-file" ${i.join(" ")}>`,`<td class="strong t-file__name"><a href="#${l}" class="src_link" title="${I(t)}">${I(t)}</a></td>`,Y(n.lines_covered_percent,n.covered_lines,n.total_lines,"line",!1)];if(s){let c=n.branches_covered_percent===void 0?100:n.branches_covered_percent;o.push(Y(c,n.covered_branches||0,n.total_branches||0,"branch",!1))}if(r){let c=n.methods_covered_percent===void 0?100:n.methods_covered_percent;o.push(Y(c,n.covered_methods||0,n.total_methods||0,"method",!1))}return o.push("</tr>"),o.join("")}function Ge(e){let{filenames:t,allCoverage:n,branchCoverage:s,methodCoverage:r}=e,l=[xs(e)];for(let i of t){let o=n[i];o&&l.push(As({filename:i,coverage:o,branchCoverage:s,methodCoverage:r}))}return l.push("</tbody></table></div></div>"),l.join("")}function Cs(e){let{lineIndex:t,lineCov:n,branchesReport:s,missedMethodLines:r,branchCoverage:l,methodCoverage:i}=e,o=t+1;if(n==="ignored")return"skipped";if(l){let c=s[o];if(c&&c.some(([,d])=>d===0))return"missed-branch"}return i&&r.has(o)?"missed-method":n===null?"never":n===0?"missed":"covered"}function Rs(e){let t={};if(!e)return t;for(let{coverage:n,report_line:s,type:r}of e){if(n==="ignored")continue;(t[s]||(t[s]=[])).push([r,n])}return t}function Ns(e){let t=new Set;if(!e)return t;for(let n of e)if(n.coverage===0&&n.start_line&&n.end_line)for(let s=n.start_line;s<=n.end_line;s++)t.add(s);return t}function Os(e){let{index:t,source:n,lineCov:s,status:r,branchCoverage:l,lineBranches:i}=e,o=t+1,c=s!==null&&s!=="ignored"?` data-hits="${s}"`:"",d=[`<li class="${r}"${c} data-linenumber="${o}">`];if(r==="covered"||s!==null&&s!=="ignored"&&s!==0?d.push(`<span class="hits" data-content="${s}"></span>`):s==="ignored"&&d.push('<span class="hits" data-content="skipped"></span>'),l&&i)for(let[p,M]of i){let w=I(p);d.push(`<span class="hits" data-content="${w}: ${M}" title="${w} branch hit ${M} times"></span>`)}return d.push(`<code class="ruby">${I(n)}</code></li>`),d.join("")}function Wt(e,t,n,s){let r=ee(e),l=t.covered_lines,i=t.total_lines,o=n&&t.covered_branches||0,c=n&&t.total_branches||0,d=s&&t.covered_methods||0,p=s&&t.total_methods||0,M=(t.methods||[]).filter(N=>N.coverage===0),w=s&&M.length>0,A=Rs(t.branches),$=Ns(t.methods),C=[`<div class="source_table" id="${r}">`,'<div class="header">',`<h2>${I(e)}</h2>`,qt({coveredLines:l,totalLines:i,coveredBranches:o,totalBranches:c,coveredMethods:d,totalMethods:p,branchCoverage:n,methodCoverage:s,showMethodToggle:w})];w&&C.push('<div class="t-missed-method-list" style="display: none"><ul>',M.map(N=>`<li><tt>${I(N.name)}</tt></li>`).join(""),"</ul></div>"),C.push("</div>","<pre><ol>");for(let N=0;N<t.source.length;N++){let le=t.lines[N],pe=Cs({lineIndex:N,lineCov:le,branchesReport:A,missedMethodLines:$,branchCoverage:n,methodCoverage:s});C.push(Os({index:N,source:t.source[N],lineCov:le,status:pe,branchCoverage:n,lineBranches:n?A[N+1]:void 0}))}return C.push("</ol></pre></div>"),C.join("")}Ue.registerLanguage("ruby",Pt);var se=null;function Ut(e){let t=e.meta,n=t.branch_coverage,s=t.method_coverage;document.title=`Code coverage for ${t.project_name}`;let r=Object.keys(e.coverage),l=e.total.lines.total>0?e.total.lines.percent:100,i=document.createElement("link");i.rel="icon",i.type="image/png",i.href=`favicon_${P(l)}.png`,document.head.appendChild(i),n&&document.body.setAttribute("data-branch-coverage","true");let o=document.getElementById("content"),c=[Ge({title:"All Files",filenames:r,stats:e.total,allCoverage:e.coverage,branchCoverage:n,methodCoverage:s})];for(let $ of Object.keys(e.groups)){let C=e.groups[$];c.push(Ge({title:$,filenames:C.files||[],stats:C,allCoverage:e.coverage,branchCoverage:n,methodCoverage:s}))}o.innerHTML=c.join("");let d={};for(let $ of r)d[ee($)]=$;se={idToFilename:d,coverage:e.coverage,branchCoverage:n,methodCoverage:s};let p=new Date(t.timestamp),M=document.getElementById("footer");M.innerHTML=`Generated <abbr class="timeago" title="${p.toISOString()}">${p.toISOString()}</abbr> by <a href="https://github.com/simplecov-ruby/simplecov">simplecov</a> v${I(t.simplecov_version)} using ${I(t.command_name)}`;let w=document.getElementById("source-legend"),A='<span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--covered"></span>Covered</span><span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--skipped"></span>Skipped</span><span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed"></span>Missed line</span>';n&&(A+='<span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-branch"></span>Missed branch</span>'),s&&(A+='<span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-method"></span>Missed method</span>'),w.innerHTML=A}function jt(e){let t=document.getElementById(e);if(t)return t;if(!se)return null;let n=se.idToFilename[e];if(!n)return null;let s=Wt(n,se.coverage[n],se.branchCoverage,se.methodCoverage),r=document.querySelector(".source_files"),l=document.createElement("div");l.innerHTML=s;let i=l.firstElementChild;return r.appendChild(i),E("pre code",i).forEach(o=>Ue.highlightElement(o)),i}var Ke=1e3,Is="t-window-hidden",zt=new WeakSet;function Hs(e,t){let n=e.querySelector("tr.t-show-all");if(!n){n=document.createElement("tr"),n.className="t-show-all";let s=document.createElement("td");s.colSpan=t,n.appendChild(s),n.addEventListener("click",r=>{r.preventDefault(),zt.add(e),re(e.closest("table"))}),e.appendChild(n)}return n}function re(e){let t=e.querySelector("tbody");if(!t)return;let n=t.querySelectorAll("tr.t-file"),s=zt.has(t),r=0;if(n.forEach(i=>{let o=i.style.display==="none";o||(r+=1),i.classList.toggle(Is,!s&&!o&&r>Ke)}),s||r<=Ke){let i=t.querySelector("tr.t-show-all");i&&(i.style.display="none");return}let l=Hs(t,n[0].children.length);l.style.display="",l.firstElementChild.innerHTML=`Showing the first ${x(Ke)} of ${x(r)} files. <a href="#" class="t-show-all__link">Show all</a>`,t.appendChild(l)}var Xt={};function $s(e,t){let n=0,s=e.children;for(let r=0;r<s.length;r++)if(s[r].style.display!=="none"){if(n===t)return r;n+=1}return null}function ks(e){if(!e)return"";let t=e.getAttribute("data-order");if(t!==null)return Number.parseFloat(t);let n=(e.textContent||"").trim(),s=Number.parseFloat(n);return Number.isNaN(s)?n.toLowerCase():s}var Gt=new WeakMap;function Vt(e,t){var l;if(t===null)return"";let n=Gt.get(e);n||(n=new Map,Gt.set(e,n));let s=n.get(t);if(s!==void 0)return s;let r=ks((l=e.children[t])!=null?l:null);return n.set(t,r),r}var Ds=new Intl.Collator;function Zt(e,t){return typeof e=="number"&&typeof t=="number"?e-t:Ds.compare(String(e),String(t))}function Yt(e){return e.id||e.getAttribute("data-sort-id")||"default"}function Xe(e,t,n){Xt[Yt(e)]={colIndex:t,direction:n};let s=0;E("thead tr:first-child th",e).forEach(r=>{let l=Number.parseInt(r.getAttribute("colspan")||"1",10);r.classList.remove("sorting_asc","sorting_desc","sorting");let i=t>=s&&t<s+l;r.classList.add(i?n==="asc"?"sorting_asc":"sorting_desc":"sorting"),s+=l})}function Qt(e,t){let n=document.createDocumentFragment();t.forEach(s=>n.appendChild(s)),e.appendChild(n)}function Kt(e,t){let n=Xt[Yt(e)],s=n&&n.colIndex===t&&n.direction==="asc"?"desc":"asc",r=e.querySelector("tbody"),l=Array.from(r.querySelectorAll("tr.t-file"));if(l.length===0){Xe(e,t,s);return}if(n&&n.colIndex===t)l.reverse();else{let i=$s(l[0],t),o=l.map(d=>({row:d,value:Vt(d,i)})),c=s==="asc"?1:-1;o.sort((d,p)=>c*Zt(d.value,p.value)),l=o.map(({row:d})=>d)}Qt(r,l),re(e),Xe(e,t,s)}var Bs=500,de=null;function Fs(){if(de)return de;let e=document.createElement("div");return e.id="sort-overlay",e.innerHTML='<span id="sort-overlay-label">Sorting\u2026</span>',e.style.display="none",document.body.appendChild(e),de=e,e}function Ps(){let e=Fs();e.style.transition="none",e.style.opacity="1",e.style.display="flex"}function qs(){if(!de)return;let e=de;e.style.transition="opacity 0.15s",e.style.opacity="0",setTimeout(()=>{e.style.display="none"},150)}function Ws(e,t){if(e.querySelectorAll("tbody tr.t-file").length<Bs){Kt(e,t);return}Ps(),requestAnimationFrame(()=>requestAnimationFrame(()=>{Kt(e,t),qs()}))}function Us(e,t){let n=0;for(let s of E("thead tr:first-child th",e)){let r=Number.parseInt(s.getAttribute("colspan")||"1",10);if(s===t)return n+r-1;n+=r}return n}function js(e,t){let n=Array.from(e.children);if(t){let r=n.findIndex(l=>l.classList.contains(`cell--${t}-pct`));if(r!==-1)return r}let s=n.findIndex(r=>r.hasAttribute("data-order"));return s===-1?null:s}function zs(e,t){let n=e.querySelector("tbody");if(!n)return;let s=Array.from(n.querySelectorAll("tr.t-file"));if(s.length===0)return;let r=js(s[0],t);if(r===null)return;let l=s.map(i=>({row:i,value:Vt(i,r)}));l.sort((i,o)=>Zt(i.value,o.value)),Qt(n,l.map(({row:i})=>i)),Xe(e,r,"asc")}function Jt(e){E("table.file_list").forEach(t=>{E("thead tr:first-child th",t).forEach(n=>{n.classList.add("sorting"),n.style.cursor="pointer",n.addEventListener("click",()=>Ws(t,Us(t,n)))}),zs(t,e),re(t)})}var fe=null;function Te(){fe=null}function en(){if(fe)return fe;let e=E(".file_list_container").filter(t=>t.style.display!=="none");return e.length?(fe=E("tbody tr.t-file",e[0]).filter(t=>t.style.display!=="none"),fe):[]}var Gs=240,Ks=160;function tn(e,t){e.style.setProperty("--bar-sizer-width",t+"px")}function Ze(){E(".file_list_container").forEach(e=>{if(e.style.display==="none"||e.offsetWidth===0)return;let t=R("table.file_list",e);if(!t||!R(".bar-sizer",t))return;let n=t.closest(".file_list--responsive");if(!n)return;n.style.visibility="hidden";let s=Ks,r=Gs;for(;s<r;){let l=Math.ceil((s+r)/2);tn(t,l),t.offsetWidth,t.scrollWidth<=n.clientWidth?s=l:r=l-1}tn(t,s),n.style.visibility=""})}var Ve=0;function ie(){Ve||(Ve=requestAnimationFrame(()=>{Ve=0,Ze()}))}var Le={line:{covered:"coveredLines",total:"relevantLines"},branch:{covered:"coveredBranches",total:"totalBranches"},method:{covered:"coveredMethods",total:"totalMethods"}};function nn(e){let t=E("tbody tr.t-file",e).filter(l=>l.style.display!=="none");function n(l){return t.reduce((i,o)=>i+(Number.parseInt(o.dataset[l]||"0",10)||0),0)}let s=R(".t-file-count",e),r=Number.parseInt(e.getAttribute("data-total-files")||"0",10);if(s){let l=t.length===1?" file":" files";s.textContent=t.length===r?x(r)+l:x(t.length)+"/"+x(r)+l}for(let l of Object.keys(Le)){let i=Le[l],o=`.t-totals__${l}`;R(o+"-pct",e)&&Xs(e,o,n(i.covered),n(i.total))}}function Xs(e,t,n,s){let r=R(t+"-pct",e),l=R(t+"-num",e),i=R(t+"-den",e);if(s===0){r&&(r.innerHTML="",r.classList.remove("green","yellow","red")),l&&(l.textContent=""),i&&(i.textContent="");return}let o=n*100/s,c=P(o);r&&(r.innerHTML=`<div class="coverage-cell">${ze(o)}<span class="coverage-pct">${U(o)}%</span></div>`,r.classList.remove("green","yellow","red"),r.classList.add(c)),l&&(l.textContent=x(n)+"/"),i&&(i.textContent=x(s))}var Vs={gt:(e,t)=>e>t,gte:(e,t)=>e>=t,eq:(e,t)=>e===t,lte:(e,t)=>e<=t,lt:(e,t)=>e<t};function Zs(e,t,n){let s=Vs[e];return s?s(t,n):!0}function Ys(e){let t=[];for(let n of E(".col-filter__value",e)){let s=n;if(!s.value)continue;let r=Number.parseFloat(s.value);if(Number.isNaN(r))continue;let l=s.dataset.type||"",i=R(`.col-filter__op[data-type="${l}"]`,e),o=i?i.value:"",c=Le[l];o&&c&&t.push({attrs:c,op:o,threshold:r})}return t}var sn=new WeakMap;function Qs(e){let t=sn.get(e);return t===void 0&&(t=(e.children[0].textContent||"").toLowerCase(),sn.set(e,t)),t}function rn(e){let t=R("table.file_list",e);if(!t)return;let n=R(".col-filter--name",e),s=n?n.value.trim().toLowerCase():"",r=Ys(e);E("tbody tr.t-file",t).forEach(l=>{let i=l,c=(!s||Qs(l).includes(s))&&r.every(d=>{let p=Number.parseInt(i.dataset[d.attrs.covered]||"0",10)||0,M=Number.parseInt(i.dataset[d.attrs.total]||"0",10)||0,w=M>0?p*100/M:100;return Zs(d.op,w,d.threshold)})?"":"none";i.style.display!==c&&(i.style.display=c)}),re(t),Te(),nn(e),ie()}function Ye(e){let t=Number.parseFloat(e.value),n=e.closest(".col-filter__coverage"),s=n?n.querySelector(".col-filter__op"):null;if(!s)return;let r=s.querySelector('option[value="gt"]'),l=s.querySelector('option[value="lt"]');if(r&&(r.disabled=t>=100),l&&(l.disabled=t<=0),s.selectedOptions[0]&&s.selectedOptions[0].disabled){let i=s.querySelector("option:not(:disabled)");i&&(s.value=i.value)}}function on(){E(".col-filter__value").forEach(e=>Ye(e)),E(".col-filter--name, .col-filter__op, .col-filter__value, .col-filter__coverage").forEach(e=>{e.addEventListener("click",t=>t.stopPropagation())}),F(document,"input",".col-filter--name, .col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&Ye(this),rn(this.closest(".file_list_container"))}),F(document,"change",".col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&Ye(this),rn(this.closest(".file_list_container"))})}var H=null;function Qe(){return H!==null}function oe(e){H&&H.classList.remove("keyboard-focus"),H=e,H&&(H.classList.add("keyboard-focus"),H.scrollIntoView({block:"nearest"}))}function Je(e){let t=en();if(!t.length)return;if(!H||t.indexOf(H)===-1){oe(e===1?t[0]:t[t.length-1]);return}let n=t.indexOf(H)+e;n>=0&&n<t.length&&oe(t[n])}function ln(){if(!H)return;let e=H.querySelector("a.src_link");e&&(window.location.hash=e.getAttribute("href").substring(1))}var j,Q,et,ge=null,xe="";function tt(){return j.open}function nt(){return Q}function an(){if(!ge)return;xe&&(ge.insertAdjacentHTML("afterbegin",xe),xe="");let e=document.querySelector(".source_files");e&&e.appendChild(ge),ge=null}function Js(e,t){an();let n=jt(e);if(!n)return;let s=n.querySelector(".header");if(s&&(xe=s.outerHTML,et.innerHTML=s.innerHTML,s.remove()),ge=n,Q.appendChild(n),j.open||j.showModal(),document.documentElement.style.overflow="hidden",Q.focus(),t){let r=Q.querySelector('li[data-linenumber="'+t+'"]');r&&(Q.scrollTop=r.offsetTop)}}function cn(e){if(oe(null),Te(),j.open&&(an(),j.close(),Q.innerHTML="",et.innerHTML="",document.documentElement.style.overflow=""),e){let n=document.querySelector(".group_tabs a."+e);if(n){E(".group_tabs li").forEach(r=>r.classList.remove("active")),n.parentElement.classList.add("active"),E(".file_list_container").forEach(r=>r.style.display="none");let s=document.getElementById(e);s&&(s.style.display="")}}let t=document.getElementById("wrapper");t&&!t.classList.contains("hide")&&ie()}function Ce(){let e=window.location.hash.substring(1);if(!e){let t=document.querySelector(".group_tabs a");t&&cn(t.getAttribute("href").replace("#",""));return}if(e.charAt(0)==="_")cn(e.substring(1));else{let t=e.split("-L");if(!document.querySelector(".group_tabs li.active")){let n=document.querySelector(".group_tabs li");n&&n.classList.add("active")}Js(t[0],t[1])}}function Ae(){let e=document.querySelector(".group_tabs li.active a");e&&(window.location.hash=e.getAttribute("href").replace("#","#_"))}function un(){j=document.getElementById("source-dialog"),Q=document.getElementById("source-dialog-body"),et=document.getElementById("source-dialog-title"),j.querySelector(".source-dialog__close").addEventListener("click",Ae),j.addEventListener("click",e=>{e.target===j&&Ae()})}function er(){return E(".source-dialog .source_table li.missed, .source-dialog .source_table li.missed-branch, .source-dialog .source_table li.missed-method")}function st(e){let t=er();if(!t.length)return;let n=nt(),s=n.scrollTop+n.clientHeight/2,r=e===1?t.find(l=>l.offsetTop>s)||t[0]:t.findLast(l=>l.offsetTop<s-10)||t[t.length-1];n.scrollTop=r.offsetTop-n.clientHeight/3}function dn(){F(document,"click",".t-missed-method-toggle",function(e){e.preventDefault();let t=this.closest(".header")||this.closest(".source-dialog__title")||this.closest(".source-dialog__header"),n=t?t.querySelector(".t-missed-method-list"):null;n&&(n.style.display=n.style.display==="none"?"":"none")}),F(document,"click","a.src_link",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").substring(1)}),F(document,"click","table.file_list tbody tr",function(e){if(e.target.closest("a"))return;let t=this.querySelector("a.src_link");t&&(window.location.hash=t.getAttribute("href").substring(1))}),F(document,"click",".source-dialog .source_table li[data-linenumber]",function(e){e.preventDefault(),nt().scrollTop=this.offsetTop;let t=this.dataset.linenumber,n=window.location.hash.substring(1).replace(/-L.*/,"");window.location.replace(window.location.href.replace(/#.*/,"#"+n+"-L"+t))}),window.addEventListener("hashchange",Ce)}var fn="simplecov-dark-mode";function tr(){try{return localStorage.getItem(fn)}catch(e){return null}}function nr(e){try{localStorage.setItem(fn,e)}catch(t){}}function gn(){let e=document.getElementById("dark-mode-toggle");if(!e)return;let t=document.documentElement;function n(){return t.classList.contains("dark-mode")||!t.classList.contains("light-mode")&&window.matchMedia("(prefers-color-scheme: dark)").matches}function s(){e.textContent=n()?"\u2600\uFE0F Light":"\u{1F319} Dark"}s(),e.addEventListener("click",()=>{let r=n();t.classList.toggle("light-mode",r),t.classList.toggle("dark-mode",!r),nr(r?"light":"dark"),s()}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{tr()||s()})}function sr(){let e=E(".file_list_container").filter(n=>n.style.display!=="none"),t=e.length?R(".col-filter--name",e[0]):null;t&&t.focus()}function rr(e,t){tt()?(e.preventDefault(),Ae()):t?e.target.blur():Qe()&&oe(null)}function ir(e){e.key==="n"&&!e.shiftKey&&(e.preventDefault(),st(1)),(e.key==="N"||e.key==="n"&&e.shiftKey||e.key==="p")&&(e.preventDefault(),st(-1))}function or(e){e.key==="j"&&(e.preventDefault(),Je(1)),e.key==="k"&&(e.preventDefault(),Je(-1)),e.key==="Enter"&&Qe()&&(e.preventDefault(),ln())}function pn(e){let t=e.target.matches("input, select, textarea");e.key==="/"&&!t?(e.preventDefault(),sr()):e.key==="Escape"?rr(e,t):t||(tt()?ir(e):or(e))}function hn(){let e=1/0;E("abbr.timeago").forEach(t=>{let n=new Date(t.getAttribute("title")||"");Number.isNaN(n.getTime())||(t.textContent=ht(n),e=Math.min(e,mt(n)))}),e<1/0&&setTimeout(hn,e)}function lr(){E(".file_list_container").forEach(e=>e.style.display="none"),E(".file_list_container").forEach(e=>{let t=e.id,n=e.querySelector(".group_name"),s=e.querySelector(".covered_percent"),r=document.createElement("li");r.setAttribute("role","tab");let l=document.createElement("a");l.href="#"+t,l.className=t,l.innerHTML=(n?n.innerHTML:"")+" ("+(s?s.innerHTML:"")+")",r.appendChild(l),document.querySelector(".group_tabs").appendChild(r)}),F(document.querySelector(".group_tabs"),"click","a",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").replace("#","#_")})}function cr(e){e&&(e.style.transition="opacity 0.3s",e.style.opacity="0",setTimeout(()=>{e.style.display="none"},300));let t=document.getElementById("wrapper");t&&t.classList.remove("hide"),Ze()}function ar(){return J(this,null,function*(){let e=window.SIMPLECOV_DATA,t=document.getElementById("loading");t&&(t.style.display=""),yield Et(Object.keys(e.coverage)),Ut(e),hn(),gn(),Jt(e.meta.primary_coverage),on(),document.addEventListener("keydown",pn),un(),dn(),lr(),window.addEventListener("resize",ie),Ce(),cr(t)})}document.addEventListener("DOMContentLoaded",ar);})();
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Code Coverage</title>
7
+ <script src="application.js" defer></script>
8
+ <link href="application.css" rel="stylesheet">
9
+ <script>
10
+ // Apply the saved dark/light preference before paint to avoid a flash.
11
+ try {
12
+ const pref = localStorage.getItem('simplecov-dark-mode');
13
+ if (pref === 'dark' || pref === 'light') {
14
+ document.documentElement.classList.add(`${pref}-mode`);
15
+ }
16
+ } catch (_error) {
17
+ // localStorage can be unavailable in locked-down browser contexts.
18
+ }
19
+ </script>
20
+ </head>
21
+
22
+ <body>
23
+ <div id="loading" style="display: none">
24
+ <div id="loading-inner">
25
+ <div id="loading-bar-track">
26
+ <div id="loading-bar-fill"></div>
27
+ </div>
28
+ <div id="loading-text">Loading...</div>
29
+ </div>
30
+ </div>
31
+
32
+ <div id="wrapper" class="hide">
33
+ <div class="tab-bar">
34
+ <ul class="group_tabs" role="tablist"></ul>
35
+ <button id="dark-mode-toggle" aria-label="Toggle dark mode"></button>
36
+ </div>
37
+
38
+ <div id="content"></div>
39
+
40
+ <div id="footer"></div>
41
+
42
+ <div class="source_files" style="display:none"></div>
43
+ </div>
44
+
45
+ <dialog id="source-dialog" class="source-dialog">
46
+ <div class="source-dialog__header">
47
+ <div class="source-dialog__title" id="source-dialog-title"></div>
48
+ <div class="source-legend" id="source-legend"></div>
49
+ <button class="source-dialog__close" aria-label="Close" title="Close">&times;</button>
50
+ </div>
51
+ <div class="source-dialog__body" id="source-dialog-body" tabindex="0"></div>
52
+ </dialog>
53
+
54
+ <script src="coverage_data.js" defer></script>
55
+ </body>
56
+ </html>
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "json"
5
+ require_relative "base"
6
+ require_relative "json_formatter"
7
+
8
+ module SimpleCov
9
+ module Formatter
10
+ # Generates an HTML coverage report by writing a coverage_data.js file
11
+ # alongside pre-compiled static assets (index.html, application.js/css).
12
+ # Uses JSONFormatter.build_hash to serialize the result, then writes both
13
+ # coverage.json and coverage_data.js from the same in-memory hash.
14
+ class HTMLFormatter < Base
15
+ DATA_FILENAME = "coverage_data.js"
16
+
17
+ def format(result)
18
+ # `coverage_data.js` feeds the client-side viewer, which renders
19
+ # source from the embedded array — it always needs `source`,
20
+ # regardless of `SimpleCov.source_in_json`. The side-file
21
+ # `coverage.json` honors the setting so downstream tools that
22
+ # read source from disk can opt into a smaller payload. When
23
+ # the setting is at its default (true), the two files share a
24
+ # single serialization.
25
+ FileUtils.mkdir_p(output_path)
26
+ viewer_json = JSON.pretty_generate(JSONFormatter.build_hash(result, include_source: true))
27
+ coverage_json = SimpleCov.source_in_json ? viewer_json : JSON.pretty_generate(JSONFormatter.build_hash(result))
28
+
29
+ atomic_write(File.join(output_path, JSONFormatter::FILENAME), coverage_json)
30
+ atomic_write(File.join(output_path, DATA_FILENAME), "window.SIMPLECOV_DATA = #{viewer_json};\n")
31
+
32
+ copy_static_assets
33
+ # stderr, not stdout: this is a status message, not the program's
34
+ # output. Keeps the line out of pipelines like `rspec -f json`. And
35
+ # $stderr.puts, not `warn`: a status line should not reach
36
+ # `Warning.warn` hooks or vanish under `-W0` (see #1225).
37
+ $stderr.puts output_message(result) unless @silent # rubocop:disable Style/StderrPuts
38
+ end
39
+
40
+ # Generate HTML from a pre-existing coverage.json file without
41
+ # needing a live SimpleCov::Result or even a running test suite.
42
+ def format_from_json(json_path, output_dir)
43
+ FileUtils.mkdir_p(output_dir)
44
+ json = File.read(json_path)
45
+ atomic_write(File.join(output_dir, DATA_FILENAME), "window.SIMPLECOV_DATA = #{json};\n")
46
+ copy_static_assets(output_dir)
47
+ end
48
+
49
+ private
50
+
51
+ def entry_point_filename
52
+ "index.html"
53
+ end
54
+
55
+ def copy_static_assets(dest_dir = output_path)
56
+ Dir[File.join(public_dir, "*")].each do |src|
57
+ atomic_write(File.join(dest_dir, File.basename(src)), File.binread(src))
58
+ end
59
+ end
60
+
61
+ # Write `content` at `dest` via a uniquely-named temp file in the
62
+ # same directory, then `File.rename` onto the final path. rename is
63
+ # atomic and overwrite-safe, so:
64
+ # - parallel writers can't race on an unlink-then-write window, and
65
+ # - read-only existing files (e.g. assets shipped at 0444 from
66
+ # /nix/store) are replaced cleanly instead of triggering EACCES
67
+ # from opening the existing path for writing.
68
+ def atomic_write(dest, content)
69
+ temp = "#{dest}.#{Process.pid}.#{rand(2**32).to_s(36)}"
70
+ begin
71
+ File.binwrite(temp, content)
72
+ File.rename(temp, dest)
73
+ ensure
74
+ FileUtils.rm_f(temp)
75
+ end
76
+ end
77
+
78
+ def public_dir
79
+ # `.to_s` collapses `__dir__`'s nil arm (only possible under eval,
80
+ # which can't happen for a file on disk) so the path is a String.
81
+ File.join(__dir__.to_s, "html_formatter/public/")
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleCov
4
+ module Formatter
5
+ class JSONFormatter
6
+ # Translates the threshold violations reported by
7
+ # `SimpleCov::CoverageViolations` into the `:errors` section of
8
+ # coverage.json. Each violation is keyed by criterion
9
+ # (`:lines` / `:branches` / `:methods`) so consumers can render
10
+ # per-criterion messages without re-deriving them.
11
+ class ErrorsFormatter
12
+ CRITERION_KEYS = {line: :lines, branch: :branches, method: :methods}.freeze
13
+ private_constant :CRITERION_KEYS
14
+
15
+ def initialize(result)
16
+ @result = result
17
+ @errors = {}
18
+ end
19
+
20
+ def call
21
+ format_minimum_overall
22
+ format_minimum_by_file
23
+ format_minimum_by_group
24
+ format_maximum_overall
25
+ format_maximum_drop
26
+ @errors
27
+ end
28
+
29
+ private
30
+
31
+ def format_minimum_overall
32
+ SimpleCov::CoverageViolations.minimum_overall(@result, SimpleCov.minimum_coverage).each do |violation|
33
+ bucket(:minimum_coverage)[key_for(violation)] = expected_actual(violation)
34
+ end
35
+ end
36
+
37
+ def format_minimum_by_file
38
+ violations = SimpleCov::CoverageViolations.minimum_by_file(
39
+ @result, SimpleCov.minimum_coverage_by_file, SimpleCov.minimum_coverage_by_file_overrides
40
+ )
41
+ violations.each { |violation| record_by_file(violation) }
42
+ end
43
+
44
+ def record_by_file(violation)
45
+ by_file = bucket(:minimum_coverage_by_file)
46
+ file_bucket = by_file[violation.fetch(:project_filename)] ||= {} #: Hash[untyped, untyped]
47
+ file_bucket[key_for(violation)] = expected_actual(violation)
48
+ end
49
+
50
+ def format_minimum_by_group
51
+ violations = SimpleCov::CoverageViolations.minimum_by_group(@result, SimpleCov.minimum_coverage_by_group)
52
+ return if violations.empty?
53
+
54
+ # `bucket` lazily creates the errors key, so only touch it when
55
+ # there is a violation to record.
56
+ by_group = bucket(:minimum_coverage_by_group)
57
+ violations.each do |violation|
58
+ group_bucket = by_group[violation.fetch(:group_name)] ||= {} #: Hash[untyped, untyped]
59
+ group_bucket[key_for(violation)] = expected_actual(violation)
60
+ end
61
+ end
62
+
63
+ def format_maximum_overall
64
+ SimpleCov::CoverageViolations.maximum_overall(@result, SimpleCov.maximum_coverage).each do |violation|
65
+ bucket(:maximum_coverage)[key_for(violation)] = expected_actual(violation)
66
+ end
67
+ end
68
+
69
+ def format_maximum_drop
70
+ SimpleCov::CoverageViolations.maximum_drop(@result, SimpleCov.maximum_coverage_drop).each do |violation|
71
+ bucket(:maximum_coverage_drop)[key_for(violation)] =
72
+ {maximum: violation.fetch(:maximum), actual: violation.fetch(:actual)}
73
+ end
74
+ end
75
+
76
+ def bucket(name)
77
+ @errors[name] ||= {} #: Hash[untyped, untyped]
78
+ end
79
+
80
+ def key_for(violation)
81
+ CRITERION_KEYS.fetch(SimpleCov.coverage_statistics_key(violation.fetch(:criterion)))
82
+ end
83
+
84
+ def expected_actual(violation)
85
+ {expected: violation.fetch(:expected), actual: violation.fetch(:actual)}
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end