simplecov 1.0.2 → 1.1.0

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -1425
  3. data/lib/simplecov/atomic_file.rb +70 -0
  4. data/lib/simplecov/cli/clean.rb +43 -3
  5. data/lib/simplecov/cli/command_helpers.rb +55 -0
  6. data/lib/simplecov/cli/coverage.rb +21 -28
  7. data/lib/simplecov/cli/coverage_file.rb +65 -0
  8. data/lib/simplecov/cli/diff.rb +43 -48
  9. data/lib/simplecov/cli/dotfile.rb +12 -6
  10. data/lib/simplecov/cli/merge.rb +12 -10
  11. data/lib/simplecov/cli/open.rb +3 -5
  12. data/lib/simplecov/cli/report.rb +31 -23
  13. data/lib/simplecov/cli/serve/report_preparer.rb +29 -0
  14. data/lib/simplecov/cli/serve/static_file_handler.rb +122 -0
  15. data/lib/simplecov/cli/serve.rb +30 -94
  16. data/lib/simplecov/cli/uncovered.rb +20 -25
  17. data/lib/simplecov/cli.rb +15 -2
  18. data/lib/simplecov/combine/branches_combiner.rb +43 -19
  19. data/lib/simplecov/combine/coverage_accumulator.rb +268 -0
  20. data/lib/simplecov/combine/identity_interner.rb +30 -0
  21. data/lib/simplecov/combine/interned_counts.rb +30 -0
  22. data/lib/simplecov/combine/lines_combiner.rb +48 -20
  23. data/lib/simplecov/combine/methods_combiner.rb +46 -21
  24. data/lib/simplecov/combine/results_combiner.rb +12 -37
  25. data/lib/simplecov/combine.rb +5 -23
  26. data/lib/simplecov/command_guesser.rb +66 -9
  27. data/lib/simplecov/configuration/coverage.rb +12 -15
  28. data/lib/simplecov/configuration/coverage_criteria.rb +34 -38
  29. data/lib/simplecov/configuration/eval_coverage.rb +41 -0
  30. data/lib/simplecov/configuration/filters.rb +11 -44
  31. data/lib/simplecov/configuration/formatting.rb +18 -9
  32. data/lib/simplecov/configuration/groups.rb +42 -0
  33. data/lib/simplecov/configuration/merging.rb +8 -7
  34. data/lib/simplecov/configuration/thresholds.rb +14 -13
  35. data/lib/simplecov/configuration.rb +13 -43
  36. data/lib/simplecov/coverage_json.rb +24 -0
  37. data/lib/simplecov/coverage_statistics.rb +1 -1
  38. data/lib/simplecov/coverage_violations.rb +15 -5
  39. data/lib/simplecov/defaults.rb +7 -3
  40. data/lib/simplecov/directive.rb +1 -1
  41. data/lib/simplecov/exit_codes/check.rb +33 -0
  42. data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +11 -20
  43. data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +3 -16
  44. data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +14 -23
  45. data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +14 -25
  46. data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +4 -17
  47. data/lib/simplecov/exit_codes.rb +1 -0
  48. data/lib/simplecov/exit_handling.rb +11 -41
  49. data/lib/simplecov/file_list.rb +5 -10
  50. data/lib/simplecov/filter.rb +43 -9
  51. data/lib/simplecov/formatter/base.rb +11 -0
  52. data/lib/simplecov/formatter/coverage_json_writer.rb +97 -0
  53. data/lib/simplecov/formatter/html_formatter/public/index.html +35 -5
  54. data/lib/simplecov/formatter/html_formatter/viewer_data_validator.rb +96 -0
  55. data/lib/simplecov/formatter/html_formatter.rb +67 -47
  56. data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +54 -56
  57. data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +78 -88
  58. data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +70 -76
  59. data/lib/simplecov/formatter/json_formatter.rb +5 -48
  60. data/lib/simplecov/formatter/multi_formatter.rb +1 -1
  61. data/lib/simplecov/formatter/simple_formatter.rb +8 -5
  62. data/lib/simplecov/formatter.rb +12 -0
  63. data/lib/simplecov/group_names.rb +32 -0
  64. data/lib/simplecov/last_run.rb +16 -9
  65. data/lib/simplecov/lines_classifier.rb +29 -8
  66. data/lib/simplecov/load_global_config.rb +5 -2
  67. data/lib/simplecov/parallel_adapters/base.rb +17 -0
  68. data/lib/simplecov/parallel_adapters/generic.rb +2 -2
  69. data/lib/simplecov/parallel_adapters/parallel_tests.rb +2 -2
  70. data/lib/simplecov/parallel_coordination.rb +6 -1
  71. data/lib/simplecov/parallel_result_merger.rb +230 -0
  72. data/lib/simplecov/report_deferral.rb +49 -0
  73. data/lib/simplecov/report_stamp.rb +28 -0
  74. data/lib/simplecov/result.rb +40 -10
  75. data/lib/simplecov/result_adapter.rb +48 -16
  76. data/lib/simplecov/result_merger/resultset_file.rb +43 -7
  77. data/lib/simplecov/result_merger/resultset_run_identity.rb +67 -0
  78. data/lib/simplecov/result_merger/resultset_store.rb +15 -12
  79. data/lib/simplecov/result_merger/unloaded_files.rb +103 -0
  80. data/lib/simplecov/result_merger.rb +69 -42
  81. data/lib/simplecov/result_processing.rb +82 -43
  82. data/lib/simplecov/run_identity.rb +77 -0
  83. data/lib/simplecov/simulate_coverage.rb +35 -11
  84. data/lib/simplecov/source_file/method.rb +7 -1
  85. data/lib/simplecov/source_file/ruby_data_parser.rb +25 -3
  86. data/lib/simplecov/source_file/skip_chunks.rb +7 -10
  87. data/lib/simplecov/source_file/source_loader.rb +23 -7
  88. data/lib/simplecov/source_file/statistics.rb +24 -16
  89. data/lib/simplecov/static_coverage_extractor/condition_folding.rb +203 -13
  90. data/lib/simplecov/static_coverage_extractor/location_conventions.rb +19 -30
  91. data/lib/simplecov/static_coverage_extractor/method_collector.rb +7 -0
  92. data/lib/simplecov/static_coverage_extractor/prism_compat.rb +55 -0
  93. data/lib/simplecov/static_coverage_extractor/value_position.rb +6 -14
  94. data/lib/simplecov/static_coverage_extractor/visitor.rb +23 -36
  95. data/lib/simplecov/unloaded_file_injector.rb +75 -0
  96. data/lib/simplecov/version.rb +1 -1
  97. data/lib/simplecov.rb +11 -5
  98. data/schemas/coverage-v1.0.schema.json +2 -2
  99. data/schemas/coverage.schema.json +2 -2
  100. data/sig/simplecov.rbs +206 -67
  101. metadata +28 -14
  102. data/doc/alternate-formatters.md +0 -66
  103. data/doc/commercial-services.md +0 -25
  104. data/doc/editor-integration.md +0 -18
  105. data/lib/simplecov/combine/files_combiner.rb +0 -70
  106. data/lib/simplecov/formatter/html_formatter/public/application.css +0 -1
  107. data/lib/simplecov/formatter/html_formatter/public/application.js +0 -18
  108. data/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
  109. data/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
  110. data/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
@@ -23,10 +23,26 @@ module SimpleCov
23
23
  raise NotImplementedError, "The base filter class is not intended for direct use"
24
24
  end
25
25
 
26
- def self.build_filter(filter_argument)
27
- return filter_argument if filter_argument.is_a?(SimpleCov::Filter)
26
+ # Whether this filter's verdict depends only on the file's path, so it can
27
+ # be decided before that file has any coverage. Used when recording which
28
+ # tracked files a process did not load, where no coverage exists yet.
29
+ # Defaults to false so a custom filter is never guessed at. See #1250.
30
+ def path_only?
31
+ false
32
+ end
28
33
 
29
- class_for_argument(filter_argument).new(filter_argument)
34
+ # `string_filter` selects the semantics of bare String arguments —
35
+ # StringFilter's segment-substring match for `add_filter`/`skip`,
36
+ # GlobFilter for `cover` — and threads through Array elements so a
37
+ # list gets the same treatment as its members.
38
+ def self.build_filter(filter_argument, string_filter: SimpleCov::StringFilter)
39
+ case filter_argument
40
+ when SimpleCov::Filter then filter_argument
41
+ when String then string_filter.new(filter_argument)
42
+ when Array
43
+ SimpleCov::ArrayFilter.new(filter_argument.map { |arg| build_filter(arg, string_filter: string_filter) })
44
+ else class_for_argument(filter_argument).new(filter_argument)
45
+ end
30
46
  end
31
47
 
32
48
  def self.class_for_argument(filter_argument)
@@ -57,6 +73,10 @@ module SimpleCov
57
73
  source_file.project_filename.match?(segment_pattern)
58
74
  end
59
75
 
76
+ def path_only?
77
+ true
78
+ end
79
+
60
80
  private
61
81
 
62
82
  def segment_pattern
@@ -68,14 +88,15 @@ module SimpleCov
68
88
  escaped = Regexp.escape(normalized)
69
89
  boundary = '(?:\A|/)'
70
90
 
