simplecov 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +56 -1451
- data/lib/simplecov/atomic_file.rb +70 -0
- data/lib/simplecov/cli/clean.rb +43 -3
- data/lib/simplecov/cli/command_helpers.rb +55 -0
- data/lib/simplecov/cli/coverage.rb +21 -28
- data/lib/simplecov/cli/coverage_file.rb +65 -0
- data/lib/simplecov/cli/diff.rb +43 -48
- data/lib/simplecov/cli/dotfile.rb +12 -6
- data/lib/simplecov/cli/merge.rb +12 -10
- data/lib/simplecov/cli/open.rb +3 -5
- data/lib/simplecov/cli/report.rb +31 -23
- data/lib/simplecov/cli/serve/report_preparer.rb +29 -0
- data/lib/simplecov/cli/serve/static_file_handler.rb +122 -0
- data/lib/simplecov/cli/serve.rb +30 -94
- data/lib/simplecov/cli/uncovered.rb +20 -25
- data/lib/simplecov/cli.rb +15 -2
- data/lib/simplecov/color.rb +4 -0
- data/lib/simplecov/combine/branches_combiner.rb +43 -19
- data/lib/simplecov/combine/coverage_accumulator.rb +268 -0
- data/lib/simplecov/combine/identity_interner.rb +30 -0
- data/lib/simplecov/combine/interned_counts.rb +30 -0
- data/lib/simplecov/combine/lines_combiner.rb +48 -20
- data/lib/simplecov/combine/methods_combiner.rb +46 -21
- data/lib/simplecov/combine/results_combiner.rb +12 -37
- data/lib/simplecov/combine.rb +5 -23
- data/lib/simplecov/command_guesser.rb +66 -9
- data/lib/simplecov/configuration/coverage.rb +12 -15
- data/lib/simplecov/configuration/coverage_criteria.rb +34 -38
- data/lib/simplecov/configuration/eval_coverage.rb +41 -0
- data/lib/simplecov/configuration/filters.rb +11 -44
- data/lib/simplecov/configuration/formatting.rb +18 -9
- data/lib/simplecov/configuration/groups.rb +42 -0
- data/lib/simplecov/configuration/merging.rb +8 -7
- data/lib/simplecov/configuration/thresholds.rb +14 -13
- data/lib/simplecov/configuration.rb +13 -43
- data/lib/simplecov/coverage_json.rb +24 -0
- data/lib/simplecov/coverage_statistics.rb +1 -1
- data/lib/simplecov/coverage_violations.rb +15 -5
- data/lib/simplecov/defaults.rb +7 -3
- data/lib/simplecov/directive.rb +1 -1
- data/lib/simplecov/exit_codes/check.rb +33 -0
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +11 -20
- data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +3 -16
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +14 -23
- data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +14 -25
- data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +4 -17
- data/lib/simplecov/exit_codes.rb +5 -0
- data/lib/simplecov/exit_handling.rb +11 -41
- data/lib/simplecov/file_list.rb +5 -10
- data/lib/simplecov/filter.rb +43 -9
- data/lib/simplecov/formatter/base.rb +16 -0
- data/lib/simplecov/formatter/coverage_json_writer.rb +97 -0
- data/lib/simplecov/formatter/html_formatter/public/index.html +36 -5
- data/lib/simplecov/formatter/html_formatter/viewer_data_validator.rb +96 -0
- data/lib/simplecov/formatter/html_formatter.rb +67 -47
- data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +54 -56
- data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +78 -88
- data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +70 -76
- data/lib/simplecov/formatter/json_formatter.rb +5 -48
- data/lib/simplecov/formatter/multi_formatter.rb +1 -1
- data/lib/simplecov/formatter/simple_formatter.rb +8 -5
- data/lib/simplecov/formatter.rb +12 -0
- data/lib/simplecov/group_names.rb +32 -0
- data/lib/simplecov/last_run.rb +16 -9
- data/lib/simplecov/lines_classifier.rb +29 -8
- data/lib/simplecov/load_global_config.rb +5 -2
- data/lib/simplecov/parallel_adapters/base.rb +17 -0
- data/lib/simplecov/parallel_adapters/generic.rb +9 -8
- data/lib/simplecov/parallel_adapters/parallel_tests.rb +2 -2
- data/lib/simplecov/parallel_adapters.rb +4 -2
- data/lib/simplecov/parallel_coordination.rb +6 -1
- data/lib/simplecov/parallel_result_merger.rb +230 -0
- data/lib/simplecov/report_deferral.rb +49 -0
- data/lib/simplecov/report_stamp.rb +28 -0
- data/lib/simplecov/result.rb +40 -10
- data/lib/simplecov/result_adapter.rb +50 -16
- data/lib/simplecov/result_merger/resultset_file.rb +43 -7
- data/lib/simplecov/result_merger/resultset_run_identity.rb +67 -0
- data/lib/simplecov/result_merger/resultset_store.rb +15 -12
- data/lib/simplecov/result_merger/unloaded_files.rb +103 -0
- data/lib/simplecov/result_merger.rb +69 -42
- data/lib/simplecov/result_processing.rb +82 -43
- data/lib/simplecov/run_identity.rb +77 -0
- data/lib/simplecov/simulate_coverage.rb +36 -11
- data/lib/simplecov/source_file/method.rb +7 -1
- data/lib/simplecov/source_file/ruby_data_parser.rb +25 -3
- data/lib/simplecov/source_file/skip_chunks.rb +7 -10
- data/lib/simplecov/source_file/source_loader.rb +23 -7
- data/lib/simplecov/source_file/statistics.rb +24 -16
- data/lib/simplecov/static_coverage_extractor/condition_folding.rb +203 -13
- data/lib/simplecov/static_coverage_extractor/location_conventions.rb +19 -30
- data/lib/simplecov/static_coverage_extractor/method_collector.rb +7 -0
- data/lib/simplecov/static_coverage_extractor/prism_compat.rb +55 -0
- data/lib/simplecov/static_coverage_extractor/value_position.rb +6 -14
- data/lib/simplecov/static_coverage_extractor/visitor.rb +23 -36
- data/lib/simplecov/unloaded_file_injector.rb +75 -0
- data/lib/simplecov/version.rb +1 -1
- data/lib/simplecov.rb +13 -6
- data/sig/simplecov.rbs +206 -67
- metadata +28 -16
- data/doc/alternate-formatters.md +0 -66
- data/doc/commercial-services.md +0 -25
- data/doc/editor-integration.md +0 -18
- data/lib/simplecov/combine/files_combiner.rb +0 -70
- data/lib/simplecov/formatter/html_formatter/public/application.css +0 -1
- data/lib/simplecov/formatter/html_formatter/public/application.js +0 -18
- data/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
- data/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
- data/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
- data/schemas/coverage-v1.0.schema.json +0 -306
- data/schemas/coverage.schema.json +0 -306
data/lib/simplecov/filter.rb
CHANGED
|
@@ -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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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.
|
|
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,22 @@ 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
|
+
rescue IOError
|
|
36
|
+
# A parallel runner can close a worker's stderr before its at_exit
|
|
37
|
+
# hooks run (rspec-conductor does). Losing the status line must not
|
|
38
|
+
# abort the exit tasks that follow report generation, i.e. the
|
|
39
|
+
# threshold checks and the .last_run.json write.
|
|
40
|
+
end
|
|
41
|
+
|
|
26
42
|
# Subclasses override to prepend a marker (e.g. "JSON ") to the
|
|
27
43
|
# summary line. Default empty for the HTML formatter, which has
|
|
28
44
|
# 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
|
-
|
|
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{--ar: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--am: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;--e: 4px;--c: 8px;--aq: 12px;--n: 16px;--ax: 20px;--o: 24px;--ay: 32px;--at: 8px;--as: 12px;--ao: 16px;--ap: 34px;--au: var(--n);--aw: calc(var(--ap) + var(--au));--i: #f0f1f3;--f: #fff;--ac: #f0f1f3;--a: #111;--g: #333;--h: #444;--ak: #f4f5f7;--b: #c0c5cc;--p: #999;--d: #0550ae;--al: #033d8b;--s: #ddf4ff;--green: #116329;--red: #a40e26;--yellow: #7a5200;--an: #953800;--j: #ccf5d0;--k: #9ae6a4;--l: #ffd8d5;--m: #ffb8b3;--z: #fff;--af: #f0f1f3;--aa: #fff0a0;--ab: #eed860;--u: #ffd0a0;--v: #ffb060;--w: #b45309;--x: #e8d0ff;--y: #d4b0ff;--q: #7b2d8e;--ah: #fff;--r: #c0c5cc;--aj: #444;--ai: #f0f1f3;--ad: #e0e3e8;--ae: #333;--ag: rgba(0, 0, 0, .5);--t: #d0d7de;--av: 6px}@media(prefers-color-scheme:dark){:root:not(.light-mode){--i: #010409;--f: #0d1117;--ac: #161b22;--a: #f0f3f6;--g: #b0b8c4;--h: #9aa5b1;--ak: #161b22;--b: #3d444d;--p: #555e68;--d: #6cb6ff;--al: #96ccff;--s: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--an: #f0883e;--j: #122d1e;--k: #1e4430;--l: #351418;--m: #4e1d20;--z: #0d1117;--af: #161b22;--aa: #302818;--ab: #443920;--u: #322218;--v: #483020;--w: #ffb86c;--x: #1e1830;--y: #2a2044;--q: #dcb8ff;--ah: #0d1117;--r: #3d444d;--aj: #9aa5b1;--ai: #161b22;--ad: #262c34;--ae: #b0b8c4;--ag: rgba(1, 4, 9, .8);--t: #3d444d}}.dark-mode{--i: #010409;--f: #0d1117;--ac: #161b22;--a: #f0f3f6;--g: #b0b8c4;--h: #9aa5b1;--ak: #161b22;--b: #3d444d;--p: #555e68;--d: #6cb6ff;--al: #96ccff;--s: #121d2f;--green: #56d364;--red: #ff6b61;--yellow: #e3b341;--an: #f0883e;--j: #122d1e;--k: #1e4430;--l: #351418;--m: #4e1d20;--z: #0d1117;--af: #161b22;--aa: #302818;--ab: #443920;--u: #322218;--v: #483020;--w: #ffb86c;--x: #1e1830;--y: #2a2044;--q: #dcb8ff;--ah: #0d1117;--r: #3d444d;--aj: #9aa5b1;--ai: #161b22;--ad: #262c34;--ae: #b0b8c4;--ag: rgba(1, 4, 9, .8);--t: #3d444d}.colorblind-mode{--green: #0060a8;--red: #c2410c;--j: #d3eaf7;--k: #a5d2ee;--l: #ffe0cc;--m: #ffc39a}@media screen and (prefers-color-scheme:dark){.colorblind-mode:not(.light-mode){--green: #6cb6ff;--red: #f0883e;--j: #0e2a45;--k: #12385c;--l: #3a2410;--m: #52331a}}@media screen{.colorblind-mode.dark-mode{--green: #6cb6ff;--red: #f0883e;--j: #0e2a45;--k: #12385c;--l: #3a2410;--m: #52331a}}html{scrollbar-gutter:stable}body{font-family:var(--ar);font-size:18px;color:var(--a);background:var(--i);padding:var(--o)}a{color:var(--d);text-decoration:none;transition:color .15s}a:hover{color:var(--al)}strong,b{font-weight:600}#loading{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--i);z-index:9999}#loading-inner{width:280px;text-align:center}#loading-bar-track{width:100%;height:6px;background:var(--t);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(--aq);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(--ag)}#sort-overlay-label{padding:var(--c) var(--n);border:1px solid var(--b);border-radius:6px;background:var(--i);font-size:16px;color:var(--h)}#wrapper{margin:0 auto}.tab-bar{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--n);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(--e);overflow-x:auto;padding-right:var(--o);mask-image:linear-gradient(to right,#000 calc(100% - var(--o)),transparent)}.group_tabs.is-scrolled{mask-image:linear-gradient(to right,transparent,#000 var(--o),#000 calc(100% - var(--o)),transparent)}.group_tabs li a{display:block;padding:var(--c) var(--n);font-size:18px;font-weight:500;color:var(--g);background:transparent;border:1px solid var(--b);border-bottom:none;border-radius:var(--as) var(--as) 0 0;white-space:nowrap;transition:color .15s,background .15s,border-color .15s}.group_tabs li a:hover{color:var(--a);background:var(--ac);border-color:var(--p);text-decoration:none}.group_tabs li.active a{color:var(--d);background:var(--f);border-color:var(--b);font-weight:600}#content{background:var(--f);border:1px solid var(--b);border-radius:0 var(--ao) var(--ao) var(--ao);padding:var(--o)}.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(--e);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(--c)}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(--b);border-radius:999px;padding:var(--e) var(--n);font-size:14px;background:var(--f);color:var(--a);outline:none}.col-filter--name:focus{border-color:var(--d)}.col-filter__coverage{display:flex;gap:var(--e)}.col-filter__op{border:1px solid var(--b);border-radius:var(--at);padding:var(--e) var(--e);font-size:14px;background:var(--f);color:var(--a);cursor:pointer}.col-filter__value{border:1px solid var(--b);border-radius:var(--at);padding:var(--e) var(--c);font-size:14px;background:var(--f);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(--f);padding:var(--c) var(--c);border-bottom:2px solid var(--p);white-space:nowrap}table.file_list tbody tr{background:var(--f);cursor:pointer}table.file_list tbody tr:nth-child(2n){background:var(--ak)}table.file_list tbody tr:hover{background:var(--s)}table.file_list tbody tr.keyboard-focus{background:var(--s);outline:2px solid var(--d);outline-offset:-2px}table.file_list tbody td{padding:var(--c) var(--c);border-bottom:1px solid var(--b);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(--aq);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(--e);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(--e)}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(--av);background:var(--t);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(--w)}.missed-method-text-color{color:var(--q)}dialog.source-dialog{position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;border:none;padding:0;background:var(--i);color:var(--a);overflow:hidden}dialog.source-dialog::backdrop{background:var(--ag)}dialog.source-dialog[open]{display:flex;flex-direction:column}.source-dialog__header{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:flex-start;padding:var(--o);background:var(--i);border-bottom:1px solid var(--b);flex-shrink:0}.source-dialog__title{display:contents;min-width:0}.source-dialog__title h2{grid-column:1;grid-row:1;font-size:22px;font-weight:700;color:var(--a);margin-bottom:var(--c);word-break:break-all}.source-dialog__title .summary-stats{display:contents}.source-dialog__title .t-line-summary{grid-column:1;grid-row:2}.source-dialog__title .t-branch-summary{grid-column:1;grid-row:3}.source-dialog__title .t-method-summary{grid-column:1;grid-row:4}.source-dialog__title>.t-missed-method-list{grid-column:1 / -1;grid-row:5}.source-legend{display:contents}.source-legend__row{display:flex;flex-wrap:wrap;gap:var(--c) var(--n);align-items:center;align-self:center;justify-content:flex-end;grid-column:2 / 4}.source-legend__row--line{grid-row:2}.source-legend__row--branch{grid-row:3}.source-legend__row--method{grid-row:4}.source-legend__item{display:flex;align-items:center;gap:var(--e);font-size:13px;color:var(--g);white-space:nowrap}.source-legend__swatch{display:inline-block;width:16px;height:16px;border-radius:3px;border:1px solid var(--b)}.source-legend__swatch--covered{background:var(--j);border-color:var(--k);color:var(--green)}.source-legend__swatch--missed{background:var(--l);border-color:var(--m);color:var(--red)}.source-legend__swatch--skipped{background:var(--aa);border-color:var(--ab);color:var(--g)}.source-legend__swatch--missed-branch{background:var(--u);border-color:var(--v);color:var(--w)}.source-legend__swatch--missed-method{background:var(--x);border-color:var(--y);color:var(--q)}.source-dialog__toggles{display:flex;align-items:center;gap:var(--c);flex-shrink:0;margin-left:var(--n);align-self:flex-start}.source-dialog__close{appearance:none;background:none;border:1px solid var(--b);border-radius:50%;width:var(--ap);height:var(--ap);font-size:0;color:var(--g);cursor:pointer;position:relative;flex-shrink:0;margin-left:var(--au);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(--n) var(--o);background:var(--f)}.source_table .header h2{font-size:22px;font-weight:700;color:var(--a);margin-bottom:var(--c)}table.file_list .totals-row td{padding:var(--c) var(--c);font-weight:600;border-bottom:2px solid var(--p);background:var(--ac)}.totals-row .t-file-count{font-size:18px;font-weight:700;color:var(--a)}.t-missed-method-toggle{color:var(--q);font-weight:600;cursor:pointer;text-decoration:none}.t-missed-method-toggle:hover{text-decoration:underline;color:var(--q)}.t-missed-method-list ul{padding-left:2em;margin-top:var(--e);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(--am);font-size:16px;line-height:24px;background:var(--ah);border:1px solid var(--r);border-top:none}.source_table code{color:inherit;font-family:var(--am)}.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(--aj);background:var(--ai);border-right:1px solid var(--r);-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(--c);background:var(--ad);color:var(--ae);font-family:var(--am);font-size:14px;text-align:center;line-height:24px;border-left:1px solid var(--r);-webkit-user-select:none;user-select:none}.source_table pre .hits:after{content:attr(data-content)}.source_table .covered{background-color:var(--j)}.source_table .missed{background-color:var(--l)}.source_table .never{background-color:var(--z)}.source_table .skipped{background-color:var(--aa)}.source_table .missed-branch{background-color:var(--u)}.source_table .missed-method{background-color:var(--x)}.source_table .covered:before{background-color:var(--k)}.source_table .missed:before{background-color:var(--m)}.source_table .never:before{background-color:var(--af)}.source_table .skipped:before{background-color:var(--ab)}.source_table .missed-branch:before{background-color:var(--v)}.source_table .missed-method:before{background-color:var(--y)}.toolbar{display:flex;align-items:flex-start;gap:var(--c);flex-shrink:0;margin-right:var(--aw)}.toolbar-toggle{appearance:none;background:transparent;color:var(--g);border:1px solid var(--b);border-radius:999px;padding:var(--e) var(--n);font-size:16px;font-family:var(--ar);cursor:pointer;white-space:nowrap;transition:color .15s,border-color .15s,background .15s}.toolbar-toggle:hover{color:var(--a);background:var(--f);border-color:var(--p)}.toolbar-toggle[aria-pressed=true]{background:var(--s);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,.source-dialog__footer{color:var(--h);font-size:16px;text-align:center}#footer{margin-top:var(--ax)}.source-dialog__footer{flex-shrink:0;padding:var(--aq) var(--o);background:var(--i);border-top:1px solid var(--b)}#footer a,.source-dialog__footer a{color:var(--g);text-decoration:underline}#footer a:hover,.source-dialog__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{--i: #fff;--f: #fff;--ac: #f4f5f7;--a: #111;--g: #333;--h: #444;--ak: #f4f5f7;--b: #c0c5cc;--p: #999;--d: #0550ae;--green: #116329;--red: #a40e26;--yellow: #7a5200;--an: #953800;--t: #d0d7de;--j: #ccf5d0;--k: #9ae6a4;--l: #ffd8d5;--m: #ffb8b3;--z: #fff;--af: #f0f1f3;--aa: #fff0a0;--ab: #eed860;--u: #ffd0a0;--v: #ffb060;--w: #b45309;--x: #e8d0ff;--y: #d4b0ff;--q: #7b2d8e;--ah: #fff;--r: #c0c5cc;--aj: #444;--ai: #f0f1f3;--ad: #e0e3e8;--ae: #333}.colorblind-mode{--green: #0060a8;--red: #c2410c;--j: #d3eaf7;--k: #a5d2ee;--l: #ffe0cc;--m: #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{display:block;border-bottom:none;padding:0 0 8pt}.source-dialog__title h2{word-break:normal;overflow-wrap:break-word}.source-legend__row{justify-content:flex-start}.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(--b);-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,.source-dialog__footer{font-size:10pt;margin-top:12pt}#footer a:after,.source-dialog__footer a:after{content:" (" attr(href) ")";font-size:9pt;color:var(--h)}}
|
|
8
|
+
</style>
|
|
9
9
|
<script>
|
|
10
|
-
// Apply the saved dark/light
|
|
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
|
-
<
|
|
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,35 @@
|
|
|
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">×</button>
|
|
50
61
|
</div>
|
|
51
62
|
<div class="source-dialog__body" id="source-dialog-body" tabindex="0"></div>
|
|
63
|
+
<div class="source-dialog__footer" id="source-dialog-footer"></div>
|
|
52
64
|
</dialog>
|
|
53
65
|
|
|
54
|
-
|
|
66
|
+
<!-- SIMPLECOV_COVERAGE_DATA -->
|
|
67
|
+
<script>"use strict";(()=>{var Bn=Object.create;var vt=Object.defineProperty;var Pn=Object.getOwnPropertyDescriptor;var Fn=Object.getOwnPropertyNames;var qn=Object.getPrototypeOf,Wn=Object.prototype.hasOwnProperty;var Un=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(n){throw t=0,n}};var jn=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Fn(t))!Wn.call(e,o)&&o!==n&&vt(e,o,{get:()=>t[o],enumerable:!(r=Pn(t,o))||r.enumerable});return e};var zn=(e,t,n)=>(n=e!=null?Bn(qn(e)):{},jn(t||!e||!e.__esModule?vt(n,"default",{value:e,enumerable:!0}):n,e));var oe=(e,t,n)=>new Promise((r,o)=>{var s=c=>{try{l(n.next(c))}catch(d){o(d)}},i=c=>{try{l(n.throw(c))}catch(d){o(d)}},l=c=>c.done?r(c.value):Promise.resolve(c.value).then(s,i);l((n=n.apply(e,t)).next())});var jt=Un((Ho,Ut)=>{function Nt(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)&&Nt(n)}),e}var Se=class{constructor(t){t.data===void 0&&(t.data={}),this.data=t.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}};function Ot(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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 Xn="</span>",Tt=e=>!!e.scope,Yn=(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}`},qe=class{constructor(t,n){this.buffer="",this.classPrefix=n.classPrefix,t.walk(this)}addText(t){this.buffer+=Ot(t)}openNode(t){if(!Tt(t))return;let n=Yn(t.scope,{prefix:this.classPrefix});this.span(n)}closeNode(t){Tt(t)&&(this.buffer+=Xn)}value(){return this.buffer}span(t){this.buffer+=`<span class="${t}">`}},Lt=(e={})=>{let t={children:[]};return Object.assign(t,e),t},We=class e{constructor(){this.rootNode=Lt(),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=Lt({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)}))}},Ue=class extends We{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 qe(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}};function de(e){return e?typeof e=="string"?e:e.source:null}function It(e){return J("(?=",e,")")}function Zn(e){return J("(?:",e,")*")}function Qn(e){return J("(?:",e,")?")}function J(...e){return e.map(n=>de(n)).join("")}function Jn(e){let t=e[e.length-1];return typeof t=="object"&&t.constructor===Object?(e.splice(e.length-1,1),t):{}}function ze(...e){return"("+(Jn(e).capture?"":"?:")+e.map(r=>de(r)).join("|")+")"}function Ht(e){return new RegExp(e.toString()+"|").exec("").length-1}function er(e,t){let n=e&&e.exec(t);return n&&n.index===0}var tr=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function Ge(e,{joinWith:t}){let n=0;return e.map(r=>{n+=1;let o=n,s=de(r),i="";for(;s.length>0;){let l=tr.exec(s);if(!l){i+=s;break}i+=s.substring(0,l.index),s=s.substring(l.index+l[0].length),l[0][0]==="\\"&&l[1]?i+="\\"+String(Number(l[1])+o):(i+=l[0],l[0]==="("&&n++)}return i}).map(r=>`(${r})`).join(t)}var nr=/\b\B/,kt="[a-zA-Z]\\w*",Ke="[a-zA-Z_]\\w*",$t="\\b\\d+(\\.\\d+)?",Dt="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",Bt="\\b(0b[01]+)",rr="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",or=(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},ir={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[fe]},sr={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[fe]},lr={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/},Le=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=ze("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},cr=Le("//","$"),ar=Le("/\\*","\\*/"),ur=Le("#","$"),dr={scope:"number",begin:$t,relevance:0},fr={scope:"number",begin:Dt,relevance:0},gr={scope:"number",begin:Bt,relevance:0},pr={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[fe,{begin:/\[/,end:/\]/,relevance:0,contains:[fe]}]},hr={scope:"title",begin:kt,relevance:0},mr={scope:"title",begin:Ke,relevance:0},br={begin:"\\.\\s*"+Ke,relevance:0},vr=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:ir,BACKSLASH_ESCAPE:fe,BINARY_NUMBER_MODE:gr,BINARY_NUMBER_RE:Bt,COMMENT:Le,C_BLOCK_COMMENT_MODE:ar,C_LINE_COMMENT_MODE:cr,C_NUMBER_MODE:fr,C_NUMBER_RE:Dt,END_SAME_AS_BEGIN:vr,HASH_COMMENT_MODE:ur,IDENT_RE:kt,MATCH_NOTHING_RE:nr,METHOD_GUARD:br,NUMBER_MODE:dr,NUMBER_RE:$t,PHRASAL_WORDS_MODE:lr,QUOTE_STRING_MODE:sr,REGEXP_MODE:pr,RE_STARTERS_RE:rr,SHEBANG:or,TITLE_MODE:hr,UNDERSCORE_IDENT_RE:Ke,UNDERSCORE_TITLE_MODE:mr});function Er(e,t){e.input[e.index-1]==="."&&t.ignoreMatch()}function _r(e,t){e.className!==void 0&&(e.scope=e.className,delete e.className)}function yr(e,t){t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=Er,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function wr(e,t){Array.isArray(e.illegal)&&(e.illegal=ze(...e.illegal))}function Mr(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 Sr(e,t){e.relevance===void 0&&(e.relevance=1)}var Tr=(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,It(n.begin)),e.starts={relevance:0,contains:[Object.assign(n,{endsParent:!0})]},e.relevance=0,delete n.beforeMatch},Lr=["of","and","for","in","not","or","if","then","parent","list","value"],Cr="keyword";function Pt(e,t,n=Cr){let r=Object.create(null);return typeof e=="string"?o(n,e.split(" ")):Array.isArray(e)?o(n,e):Object.keys(e).forEach(function(s){Object.assign(r,Pt(e[s],t,s))}),r;function o(s,i){t&&(i=i.map(l=>l.toLowerCase())),i.forEach(function(l){let c=l.split("|");r[c[0]]=[s,xr(c[0],c[1])]})}}function xr(e,t){return t?Number(t):Ar(e)?0:1}function Ar(e){return Lr.includes(e.toLowerCase())}var Ct={},Q=e=>{console.error(e)},xt=(e,...t)=>{console.log(`WARN: ${e}`,...t)},se=(e,t)=>{Ct[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),Ct[`${e}/${t}`]=!0)},Te=new Error;function Ft(e,t,{key:n}){let r=0,o=e[n],s={},i={};for(let l=1;l<=t.length;l++)i[l+r]=o[l],s[l+r]=!0,r+=Ht(t[l-1]);e[n]=i,e[n]._emit=s,e[n]._multi=!0}function Rr(e){if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw Q("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),Te;if(typeof e.beginScope!="object"||e.beginScope===null)throw Q("beginScope must be object"),Te;Ft(e,e.begin,{key:"beginScope"}),e.begin=Ge(e.begin,{joinWith:""})}}function Nr(e){if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw Q("skip, excludeEnd, returnEnd not compatible with endScope: {}"),Te;if(typeof e.endScope!="object"||e.endScope===null)throw Q("endScope must be object"),Te;Ft(e,e.end,{key:"endScope"}),e.end=Ge(e.end,{joinWith:""})}}function Or(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function Ir(e){Or(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),Rr(e),Nr(e)}function Hr(e){function t(i,l){return new RegExp(de(i),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(l?"g":""))}class n{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(l,c){c.position=this.position++,this.matchIndexes[this.matchAt]=c,this.regexes.push([c,l]),this.matchAt+=Ht(l)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);let l=this.regexes.map(c=>c[1]);this.matcherRe=t(Ge(l,{joinWith:"|"}),!0),this.lastIndex=0}exec(l){this.matcherRe.lastIndex=this.lastIndex;let c=this.matcherRe.exec(l);if(!c)return null;let d=c.findIndex((_,M)=>M>0&&_!==void 0),h=this.matchIndexes[d];return c.splice(0,d),Object.assign(c,h)}}class r{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(l){if(this.multiRegexes[l])return this.multiRegexes[l];let c=new n;return this.rules.slice(l).forEach(([d,h])=>c.addRule(d,h)),c.compile(),this.multiRegexes[l]=c,c}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(l,c){this.rules.push([l,c]),c.type==="begin"&&this.count++}exec(l){let c=this.getMatcher(this.regexIndex);c.lastIndex=this.lastIndex;let d=c.exec(l);if(this.resumingScanAtSamePosition()&&!(d&&d.index===this.lastIndex)){let h=this.getMatcher(0);h.lastIndex=this.lastIndex+1,d=h.exec(l)}return d&&(this.regexIndex+=d.position+1,this.regexIndex===this.count&&this.considerAll()),d}}function o(i){let l=new r;return i.contains.forEach(c=>l.addRule(c.begin,{rule:c,type:"begin"})),i.terminatorEnd&&l.addRule(i.terminatorEnd,{type:"end"}),i.illegal&&l.addRule(i.illegal,{type:"illegal"}),l}function s(i,l){let c=i;if(i.isCompiled)return c;[_r,Mr,Ir,Tr].forEach(h=>h(i,l)),e.compilerExtensions.forEach(h=>h(i,l)),i.__beforeBegin=null,[yr,wr,Sr].forEach(h=>h(i,l)),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=Pt(i.keywords,e.case_insensitive)),c.keywordPatternRe=t(d,!0),l&&(i.begin||(i.begin=/\B|\b/),c.beginRe=t(c.begin),!i.end&&!i.endsWithParent&&(i.end=/\B|\b/),i.end&&(c.endRe=t(c.end)),c.terminatorEnd=de(c.end)||"",i.endsWithParent&&l.terminatorEnd&&(c.terminatorEnd+=(i.end?"|":"")+l.terminatorEnd)),i.illegal&&(c.illegalRe=t(i.illegal)),i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map(function(h){return kr(h==="self"?i:h)})),i.contains.forEach(function(h){s(h,c)}),i.starts&&s(i.starts,l),c.matcher=o(c),c}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=V(e.classNameAliases||{}),s(e)}function qt(e){return e?e.endsWithParent||qt(e.starts):!1}function kr(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(t){return V(e,{variants:null},t)})),e.cachedVariants?e.cachedVariants:qt(e)?V(e,{starts:e.starts?V(e.starts):null}):Object.isFrozen(e)?V(e):e}var $r="11.11.1",je=class extends Error{constructor(t,n){super(t),this.name="HTMLInjectionError",this.html=n}},Fe=Ot,At=V,Rt=Symbol("nomatch"),Dr=7,Wt=function(e){let t=Object.create(null),n=Object.create(null),r=[],o=!0,s="Could not find the language '{}', did you forget to load/include a language module?",i={disableAutodetect:!0,name:"Plain text",contains:[]},l={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:Ue};function c(a){return l.noHighlightRe.test(a)}function d(a){let g=a.className+" ";g+=a.parentNode?a.parentNode.className:"";let b=l.languageDetectRe.exec(g);if(b){let y=W(b[1]);return y||(xt(s.replace("{}",b[1])),xt("Falling back to no-highlight mode for this block.",a)),y?b[1]:"no-highlight"}return g.split(/\s+/).find(y=>c(y)||W(y))}function h(a,g,b){let y="",T="";typeof g=="object"?(y=a,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.
|
|
68
|
+
https://github.com/highlightjs/highlight.js/issues/2277`),T=a,y=g),b===void 0&&(b=!0);let D={code:y,language:T};Ee("before:highlight",D);let K=D.result?D.result:_(D.language,D.code,b);return K.code=D.code,Ee("after:highlight",K),K}function _(a,g,b,y){let T=Object.create(null);function D(u,f){return u.keywords[f]}function K(){if(!p.keywords){C.addText(w);return}let u=0;p.keywordPatternRe.lastIndex=0;let f=p.keywordPatternRe.exec(w),m="";for(;f;){m+=w.substring(u,f.index);let E=P.case_insensitive?f[0].toLowerCase():f[0],A=D(p,E);if(A){let[U,$n]=A;if(C.addText(m),m="",T[E]=(T[E]||0)+1,T[E]<=Dr&&(we+=$n),U.startsWith("_"))m+=f[0];else{let Dn=P.classNameAliases[U]||U;B(f[0],Dn)}}else m+=f[0];u=p.keywordPatternRe.lastIndex,f=p.keywordPatternRe.exec(w)}m+=w.substring(u),C.addText(m)}function _e(){if(w==="")return;let u=null;if(typeof p.subLanguage=="string"){if(!t[p.subLanguage]){C.addText(w);return}u=_(p.subLanguage,w,!0,bt[p.subLanguage]),bt[p.subLanguage]=u._top}else u=L(w,p.subLanguage.length?p.subLanguage:null);p.relevance>0&&(we+=u.relevance),C.__addSublanguage(u._emitter,u.language)}function H(){p.subLanguage!=null?_e():K(),w=""}function B(u,f){u!==""&&(C.startScope(f),C.addText(u),C.endScope())}function gt(u,f){let m=1,E=f.length-1;for(;m<=E;){if(!u._emit[m]){m++;continue}let A=P.classNameAliases[u[m]]||u[m],U=f[m];A?B(U,A):(w=U,K(),w=""),m++}}function pt(u,f){return u.scope&&typeof u.scope=="string"&&C.openNode(P.classNameAliases[u.scope]||u.scope),u.beginScope&&(u.beginScope._wrap?(B(w,P.classNameAliases[u.beginScope._wrap]||u.beginScope._wrap),w=""):u.beginScope._multi&&(gt(u.beginScope,f),w="")),p=Object.create(u,{parent:{value:p}}),p}function ht(u,f,m){let E=er(u.endRe,m);if(E){if(u["on:end"]){let A=new Se(u);u["on:end"](f,A),A.isMatchIgnored&&(E=!1)}if(E){for(;u.endsParent&&u.parent;)u=u.parent;return u}}if(u.endsWithParent)return ht(u.parent,f,m)}function Nn(u){return p.matcher.regexIndex===0?(w+=u[0],1):(Be=!0,0)}function On(u){let f=u[0],m=u.rule,E=new Se(m),A=[m.__beforeBegin,m["on:begin"]];for(let U of A)if(U&&(U(u,E),E.isMatchIgnored))return Nn(f);return m.skip?w+=f:(m.excludeBegin&&(w+=f),H(),!m.returnBegin&&!m.excludeBegin&&(w=f)),pt(m,u),m.returnBegin?0:f.length}function In(u){let f=u[0],m=g.substring(u.index),E=ht(p,u,m);if(!E)return Rt;let A=p;p.endScope&&p.endScope._wrap?(H(),B(f,p.endScope._wrap)):p.endScope&&p.endScope._multi?(H(),gt(p.endScope,u)):A.skip?w+=f:(A.returnEnd||A.excludeEnd||(w+=f),H(),A.excludeEnd&&(w=f));do p.scope&&C.closeNode(),!p.skip&&!p.subLanguage&&(we+=p.relevance),p=p.parent;while(p!==E.parent);return E.starts&&pt(E.starts,u),A.returnEnd?0:f.length}function Hn(){let u=[];for(let f=p;f!==P;f=f.parent)f.scope&&u.unshift(f.scope);u.forEach(f=>C.openNode(f))}let ye={};function mt(u,f){let m=f&&f[0];if(w+=u,m==null)return H(),0;if(ye.type==="begin"&&f.type==="end"&&ye.index===f.index&&m===""){if(w+=g.slice(f.index,f.index+1),!o){let E=new Error(`0 width match regex (${a})`);throw E.languageName=a,E.badRule=ye.rule,E}return 1}if(ye=f,f.type==="begin")return On(f);if(f.type==="illegal"&&!b){let E=new Error('Illegal lexeme "'+m+'" for mode "'+(p.scope||"<unnamed>")+'"');throw E.mode=p,E}else if(f.type==="end"){let E=In(f);if(E!==Rt)return E}if(f.type==="illegal"&&m==="")return w+=`
|
|
69
|
+
`,1;if(De>1e5&&De>f.index*3)throw new Error("potential infinite loop, way more iterations than matches");return w+=m,m.length}let P=W(a);if(!P)throw Q(s.replace("{}",a)),new Error('Unknown language: "'+a+'"');let kn=Hr(P),$e="",p=y||kn,bt={},C=new l.__emitter(l);Hn();let w="",we=0,Z=0,De=0,Be=!1;try{if(P.__emitTokens)P.__emitTokens(g,C);else{for(p.matcher.considerAll();;){De++,Be?Be=!1:p.matcher.considerAll(),p.matcher.lastIndex=Z;let u=p.matcher.exec(g);if(!u)break;let f=g.substring(Z,u.index),m=mt(f,u);Z=u.index+m}mt(g.substring(Z))}return C.finalize(),$e=C.toHTML(),{language:a,value:$e,relevance:we,illegal:!1,_emitter:C,_top:p}}catch(u){if(u.message&&u.message.includes("Illegal"))return{language:a,value:Fe(g),illegal:!0,relevance:0,_illegalBy:{message:u.message,index:Z,context:g.slice(Z-100,Z+100),mode:u.mode,resultSoFar:$e},_emitter:C};if(o)return{language:a,value:Fe(g),illegal:!1,relevance:0,errorRaised:u,_emitter:C,_top:p};throw u}}function M(a){let g={value:Fe(a),illegal:!1,relevance:0,_top:i,_emitter:new l.__emitter(l)};return g._emitter.addText(a),g}function L(a,g){g=g||l.languages||Object.keys(t);let b=M(a),y=g.filter(W).filter(ve).map(H=>_(H,a,!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,_e=D;return _e.secondBest=K,_e}function S(a,g,b){let y=g&&n[g]||b;a.classList.add("hljs"),a.classList.add(`language-${y}`)}function N(a){let g=null,b=d(a);if(c(b))return;if(Ee("before:highlightElement",{el:a,language:b}),a.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",a);return}if(a.children.length>0&&(l.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(a)),l.throwUnescapedHTML))throw new je("One of your code blocks includes unescaped HTML.",a.innerHTML);g=a;let y=g.textContent,T=b?h(y,{language:b,ignoreIllegals:!0}):L(y);a.innerHTML=T.value,a.dataset.highlighted="yes",S(a,b,T.language),a.result={language:T.language,re:T.relevance,relevance:T.relevance},T.secondBest&&(a.secondBest={language:T.secondBest.language,relevance:T.secondBest.relevance}),Ee("after:highlightElement",{el:a,result:T,text:y})}function O(a){l=At(l,a)}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 a(){X()}if(document.readyState==="loading"){re||window.addEventListener("DOMContentLoaded",a,!1),re=!0;return}document.querySelectorAll(l.cssSelector).forEach(N)}function dt(a,g){let b=null;try{b=g(e)}catch(y){if(Q("Language definition for '{}' could not be registered.".replace("{}",a)),o)Q(y);else throw y;b=i}b.name||(b.name=a),t[a]=b,b.rawDefinition=g.bind(null,e),b.aliases&&ke(b.aliases,{languageName:a})}function Y(a){delete t[a];for(let g of Object.keys(n))n[g]===a&&delete n[g]}function ft(){return Object.keys(t)}function W(a){return a=(a||"").toLowerCase(),t[a]||t[n[a]]}function ke(a,{languageName:g}){typeof a=="string"&&(a=[a]),a.forEach(b=>{n[b.toLowerCase()]=g})}function ve(a){let g=W(a);return g&&!g.disableAutodetect}function Cn(a){a["before:highlightBlock"]&&!a["before:highlightElement"]&&(a["before:highlightElement"]=g=>{a["before:highlightBlock"](Object.assign({block:g.el},g))}),a["after:highlightBlock"]&&!a["after:highlightElement"]&&(a["after:highlightElement"]=g=>{a["after:highlightBlock"](Object.assign({block:g.el},g))})}function xn(a){Cn(a),r.push(a)}function An(a){let g=r.indexOf(a);g!==-1&&r.splice(g,1)}function Ee(a,g){let b=a;r.forEach(function(y){y[b]&&y[b](g)})}function Rn(a){return se("10.7.0","highlightBlock will be removed entirely in v12.0"),se("10.7.0","Please use highlightElement now."),N(a)}Object.assign(e,{highlight:h,highlightAuto:L,highlightAll:X,highlightElement:N,highlightBlock:Rn,configure:O,initHighlighting:G,initHighlightingOnLoad:I,registerLanguage:dt,unregisterLanguage:Y,listLanguages:ft,getLanguage:W,registerAliases:ke,autoDetection:ve,inherit:At,addPlugin:xn,removePlugin:An}),e.debugMode=function(){o=!1},e.safeMode=function(){o=!0},e.versionString=$r,e.regex={concat:J,lookahead:It,either:ze,optional:Qn,anyNumberOfTimes:Zn};for(let a in Me)typeof Me[a]=="object"&&Nt(Me[a]);return Object.assign(e,Me),e},le=Wt({});le.newInstance=()=>Wt({});Ut.exports=le;le.HighlightJS=le;le.default=le});function x(e,t){return(t||document).querySelector(e)}function v(e,t){return Array.from((t||document).querySelectorAll(e))}function F(e,t,n,r){typeof n=="function"?e.addEventListener(t,n):e.addEventListener(t,function(o){let s=o.target.closest(n);s&&e.contains(s)&&r&&r.call(s,o)})}var Gn={"&":"&","<":"<",">":">",'"':""","'":"'"};function k(e){return e.replace(/[&<>"']/g,t=>Gn[t])}function Et(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 Kn=90,Vn=75;function q(e){return e>=Kn?"green":e>=Vn?"yellow":"red"}function R(e){return e.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}function j(e){return(Math.floor(e*100)/100).toFixed(2)}function _t(e){return"g-"+e.replace(/[^a-zA-Z0-9-]/gu,t=>`_${t.codePointAt(0).toString(16)}_`)}var yt=[[31536e3,"year"],[2592e3,"month"],[86400,"day"],[3600,"hour"],[60,"minute"],[1,"second"]];function wt(e){let t=Math.floor((Date.now()-e.getTime())/1e3);for(let[n,r]of yt){let o=Math.floor(t/n);if(o>=1)return o===1?`about 1 ${r} ago`:`${o} ${r}s ago`}return"just now"}function Mt(e){let t=(Date.now()-e.getTime())/1e3;for(let[n]of yt){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 Pe=new Map;function ie(e){let t=Pe.get(e);if(t===void 0)throw new Error(`File ID was not precomputed for ${e}`);return t}function St(e){return oe(this,null,function*(){Pe.clear();let t=[...new Set(e)],n=yield Promise.all(t.map(Et)),r=new Map;t.forEach((o,s)=>{let i=n[s],l=r.get(i)||[];l.push(o),r.set(i,l)});for(let[o,s]of r)s.sort().forEach((i,l)=>{Pe.set(i,l===0?o:`${o}-${l}`)})})}var zt=zn(jt(),1);var Ve=zt.default;function Gt(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"]},l={className:"doctag",begin:"@[A-Za-z]+"},c={begin:"#<",end:">"},d=[e.COMMENT("#","$",{contains:[l]}),e.COMMENT("^=begin","^=end",{contains:[l],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],h={className:"subst",begin:/#\{/,end:/\}/,keywords:i},_={className:"string",contains:[e.BACKSLASH_ESCAPE,h],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,h]})]}]},M="[1-9](_?[0-9])*|0",L="[0-9](_?[0-9])*",S={className:"number",relevance:0,variants:[{begin:`\\b(${M})(\\.(${L}))?([eE][+-]?(${L})|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"}]},N={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:[N]},{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,h],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(c,d),relevance:0}].concat(c,d);h.contains=Y,N.contains=Y;let ve=[{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(c),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(ve).concat(d).concat(Y)}}function Br(e){if(e==="oneshot_line")return"line";if(e==="line"||e==="branch"||e==="method")return e}function Kt(e){let t=Br(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 Pr(e,t){return t==="line"?e.lines:t==="branch"?e.branches:e.methods}function Ce(e,t){return Pr(e,t)||e.lines||e.branches||e.methods}function Ye(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 s=q(e),i=j(e),l=`<div class="coverage-cell">${Ye(e)}<span class="coverage-pct">${i}%</span></div>`;if(o)return`<td class="cell--coverage strong t-totals__${r}-pct ${s}">${l}</td><td class="cell--numerator strong t-totals__${r}-num">${R(t)}/</td><td class="cell--denominator strong t-totals__${r}-den">${R(n)}</td>`;let c=` data-order="${j(e)}"`;return`<td class="cell--coverage cell--${r}-pct ${s}"${c}>${l}</td><td class="cell--numerator" data-order="${t}">${R(t)}/</td><td class="cell--denominator" data-order="${n}">${R(n)}</td>`}function xe(e,t,n,r){return`<th class="cell--coverage" data-sort-key="${t}-percent">
|
|
70
|
+
<div class="th-with-filter">
|
|
71
|
+
<span class="th-label">${e}</span>
|
|
72
|
+
<div class="col-filter__coverage">
|
|
73
|
+
<select class="col-filter__op" data-type="${t}"><option value="lt"><</option><option value="lte" selected>≤</option><option value="eq">=</option><option value="gte">≥</option><option value="gt">></option></select>
|
|
74
|
+
<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>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</th>
|
|
78
|
+
<th class="cell--numerator" data-sort-key="${t}-covered">${n}</th>
|
|
79
|
+
<th class="cell--denominator" data-sort-key="${t}-total">${r}</th>`}function Xe(e){let{type:t,label:n,covered:r,total:o,enabled:s,toggle:i}=e;if(!s)return`<div class="t-${t}-summary">
|
|
80
|
+
${n}: <span class="coverage-disabled">disabled</span>
|
|
81
|
+
</div>`;let l=o-r,c=o>0?r*100/o:100,d=q(c),h=e.suffix||"covered",_=e.missedClass||"red",M=`<div class="t-${t}-summary">
|
|
82
|
+
${n}: <span class="${d}"><b>${j(c)}%</b></span><span class="coverage-cell__fraction"> ${r}/${o} ${h}</span>`;if(l>0){let L=i?`<a href="#" class="t-missed-method-toggle"><b>${l}</b> missed</a>`:`<span class="${_}"><b>${l}</b> missed</span>`;M+=`<span class="coverage-cell__fraction">,</span>
|
|
83
|
+
${L}`}return M+=`
|
|
84
|
+
</div>`,M}function Vt(e){return'<div class="summary-stats">'+Xe({type:"line",label:"Line coverage",covered:e.coveredLines,total:e.totalLines,enabled:e.lineCoverage,suffix:"relevant lines covered"})+Xe({type:"branch",label:"Branch coverage",covered:e.coveredBranches,total:e.totalBranches,enabled:e.branchCoverage,missedClass:"missed-branch-text"})+Xe({type:"method",label:"Method coverage",covered:e.coveredMethods,total:e.totalMethods,enabled:e.methodCoverage,missedClass:"missed-method-text-color",toggle:e.showMethodToggle})+"</div>"}function Fr(e){let{containerId:t,title:n,filenames:r,stats:o,lineCoverage:s,branchCoverage:i,methodCoverage:l,primaryCoverage:c}=e,d=s?o.lines:void 0,h=i?o.branches:void 0,_=l?o.methods:void 0,M=Ce(o,c),L=M?M.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(L)}">${j(L)}%</span></span>`,'<div class="file_list--responsive"><table class="file_list"><thead><tr>','<th class="cell--left" data-sort-key="file"><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(xe("Line Coverage","line","Covered","Lines")),i&&S.push(xe("Branch Coverage","branch","Covered","Branches")),l&&S.push(xe("Method Coverage","method","Covered","Methods")),S.push("</tr>");let N=r.length===1?"file":"files";return S.push(`<tr class="totals-row"><td class="strong t-file-count">${R(r.length)} ${N}</td>`),d&&S.push(ee(d.percent,d.covered,d.total,"line",!0)),h&&S.push(ee(h.percent,h.covered,h.total,"branch",!0)),_&&S.push(ee(_.percent,_.covered,_.total,"method",!0)),S.push("</tr></thead><tbody>"),S.join("")}function qr(e){let{filename:t,coverage:n,lineCoverage:r,branchCoverage:o,methodCoverage:s}=e,i=ie(t),l=[];r&&l.push(`data-covered-lines="${n.covered_lines||0}"`,`data-relevant-lines="${n.total_lines||0}"`),o&&l.push(`data-covered-branches="${n.covered_branches||0}"`,`data-total-branches="${n.total_branches||0}"`),s&&l.push(`data-covered-methods="${n.covered_methods||0}"`,`data-total-methods="${n.total_methods||0}"`);let c=[`<tr class="t-file" ${l.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;c.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;c.push(ee(d,n.covered_branches||0,n.total_branches||0,"branch",!1))}if(s){let d=n.methods_covered_percent===void 0?100:n.methods_covered_percent;c.push(ee(d,n.covered_methods||0,n.total_methods||0,"method",!1))}return c.push("</tr>"),c.join("")}function Ze(e){let{filenames:t,allCoverage:n,lineCoverage:r,branchCoverage:o,methodCoverage:s}=e,i=[Fr(e)];for(let l of t){let c=n[l];c&&i.push(qr({filename:l,coverage:c,lineCoverage:r,branchCoverage:o,methodCoverage:s}))}return i.push("</tbody></table></div></div>"),i.join("")}function Wr(e){let{lineIndex:t,lineCov:n,branchesReport:r,missedMethodLines:o,branchCoverage:s,methodCoverage:i}=e,l=t+1;if(n==="ignored")return"skipped";if(s){let c=r[l];if(c&&c.some(([,d])=>d===0))return"missed-branch"}return i&&o.has(l)?"missed-method":n==null?"never":n===0?"missed":"covered"}function Ur(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 jr(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 zr(e){let{index:t,source:n,lineCov:r,status:o,branchCoverage:s,lineBranches:i}=e,l=t+1,c=typeof r=="number"?` data-hits="${r}"`:"",d=[`<li class="${o}"${c} data-linenumber="${l}">`];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>'),s&&i)for(let[h,_]of i){let M=k(h);d.push(`<span class="hits" data-content="${M}: ${_}" title="${M} branch hit ${_} times"></span>`)}return d.push(`<code class="ruby">${k(n)}</code></li>`),d.join("")}function Xt(e,t,n,r,o){var G;let s=ie(e),i=n&&t.covered_lines||0,l=n&&t.total_lines||0,c=r&&t.covered_branches||0,d=r&&t.total_branches||0,h=o&&t.covered_methods||0,_=o&&t.total_methods||0,M=(t.methods||[]).filter(I=>I.coverage===0),L=o&&M.length>0,S=Ur(t.branches),N=jr(t.methods),O=[`<div class="source_table" id="${s}">`,'<div class="header">',`<h2>${k(e)}</h2>`,Vt({coveredLines:i,totalLines:l,coveredBranches:c,totalBranches:d,coveredMethods:h,totalMethods:_,lineCoverage:n,branchCoverage:r,methodCoverage:o,showMethodToggle:L})];L&&O.push('<div class="t-missed-method-list" style="display: none"><ul>',M.map(I=>`<li><tt>${k(I.name)}</tt></li>`).join(""),"</ul></div>"),O.push("</div>","<pre><ol>");for(let I=0;I<t.source.length;I++){let re=(G=t.lines)==null?void 0:G[I],X=Wr({lineIndex:I,lineCov:re,branchesReport:S,missedMethodLines:N,branchCoverage:r,methodCoverage:o});O.push(zr({index:I,source:t.source[I],lineCov:re,status:X,branchCoverage:r,lineBranches:r?S[I+1]:void 0}))}return O.push("</ol></pre></div>"),O.join("")}Ve.registerLanguage("ruby",Gt);var Qe=null;function ge(){if(!Qe)return;let e=getComputedStyle(document.documentElement).getPropertyValue(`--${Qe}`).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 Yt(e){let t=e.meta,n=t.line_coverage,r=t.branch_coverage,o=t.method_coverage,s=Kt(t);document.title=`Code coverage for ${t.project_name}`;let i=Object.keys(e.coverage),l=Ce(e.total,s),c=l&&l.total>0?l.percent:100;Qe=q(c),ge(),r&&document.body.setAttribute("data-branch-coverage","true");let d=document.getElementById("content"),h=[Ze({containerId:"g-total",title:"All Files",filenames:i,stats:e.total,allCoverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o,primaryCoverage:s})];for(let O of Object.keys(e.groups)){let G=e.groups[O];h.push(Ze({containerId:_t(`group-${O}`),title:O,filenames:G.files||[],stats:G,allCoverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o,primaryCoverage:s}))}d.innerHTML=h.join("");let _={};for(let O of i)_[ie(O)]=O;te={idToFilename:_,coverage:e.coverage,lineCoverage:n,branchCoverage:r,methodCoverage:o};let M=new Date(t.timestamp),L=`Generated <abbr class="timeago" title="${M.toISOString()}">${M.toISOString()}</abbr> by <a href="https://github.com/simplecov-ruby/simplecov">simplecov</a> v${k(t.simplecov_version)} using ${k(t.command_name)}`;document.getElementById("footer").innerHTML=L,document.getElementById("source-dialog-footer").innerHTML=L;let S=document.getElementById("source-legend"),N="";n&&(N+='<div class="source-legend__row source-legend__row--line"><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></div>'),r&&(N+='<div class="source-legend__row source-legend__row--branch"><span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-branch"></span>Missed branch</span></div>'),o&&(N+='<div class="source-legend__row source-legend__row--method"><span class="source-legend__item"><span class="source-legend__swatch source-legend__swatch--missed-method"></span>Missed method</span></div>'),S.innerHTML=N}function Zt(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=Xt(n,te.coverage[n],te.lineCoverage,te.branchCoverage,te.methodCoverage),o=document.querySelector(".source_files"),s=document.createElement("div");s.innerHTML=r;let i=s.firstElementChild;return o.appendChild(i),v("pre code",i).forEach(l=>Ve.highlightElement(l)),i}var Je=1e3,Gr="t-window-hidden",Qt=new WeakSet;function Kr(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(),Qt.add(e),ce(e.closest("table"))}),e.appendChild(n)}return n}function ce(e){let t=e.querySelector("tbody");if(!t)return;let n=t.querySelectorAll("tr.t-file"),r=Qt.has(t),o=0;if(n.forEach(i=>{let l=i.style.display==="none";l||(o+=1),i.classList.toggle(Gr,!r&&!l&&o>Je)}),r||o<=Je){let i=t.querySelector("tr.t-show-all");i&&(i.style.display="none");return}let s=Kr(t,n[0].children.length);s.style.display="",s.firstElementChild.innerHTML=`Showing the first ${R(Je)} of ${R(o)} files. <a href="#" class="t-show-all__link">Show all</a>`,t.appendChild(s)}function Ae(e){try{return localStorage.getItem(e)}catch(t){return null}}function pe(e,t){try{localStorage.setItem(e,t)}catch(n){}}var tt=new WeakMap,rn="simplecov-sort";function Vr(){let e=Ae(rn);if(!e)return null;try{let t=JSON.parse(e);return typeof t.column!="string"||!t.column||t.direction!=="asc"&&t.direction!=="desc"?null:{column:t.column,direction:t.direction}}catch(t){return null}}function Xr(e){pe(rn,JSON.stringify(e))}function Yr(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 Zr(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 Jt=new WeakMap;function en(e,t){var s;if(t===null)return"";let n=Jt.get(e);n||(n=new Map,Jt.set(e,n));let r=n.get(t);if(r!==void 0)return r;let o=Zr((s=e.children[t])!=null?s:null);return n.set(t,o),o}var Qr=new Intl.Collator;function tn(e,t){return typeof e=="number"&&typeof t=="number"?e-t:Qr.compare(String(e),String(t))}function on(e,t,n){let r=e.map(s=>({row:s,value:en(s,t),filename:en(s,0)})),o=n==="asc"?1:-1;return r.sort((s,i)=>o*(tn(s.value,i.value)||tn(s.filename,i.filename))),r.map(({row:s})=>s)}function et(e,t,n){tt.set(e,{colIndex:t,direction:n});let r=0;v("thead tr:first-child th",e).forEach(o=>{let s=Number.parseInt(o.getAttribute("colspan")||"1",10);o.classList.remove("sorting_asc","sorting_desc","sorting");let i=t>=r&&t<r+s;o.classList.add(i?n==="asc"?"sorting_asc":"sorting_desc":"sorting"),r+=s})}function sn(e,t){let n=document.createDocumentFragment();t.forEach(r=>n.appendChild(r)),e.appendChild(n)}function nn(e,t,n){let r=tt.get(e),o=e.querySelector("tbody"),s=Array.from(o.querySelectorAll("tr.t-file"));if(s.length===0){et(e,t,n);return}if(r&&r.colIndex===t&&r.direction!==n)s.reverse();else{let i=Yr(s[0],t);s=on(s,i,n)}sn(o,s),ce(e),et(e,t,n)}var Jr=500,he=null;function eo(){if(he)return he;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),he=e,e}function to(){let e=eo();e.style.transition="none",e.style.opacity="1",e.style.display="flex"}function no(){if(!he)return;let e=he;e.style.transition="opacity 0.15s",e.style.opacity="0",setTimeout(()=>{e.style.display="none"},150)}function ro(e,t){let n=ln(e,t),r=tt.get(e),o=r&&r.colIndex===n&&r.direction==="asc"?"desc":"asc",s=t.getAttribute("data-sort-key");if(s&&Xr({column:s,direction:o}),e.querySelectorAll("tbody tr.t-file").length<Jr){nn(e,n,o);return}to(),requestAnimationFrame(()=>requestAnimationFrame(()=>{nn(e,n,o),no()}))}function ln(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 oo(e,t){let n=Array.from(e.children);if(t){let o=n.findIndex(s=>s.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 io(e,t,n){let r=e.querySelector("tbody");if(!r)return;let o=Array.from(r.querySelectorAll("tr.t-file"));if(o.length===0)return;let s=n&&v("thead tr:first-child th",e).find(c=>c.getAttribute("data-sort-key")===n.column),i=s?ln(e,s):oo(o[0],t);if(i===null)return;let l=s?n.direction:"asc";sn(r,on(o,i,l)),et(e,i,l)}function cn(e){let t=Vr();v("table.file_list").forEach(n=>{v("thead tr:first-child th",n).forEach(r=>{r.classList.add("sorting"),r.style.cursor="pointer",r.addEventListener("click",()=>ro(n,r))}),io(n,e,t),ce(n)})}var me=null;function Re(){me=null}function an(){if(me)return me;let e=v(".file_list_container").filter(t=>t.style.display!=="none");return e.length?(me=v("tbody tr.t-file",e[0]).filter(t=>t.style.display!=="none"),me):[]}var so=240,lo=160;function un(e,t){e.style.setProperty("--bar-sizer-width",t+"px")}var co=8;function ao(e,t){let n=lo,r=so;for(;r-n>co;){let o=Math.ceil((n+r)/2);un(e,o),e.offsetWidth,e.scrollWidth<=t?n=o:r=o-1}return n}function rt(){v(".file_list_container").forEach(e=>{if(e.style.display==="none"||e.offsetWidth===0)return;let t=x("table.file_list",e);if(!t||!x(".bar-sizer",t))return;let n=t.closest(".file_list--responsive");n&&(n.style.visibility="hidden",un(t,ao(t,n.clientWidth)),n.style.visibility="")})}var nt=0;function ae(){nt||(nt=requestAnimationFrame(()=>{nt=0,rt()}))}var Ne={line:{covered:"coveredLines",total:"relevantLines"},branch:{covered:"coveredBranches",total:"totalBranches"},method:{covered:"coveredMethods",total:"totalMethods"}};function dn(e){let t=v("tbody tr.t-file",e).filter(s=>s.style.display!=="none");function n(s){return t.reduce((i,l)=>i+(Number.parseInt(l.dataset[s]||"0",10)||0),0)}let r=x(".t-file-count",e),o=Number.parseInt(e.getAttribute("data-total-files")||"0",10);if(r){let s=t.length===1?" file":" files";r.textContent=t.length===o?R(o)+s:R(t.length)+"/"+R(o)+s}for(let s of Object.keys(Ne)){let i=Ne[s],l=`.t-totals__${s}`;x(l+"-pct",e)&&uo(e,l,n(i.covered),n(i.total))}}function uo(e,t,n,r){let o=x(t+"-pct",e),s=x(t+"-num",e),i=x(t+"-den",e);if(r===0){o&&(o.innerHTML="",o.classList.remove("green","yellow","red")),s&&(s.textContent=""),i&&(i.textContent="");return}let l=n*100/r,c=q(l);o&&(o.innerHTML=`<div class="coverage-cell">${Ye(l)}<span class="coverage-pct">${j(l)}%</span></div>`,o.classList.remove("green","yellow","red"),o.classList.add(c)),s&&(s.textContent=R(n)+"/"),i&&(i.textContent=R(r))}var fo={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 go(e,t,n){let r=fo[e];return r?r(t,n):!0}function po(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 s=r.dataset.type||"",i=x(`.col-filter__op[data-type="${s}"]`,e),l=i?i.value:"",c=Ne[s];l&&c&&t.push({attrs:c,op:l,threshold:o})}return t}var fn=new WeakMap;function ho(e){let t=fn.get(e);return t===void 0&&(t=(e.children[0].textContent||"").toLowerCase(),fn.set(e,t)),t}function gn(e){let t=x("table.file_list",e);if(!t)return;let n=x(".col-filter--name",e),r=n?n.value.trim().toLowerCase():"",o=po(e);v("tbody tr.t-file",t).forEach(s=>{let i=s,c=(!r||ho(s).includes(r))&&o.every(d=>{let h=Number.parseInt(i.dataset[d.attrs.covered]||"0",10)||0,_=Number.parseInt(i.dataset[d.attrs.total]||"0",10)||0,M=_>0?h*100/_:100;return go(d.op,M,d.threshold)})?"":"none";i.style.display!==c&&(i.style.display=c)}),ce(t),Re(),dn(e),ae()}function ot(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"]'),s=r.querySelector('option[value="lt"]');if(o&&(o.disabled=t>=100),s&&(s.disabled=t<=0),r.selectedOptions[0]&&r.selectedOptions[0].disabled){let i=r.querySelector("option:not(:disabled)");i&&(r.value=i.value)}}function pn(){v(".col-filter__value").forEach(e=>ot(e)),v(".col-filter--name, .col-filter__op, .col-filter__value, .col-filter__coverage").forEach(e=>{e.addEventListener("click",t=>t.stopPropagation())}),F(document,"input",".col-filter--name, .col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&ot(this),gn(this.closest(".file_list_container"))}),F(document,"change",".col-filter__op, .col-filter__value",function(){this.classList.contains("col-filter__value")&&ot(this),gn(this.closest(".file_list_container"))})}var $=null;function it(){return $!==null}function ue(e){$&&$.classList.remove("keyboard-focus"),$=e,$&&($.classList.add("keyboard-focus"),$.scrollIntoView({block:"nearest"}))}function st(e){let t=an();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 hn(){if(!$)return;let e=$.querySelector("a.src_link");e&&(window.location.hash=e.getAttribute("href").substring(1))}var z,ne,lt,be=null,Oe="";function ct(){return z.open}function at(){return ne}function bn(){if(!be)return;Oe&&(be.insertAdjacentHTML("afterbegin",Oe),Oe="");let e=document.querySelector(".source_files");e&&e.appendChild(be),be=null}function mo(e,t){bn();let n=Zt(e);if(!n)return;let r=n.querySelector(".header");if(r&&(Oe=r.outerHTML,lt.innerHTML=r.innerHTML,r.remove()),be=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 mn(e){if(ue(null),Re(),z.open&&(bn(),z.close(),ne.innerHTML="",lt.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")&&ae()}function He(){let e=window.location.hash.substring(1);if(!e){let t=document.querySelector(".group_tabs a");t&&mn(t.getAttribute("href").replace("#",""));return}if(e.charAt(0)==="_")mn(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")}mo(t[0],t[1])}}function Ie(){let e=document.querySelector(".group_tabs li.active a");e&&(window.location.hash=e.getAttribute("href").replace("#","#_"))}function vn(){z=document.getElementById("source-dialog"),ne=document.getElementById("source-dialog-body"),lt=document.getElementById("source-dialog-title"),z.querySelector(".source-dialog__close").addEventListener("click",Ie),z.addEventListener("click",e=>{e.target===z&&Ie()})}function bo(){return v(".source-dialog .source_table li.missed, .source-dialog .source_table li.missed-branch, .source-dialog .source_table li.missed-method")}function ut(e){let t=bo();if(!t.length)return;let n=at(),r=n.scrollTop+n.clientHeight/2,o=e===1?t.find(s=>s.offsetTop>r)||t[0]:t.findLast(s=>s.offsetTop<r-10)||t[t.length-1];n.scrollTop=o.offsetTop-n.clientHeight/3}function En(){F(document,"click",".t-missed-method-toggle",function(e){e.preventDefault();let t=this.closest(".header")||this.closest(".source-dialog__title")||this.closest(".source-dialog__header"),n=t?t.querySelector(".t-missed-method-list"):null;n&&(n.style.display=n.style.display==="none"?"":"none")}),F(document,"click","a.src_link",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").substring(1)}),F(document,"click","table.file_list tbody tr",function(e){if(e.target.closest("a"))return;let t=this.querySelector("a.src_link");t&&(window.location.hash=t.getAttribute("href").substring(1))}),F(document,"click",".source-dialog .source_table li[data-linenumber]",function(e){e.preventDefault(),at().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",He)}var _n="simplecov-dark-mode",vo="simplecov-colorblind-mode";function Eo(){return Ae(_n)}function yn(e){return Array.from(document.querySelectorAll(`[data-toggle="${e}"]`))}function wn(){let e=yn("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");pe(vo,o?"on":"off"),n(),ge()}))}function Mn(){let e=yn("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(s=>{s.textContent=o?"\u2600\uFE0F Light":"\u{1F319} Dark",s.setAttribute("aria-label",o?"Switch to light mode":"Switch to dark mode")})}r(),e.forEach(o=>o.addEventListener("click",()=>{let s=n();t.classList.toggle("light-mode",s),t.classList.toggle("dark-mode",!s),pe(_n,s?"light":"dark"),r(),ge()})),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Eo()||r(),ge()})}function _o(){let e=v(".file_list_container").filter(n=>n.style.display!=="none"),t=e.length?x(".col-filter--name",e[0]):null;t&&t.focus()}function yo(e,t){ct()?(e.preventDefault(),Ie()):t?e.target.blur():it()&&ue(null)}function wo(e){e.key==="n"&&!e.shiftKey&&(e.preventDefault(),ut(1)),(e.key==="N"||e.key==="n"&&e.shiftKey||e.key==="p")&&(e.preventDefault(),ut(-1))}function Mo(e){e.key==="j"&&(e.preventDefault(),st(1)),e.key==="k"&&(e.preventDefault(),st(-1)),e.key==="Enter"&&it()&&(e.preventDefault(),hn())}function Sn(e){let t=e.target.matches("input, select, textarea");e.key==="/"&&!t?(e.preventDefault(),_o()):e.key==="Escape"?yo(e,t):t||(ct()?wo(e):Mo(e))}function Tn(){let e=x(".group_tabs");if(!e)return;let t=()=>{e.classList.toggle("is-scrolled",e.scrollLeft>0)};e.addEventListener("scroll",t),window.addEventListener("resize",t),t()}function Ln(){let e=1/0;v("abbr.timeago").forEach(t=>{let n=new Date(t.getAttribute("title")||"");Number.isNaN(n.getTime())||(t.textContent=wt(n),e=Math.min(e,Mt(n)))}),e<1/0&&setTimeout(Ln,e)}function So(){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 s=document.createElement("a");s.href="#"+t,s.className=t,s.innerHTML=(n?n.innerHTML:"")+" ("+(r?r.innerHTML:"")+")",o.appendChild(s),document.querySelector(".group_tabs").appendChild(o)}),F(document.querySelector(".group_tabs"),"click","a",function(e){e.preventDefault(),window.location.hash=this.getAttribute("href").replace("#","#_")})}function To(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"),rt()}function Lo(){return oe(this,null,function*(){let e=window.SIMPLECOV_DATA,t=document.getElementById("loading");t&&(t.style.display=""),yield St(Object.keys(e.coverage)),Yt(e),Ln(),Mn(),wn(),cn(e.meta.primary_coverage),pn(),document.addEventListener("keydown",Sn),vn(),En(),So(),Tn(),window.addEventListener("resize",ae),He(),To(t)})}document.addEventListener("DOMContentLoaded",Lo);})();
|
|
85
|
+
</script>
|
|
55
86
|
</body>
|
|
56
87
|
</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
|