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