71
- if normalized.include?(".")
72
- # Filename pattern (e.g. "test.rb" matches "faked_test.rb"): allow
73
- # substring match within the last path segment, anchored to a
74
- # segment boundary.
75
- %r{#{boundary}[^/]*#{escaped}}
76
- elsif normalized.end_with?("/")
91
+ if normalized.end_with?("/")
77
92
  # Trailing slash signals directory-only matching.
78
93
  /#{boundary}#{escaped}/
94
+ elsif normalized.include?(".") && !normalized.include?("/")
95
+ # Bare filename pattern (e.g. "test.rb" matches "faked_test.rb"):
96
+ # allow a substring match within a single path segment. Multi-segment
97
+ # arguments must not get this relaxation, or "app/models/user.rb"
98
+ # would also match "webapp/models/user.rb".
99
+ %r{#{boundary}[^/]*#{escaped}(?=[/.]|\z)}
79
100
  else
80
101
  # Directory or path: require a segment-boundary match so "lib"
81
102
  # matches "lib/" but not "library/".
@@ -95,6 +116,10 @@ module SimpleCov
95
116
  def matches?(source_file)
96
117
  filter_argument.match?(source_file.project_filename)
97
118
  end
119
+
120
+ def path_only?
121
+ true
122
+ end
98
123
  end
99
124
 
100
125
  # Filter that matches when the configured block returns truthy for the
@@ -115,6 +140,10 @@ module SimpleCov
115
140
  def matches?(source_file)
116
141
  File.fnmatch?(filter_argument, source_file.project_filename, File::FNM_PATHNAME | File::FNM_EXTGLOB)
117
142
  end
143
+
144
+ def path_only?
145
+ true
146
+ end
118
147
  end
119
148
 
120
149
  # Filter that matches when any of its component filters (built from the
@@ -128,6 +157,11 @@ module SimpleCov
128
157
  super(filter_objects)
129
158
  end
130
159
 
160
+ # Path-decidable only when every component filter is.
161
+ def path_only?
162
+ filter_argument.all?(&:path_only?)
163
+ end
164
+
131
165
  # Returns true if any of the filters in the array match the given source file.
132
166
  # Configure this Filter like StringFilter.new(['some/path', /^some_regex/, Proc.new {|src_file| ... }])
133
167
  def matches?(source_files_list)
@@ -23,6 +23,17 @@ module SimpleCov
23
23
 
24
24
  private
25
25
 
26
+ # The one home of the "status lines go to stderr, not through warn"
27
+ # decision (see #1225). stderr rather than stdout because this is a
28
+ # status message, not the program's output, so it stays out of
29
+ # pipelines like `rspec -f json`. And `$stderr.puts` rather than
30
+ # `warn` so the line neither reaches `Warning.warn` hooks (warning
31
+ # trackers, raise-on-warning test setups) nor vanishes under `-W0`.
32
+ # Subclasses call this at the end of their `format`.
33
+ def emit_status(result)
34
+ $stderr.puts output_message(result) unless @silent # rubocop:disable Style/StderrPuts
35
+ end
36
+
26
37
  # Subclasses override to prepend a marker (e.g. "JSON ") to the
27
38
  # summary line. Default empty for the HTML formatter, which has
28
39
  # historically been the unmarked default.
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "time"
5
+ require_relative "../atomic_file"
6
+
7
+ module SimpleCov
8
+ module Formatter
9
+ # Shared writer for the coverage.json artifact, used by JSONFormatter
10
+ # (as its report) and HTMLFormatter (as the side file feeding
11
+ # `simplecov serve` and external tools). Centralizing the write keeps
12
+ # the two copies byte-identical (same pretty printing, same binary
13
+ # mode, so no CRLF translation on Windows depending on which
14
+ # formatter wrote last) and gives both formatters the
15
+ # concurrent-overwrite warning of issue #1171.
16
+ module CoverageJSONWriter
17
+ FILENAME = "coverage.json"
18
+
19
+ # The previous report can embed the project's entire source text,
20
+ # so the overwrite check bounds how much of it is read looking for
21
+ # the meta object before falling back to a full parse.
22
+ META_SCAN_BYTES = 64 * 1024
23
+ private_constant :META_SCAN_BYTES
24
+
25
+ module_function
26
+
27
+ def write(output_path, hash, result)
28
+ path = File.join(output_path, FILENAME)
29
+ warn_if_concurrent_overwrite(path, result)
30
+ AtomicFile.write(path, JSON.pretty_generate(hash), binary: true)
31
+ path
32
+ end
33
+
34
+ # Warns when the existing coverage.json has a timestamp newer than this
35
+ # process's start time — a strong signal that a sibling test process
36
+ # (e.g., parallel_tests) wrote it while we were running, and that our
37
+ # write is about to clobber their data.
38
+ def warn_if_concurrent_overwrite(path, result)
39
+ start_time = SimpleCov.process_start_time or return
40
+ existing = existing_meta(path) or return
41
+ return unless existing[:timestamp] > start_time
42
+
43
+ # Both formatters write coverage.json through this method, so when
44
+ # they are configured together the file found here was just written
45
+ # by our own run, not a concurrent one. A matching command_name
46
+ # means the same merged result, so there's nothing to lose by
47
+ # overwriting. See issue #1171.
48
+ return if existing[:command_name] == result.command_name
49
+
50
+ warn "simplecov: #{path} was written at #{existing[:timestamp].iso8601} — after " \
51
+ "this process started at #{start_time.iso8601}. Overwriting " \
52
+ "likely loses coverage data from a concurrent test run. For " \
53
+ "parallel test setups, use SimpleCov::ResultMerger or run a single " \
54
+ "collation step after all workers finish."
55
+ end
56
+
57
+ def existing_meta(path)
58
+ return nil unless File.exist?(path)
59
+
60
+ meta = parse_meta(path) or return nil
61
+ timestamp = meta[:timestamp] or return nil
62
+
63
+ {timestamp: Time.iso8601(timestamp), command_name: meta[:command_name]}
64
+ rescue ArgumentError
65
+ # An unparseable timestamp disables the check for this file.
66
+ nil
67
+ end
68
+
69
+ def parse_meta(path)
70
+ parse_meta_head(path) || parse_meta_full(path)
71
+ end
72
+
73
+ # The meta object is flat and sits at the head of every file this
74
+ # module writes, so the common case parses just that slice instead
75
+ # of a multi-megabyte report. A miss (foreign key order, a brace
76
+ # inside a meta string) falls back to the full parse.
77
+ def parse_meta_head(path)
78
+ head = File.read(path, META_SCAN_BYTES).to_s
79
+ slice = head[/"meta"\s*:\s*(\{.*?\})/m, 1]
80
+ return nil unless slice
81
+
82
+ # The captured slice is always a JSON object, so a successful parse
83
+ # is always a Hash.
84
+ JSON.parse(slice, symbolize_names: true)
85
+ rescue JSON::ParserError
86
+ nil
87
+ end
88
+
89
+ def parse_meta_full(path)
90
+ parsed = JSON.parse(File.read(path), symbolize_names: true)
91
+ parsed.is_a?(Hash) ? parsed[:meta] : nil
92
+ rescue JSON::ParserError
93
+ nil
94
+ end
95
+ end
96
+ end
97
+ end
@@ -4,15 +4,19 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Code Coverage</title>
7
- <script src="application.js" defer></script>
8
- <link href="application.css" rel="stylesheet">
7
+ <style>*,*: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{--ap: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--ae: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;--f: 4px;--b: 8px;--as: 12px;--k: 16px;--au: 20px;--ac: 24px;--av: 32px;--ar: 8px;--aq: 12px;--ao: 16px;--o: #f0f1f3;--e: #fff;--ad: #f0f1f3;--a: #111;--g: #333;--h: #444;--al: #f4f5f7;--c: #c0c5cc;--p: #999;--d: #0550ae;--am: #033d8b;--v: #ddf4ff;--green: #116329;--red: #a40e26;--yellow: #7a5200;--an: #953800;--l: #ccf5d0;--i: #9ae6a4;--m: #ffd8d5;--j: #ffb8b3;--z: #fff;--ah: #f0f1f3;--aa: #fff0a0;--u: #eed860;--x: #ffd0a0;--r: #ffb060;--s: #b45309;--y: #e8d0ff;--t: #d4b0ff;--n: #7b2d8e;--aj: #fff;--q: #c0c5cc;--ak: #444;--ab: #f0f1f3;--af: #e0e3e8;--ag: #333;--ai: rgba(0, 0, 0, .5);--w: #d0d7de;--at: 6px}@media(prefers-color-scheme:dark){:root:not(.light-mode){--o: #010409;--e: #0d1117;--ad: #161b22;--a: #f0f3f6;--g: #b0b8c4;--h: #9aa5b1;--al: #161b22;--c: #3d444d;--p: #555e68;--d: #6cb6ff;--am: #96ccff;--v: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--an: #f0883e;--l: #122d1e;--i: #1e4430;--m: #351418;--j: #4e1d20;--z: #0d1117;--ah: #161b22;--aa: #302818;--u: #443920;--x: #322218;--r: #483020;--s: #ffb86c;--y: #1e1830;--t: #2a2044;--n: #dcb8ff;--aj: #0d1117;--q: #3d444d;--ak: #9aa5b1;--ab: #161b22;--af: #262c34;--ag: #b0b8c4;--ai: rgba(1, 4, 9, .8);--w: #3d444d}}.dark-mode{--o: #010409;--e: #0d1117;--ad: #161b22;--a: #f0f3f6;--g: #b0b8c4;--h: #9aa5b1;--al: #161b22;--c: #3d444d;--p: #555e68;--d: #6cb6ff;--am: #96ccff;--v: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--an: #f0883e;--l: #122d1e;--i: #1e4430;--m: #351418;--j: #4e1d20;--z: #0d1117;--ah: #161b22;--aa: #302818;--u: #443920;--x: #322218;--r: #483020;--s: #ffb86c;--y: #1e1830;--t: #2a2044;--n: #dcb8ff;--aj: #0d1117;--q: #3d444d;--ak: #9aa5b1;--ab: #161b22;--af: #262c34;--ag: #b0b8c4;--ai: rgba(1, 4, 9, .8);--w: #3d444d}.colorblind-mode{--green: #0060a8;--red: #c2410c;--l: #d3eaf7;--i: #a5d2ee;--m: #ffe0cc;--j: #ffc39a}@media screen and (prefers-color-scheme:dark){.colorblind-mode:not(.light-mode){--green: #6cb6ff;--red: #f0883e;--l: #0e2a45;--i: #12385c;--m: #3a2410;--j: #52331a}}@media screen{.colorblind-mode.dark-mode{--green: #6cb6ff;--red: #f0883e;--l: #0e2a45;--i: #12385c;--m: #3a2410;--j: #52331a}}body{font-family:var(--ap);font-size:18px;color:var(--a);background:var(--o);padding:var(--ac)}a{color:var(--d);text-decoration:none;transition:color .15s}a:hover{color:var(--am)}strong,b{font-weight:600}#loading{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--o);z-index:9999}#loading-inner{width:280px;text-align:center}#loading-bar-track{width:100%;height:6px;background:var(--w);border-radius:6px;overflow:hidden}#loading-bar-fill{width:0%;height:100%;background:var(--d);border-radius:6px;transition:width .15s ease-out}#loading-text{margin-top:var(--as);font-size:18px;color:var(--h)}#sort-overlay{position:fixed;inset:0;z-index:9998;display:flex;align-items:center;justify-content:center;background:var(--ai)}#sort-overlay-label{padding:var(--b) var(--k);border:1px solid var(--c);border-radius:6px;background:var(--o);font-size:16px;color:var(--h)}#wrapper{margin:0 auto}.tab-bar{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--k);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(--f);overflow-x:auto}.group_tabs li a{display:block;padding:var(--b) var(--k);font-size:18px;font-weight:500;color:var(--g);background:transparent;border:1px solid transparent;border-bottom:none;border-radius:var(--aq) var(--aq) 0 0;white-space:nowrap;transition:color .15s,background .15s}.group_tabs li a:hover{color:var(--a);background:var(--ad);text-decoration:none}.group_tabs li.active a{color:var(--d);background:var(--e);border-color:var(--c);font-weight:600}#content{background:var(--e);border:1px solid var(--c);border-radius:0 var(--ao) var(--ao) var(--ao);padding:var(--ac)}.file_list_container h2{font-size:24px;font-weight:600;color:var(--a);margin:0}.file_list_container h2 .covered_percent{font-weight:600}.summary-stats{display:flex;flex-direction:column;gap:var(--f);font-size:18px;color:var(--g)}.summary-stats b{color:var(--a)}.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(--h);font-style:italic}.th-with-filter{display:flex;align-items:center;gap:var(--b)}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(--c);border-radius:999px;padding:var(--f) var(--k);font-size:14px;background:var(--e);color:var(--a);outline:none}.col-filter--name:focus{border-color:var(--d)}.col-filter__coverage{display:flex;gap:var(--f)}.col-filter__op{border:1px solid var(--c);border-radius:var(--ar);padding:var(--f) var(--f);font-size:14px;background:var(--e);color:var(--a);cursor:pointer}.col-filter__value{border:1px solid var(--c);border-radius:var(--ar);padding:var(--f) var(--b);font-size:14px;background:var(--e);color:var(--a);width:60px;outline:none}.col-filter__value:focus{border-color:var(--d)}.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(--h);background:var(--e);padding:var(--b) var(--b);border-bottom:2px solid var(--p);white-space:nowrap}table.file_list tbody tr{background:var(--e);cursor:pointer}table.file_list tbody tr:nth-child(2n){background:var(--al)}table.file_list tbody tr:hover{background:var(--v)}table.file_list tbody tr.keyboard-focus{background:var(--v);outline:2px solid var(--d);outline-offset:-2px}table.file_list tbody td{padding:var(--b) var(--b);border-bottom:1px solid var(--c);color:var(--a)}table.file_list td.cell--number{text-align:right;font-variant-numeric:tabular-nums;color:var(--a)}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(--a)}table.file_list td.t-file__name{white-space:nowrap}a.src_link{color:var(--d);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(--as);text-align:center;color:var(--h);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(--f);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(--f)}table.file_list .totals-row td.cell--numerator{color:var(--a);padding-right:0}table.file_list .totals-row td.cell--denominator{color:var(--a);padding-left:0}.coverage-cell__fraction{font-variant-numeric:tabular-nums;color:var(--g);font-size:14px;white-space:nowrap}.coverage-bar{width:100%;height:var(--at);background:var(--w);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(--s)}.missed-method-text-color{color:var(--n)}dialog.source-dialog{position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;border:none;padding:0;background:var(--o);color:var(--a);overflow:hidden}dialog.source-dialog::backdrop{background:var(--ai)}dialog.source-dialog[open]{display:flex;flex-direction:column}.source-dialog__header{display:flex;align-items:flex-start;justify-content:space-between;padding:var(--k) var(--ac);background:var(--e);border-bottom:1px solid var(--c);flex-shrink:0}.source-dialog__title{flex:1;min-width:0}.source-dialog__title h2{font-size:22px;font-weight:700;color:var(--a);margin-bottom:var(--b);word-break:break-all}.source-legend{display:flex;flex-wrap:wrap;gap:var(--b) var(--k);align-items:center;align-self:flex-end;flex-shrink:0;margin-left:auto;padding-left:var(--ac)}.source-legend__item{display:flex;align-items:center;gap:var(--f);font-size:13px;color:var(--g);white-space:nowrap}.source-legend__swatch{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1px solid var(--c);font-family:var(--ae);font-size:12px;font-weight:700;line-height:1}.source-legend__swatch--covered{background:var(--l);border-color:var(--i);color:var(--green)}.source-legend__swatch--missed{background:var(--m);border-color:var(--j);color:var(--red)}.source-legend__swatch--skipped{background:var(--aa);border-color:var(--u);color:var(--g)}.source-legend__swatch--missed-branch{background:var(--x);border-color:var(--r);color:var(--s)}.source-legend__swatch--missed-method{background:var(--y);border-color:var(--t);color:var(--n)}.source-legend__swatch--covered:after{content:"+"}.source-legend__swatch--missed:after{content:"\2212"}.source-legend__swatch--skipped:after{content:"~"}.source-legend__swatch--missed-branch:after{content:"\b1"}.source-legend__swatch--missed-method:after{content:"\192"}.source-dialog__toggles{display:flex;align-items:center;gap:var(--b);flex-shrink:0;margin-left:var(--k);align-self:flex-start}.source-dialog__close{appearance:none;background:none;border:1px solid var(--c);border-radius:50%;width:34px;height:34px;font-size:0;color:var(--g);cursor:pointer;position:relative;flex-shrink:0;margin-left:var(--k);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(--a);border-color:var(--p)}.source-dialog__body{flex:1;overflow:auto}.source_table .header{padding:var(--k) var(--ac);background:var(--e)}.source_table .header h2{font-size:22px;font-weight:700;color:var(--a);margin-bottom:var(--b)}table.file_list .totals-row td{padding:var(--b) var(--b);font-weight:600;border-bottom:2px solid var(--p);background:var(--ad)}.totals-row .t-file-count{font-size:18px;font-weight:700;color:var(--a)}.t-missed-method-toggle{color:var(--n);font-weight:600;cursor:pointer;text-decoration:none}.t-missed-method-toggle:hover{text-decoration:underline;color:var(--n)}.t-missed-method-list ul{padding-left:2em;margin-top:var(--f);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(--a);font-family:var(--ae);font-size:16px;line-height:24px;background:var(--aj);border:1px solid var(--q);border-top:none}.source_table code{color:inherit;font-family:var(--ae)}.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(--z)}.source_table pre li:before{content:counter(linenumber);flex-shrink:0;width:50px;padding:0 8px;text-align:right;color:var(--ak);background:var(--ab);border-right:1px solid var(--q);-webkit-user-select:none;user-select:none;cursor:pointer}.source_table pre li:hover:before{color:var(--a)}.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(--b);background:var(--af);color:var(--ag);font-family:var(--ae);font-size:14px;text-align:center;line-height:24px;border-left:1px solid var(--q);-webkit-user-select:none;user-select:none}.source_table pre .hits:after{content:attr(data-content)}.source_table .covered{background-color:var(--l)}.source_table .missed{background-color:var(--m)}.source_table .never{background-color:var(--z)}.source_table .skipped{background-color:var(--aa)}.source_table .missed-branch{background-color:var(--x)}.source_table .missed-method{background-color:var(--y)}.source_table .covered:before{background-color:var(--i)}.source_table .missed:before{background-color:var(--j)}.source_table .never:before{background-color:var(--ah)}.source_table .skipped:before{background-color:var(--u)}.source_table .missed-branch:before{background-color:var(--r)}.source_table .missed-method:before{background-color:var(--t)}.source_table pre li:after{order:-1;content:"";flex-shrink:0;width:1.6em;text-align:center;font-weight:700;color:var(--g);background:var(--ab);border-right:1px solid var(--q);-webkit-user-select:none;user-select:none}.source_table .covered:after{content:"+";color:var(--green);background:var(--i)}.source_table .missed:after{content:"\2212";color:var(--red);background:var(--j)}.source_table .skipped:after{content:"~";background:var(--u)}.source_table .missed-branch:after{content:"\b1";color:var(--s);background:var(--r)}.source_table .missed-method:after{content:"\192";color:var(--n);background:var(--t)}.toolbar{display:flex;align-items:flex-start;gap:var(--b);flex-shrink:0}.toolbar-toggle{appearance:none;background:var(--e);color:var(--g);border:1px solid var(--c);border-radius:999px;padding:var(--f) var(--k);font-size:16px;font-family:var(--ap);cursor:pointer;white-space:nowrap;transition:color .15s,border-color .15s,background .15s}.toolbar-toggle:hover{color:var(--a);border-color:var(--p)}.toolbar-toggle[aria-pressed=true]{background:var(--v);color:var(--d);border-color:var(--d)}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,[tabindex]:focus-visible,.source_table pre li:focus-visible{outline:2px solid var(--d);outline-offset:2px;border-radius:3px}#footer{color:var(--h);font-size:16px;margin-top:var(--au);text-align:center}#footer a{color:var(--g);text-decoration:underline}#footer a:hover{color:var(--a)}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(--h)}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{--o: #fff;--e: #fff;--ad: #f4f5f7;--a: #111;--g: #333;--h: #444;--al: #f4f5f7;--c: #c0c5cc;--p: #999;--d: #0550ae;--green: #116329;--red: #a40e26;--yellow: #7a5200;--an: #953800;--w: #d0d7de;--l: #ccf5d0;--i: #9ae6a4;--m: #ffd8d5;--j: #ffb8b3;--z: #fff;--ah: #f0f1f3;--aa: #fff0a0;--u: #eed860;--x: #ffd0a0;--r: #ffb060;--s: #b45309;--y: #e8d0ff;--t: #d4b0ff;--n: #7b2d8e;--aj: #fff;--q: #c0c5cc;--ak: #444;--ab: #f0f1f3;--af: #e0e3e8;--ag: #333}.colorblind-mode{--green: #0060a8;--red: #c2410c;--l: #d3eaf7;--i: #a5d2ee;--m: #ffe0cc;--j: #ffc39a}body{padding:0;font-size:12pt}#loading,#sort-overlay,.toolbar,.source-dialog__toggles,.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(--b)}.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(--c);-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(--h)}}
8
+ </style>
9
9
  <script>
10
- // Apply the saved dark/light preference before paint to avoid a flash.
10
+ // Apply the saved dark/light and colorblind preferences before paint to
11
+ // avoid a flash of the wrong palette.
11
12
  try {
12
13
  const pref = localStorage.getItem('simplecov-dark-mode');
13
14
  if (pref === 'dark' || pref === 'light') {
14
15
  document.documentElement.classList.add(`${pref}-mode`);
15
16
  }
17
+ if (localStorage.getItem('simplecov-colorblind-mode') === 'on') {
18
+ document.documentElement.classList.add('colorblind-mode');
19
+ }
16
20
  } catch (_error) {
17
21
  // localStorage can be unavailable in locked-down browser contexts.
18
22
  }
@@ -32,7 +36,10 @@
32
36
  <div id="wrapper" class="hide">
33
37
  <div class="tab-bar">
34
38
  <ul class="group_tabs" role="tablist"></ul>
35
- <button id="dark-mode-toggle" aria-label="Toggle dark mode"></button>
39
+ <div class="toolbar">
40
+ <button class="toolbar-toggle" type="button" data-toggle="colorblind" aria-pressed="false" title="Use a colorblind-friendly palette and coverage symbols">🎨 Colorblind</button>
41
+ <button class="toolbar-toggle" type="button" data-toggle="dark"></button>
42
+ </div>
36
43
  </div>
37
44
 
38
45
  <div id="content"></div>
@@ -46,11 +53,34 @@
46
53
  <div class="source-dialog__header">
47
54
  <div class="source-dialog__title" id="source-dialog-title"></div>
48
55
  <div class="source-legend" id="source-legend"></div>
56
+ <div class="source-dialog__toggles">
57
+ <button class="toolbar-toggle" type="button" data-toggle="colorblind" aria-pressed="false" title="Use a colorblind-friendly palette and coverage symbols">🎨 Colorblind</button>
58
+ <button class="toolbar-toggle" type="button" data-toggle="dark"></button>
59
+ </div>
49
60
  <button class="source-dialog__close" aria-label="Close" title="Close">&times;</button>
50
61
  </div>
51
62
  <div class="source-dialog__body" id="source-dialog-body" tabindex="0"></div>
52
63
  </dialog>
53
64
 
54
- <script src="coverage_data.js" defer></script>
65
+ <!-- SIMPLECOV_COVERAGE_DATA -->
66
+ <script>"use strict";(()=>{var In=Object.create;var ht=Object.defineProperty;var Hn=Object.getOwnPropertyDescriptor;var kn=Object.getOwnPropertyNames;var $n=Object.getPrototypeOf,Dn=Object.prototype.hasOwnProperty;var Bn=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(n){throw t=0,n}};var Fn=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of kn(t))!Dn.call(e,o)&&o!==n&&ht(e,o,{get:()=>t[o],enumerable:!(r=Hn(t,o))||r.enumerable});return e};var Pn=(e,t,n)=>(n=e!=null?In($n(e)):{},Fn(t||!e||!e.__esModule?ht(n,"default",{value:e,enumerable:!0}):n,e));var oe=(e,t,n)=>new Promise((r,o)=>{var l=a=>{try{s(n.next(a))}catch(d){o(d)}},i=a=>{try{s(n.throw(a))}catch(d){o(d)}},s=a=>a.done?r(a.value):Promise.resolve(a.value).then(l,i);s((n=n.apply(e,t)).next())});var qt=Bn((Ao,Pt)=>{function xt(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],r=typeof n;(r==="object"||r==="function")&&!Object.isFrozen(n)&&xt(n)}),e}var we=class{constructor(t){t.data===void 0&&(t.data={}),this.data=t.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}};function At(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function V(e,...t){let n=Object.create(null);for(let r in e)n[r]=e[r];return t.forEach(function(r){for(let o in r)n[o]=r[o]}),n}var jn="</span>",Mt=e=>!!e.scope,zn=(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((r,o)=>`${r}${"_".repeat(o+1)}`)].join(" ")}return`${t}${e}`},Fe=class{constructor(t,n){this.buffer="",this.classPrefix=n.classPrefix,t.walk(this)}addText(t){this.buffer+=At(t)}openNode(t){if(!Mt(t))return;let n=zn(t.scope,{prefix:this.classPrefix});this.span(n)}closeNode(t){Mt(t)&&(this.buffer+=jn)}value(){return this.buffer}span(t){this.buffer+=`<span class="${t}">`}},wt=(e={})=>{let t={children:[]};return Object.assign(t,e),t},Pe=class e{constructor(){this.rootNode=wt(),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=wt({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(r=>this._walk(t,r)),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)}))}},qe=class extends Pe{constructor(t){super(),this.options=t}addText(t){t!==""&&this.add(t)}startScope(t){this.openNode(t)}endScope(){this.closeNode()}__addSublanguage(t,n){let r=t.root;n&&(r.scope=`language:${n}`),this.add(r)}toHTML(){return new Fe(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}};function de(e){return e?typeof e=="string"?e:e.source:null}function Rt(e){return J("(?=",e,")")}function Gn(e){return J("(?:",e,")*")}function Kn(e){return J("(?:",e,")?")}function J(...e){return e.map(n=>de(n)).join("")}function Vn(e){let t=e[e.length-1];return typeof t=="object"&&t.constructor===Object?(e.splice(e.length-1,1),t):{}}function Ue(...e){return"("+(Vn(e).capture?"":"?:")+e.map(r=>de(r)).join("|")+")"}function Nt(e){return new RegExp(e.toString()+"|").exec("").length-1}function Xn(e,t){let n=e&&e.exec(t);return n&&n.index===0}var Yn=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function je(e,{joinWith:t}){let n=0;return e.map(r=>{n+=1;let o=n,l=de(r),i="";for(;l.length>0;){let s=Yn.exec(l);if(!s){i+=l;break}i+=l.substring(0,s.index),l=l.substring(s.index+s[0].length),s[0][0]==="\\"&&s[1]?i+="\\"+String(Number(s[1])+o):(i+=s[0],s[0]==="("&&n++)}return i}).map(r=>`(${r})`).join(t)}var Zn=/\b\B/,Ot="[a-zA-Z]\\w*",ze="[a-zA-Z_]\\w*",It="\\b\\d+(\\.\\d+)?",Ht="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",kt="\\b(0b[01]+)",Qn="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",Jn=(e={})=>{let t=/^#![ ]*\//;return e.binary&&(e.begin=J(t,/.*\b/,e.binary,/\b.*/)),V({scope:"meta",begin:t,end:/$/,relevance:0,"on:begin":(n,r)=>{n.index!==0&&r.ignoreMatch()}},e)},fe={begin:"\\\\[\\s\\S]",relevance:0},er={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[fe]},tr={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[fe]},nr={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/},Te=function(e,t,n={}){let r=V({scope:"comment",begin:e,end:t,contains:[]},n);r.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 o=Ue("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 r.contains.push({begin:J(/[ ]+/,"(",o,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),r},rr=Te("//","$"),or=Te("/\\*","\\*/"),ir=Te("#","$"),sr={scope:"number",begin:It,relevance:0},lr={scope:"number",begin:Ht,relevance:0},ar={scope:"number",begin:kt,relevance:0},cr={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[fe,{begin:/\[/,end:/\]/,relevance:0,contains:[fe]}]},ur={scope:"title",begin:Ot,relevance:0},dr={scope:"title",begin:ze,relevance:0},fr={begin:"\\.\\s*"+ze,relevance:0},gr=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()}})},Me=Object.freeze({__proto__:null,APOS_STRING_MODE:er,BACKSLASH_ESCAPE:fe,BINARY_NUMBER_MODE:ar,BINARY_NUMBER_RE:kt,COMMENT:Te,C_BLOCK_COMMENT_MODE:or,C_LINE_COMMENT_MODE:rr,C_NUMBER_MODE:lr,C_NUMBER_RE:Ht,END_SAME_AS_BEGIN:gr,HASH_COMMENT_MODE:ir,IDENT_RE:Ot,MATCH_NOTHING_RE:Zn,METHOD_GUARD:fr,NUMBER_MODE:sr,NUMBER_RE:It,PHRASAL_WORDS_MODE:nr,QUOTE_STRING_MODE:tr,REGEXP_MODE:cr,RE_STARTERS_RE:Qn,SHEBANG:Jn,TITLE_MODE:ur,UNDERSCORE_IDENT_RE:ze,UNDERSCORE_TITLE_MODE:dr});function pr(e,t){e.input[e.index-1]==="."&&t.ignoreMatch()}function hr(e,t){e.className!==void 0&&(e.scope=e.className,delete e.className)}function mr(e,t){t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=pr,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function br(e,t){Array.isArray(e.illegal)&&(e.illegal=Ue(...e.illegal))}function vr(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 Er(e,t){e.relevance===void 0&&(e.relevance=1)}var _r=(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(r=>{delete e[r]}),e.keywords=n.keywords,e.begin=J(n.beforeMatch,Rt(n.begin)),e.starts={relevance:0,contains:[Object.assign(n,{endsParent:!0})]},e.relevance=0,delete n.beforeMatch},yr=["of","and","for","in","not","or","if","then","parent","list","value"],Mr="keyword";function $t(e,t,n=Mr){let r=Object.create(null);return typeof e=="string"?o(n,e.split(" ")):Array.isArray(e)?o(n,e):Object.keys(e).forEach(function(l){Object.assign(r,$t(e[l],t,l))}),r;function o(l,i){t&&(i=i.map(s=>s.toLowerCase())),i.forEach(function(s){let a=s.split("|");r[a[0]]=[l,wr(a[0],a[1])]})}}function wr(e,t){return t?Number(t):Sr(e)?0:1}function Sr(e){return yr.includes(e.toLowerCase())}var St={},Q=e=>{console.error(e)},Tt=(e,...t)=>{console.log(`WARN: ${e}`,...t)},se=(e,t)=>{St[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),St[`${e}/${t}`]=!0)},Se=new Error;function Dt(e,t,{key:n}){let r=0,o=e[n],l={},i={};for(let s=1;s<=t.length;s++)i[s+r]=o[s],l[s+r]=!0,r+=Nt(t[s-1]);e[n]=i,e[n]._emit=l,e[n]._multi=!0}function Tr(e){if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw Q("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),Se;if(typeof e.beginScope!="object"||e.beginScope===null)throw Q("beginScope must be object"),Se;Dt(e,e.begin,{key:"beginScope"}),e.begin=je(e.begin,{joinWith:""})}}function Lr(e){if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw Q("skip, excludeEnd, returnEnd not compatible with endScope: {}"),Se;if(typeof e.endScope!="object"||e.endScope===null)throw Q("endScope must be object"),Se;Dt(e,e.end,{key:"endScope"}),e.end=je(e.end,{joinWith:""})}}function Cr(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function xr(e){Cr(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),Tr(e),Lr(e)}function Ar(e){function t(i,s){return new RegExp(de(i),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(s?"g":""))}class n{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(s,a){a.position=this.position++,this.matchIndexes[this.matchAt]=a,this.regexes.push([a,s]),this.matchAt+=Nt(s)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);let s=this.regexes.map(a=>a[1]);this.matcherRe=t(je(s,{joinWith:"|"}),!0),this.lastIndex=0}exec(s){this.matcherRe.lastIndex=this.lastIndex;let a=this.matcherRe.exec(s);if(!a)return null;let d=a.findIndex((_,w)=>w>0&&_!==void 0),p=this.matchIndexes[d];return a.splice(0,d),Object.assign(a,p)}}class r{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(s){if(this.multiRegexes[s])return this.multiRegexes[s];let a=new n;return this.rules.slice(s).forEach(([d,p])=>a.addRule(d,p)),a.compile(),this.multiRegexes[s]=a,a}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(s,a){this.rules.push([s,a]),a.type==="begin"&&this.count++}exec(s){let a=this.getMatcher(this.regexIndex);a.lastIndex=this.lastIndex;let d=a.exec(s);if(this.resumingScanAtSamePosition()&&!(d&&d.index===this.lastIndex)){let p=this.getMatcher(0);p.lastIndex=this.lastIndex+1,d=p.exec(s)}return d&&(this.regexIndex+=d.position+1,this.regexIndex===this.count&&this.considerAll()),d}}function o(i){let s=new r;return i.contains.forEach(a=>s.addRule(a.begin,{rule:a,type:"begin"})),i.terminatorEnd&&s.addRule(i.terminatorEnd,{type:"end"}),i.illegal&&s.addRule(i.illegal,{type:"illegal"}),s}function l(i,s){let a=i;if(i.isCompiled)return a;[hr,vr,xr,_r].forEach(p=>p(i,s)),e.compilerExtensions.forEach(p=>p(i,s)),i.__beforeBegin=null,[mr,br,Er].forEach(p=>p(i,s)),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=$t(i.keywords,e.case_insensitive)),a.keywordPatternRe=t(d,!0),s&&(i.begin||(i.begin=/\B|\b/),a.beginRe=t(a.begin),!i.end&&!i.endsWithParent&&(i.end=/\B|\b/),i.end&&(a.endRe=t(a.end)),a.terminatorEnd=de(a.end)||"",i.endsWithParent&&s.terminatorEnd&&(a.terminatorEnd+=(i.end?"|":"")+s.terminatorEnd)),i.illegal&&(a.illegalRe=t(i.illegal)),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map(function(p){return Rr(p==="self"?i:p)})),i.contains.forEach(function(p){l(p,a)}),i.starts&&l(i.starts,s),a.matcher=o(a),a}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=V(e.classNameAliases||{}),l(e)}function Bt(e){return e?e.endsWithParent||Bt(e.starts):!1}function Rr(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(t){return V(e,{variants:null},t)})),e.cachedVariants?e.cachedVariants:Bt(e)?V(e,{starts:e.starts?V(e.starts):null}):Object.isFrozen(e)?V(e):e}var Nr="11.11.1",We=class extends Error{constructor(t,n){super(t),this.name="HTMLInjectionError",this.html=n}},Be=At,Lt=V,Ct=Symbol("nomatch"),Or=7,Ft=function(e){let t=Object.create(null),n=Object.create(null),r=[],o=!0,l="Could not find the language '{}', did you forget to load/include a language module?",i={disableAutodetect:!0,name:"Plain text",contains:[]},s={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:qe};function a(c){return s.noHighlightRe.test(c)}function d(c){let g=c.className+" ";g+=c.parentNode?c.parentNode.className:"";let b=s.languageDetectRe.exec(g);if(b){let y=W(b[1]);return y||(Tt(l.replace("{}",b[1])),Tt("Falling back to no-highlight mode for this block.",c)),y?b[1]:"no-highlight"}return g.split(/\s+/).find(y=>a(y)||W(y))}function p(c,g,b){let y="",T="";typeof g=="object"?(y=c,b=g.ignoreIllegals,T=g.language):(se("10.7.0","highlight(lang, code, ...args) has been deprecated."),se("10.7.0",`Please use highlight(code, options) instead.
67
+ https://github.com/highlightjs/highlight.js/issues/2277`),T=c,y=g),b===void 0&&(b=!0);let D={code:y,language:T};ve("before:highlight",D);let K=D.result?D.result:_(D.language,D.code,b);return K.code=D.code,ve("after:highlight",K),K}function _(c,g,b,y){let T=Object.create(null);function D(u,f){return u.keywords[f]}function K(){if(!h.keywords){L.addText(M);return}let u=0;h.keywordPatternRe.lastIndex=0;let f=h.keywordPatternRe.exec(M),m="";for(;f;){m+=M.substring(u,f.index);let E=F.case_insensitive?f[0].toLowerCase():f[0],x=D(h,E);if(x){let[U,Nn]=x;if(L.addText(m),m="",T[E]=(T[E]||0)+1,T[E]<=Or&&(ye+=Nn),U.startsWith("_"))m+=f[0];else{let On=F.classNameAliases[U]||U;B(f[0],On)}}else m+=f[0];u=h.keywordPatternRe.lastIndex,f=h.keywordPatternRe.exec(M)}m+=M.substring(u),L.addText(m)}function Ee(){if(M==="")return;let u=null;if(typeof h.subLanguage=="string"){if(!t[h.subLanguage]){L.addText(M);return}u=_(h.subLanguage,M,!0,pt[h.subLanguage]),pt[h.subLanguage]=u._top}else u=C(M,h.subLanguage.length?h.subLanguage:null);h.relevance>0&&(ye+=u.relevance),L.__addSublanguage(u._emitter,u.language)}function H(){h.subLanguage!=null?Ee():K(),M=""}function B(u,f){u!==""&&(L.startScope(f),L.addText(u),L.endScope())}function ut(u,f){let m=1,E=f.length-1;for(;m<=E;){if(!u._emit[m]){m++;continue}let x=F.classNameAliases[u[m]]||u[m],U=f[m];x?B(U,x):(M=U,K(),M=""),m++}}function dt(u,f){return u.scope&&typeof u.scope=="string"&&L.openNode(F.classNameAliases[u.scope]||u.scope),u.beginScope&&(u.beginScope._wrap?(B(M,F.classNameAliases[u.beginScope._wrap]||u.beginScope._wrap),M=""):u.beginScope._multi&&(ut(u.beginScope,f),M="")),h=Object.create(u,{parent:{value:h}}),h}function ft(u,f,m){let E=Xn(u.endRe,m);if(E){if(u["on:end"]){let x=new we(u);u["on:end"](f,x),x.isMatchIgnored&&(E=!1)}if(E){for(;u.endsParent&&u.parent;)u=u.parent;return u}}if(u.endsWithParent)return ft(u.parent,f,m)}function Ln(u){return h.matcher.regexIndex===0?(M+=u[0],1):($e=!0,0)}function Cn(u){let f=u[0],m=u.rule,E=new we(m),x=[m.__beforeBegin,m["on:begin"]];for(let U of x)if(U&&(U(u,E),E.isMatchIgnored))return Ln(f);return m.skip?M+=f:(m.excludeBegin&&(M+=f),H(),!m.returnBegin&&!m.excludeBegin&&(M=f)),dt(m,u),m.returnBegin?0:f.length}function xn(u){let f=u[0],m=g.substring(u.index),E=ft(h,u,m);if(!E)return Ct;let x=h;h.endScope&&h.endScope._wrap?(H(),B(f,h.endScope._wrap)):h.endScope&&h.endScope._multi?(H(),ut(h.endScope,u)):x.skip?M+=f:(x.returnEnd||x.excludeEnd||(M+=f),H(),x.excludeEnd&&(M=f));do h.scope&&L.closeNode(),!h.skip&&!h.subLanguage&&(ye+=h.relevance),h=h.parent;while(h!==E.parent);return E.starts&&dt(E.starts,u),x.returnEnd?0:f.length}function An(){let u=[];for(let f=h;f!==F;f=f.parent)f.scope&&u.unshift(f.scope);u.forEach(f=>L.openNode(f))}let _e={};function gt(u,f){let m=f&&f[0];if(M+=u,m==null)return H(),0;if(_e.type==="begin"&&f.type==="end"&&_e.index===f.index&&m===""){if(M+=g.slice(f.index,f.index+1),!o){let E=new Error(`0 width match regex (${c})`);throw E.languageName=c,E.badRule=_e.rule,E}return 1}if(_e=f,f.type==="begin")return Cn(f);if(f.type==="illegal"&&!b){let E=new Error('Illegal lexeme "'+m+'" for mode "'+(h.scope||"<unnamed>")+'"');throw E.mode=h,E}else if(f.type==="end"){let E=xn(f);if(E!==Ct)return E}if(f.type==="illegal"&&m==="")return M+=`
68
+ `,1;if(ke>1e5&&ke>f.index*3)throw new Error("potential infinite loop, way more iterations than matches");return M+=m,m.length}let F=W(c);if(!F)throw Q(l.replace("{}",c)),new Error('Unknown language: "'+c+'"');let Rn=Ar(F),He="",h=y||Rn,pt={},L=new s.__emitter(s);An();let M="",ye=0,Z=0,ke=0,$e=!1;try{if(F.__emitTokens)F.__emitTokens(g,L);else{for(h.matcher.considerAll();;){ke++,$e?$e=!1:h.matcher.considerAll(),h.matcher.lastIndex=Z;let u=h.matcher.exec(g);if(!u)break;let f=g.substring(Z,u.index),m=gt(f,u);Z=u.index+m}gt(g.substring(Z))}return L.finalize(),He=L.toHTML(),{language:c,value:He,relevance:ye,illegal:!1,_emitter:L,_top:h}}catch(u){if(u.message&&u.message.includes("Illegal"))return{language:c,value:Be(g),illegal:!0,relevance:0,_illegalBy:{message:u.message,index:Z,context:g.slice(Z-100,Z+100),mode:u.mode,resultSoFar:He},_emitter:L};if(o)return{language:c,value:Be(g),illegal:!1,relevance:0,errorRaised:u,_emitter:L,_top:h};throw u}}function w(c){let g={value:Be(c),illegal:!1,relevance:0,_top:i,_emitter:new s.__emitter(s)};return g._emitter.addText(c),g}function C(c,g){g=g||s.languages||Object.keys(t);let b=w(c),y=g.filter(W).filter(be).map(H=>_(H,c,!1));y.unshift(b);let T=y.sort((H,B)=>{if(H.relevance!==B.relevance)return B.relevance-H.relevance;if(H.language&&B.language){if(W(H.language).supersetOf===B.language)return 1;if(W(B.language).supersetOf===H.language)return-1}return 0}),[D,K]=T,Ee=D;return Ee.secondBest=K,Ee}function S(c,g,b){let y=g&&n[g]||b;c.classList.add("hljs"),c.classList.add(`language-${y}`)}function R(c){let g=null,b=d(c);if(a(b))return;if(ve("before:highlightElement",{el:c,language:b}),c.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",c);return}if(c.children.length>0&&(s.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(c)),s.throwUnescapedHTML))throw new We("One of your code blocks includes unescaped HTML.",c.innerHTML);g=c;let y=g.textContent,T=b?p(y,{language:b,ignoreIllegals:!0}):C(y);c.innerHTML=T.value,c.dataset.highlighted="yes",S(c,b,T.language),c.result={language:T.language,re:T.relevance,relevance:T.relevance},T.secondBest&&(c.secondBest={language:T.secondBest.language,relevance:T.secondBest.relevance}),ve("after:highlightElement",{el:c,result:T,text:y})}function N(c){s=Lt(s,c)}let G=()=>{X(),se("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function I(){X(),se("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let re=!1;function X(){function c(){X()}if(document.readyState==="loading"){re||window.addEventListener("DOMContentLoaded",c,!1),re=!0;return}document.querySelectorAll(s.cssSelector).forEach(R)}function at(c,g){let b=null;try{b=g(e)}catch(y){if(Q("Language definition for '{}' could not be registered.".replace("{}",c)),o)Q(y);else throw y;b=i}b.name||(b.name=c),t[c]=b,b.rawDefinition=g.bind(null,e),b.aliases&&Ie(b.aliases,{languageName:c})}function Y(c){delete t[c];for(let g of Object.keys(n))n[g]===c&&delete n[g]}function ct(){return Object.keys(t)}function W(c){return c=(c||"").toLowerCase(),t[c]||t[n[c]]}function Ie(c,{languageName:g}){typeof c=="string"&&(c=[c]),c.forEach(b=>{n[b.toLowerCase()]=g})}function be(c){let g=W(c);return g&&!g.disableAutodetect}function Mn(c){c["before:highlightBlock"]&&!c["before:highlightElement"]&&(c["before:highlightElement"]=g=>{c["before:highlightBlock"](Object.assign({block:g.el},g))}),c["after:highlightBlock"]&&!c["after:highlightElement"]&&(c["after:highlightElement"]=g=>{c["after:highlightBlock"](Object.assign({block:g.el},g))})}function wn(c){Mn(c),r.push(c)}function Sn(c){let g=r.indexOf(c);g!==-1&&r.splice(g,1)}function ve(c,g){let b=c;r.forEach(function(y){y[b]&&y[b](g)})}function Tn(c){return se("10.7.0","highlightBlock will be removed entirely in v12.0"),se("10.7.0","Please use highlightElement now."),R(c)}Object.assign(e,{highlight:p,highlightAuto:C,highlightAll:X,highlightElement:R,highlightBlock:Tn,configure:N,initHighlighting:G,initHighlightingOnLoad:I,registerLanguage:at,unregisterLanguage:Y,listLanguages:ct,getLanguage:W,registerAliases:Ie,autoDetection:be,inherit:Lt,addPlugin:wn,removePlugin:Sn}),e.debugMode=function(){o=!1},e.safeMode=function(){o=!0},e.versionString=Nr,e.regex={concat:J,lookahead:Rt,either:Ue,optional:Kn,anyNumberOfTimes:Gn};for(let c in Me)typeof Me[c]=="object"&&xt(Me[c]);return Object.assign(e,Me),e},le=Ft({});le.newInstance=()=>Ft({});Pt.exports=le;le.HighlightJS=le;le.default=le});function O(e,t){return(t||document).querySelector(e)}function v(e,t){return Array.from((t||document).querySelectorAll(e))}function P(e,t,n,r){typeof n=="function"?e.addEventListener(t,n):e.addEventListener(t,function(o){let l=o.target.closest(n);l&&e.contains(l)&&r&&r.call(l,o)})}var qn={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function k(e){return e.replace(/[&<>"']/g,t=>qn[t])}function mt(e){return oe(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),r=>r.toString(16).padStart(2,"0")).join("")})}var Wn=90,Un=75;function q(e){return e>=Wn?"green":e>=Un?"yellow":"red"}function A(e){return e.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function j(e){return(Math.floor(e*100)/100).toFixed(2)}function bt(e){return"g-"+e.replace(/[^a-zA-Z0-9-]/gu,t=>`_${t.codePointAt(0).toString(16)}_`)}var vt=[[31536e3,"year"],[2592e3,"month"],[86400,"day"],[3600,"hour"],[60,"minute"],[1,"second"]];function Et(e){let t=Math.floor((Date.now()-e.getTime())/1e3);for(let[n,r]of vt){let o=Math.floor(t/n);if(o>=1)return o===1?`about 1 ${r} ago`:`${o} ${r}s ago`}return"just now"}function _t(e){let t=(Date.now()-e.getTime())/1e3;for(let[n]of vt){let r=Math.floor(t/n);if(r>=1){let o=(r+1)*n;return Math.max((o-t)*1e3+500,1e3)}}return 1e3}var De=new Map;function ie(e){let t=De.get(e);if(t===void 0)throw new Error(`File ID was not precomputed for ${e}`);return t}function yt(e){return oe(this,null,function*(){De.clear();let t=[...new Set(e)],n=yield Promise.all(t.map(mt)),r=new Map;t.forEach((o,l)=>{let i=n[l],s=r.get(i)||[];s.push(o),r.set(i,s)});for(let[o,l]of r)l.sort().forEach((i,s)=>{De.set(i,s===0?o:`${o}-${s}`)})})}var Wt=Pn(qt(),1);var Ge=Wt.default;function Ut(e){let t=e.regex,n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",r=t.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),o=t.concat(r,/(::\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"]},s={className:"doctag",begin:"@[A-Za-z]+"},a={begin:"#<",end:">"},d=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],p={className:"subst",begin:/#\{/,end:/\}/,keywords:i},_={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",C="[0-9](_?[0-9])*",S={className:"number",relevance:0,variants:[{begin:`\\b(${w})(\\.(${C}))?([eE][+-]?(${C})|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"}]},R={variants:[{match:/\(\)/},{className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0,keywords:i}]},Y=[_,{variants:[{match:[/class\s+/,o,/\s+<\s+/,o]},{match:[/\b(class|module)\s+/,o]}],scope:{2:"title.class",4:"title.class.inherited"},keywords:i},{match:[/(include|extend)\s+/,o],scope:{2:"title.class"},keywords:i},{relevance:0,match:[o,/\.new[. (]/],scope:{1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{relevance:0,match:r,scope:"title.class"},{match:[/def/,/\s+/,n],scope:{1:"keyword",3:"title.function"},contains:[R]},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[_,{begin:n}],relevance:0},S,{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(a,d),relevance:0}].concat(a,d);p.contains=Y,R.contains=Y;let be=[{begin:/^\s*=>/,starts:{end:"$",contains:Y}},{className:"meta.prompt",begin:"^("+"[>?]>"+"|"+"[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]"+"|"+"(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>"+")(?=[ ])",starts:{end:"$",keywords:i,contains:Y}}];return d.unshift(a),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(be).concat(d).concat(Y)}}function Ir(e){if(e==="oneshot_line")return"line";if(e==="line"||e==="branch"||e==="method")return e}function jt(e){let t=Ir(e.primary_coverage);return t==="line"&&e.line_coverage||t==="branch"&&e.branch_coverage||t==="method"&&e.method_coverage?t:e.line_coverage?"line":e.branch_coverage?"branch":"method"}function Hr(e,t){return t==="line"?e.lines:t==="branch"?e.branches:e.methods}function Le(e,t){return Hr(e,t)||e.lines||e.branches||e.methods}function Ve(e){let t=q(e),n=j(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 ee(e,t,n,r,o){let l=q(e),i=j(e),s=`<div class="coverage-cell">${Ve(e)}<span class="coverage-pct">${i}%</span></div>`;if(o)return`<td class="cell--coverage strong t-totals__${r}-pct ${l}">${s}</td><td class="cell--numerator strong t-totals__${r}-num">${A(t)}/</td><td class="cell--denominator strong t-totals__${r}-den">${A(n)}</td>`;let a=` data-order="${j(e)}"`;return`<td class="cell--coverage cell--${r}-pct ${l}"${a}>${s}</td><td class="cell--numerator">${A(t)}/</td><td class="cell--denominator">${A(n)}</td>`}function Ce(e,t,n,r){return`<th class="cell--coverage">
69
+ <div class="th-with-filter">
70
+ <span class="th-label">${e}</span>
71
+ <div class="col-filter__coverage">
72
+ <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>
73
+ <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>
74
+ </div>
75
+ </div>
76
+ </th>
77
+ <th class="cell--numerator">${n}</th>
78
+ <th class="cell--denominator">${r}</th>`}function Ke(e){let{type:t,label:n,covered:r,total:o,enabled:l,toggle:i}=e;if(!l)return`<div class="t-${t}-summary">
79
+ ${n}: <span class="coverage-disabled">disabled</span>
80
+ </div>`;let s=o-r,a=o>0?r*100/o:100,d=q(a),p=e.suffix||"covered",_=e.missedClass||"red",w=`<div class="t-${t}-summary">
81
+ ${n}: <span class="${d}"><b>${j(a)}%</b></span><span class="coverage-cell__fraction"> ${r}/${o} ${p}</span>`;if(s>0){let C=i?`<a href="#" class="t-missed-method-toggle"><b>${s}</b> missed</a>`:`<span class="${_}"><b>${s}</b> missed</span>`;w+=`<span class="coverage-cell__fraction">,</span>
82
+ ${C}`}return w+=`
83
+ </div>`,w}function zt(e){return'<div class="summary-stats">'+Ke({type:"line",label:"Line coverage",covered:e.coveredLines,total:e.totalLines,enabled:e.lineCoverage,suffix:"relevant lines covered"})+Ke({type:"branch",label:"Branch coverage",covered:e.coveredBranches,total:e.totalBranches,enabled:e.branchCoverage,missedClass:"missed-branch-text"})+Ke({type:"method",label:"Method coverage",covered:e.coveredMethods,total:e.totalMethods,enabled:e.methodCoverage,missedClass:"missed-method-text-color",toggle:e.showMethodToggle})+"</div>"}function kr(e){let{containerId:t,title:n,filenames:r,stats:o,lineCoverage:l,branchCoverage:i,methodCoverage:s,primaryCoverage:a}=e,d=l?o.lines:void 0,p=i?o.branches:void 0,_=s?o.methods:void 0,w=Le(o,a),C=w?w.percent:100,S=[`<div class="file_list_container" id="${t}" data-total-files="${r.length}">`,`<span class="group_name hide">${k(n)}</span>`,`<span class="covered_percent hide"><span class="${q(C)}">${j(C)}%</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>'];d&&S.push(Ce("Line Coverage","line","Covered","Lines")),i&&S.push(Ce("Branch Coverage","branch","Covered","Branches")),s&&S.push(Ce("Method Coverage","method","Covered","Methods")),S.push("</tr>");let R=r.length===1?"file":"files";return S.push(`<tr class="totals-row"><td class="strong t-file-count">${A(r.length)} ${R}</td>`),d&&S.push(ee(d.percent,d.covered,d.total,"line",!0)),p&&S.push(ee(p.percent,p.covered,p.total,"branch",!0)),_&&S.push(ee(_.percent,_.covered,_.total,"method",!0)),S.push("</tr></thead><tbody>"),S.join("")}function $r(e){let{filename:t,coverage:n,lineCoverage:r,branchCoverage:o,methodCoverage:l}=e,i=ie(t),s=[];r&&s.push(`data-covered-lines="${n.covered_lines||0}"`,`data-relevant-lines="${n.total_lines||0}"`),o&&s.push(`data-covered-branches="${n.covered_branches||0}"`,`data-total-branches="${n.total_branches||0}"`),l&&s.push(`data-covered-methods="${n.covered_methods||0}"`,`data-total-methods="${n.total_methods||0}"`);let a=[`<tr class="t-file" ${s.join(" ")}>`,`<td class="strong t-file__name"><a href="#${i}" class="src_link" title="${k(t)}">${k(t)}</a></td>`];if(r){let d=n.lines_covered_percent===void 0?100:n.lines_covered_percent;a.push(ee(d,n.covered_lines||0,n.total_lines||0,"line",!1))}if(o){let d=n.branches_covered_percent===void 0?100:n.branches_covered_percent;a.push(ee(d,n.covered_branches||0,n.total_branches||0,"branch",!1))}if(l){let d=n.methods_covered_percent===void 0?100:n.methods_covered_percent;a.push(ee(d,n.covered_methods||0,n.total_methods||0,"method",!1))}return a.push("</tr>"),a.join("")}function Xe(e){let{filenames:t,allCoverage:n,lineCoverage:r,branchCoverage:o,methodCoverage:l}=e,i=[kr(e)];for(let s of t){let a=n[s];a&&i.push($r({filename:s,coverage:a,lineCoverage:r,branchCoverage:o,methodCoverage:l}))}return i.push("</tbody></table></div></div>"),i.join("")}function Dr(e){let{lineIndex:t,lineCov:n,branchesReport:r,missedMethodLines:o,branchCoverage:l,methodCoverage:i}=e,s=t+1;if(n==="ignored")return"skipped";if(l){let a=r[s];if(a&&a.some(([,d])=>d===0))return"missed-branch"}return i&&o.has(s)?"missed-method":n==null?"never":n===0?"missed":"covered"}function Br(e){let t={};if(!e)return t;for(let{coverage:n,report_line:r,type:o}of e){if(n==="ignored")continue;(t[r]||(t[r]=[])).push([o,n])}return t}function Fr(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 r=n.start_line;r<=n.end_line;r++)t.add(r);return t}function Pr(e){let{index:t,source:n,lineCov:r,status:o,branchCoverage:l,lineBranches:i}=e,s=t+1,a=typeof r=="number"?` data-hits="${r}"`:"",d=[`<li class="${o}"${a} data-linenumber="${s}">`];if(typeof r=="number"&&r>0?d.push(`<span class="hits" data-content="${r}"></span>`):r==="ignored"&&d.push('<span class="hits" data-content="skipped"></span>'),l&&i)for(let[p,_]of i){let w=k(p);d.push(`<span class="hits" data-content="${w}: ${_}" title="${w} branch hit ${_} times"></span>`)}return d.push(`<code class="ruby">${k(n)}</code></li>`),d.join("")}function Gt(e,t,n,r,o){var G;let l=ie(e),i=n&&t.covered_lines||0,s=n&&t.total_lines||0,a=r&&t.covered_branches||0,d=r&&t.total_branches||0,p=o&&t.covered_methods||0,_=o&&t.total_methods||0,w=(t.methods||[]).filter(I=>I.coverage===0),C=o&&w.length>0,S=Br(t.branches),R=Fr(t.methods),N=[`<div class="source_table" id="${l}">`,'<div class="header">',`<h2>${k(e)}</h2>`,zt({coveredLines:i,totalLines:s,coveredBranches:a,totalBranches:d,coveredMethods:p,totalMethods:_,lineCoverage:n,branchCoverage:r,methodCoverage:o,showMethodToggle:C})];C&&N.push('<div class="t-missed-method-list" style="display: none"><ul>',w.map(I=>`<li><tt>${k(I.name)}</tt></li>`).join(""),"</ul></div>"),N.push("</div>","<pre><ol>");for(let I=0;I<t.source.length;I++){let re=(G=t.lines)==null?void 0:G[I],X=Dr({lineIndex:I,lineCov:re,branchesReport:S,missedMethodLines:R,branchCoverage:r,methodCoverage:o});N.push(Pr({index:I,source:t.source[I],lineCov:re,status:X,branchCoverage:r,lineBranches:r?S[I+1]:void 0}))}return N.push("</ol></pre></div>"),N.join("")}Ge.registerLanguage("ruby",Ut);var Ye=null;function ge(){if(!Ye)return;let e=getComputedStyle(document.documentElement).getPropertyValue(`--${Ye}`).trim(),t=document.createElement("canvas");t.width=t.height=16;let n=t.getContext("2d");if(!e||!n)return;n.fillStyle=e,n.fillRect(0,0,16,16);let r=document.querySelector('link[rel="icon"]');r||(r=document.createElement("link"),r.rel="icon",r.type="image/png",document.head.appendChild(r)),r.href=t.toDataURL("image/png")}var te=null;function Kt(e){let t=e.meta,n=t.line_coverage,r=t.branch_coverage,o=t.method_coverage,l=jt(t);document.title=`Code coverage for ${t.project_name}`;let i=Object.keys(e.coverage),s=Le(e.total,l),a=s&&s.total>0?s.percent:100;Ye=q(a),ge(),r&&document.body.setAttribute("data-branch-coverage","true");let d=document.getElementById("content"),p=[Xe({containerId:"g-total",title:"All Files",filenames:i,stats:e.total,allCoverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o,primaryCoverage:l})];for(let N of Object.keys(e.groups)){let G=e.groups[N];p.push(Xe({containerId:bt(`group-${N}`),title:N,filenames:G.files||[],stats:G,allCoverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o,primaryCoverage:l}))}d.innerHTML=p.join("");let _={};for(let N of i)_[ie(N)]=N;te={idToFilename:_,coverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o};let w=new Date(t.timestamp),C=document.getElementById("footer");C.innerHTML=`Generated <abbr class="timeago" title="${w.toISOString()}">${w.toISOString()}</abbr> by <a href="https://github.com/simplecov-ruby/simplecov">simplecov</a> v${k(t.simplecov_version)} using ${k(t.command_name)}`;let S=document.getElementById("source-legend"),R="";n&&(R+='<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>'),r&&(R+='<span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-branch"></span>Missed branch</span>'),o&&(R+='<span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-method"></span>Missed method</span>'),S.innerHTML=R}function Vt(e){let t=document.getElementById(e);if(t)return t;if(!te)return null;let n=te.idToFilename[e];if(!n)return null;let r=Gt(n,te.coverage[n],te.lineCoverage,te.branchCoverage,te.methodCoverage),o=document.querySelector(".source_files"),l=document.createElement("div");l.innerHTML=r;let i=l.firstElementChild;return o.appendChild(i),v("pre code",i).forEach(s=>Ge.highlightElement(s)),i}var Ze=1e3,qr="t-window-hidden",Xt=new WeakSet;function Wr(e,t){let n=e.querySelector("tr.t-show-all");if(!n){n=document.createElement("tr"),n.className="t-show-all";let r=document.createElement("td");r.colSpan=t,n.appendChild(r),n.addEventListener("click",o=>{o.preventDefault(),Xt.add(e),ae(e.closest("table"))}),e.appendChild(n)}return n}function ae(e){let t=e.querySelector("tbody");if(!t)return;let n=t.querySelectorAll("tr.t-file"),r=Xt.has(t),o=0;if(n.forEach(i=>{let s=i.style.display==="none";s||(o+=1),i.classList.toggle(qr,!r&&!s&&o>Ze)}),r||o<=Ze){let i=t.querySelector("tr.t-show-all");i&&(i.style.display="none");return}let l=Wr(t,n[0].children.length);l.style.display="",l.firstElementChild.innerHTML=`Showing the first ${A(Ze)} of ${A(o)} files. <a href="#" class="t-show-all__link">Show all</a>`,t.appendChild(l)}var Qt=new WeakMap;function Ur(e,t){let n=0,r=e.children;for(let o=0;o<r.length;o++)if(r[o].style.display!=="none"){if(n===t)return o;n+=1}return null}function jr(e){if(!e)return"";let t=e.getAttribute("data-order");if(t!==null)return Number.parseFloat(t);let n=(e.textContent||"").trim(),r=Number.parseFloat(n);return Number.isNaN(r)?n.toLowerCase():r}var Yt=new WeakMap;function Jt(e,t){var l;if(t===null)return"";let n=Yt.get(e);n||(n=new Map,Yt.set(e,n));let r=n.get(t);if(r!==void 0)return r;let o=jr((l=e.children[t])!=null?l:null);return n.set(t,o),o}var zr=new Intl.Collator;function en(e,t){return typeof e=="number"&&typeof t=="number"?e-t:zr.compare(String(e),String(t))}function Qe(e,t,n){Qt.set(e,{colIndex:t,direction:n});let r=0;v("thead tr:first-child th",e).forEach(o=>{let l=Number.parseInt(o.getAttribute("colspan")||"1",10);o.classList.remove("sorting_asc","sorting_desc","sorting");let i=t>=r&&t<r+l;o.classList.add(i?n==="asc"?"sorting_asc":"sorting_desc":"sorting"),r+=l})}function tn(e,t){let n=document.createDocumentFragment();t.forEach(r=>n.appendChild(r)),e.appendChild(n)}function Zt(e,t){let n=Qt.get(e),r=n&&n.colIndex===t&&n.direction==="asc"?"desc":"asc",o=e.querySelector("tbody"),l=Array.from(o.querySelectorAll("tr.t-file"));if(l.length===0){Qe(e,t,r);return}if(n&&n.colIndex===t)l.reverse();else{let i=Ur(l[0],t),s=l.map(d=>({row:d,value:Jt(d,i)})),a=r==="asc"?1:-1;s.sort((d,p)=>a*en(d.value,p.value)),l=s.map(({row:d})=>d)}tn(o,l),ae(e),Qe(e,t,r)}var Gr=500,pe=null;function Kr(){if(pe)return pe;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),pe=e,e}function Vr(){let e=Kr();e.style.transition="none",e.style.opacity="1",e.style.display="flex"}function Xr(){if(!pe)return;let e=pe;e.style.transition="opacity 0.15s",e.style.opacity="0",setTimeout(()=>{e.style.display="none"},150)}function Yr(e,t){if(e.querySelectorAll("tbody tr.t-file").length<Gr){Zt(e,t);return}Vr(),requestAnimationFrame(()=>requestAnimationFrame(()=>{Zt(e,t),Xr()}))}function Zr(e,t){let n=0;for(let r of v("thead tr:first-child th",e)){let o=Number.parseInt(r.getAttribute("colspan")||"1",10);if(r===t)return n+o-1;n+=o}return n}function Qr(e,t){let n=Array.from(e.children);if(t){let o=n.findIndex(l=>l.classList.contains(`cell--${t}-pct`));if(o!==-1)return o}let r=n.findIndex(o=>o.hasAttribute("data-order"));return r===-1?null:r}function Jr(e,t){let n=e.querySelector("tbody");if(!n)return;let r=Array.from(n.querySelectorAll("tr.t-file"));if(r.length===0)return;let o=Qr(r[0],t);if(o===null)return;let l=r.map(i=>({row:i,value:Jt(i,o)}));l.sort((i,s)=>en(i.value,s.value)),tn(n,l.map(({row:i})=>i)),Qe(e,o,"asc")}function nn(e){v("table.file_list").forEach(t=>{v("thead tr:first-child th",t).forEach(n=>{n.classList.add("sorting"),n.style.cursor="pointer",n.addEventListener("click",()=>Yr(t,Zr(t,n)))}),Jr(t,e),ae(t)})}var he=null;function xe(){he=null}function rn(){if(he)return he;let e=v(".file_list_container").filter(t=>t.style.display!=="none");return e.length?(he=v("tbody tr.t-file",e[0]).filter(t=>t.style.display!=="none"),he):[]}var eo=240,to=160;function on(e,t){e.style.setProperty("--bar-sizer-width",t+"px")}var no=8;function ro(e,t){let n=to,r=eo;for(;r-n>no;){let o=Math.ceil((n+r)/2);on(e,o),e.offsetWidth,e.scrollWidth<=t?n=o:r=o-1}return n}function et(){v(".file_list_container").forEach(e=>{if(e.style.display==="none"||e.offsetWidth===0)return;let t=O("table.file_list",e);if(!t||!O(".bar-sizer",t))return;let n=t.closest(".file_list--responsive");n&&(n.style.visibility="hidden",on(t,ro(t,n.clientWidth)),n.style.visibility="")})}var Je=0;function ce(){Je||(Je=requestAnimationFrame(()=>{Je=0,et()}))}var Ae={line:{covered:"coveredLines",total:"relevantLines"},branch:{covered:"coveredBranches",total:"totalBranches"},method:{covered:"coveredMethods",total:"totalMethods"}};function sn(e){let t=v("tbody tr.t-file",e).filter(l=>l.style.display!=="none");function n(l){return t.reduce((i,s)=>i+(Number.parseInt(s.dataset[l]||"0",10)||0),0)}let r=O(".t-file-count",e),o=Number.parseInt(e.getAttribute("data-total-files")||"0",10);if(r){let l=t.length===1?" file":" files";r.textContent=t.length===o?A(o)+l:A(t.length)+"/"+A(o)+l}for(let l of Object.keys(Ae)){let i=Ae[l],s=`.t-totals__${l}`;O(s+"-pct",e)&&oo(e,s,n(i.covered),n(i.total))}}function oo(e,t,n,r){let o=O(t+"-pct",e),l=O(t+"-num",e),i=O(t+"-den",e);if(r===0){o&&(o.innerHTML="",o.classList.remove("green","yellow","red")),l&&(l.textContent=""),i&&(i.textContent="");return}let s=n*100/r,a=q(s);o&&(o.innerHTML=`<div class="coverage-cell">${Ve(s)}<span class="coverage-pct">${j(s)}%</span></div>`,o.classList.remove("green","yellow","red"),o.classList.add(a)),l&&(l.textContent=A(n)+"/"),i&&(i.textContent=A(r))}var io={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 so(e,t,n){let r=io[e];return r?r(t,n):!0}function lo(e){let t=[];for(let n of v(".col-filter__value",e)){let r=n;if(!r.value)continue;let o=Number.parseFloat(r.value);if(Number.isNaN(o))continue;let l=r.dataset.type||"",i=O(`.col-filter__op[data-type="${l}"]`,e),s=i?i.value:"",a=Ae[l];s&&a&&t.push({attrs:a,op:s,threshold:o})}return t}var ln=new WeakMap;function ao(e){let t=ln.get(e);return t===void 0&&(t=(e.children[0].textContent||"").toLowerCase(),ln.set(e,t)),t}function an(e){let t=O("table.file_list",e);if(!t)return;let n=O(".col-filter--name",e),r=n?n.value.trim().toLowerCase():"",o=lo(e);v("tbody tr.t-file",t).forEach(l=>{let i=l,a=(!r||ao(l).includes(r))&&o.every(d=>{let p=Number.parseInt(i.dataset[d.attrs.covered]||"0",10)||0,_=Number.parseInt(i.dataset[d.attrs.total]||"0",10)||0,w=_>0?p*100/_:100;return so(d.op,w,d.threshold)})?"":"none";i.style.display!==a&&(i.style.display=a)}),ae(t),xe(),sn(e),ce()}function tt(e){let t=Number.parseFloat(e.value),n=e.closest(".col-filter__coverage"),r=n?n.querySelector(".col-filter__op"):null;if(!r)return;let o=r.querySelector('option[value="gt"]'),l=r.querySelector('option[value="lt"]');if(o&&(o.disabled=t>=100),l&&(l.disabled=t<=0),r.selectedOptions[0]&&r.selectedOptions[0].disabled){let i=r.querySelector("option:not(:disabled)");i&&(r.value=i.value)}}function cn(){v(".col-filter__value").forEach(e=>tt(e)),v(".col-filter--name, .col-filter__op, .col-filter__value, .col-filter__coverage").forEach(e=>{e.addEventListener("click",t=>t.stopPropagation())}),P(document,"input",".col-filter--name, .col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&tt(this),an(this.closest(".file_list_container"))}),P(document,"change",".col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&tt(this),an(this.closest(".file_list_container"))})}var $=null;function nt(){return $!==null}function ue(e){$&&$.classList.remove("keyboard-focus"),$=e,$&&($.classList.add("keyboard-focus"),$.scrollIntoView({block:"nearest"}))}function rt(e){let t=rn();if(!t.length)return;if(!$||t.indexOf($)===-1){ue(e===1?t[0]:t[t.length-1]);return}let n=t.indexOf($)+e;n>=0&&n<t.length&&ue(t[n])}function un(){if(!$)return;let e=$.querySelector("a.src_link");e&&(window.location.hash=e.getAttribute("href").substring(1))}var z,ne,ot,me=null,Re="";function it(){return z.open}function st(){return ne}function fn(){if(!me)return;Re&&(me.insertAdjacentHTML("afterbegin",Re),Re="");let e=document.querySelector(".source_files");e&&e.appendChild(me),me=null}function co(e,t){fn();let n=Vt(e);if(!n)return;let r=n.querySelector(".header");if(r&&(Re=r.outerHTML,ot.innerHTML=r.innerHTML,r.remove()),me=n,ne.appendChild(n),z.open||z.showModal(),document.documentElement.style.overflow="hidden",ne.focus(),t){let o=ne.querySelector('li[data-linenumber="'+t+'"]');o&&(ne.scrollTop=o.offsetTop)}}function dn(e){if(ue(null),xe(),z.open&&(fn(),z.close(),ne.innerHTML="",ot.innerHTML="",document.documentElement.style.overflow=""),e){let n=document.querySelector(".group_tabs a."+e);if(n){v(".group_tabs li").forEach(o=>o.classList.remove("active")),n.parentElement.classList.add("active"),v(".file_list_container").forEach(o=>o.style.display="none");let r=document.getElementById(e);r&&(r.style.display="")}}let t=document.getElementById("wrapper");t&&!t.classList.contains("hide")&&ce()}function Oe(){let e=window.location.hash.substring(1);if(!e){let t=document.querySelector(".group_tabs a");t&&dn(t.getAttribute("href").replace("#",""));return}if(e.charAt(0)==="_")dn(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")}co(t[0],t[1])}}function Ne(){let e=document.querySelector(".group_tabs li.active a");e&&(window.location.hash=e.getAttribute("href").replace("#","#_"))}function gn(){z=document.getElementById("source-dialog"),ne=document.getElementById("source-dialog-body"),ot=document.getElementById("source-dialog-title"),z.querySelector(".source-dialog__close").addEventListener("click",Ne),z.addEventListener("click",e=>{e.target===z&&Ne()})}function uo(){return v(".source-dialog .source_table li.missed, .source-dialog .source_table li.missed-branch, .source-dialog .source_table li.missed-method")}function lt(e){let t=uo();if(!t.length)return;let n=st(),r=n.scrollTop+n.clientHeight/2,o=e===1?t.find(l=>l.offsetTop>r)||t[0]:t.findLast(l=>l.offsetTop<r-10)||t[t.length-1];n.scrollTop=o.offsetTop-n.clientHeight/3}function pn(){P(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")}),P(document,"click","a.src_link",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").substring(1)}),P(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))}),P(document,"click",".source-dialog .source_table li[data-linenumber]",function(e){e.preventDefault(),st().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",Oe)}var hn="simplecov-dark-mode",fo="simplecov-colorblind-mode";function go(e){try{return localStorage.getItem(e)}catch(t){return null}}function mn(e,t){try{localStorage.setItem(e,t)}catch(n){}}function po(){return go(hn)}function bn(e){return Array.from(document.querySelectorAll(`[data-toggle="${e}"]`))}function vn(){let e=bn("colorblind");if(e.length===0)return;let t=document.documentElement,n=()=>{let r=String(t.classList.contains("colorblind-mode"));e.forEach(o=>o.setAttribute("aria-pressed",r))};n(),e.forEach(r=>r.addEventListener("click",()=>{let o=t.classList.toggle("colorblind-mode");mn(fo,o?"on":"off"),n(),ge()}))}function En(){let e=bn("dark");if(e.length===0)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 r(){let o=n();e.forEach(l=>{l.textContent=o?"\u2600\uFE0F Light":"\u{1F319} Dark",l.setAttribute("aria-label",o?"Switch to light mode":"Switch to dark mode")})}r(),e.forEach(o=>o.addEventListener("click",()=>{let l=n();t.classList.toggle("light-mode",l),t.classList.toggle("dark-mode",!l),mn(hn,l?"light":"dark"),r(),ge()})),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{po()||r(),ge()})}function ho(){let e=v(".file_list_container").filter(n=>n.style.display!=="none"),t=e.length?O(".col-filter--name",e[0]):null;t&&t.focus()}function mo(e,t){it()?(e.preventDefault(),Ne()):t?e.target.blur():nt()&&ue(null)}function bo(e){e.key==="n"&&!e.shiftKey&&(e.preventDefault(),lt(1)),(e.key==="N"||e.key==="n"&&e.shiftKey||e.key==="p")&&(e.preventDefault(),lt(-1))}function vo(e){e.key==="j"&&(e.preventDefault(),rt(1)),e.key==="k"&&(e.preventDefault(),rt(-1)),e.key==="Enter"&&nt()&&(e.preventDefault(),un())}function _n(e){let t=e.target.matches("input, select, textarea");e.key==="/"&&!t?(e.preventDefault(),ho()):e.key==="Escape"?mo(e,t):t||(it()?bo(e):vo(e))}function yn(){let e=1/0;v("abbr.timeago").forEach(t=>{let n=new Date(t.getAttribute("title")||"");Number.isNaN(n.getTime())||(t.textContent=Et(n),e=Math.min(e,_t(n)))}),e<1/0&&setTimeout(yn,e)}function Eo(){v(".file_list_container").forEach(e=>e.style.display="none"),v(".file_list_container").forEach(e=>{let t=e.id,n=e.querySelector(".group_name"),r=e.querySelector(".covered_percent"),o=document.createElement("li");o.setAttribute("role","tab");let l=document.createElement("a");l.href="#"+t,l.className=t,l.innerHTML=(n?n.innerHTML:"")+" ("+(r?r.innerHTML:"")+")",o.appendChild(l),document.querySelector(".group_tabs").appendChild(o)}),P(document.querySelector(".group_tabs"),"click","a",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").replace("#","#_")})}function _o(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"),et()}function yo(){return oe(this,null,function*(){let e=window.SIMPLECOV_DATA,t=document.getElementById("loading");t&&(t.style.display=""),yield yt(Object.keys(e.coverage)),Kt(e),yn(),En(),vn(),nn(e.meta.primary_coverage),cn(),document.addEventListener("keydown",_n),gn(),pn(),Eo(),window.addEventListener("resize",ce),Oe(),_o(t)})}document.addEventListener("DOMContentLoaded",yo);})();
84
+ </script>
55
85
  </body>
56
86
  </html>
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ module SimpleCov
6
+ module Formatter
7
+ class HTMLFormatter
8
+ # Validates the subset of coverage.json that the browser viewer
9
+ # dereferences without defensive fallbacks.
10
+ module ViewerDataValidator
11
+ META_STRINGS = %w[simplecov_version command_name project_name timestamp].freeze
12
+ COVERAGE_FLAGS = {
13
+ "line_coverage" => "lines",
14
+ "branch_coverage" => "branches",
15
+ "method_coverage" => "methods"
16
+ }.freeze
17
+ STAT_FIELDS = %w[covered missed total percent strength].freeze
18
+ private_constant :META_STRINGS, :COVERAGE_FLAGS, :STAT_FIELDS
19
+
20
+ class << self
21
+ def call(data)
22
+ %w[meta total coverage groups].each { |key| validate_section!(data, key) }
23
+ meta = data.fetch("meta")
24
+ validate_meta!(meta)
25
+ validate_statistics!(data.fetch("total"), meta, "total")
26
+ data.fetch("coverage").each { |filename, file| validate_file!(filename, file) }
27
+ data.fetch("groups").each { |name, group| validate_group!(name, group, meta) }
28
+ data
29
+ end
30
+
31
+ private
32
+
33
+ def validate_section!(data, key)
34
+ return if data[key].is_a?(Hash)
35
+
36
+ raise SimpleCov::CoverageJSON::Error, "#{key.inspect} must be an object"
37
+ end
38
+
39
+ def validate_file!(filename, file)
40
+ unless file.is_a?(Hash)
41
+ raise SimpleCov::CoverageJSON::Error, "coverage entry #{filename.inspect} must be an object"
42
+ end
43
+
44
+ source = file["source"]
45
+ return if source.is_a?(Array) && source.all?(String)
46
+
47
+ raise SimpleCov::CoverageJSON::Error,
48
+ "coverage entry #{filename.inspect} must include an array of source strings; " \
49
+ "regenerate with source_in_json true"
50
+ end
51
+
52
+ def validate_meta!(meta)
53
+ META_STRINGS.each { |key| validate_type!(meta, key, String, "meta") }
54
+ Time.iso8601(meta.fetch("timestamp"))
55
+ COVERAGE_FLAGS.each_key { |key| validate_boolean!(meta, key) }
56
+ rescue ArgumentError
57
+ raise SimpleCov::CoverageJSON::Error, "meta.timestamp must be an ISO 8601 date-time"
58
+ end
59
+
60
+ def validate_statistics!(statistics, meta, location)
61
+ COVERAGE_FLAGS.each do |flag, criterion|
62
+ next unless meta.fetch(flag)
63
+
64
+ values = validate_type!(statistics, criterion, Hash, location)
65
+ STAT_FIELDS.each { |field| validate_type!(values, field, Numeric, "#{location}.#{criterion}") }
66
+ end
67
+ end
68
+
69
+ def validate_group!(name, group, meta)
70
+ raise SimpleCov::CoverageJSON::Error, "group #{name.inspect} must be an object" unless group.is_a?(Hash)
71
+
72
+ files = group["files"]
73
+ unless files.is_a?(Array) && files.all?(String)
74
+ raise SimpleCov::CoverageJSON::Error, "group #{name.inspect}.files must be an array of strings"
75
+ end
76
+
77
+ validate_statistics!(group, meta, "group #{name.inspect}")
78
+ end
79
+
80
+ def validate_type!(object, key, type, location)
81
+ value = object[key]
82
+ return value if value.is_a?(type)
83
+
84
+ raise SimpleCov::CoverageJSON::Error, "#{location}.#{key} must be a #{type.name.downcase}"
85
+ end
86
+
87
+ def validate_boolean!(meta, key)
88
+ return if [true, false].include?(meta[key])
89
+
90
+ raise SimpleCov::CoverageJSON::Error, "meta.#{key} must be a boolean"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end