├── .gitignore ├── README.md ├── build-zip ├── icon.svg ├── img ├── graphics.png ├── preview.png └── usage.png ├── src ├── background.js ├── icons │ ├── icon128.png │ ├── icon16.png │ ├── icon24.png │ ├── icon32.png │ └── icon48.png ├── manifest.json └── style.css └── test ├── package-lock.json ├── package.json ├── sample ├── README.md └── image.png ├── screenshots ├── folder-root-expected.png ├── project-root-expected.png ├── readme-file-expected.png └── wiki-expected.png ├── test-case.js ├── test-runner.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.zip 3 | node_modules 4 | test/screenshots/*-actual.png 5 | test/screenshots/*-diff.png 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # github-markdown-printer 2 | 3 | Print GitHub Flavored Markdown _exactly_ as it appears on GitHub, with just two clicks. 4 | 5 | Get it from the [Chrome Web Store](https://chrome.google.com/webstore/detail/github-markdown-printer/fehpdlpmcegfpbkgcnaleindodeegapk) or the [Edge Web Store](https://microsoftedge.microsoft.com/addons/detail/github-markdown-printer/njdhaokfdmnighagdlhbfpkmcgojljcl). 6 | 7 | ![GitHub Markdown Printer demo image](./img/preview.png) 8 | 9 | ### Advantages over other markdown converters 10 | 11 | This is easier and faster than downloading the markdown file and running it through a converter. This also produces better results. 12 | 13 | ## Usage 14 | 15 | 1. Go to any page on GitHub where there's a markdown preview 16 | 2. Right-click the page and select "Print GitHub Markdown" 17 | 3. Select your printer or save as PDF and print 18 | 19 | ![GitHub Markdown Printer usage](./img/usage.png) 20 | 21 | ## Troubleshooting 22 | 23 | If you're experiencing an issue that isn't listed below, please [submit an issue](https://github.com/jerry1100/github-markdown-printer/issues/new). 24 | 25 | ### Code blocks aren't shaded 26 | 27 | Make sure "Background graphics" are enabled in the print preview. To check, click "More settings" in the print preview, then look for "Background graphics". 28 | 29 | Background graphics setting 30 | 31 | ### Indentation is weird in code blocks 32 | 33 | Long pieces of code that do not fit within the page will be wrapped to the next line. This wrapping may mess up the indentation. 34 | 35 | ### Jupyter notebooks formatting is off 36 | 37 | Keep trying until the formatting looks correct. Notebooks are rendered using iframes, which we don't have much control over, so the formatting can often be wrong. For whatever reason, it sometimes gets it right after several attempts. 38 | 39 | ### Mermaid diagrams are cut off 40 | 41 | Keep trying until they're not cut off. Like notebooks, mermaid diagrams are rendered using iframes, which we don't have much control over. Despite many hours of trying, I haven't been able to get them to render correctly on the first try. 42 | -------------------------------------------------------------------------------- /build-zip: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Packages the src files into a .zip archive 4 | 5 | package_name="$(basename $(git rev-parse --show-toplevel)).zip" 6 | 7 | if [[ "$OS" == "Windows_NT" ]]; then 8 | powershell "Compress-Archive src/* ${package_name}" 9 | else 10 | cd src && zip -r -9 "../${package_name}" * 11 | fi 12 | 13 | echo "Created ${package_name}" 14 | -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /img/graphics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/img/graphics.png -------------------------------------------------------------------------------- /img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/img/preview.png -------------------------------------------------------------------------------- /img/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/img/usage.png -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | const GITHUB_MARKDOWN_PRINTER = 'GITHUB_MARKDOWN_PRINTER'; 2 | 3 | // Respond to clicks on the extension icon 4 | chrome.action.onClicked.addListener((tab) => { 5 | printPageForTab(tab.id); 6 | }); 7 | 8 | // Create context menu 9 | chrome.contextMenus.create({ 10 | title: 'Print GitHub Markdown', 11 | id: GITHUB_MARKDOWN_PRINTER, 12 | documentUrlPatterns: ['https://*.github.com/*'], 13 | }); 14 | 15 | // Respond to context menu clicks 16 | chrome.contextMenus.onClicked.addListener((clickInfo, tab) => { 17 | if (clickInfo.menuItemId === GITHUB_MARKDOWN_PRINTER) { 18 | printPageForTab(tab.id); 19 | } 20 | }); 21 | 22 | function printPageForTab(tabId) { 23 | chrome.scripting.executeScript({ 24 | target: { tabId }, 25 | function: printPage, 26 | }); 27 | } 28 | 29 | function printPage() { 30 | const content = 31 | document.querySelector('.markdown-body') ?? 32 | document.querySelector('div[data-type="ipynb"]'); 33 | 34 | if (!content) { 35 | alert('No printable content found on this page'); 36 | return; 37 | } 38 | 39 | const link = document.createElement('link'); 40 | link.rel = 'stylesheet'; 41 | link.href = chrome.runtime.getURL('style.css'); 42 | 43 | document.head.appendChild(link); 44 | link.addEventListener('load', async () => { 45 | const bodyHtml = document.body.innerHTML; 46 | const theme = document.documentElement.dataset.colorMode; 47 | 48 | // Use light theme or else text contrast is bad 49 | document.documentElement.dataset.colorMode = 'light'; 50 | 51 | // For all iframes, change 'color_mode=dark' to 'color_mode=light' so that content 52 | // is visible when printed 53 | for (const iframe of document.querySelectorAll('iframe')) { 54 | iframe.src = iframe.src.replace('color_mode=dark', 'color_mode=light'); 55 | } 56 | 57 | // Have markdown content occupy entire page 58 | document.body.replaceChildren(content); 59 | 60 | await waitForMermaidDiagramsToLoad(); 61 | await waitForJupyterNotebooksToLoad(); 62 | const revertHeadingsLinkable = makeHeadingsLinkable(); 63 | 64 | window.print(); 65 | 66 | // Clean up - revert to original 67 | revertHeadingsLinkable(); 68 | document.body.innerHTML = bodyHtml; 69 | document.documentElement.dataset.colorMode = theme; 70 | document.head.removeChild(link); 71 | }); 72 | 73 | async function waitForMermaidDiagramsToLoad() { 74 | // Keep track of iframes that have loaded. We aren't able to peer inside the frame 75 | // due to cross-origin restrictions, so we just wait for the frame to send us a 76 | // message when it's ready. 77 | const loadedFrames = new Set(); 78 | 79 | window.addEventListener('message', ({ data }) => { 80 | if (data.body === 'ready') { 81 | loadedFrames.add(data.identity); 82 | } 83 | }); 84 | 85 | // Wait for all mermaid diagrams to load 86 | const mermaidIds = Array.from( 87 | document.querySelectorAll('section[data-type="mermaid"]') 88 | ).map((node) => node.dataset.identity); 89 | 90 | await new Promise((resolve) => { 91 | const interval = setInterval(() => { 92 | if (mermaidIds.every((id) => loadedFrames.has(id))) { 93 | clearInterval(interval); 94 | resolve(); 95 | } 96 | }, 100); 97 | }); 98 | } 99 | 100 | async function waitForJupyterNotebooksToLoad() { 101 | // Give jupyter notebooks some time to load before attempting to print. Tried to 102 | // extend iframe waiting logic to handle this case, but for some reason the iframe 103 | // doesn't send the ready event after content is replaced. 104 | const notebook = document.querySelector('div[data-type="ipynb"]'); 105 | if (notebook) { 106 | await new Promise((resolve) => setTimeout(resolve, 2000)); 107 | } 108 | } 109 | 110 | function makeHeadingsLinkable() { 111 | const headings = [ 112 | ...document.getElementsByTagName('h1'), 113 | ...document.getElementsByTagName('h2'), 114 | ...document.getElementsByTagName('h3'), 115 | ...document.getElementsByTagName('h4'), 116 | ...document.getElementsByTagName('h5'), 117 | ...document.getElementsByTagName('h6'), 118 | ]; 119 | 120 | const normalize = (text) => { 121 | return text 122 | .trim() 123 | .toLowerCase() 124 | .replaceAll(' ', '-') 125 | .replace(/[^a-z0-9\-]/g, ''); // only keep letters, numbers, and hyphens 126 | }; 127 | 128 | // Add ids to all headings 129 | const ids = new Set(); 130 | for (const heading of headings) { 131 | heading.id = normalize(heading.textContent); 132 | ids.add(heading.id); 133 | } 134 | 135 | // Update internal links to point to the new ids 136 | const internalLinks = document.querySelectorAll( 137 | 'a[href^="#"]:not(.markdown-heading a)' 138 | ); 139 | const originalHrefs = new Map(); // store original hrefs to revert later 140 | for (const link of internalLinks) { 141 | const href = link.getAttribute('href'); 142 | const normalized = normalize(href.slice(1)); // remove leading '#' 143 | 144 | if (ids.has(normalized)) { 145 | originalHrefs.set(link, href); 146 | link.href = `#${normalized}`; 147 | } 148 | } 149 | 150 | // Cleanup 151 | return () => { 152 | // Revert all heading ids 153 | for (const heading of headings) { 154 | heading.removeAttribute('id'); 155 | } 156 | 157 | // Revert internal links back to their original hrefs 158 | for (const [link, href] of originalHrefs) { 159 | link.setAttribute('href', href); 160 | } 161 | }; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/src/icons/icon128.png -------------------------------------------------------------------------------- /src/icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/src/icons/icon16.png -------------------------------------------------------------------------------- /src/icons/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/src/icons/icon24.png -------------------------------------------------------------------------------- /src/icons/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/src/icons/icon32.png -------------------------------------------------------------------------------- /src/icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/src/icons/icon48.png -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "GitHub Markdown Printer", 4 | "version": "0.13", 5 | "description": "Print GitHub Flavored Markdown exactly as it appears on GitHub, with just two clicks.", 6 | "homepage_url": "https://github.com/jerry1100/github-markdown-printer", 7 | "icons": { 8 | "16": "icons/icon16.png", 9 | "48": "icons/icon48.png", 10 | "128": "icons/icon128.png" 11 | }, 12 | "action": { 13 | "default_icon": { 14 | "16": "icons/icon16.png", 15 | "24": "icons/icon24.png", 16 | "32": "icons/icon32.png" 17 | }, 18 | "default_title": "Print Markdown" 19 | }, 20 | "background": { 21 | "service_worker": "background.js" 22 | }, 23 | "permissions": ["activeTab", "scripting", "contextMenus"], 24 | "web_accessible_resources": [ 25 | { 26 | "resources": ["style.css"], 27 | "matches": ["https://*.github.com/*"] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | /* Wraps long lines of code */ 2 | pre { 3 | white-space: pre-wrap !important; 4 | } 5 | 6 | /* Hide copy button for code blocks */ 7 | pre + div.zeroclipboard-container { 8 | display: none; 9 | } 10 | 11 | @page { 12 | size: auto; 13 | margin: 54pt; 14 | } 15 | 16 | /* 17 | Mermaid diagrams (or iframes in general) aren't positioned well when printed. 18 | The space reserved for the diagram is normal, but for some reason the diagram 19 | is shifted so that it starts on the next page. It seems this is done to prevent 20 | the diagram from getting split by the page boundary. Unfortunately, this results 21 | in the diagram overlapping with other content below. Add a red border to see this. 22 | */ 23 | section[data-type="mermaid"] { 24 | /* In case of overlap, this allows you to see the content behind the diagram */ 25 | position: static !important; 26 | 27 | /* Extra spacing for diagrams to prevent overlap, doesn't work for long diagrams */ 28 | margin-bottom: 225px !important; 29 | } 30 | 31 | /* 32 | Some of GitHub's light theme color tokens are missing when manually changing to the 33 | light theme, which breaks things like underlines under headers. This fixes that by 34 | redefining all the missing color tokens, and more. 35 | */ 36 | html { 37 | --color-canvas-default-transparent: rgba(255,255,255,0); 38 | --color-page-header-bg: #f6f8fa; 39 | --color-marketing-icon-primary: #218bff; 40 | --color-marketing-icon-secondary: #54aeff; 41 | --color-diff-blob-addition-num-text: #1F2328; 42 | --color-diff-blob-addition-fg: #1F2328; 43 | --color-diff-blob-addition-num-bg: #ccffd8; 44 | --color-diff-blob-addition-line-bg: #e6ffec; 45 | --color-diff-blob-addition-word-bg: #abf2bc; 46 | --color-diff-blob-deletion-num-text: #1F2328; 47 | --color-diff-blob-deletion-fg: #1F2328; 48 | --color-diff-blob-deletion-num-bg: #ffd7d5; 49 | --color-diff-blob-deletion-line-bg: #ffebe9; 50 | --color-diff-blob-deletion-word-bg: rgba(255,129,130,0.4); 51 | --color-diff-blob-hunk-num-bg: rgba(84,174,255,0.4); 52 | --color-diff-blob-expander-icon: #656d76; 53 | --color-diff-blob-selected-line-highlight-mix-blend-mode: multiply; 54 | --color-diffstat-deletion-border: rgba(31,35,40,0.15); 55 | --color-diffstat-addition-border: rgba(31,35,40,0.15); 56 | --color-diffstat-addition-bg: #1f883d; 57 | --color-search-keyword-hl: #fff8c5; 58 | --color-prettylights-syntax-comment: #6e7781; 59 | --color-prettylights-syntax-constant: #0550ae; 60 | --color-prettylights-syntax-entity: #8250df; 61 | --color-prettylights-syntax-storage-modifier-import: #24292f; 62 | --color-prettylights-syntax-entity-tag: #116329; 63 | --color-prettylights-syntax-keyword: #cf222e; 64 | --color-prettylights-syntax-string: #0a3069; 65 | --color-prettylights-syntax-variable: #953800; 66 | --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; 67 | --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; 68 | --color-prettylights-syntax-invalid-illegal-bg: #82071e; 69 | --color-prettylights-syntax-carriage-return-text: #f6f8fa; 70 | --color-prettylights-syntax-carriage-return-bg: #cf222e; 71 | --color-prettylights-syntax-string-regexp: #116329; 72 | --color-prettylights-syntax-markup-list: #3b2300; 73 | --color-prettylights-syntax-markup-heading: #0550ae; 74 | --color-prettylights-syntax-markup-italic: #24292f; 75 | --color-prettylights-syntax-markup-bold: #24292f; 76 | --color-prettylights-syntax-markup-deleted-text: #82071e; 77 | --color-prettylights-syntax-markup-deleted-bg: #ffebe9; 78 | --color-prettylights-syntax-markup-inserted-text: #116329; 79 | --color-prettylights-syntax-markup-inserted-bg: #dafbe1; 80 | --color-prettylights-syntax-markup-changed-text: #953800; 81 | --color-prettylights-syntax-markup-changed-bg: #ffd8b5; 82 | --color-prettylights-syntax-markup-ignored-text: #eaeef2; 83 | --color-prettylights-syntax-markup-ignored-bg: #0550ae; 84 | --color-prettylights-syntax-meta-diff-range: #8250df; 85 | --color-prettylights-syntax-brackethighlighter-angle: #57606a; 86 | --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; 87 | --color-prettylights-syntax-constant-other-reference-link: #0a3069; 88 | --color-codemirror-text: #1F2328; 89 | --color-codemirror-bg: #ffffff; 90 | --color-codemirror-gutters-bg: #ffffff; 91 | --color-codemirror-guttermarker-text: #ffffff; 92 | --color-codemirror-guttermarker-subtle-text: #6e7781; 93 | --color-codemirror-linenumber-text: #656d76; 94 | --color-codemirror-cursor: #1F2328; 95 | --color-codemirror-selection-bg: rgba(84,174,255,0.4); 96 | --color-codemirror-activeline-bg: rgba(234,238,242,0.5); 97 | --color-codemirror-matchingbracket-text: #1F2328; 98 | --color-codemirror-lines-bg: #ffffff; 99 | --color-codemirror-syntax-comment: #24292f; 100 | --color-codemirror-syntax-constant: #0550ae; 101 | --color-codemirror-syntax-entity: #8250df; 102 | --color-codemirror-syntax-keyword: #cf222e; 103 | --color-codemirror-syntax-storage: #cf222e; 104 | --color-codemirror-syntax-string: #0a3069; 105 | --color-codemirror-syntax-support: #0550ae; 106 | --color-codemirror-syntax-variable: #953800; 107 | --color-checks-bg: #24292f; 108 | --color-checks-run-border-width: 0px; 109 | --color-checks-container-border-width: 0px; 110 | --color-checks-text-primary: #f6f8fa; 111 | --color-checks-text-secondary: #8c959f; 112 | --color-checks-text-link: #54aeff; 113 | --color-checks-btn-icon: #afb8c1; 114 | --color-checks-btn-hover-icon: #f6f8fa; 115 | --color-checks-btn-hover-bg: rgba(255,255,255,0.125); 116 | --color-checks-input-text: #eaeef2; 117 | --color-checks-input-placeholder-text: #8c959f; 118 | --color-checks-input-focus-text: #8c959f; 119 | --color-checks-input-bg: #32383f; 120 | --color-checks-input-shadow: none; 121 | --color-checks-donut-error: #fa4549; 122 | --color-checks-donut-pending: #bf8700; 123 | --color-checks-donut-success: #1f883d; 124 | --color-checks-donut-neutral: #afb8c1; 125 | --color-checks-dropdown-text: #afb8c1; 126 | --color-checks-dropdown-bg: #32383f; 127 | --color-checks-dropdown-border: #424a53; 128 | --color-checks-dropdown-shadow: rgba(31,35,40,0.3); 129 | --color-checks-dropdown-hover-text: #f6f8fa; 130 | --color-checks-dropdown-hover-bg: #424a53; 131 | --color-checks-dropdown-btn-hover-text: #f6f8fa; 132 | --color-checks-dropdown-btn-hover-bg: #32383f; 133 | --color-checks-scrollbar-thumb-bg: #57606a; 134 | --color-checks-header-label-text: #d0d7de; 135 | --color-checks-header-label-open-text: #f6f8fa; 136 | --color-checks-header-border: #32383f; 137 | --color-checks-header-icon: #8c959f; 138 | --color-checks-line-text: #d0d7de; 139 | --color-checks-line-num-text: rgba(140,149,159,0.75); 140 | --color-checks-line-timestamp-text: #8c959f; 141 | --color-checks-line-hover-bg: #32383f; 142 | --color-checks-line-selected-bg: rgba(33,139,255,0.15); 143 | --color-checks-line-selected-num-text: #54aeff; 144 | --color-checks-line-dt-fm-text: #24292f; 145 | --color-checks-line-dt-fm-bg: #9a6700; 146 | --color-checks-gate-bg: rgba(125,78,0,0.15); 147 | --color-checks-gate-text: #d0d7de; 148 | --color-checks-gate-waiting-text: #d4a72c; 149 | --color-checks-step-header-open-bg: #32383f; 150 | --color-checks-step-error-text: #ff8182; 151 | --color-checks-step-warning-text: #d4a72c; 152 | --color-checks-logline-text: #8c959f; 153 | --color-checks-logline-num-text: rgba(140,149,159,0.75); 154 | --color-checks-logline-debug-text: #c297ff; 155 | --color-checks-logline-error-text: #d0d7de; 156 | --color-checks-logline-error-num-text: #ff8182; 157 | --color-checks-logline-error-bg: rgba(164,14,38,0.15); 158 | --color-checks-logline-warning-text: #d0d7de; 159 | --color-checks-logline-warning-num-text: #d4a72c; 160 | --color-checks-logline-warning-bg: rgba(125,78,0,0.15); 161 | --color-checks-logline-command-text: #54aeff; 162 | --color-checks-logline-section-text: #4ac26b; 163 | --color-checks-ansi-black: #24292f; 164 | --color-checks-ansi-black-bright: #32383f; 165 | --color-checks-ansi-white: #d0d7de; 166 | --color-checks-ansi-white-bright: #d0d7de; 167 | --color-checks-ansi-gray: #8c959f; 168 | --color-checks-ansi-red: #ff8182; 169 | --color-checks-ansi-red-bright: #ffaba8; 170 | --color-checks-ansi-green: #4ac26b; 171 | --color-checks-ansi-green-bright: #6fdd8b; 172 | --color-checks-ansi-yellow: #d4a72c; 173 | --color-checks-ansi-yellow-bright: #eac54f; 174 | --color-checks-ansi-blue: #54aeff; 175 | --color-checks-ansi-blue-bright: #80ccff; 176 | --color-checks-ansi-magenta: #c297ff; 177 | --color-checks-ansi-magenta-bright: #d8b9ff; 178 | --color-checks-ansi-cyan: #76e3ea; 179 | --color-checks-ansi-cyan-bright: #b3f0ff; 180 | --color-project-header-bg: #24292f; 181 | --color-project-sidebar-bg: #ffffff; 182 | --color-project-gradient-in: #ffffff; 183 | --color-project-gradient-out: rgba(255,255,255,0); 184 | --color-mktg-btn-bg: #1b1f23; 185 | --color-mktg-btn-shadow-outline: rgb(0 0 0 / 15%) 0 0 0 1px inset; 186 | --color-mktg-btn-shadow-focus: rgb(0 0 0 / 15%) 0 0 0 4px; 187 | --color-mktg-btn-shadow-hover: 0 3px 2px rgba(0, 0, 0, 0.07), 0 7px 5px rgba(0, 0, 0, 0.04), 0 12px 10px rgba(0, 0, 0, 0.03), 0 22px 18px rgba(0, 0, 0, 0.03), 0 42px 33px rgba(0, 0, 0, 0.02), 0 100px 80px rgba(0, 0, 0, 0.02); 188 | --color-mktg-btn-shadow-hover-muted: rgb(0 0 0 / 70%) 0 0 0 2px inset; 189 | --color-control-border-color-emphasis: #858F99; 190 | --color-avatar-bg: #ffffff; 191 | --color-avatar-border: rgba(31,35,40,0.15); 192 | --color-avatar-stack-fade: #afb8c1; 193 | --color-avatar-stack-fade-more: #d0d7de; 194 | --color-avatar-child-shadow: 0 0 0 2px rgba(255,255,255,0.8); 195 | --color-topic-tag-border: rgba(0,0,0,0); 196 | --color-counter-border: rgba(0,0,0,0); 197 | --color-select-menu-backdrop-border: rgba(0,0,0,0); 198 | --color-select-menu-tap-highlight: rgba(175,184,193,0.5); 199 | --color-select-menu-tap-focus-bg: #b6e3ff; 200 | --color-overlay-shadow: 0 1px 3px rgba(31,35,40,0.12), 0 8px 24px rgba(66,74,83,0.12); 201 | --color-header-text: rgba(255,255,255,0.7); 202 | --color-header-bg: #24292f; 203 | --color-header-divider: #57606a; 204 | --color-header-logo: #ffffff; 205 | --color-header-search-bg: #24292f; 206 | --color-header-search-border: #57606a; 207 | --color-sidenav-selected-bg: #ffffff; 208 | --color-menu-bg-active: rgba(0,0,0,0); 209 | --color-input-disabled-bg: rgba(175,184,193,0.2); 210 | --color-timeline-badge-bg: #eaeef2; 211 | --color-ansi-black: #24292f; 212 | --color-ansi-black-bright: #57606a; 213 | --color-ansi-white: #6e7781; 214 | --color-ansi-white-bright: #8c959f; 215 | --color-ansi-gray: #6e7781; 216 | --color-ansi-red: #cf222e; 217 | --color-ansi-red-bright: #a40e26; 218 | --color-ansi-green: #116329; 219 | --color-ansi-green-bright: #1a7f37; 220 | --color-ansi-yellow: #4d2d00; 221 | --color-ansi-yellow-bright: #633c01; 222 | --color-ansi-blue: #0969da; 223 | --color-ansi-blue-bright: #218bff; 224 | --color-ansi-magenta: #8250df; 225 | --color-ansi-magenta-bright: #a475f9; 226 | --color-ansi-cyan: #1b7c83; 227 | --color-ansi-cyan-bright: #3192aa; 228 | --color-btn-text: #24292f; 229 | --color-btn-bg: #f6f8fa; 230 | --color-btn-border: rgba(31,35,40,0.15); 231 | --color-btn-shadow: 0 1px 0 rgba(31,35,40,0.04); 232 | --color-btn-inset-shadow: inset 0 1px 0 rgba(255,255,255,0.25); 233 | --color-btn-hover-bg: #f3f4f6; 234 | --color-btn-hover-border: rgba(31,35,40,0.15); 235 | --color-btn-active-bg: hsla(220,14%,93%,1); 236 | --color-btn-active-border: rgba(31,35,40,0.15); 237 | --color-btn-selected-bg: hsla(220,14%,94%,1); 238 | --color-btn-counter-bg: rgba(31,35,40,0.08); 239 | --color-btn-primary-text: #ffffff; 240 | --color-btn-primary-bg: #1f883d; 241 | --color-btn-primary-border: rgba(31,35,40,0.15); 242 | --color-btn-primary-shadow: 0 1px 0 rgba(31,35,40,0.1); 243 | --color-btn-primary-inset-shadow: inset 0 1px 0 rgba(255,255,255,0.03); 244 | --color-btn-primary-hover-bg: #1a7f37; 245 | --color-btn-primary-hover-border: rgba(31,35,40,0.15); 246 | --color-btn-primary-selected-bg: hsla(137,66%,28%,1); 247 | --color-btn-primary-selected-shadow: inset 0 1px 0 rgba(0,45,17,0.2); 248 | --color-btn-primary-disabled-text: rgba(255,255,255,0.8); 249 | --color-btn-primary-disabled-bg: #94d3a2; 250 | --color-btn-primary-disabled-border: rgba(31,35,40,0.15); 251 | --color-btn-primary-icon: rgba(255,255,255,0.8); 252 | --color-btn-primary-counter-bg: rgba(255,255,255,0.2); 253 | --color-btn-outline-text: #0969da; 254 | --color-btn-outline-hover-text: #ffffff; 255 | --color-btn-outline-hover-bg: #0969da; 256 | --color-btn-outline-hover-border: rgba(31,35,40,0.15); 257 | --color-btn-outline-hover-shadow: 0 1px 0 rgba(31,35,40,0.1); 258 | --color-btn-outline-hover-inset-shadow: inset 0 1px 0 rgba(255,255,255,0.03); 259 | --color-btn-outline-hover-counter-bg: rgba(255,255,255,0.2); 260 | --color-btn-outline-selected-text: #ffffff; 261 | --color-btn-outline-selected-bg: hsla(212,92%,42%,1); 262 | --color-btn-outline-selected-border: rgba(31,35,40,0.15); 263 | --color-btn-outline-selected-shadow: inset 0 1px 0 rgba(0,33,85,0.2); 264 | --color-btn-outline-disabled-text: rgba(9,105,218,0.5); 265 | --color-btn-outline-disabled-bg: #f6f8fa; 266 | --color-btn-outline-disabled-counter-bg: rgba(9,105,218,0.05); 267 | --color-btn-outline-counter-bg: rgba(9,105,218,0.1); 268 | --color-btn-danger-text: #cf222e; 269 | --color-btn-danger-hover-text: #ffffff; 270 | --color-btn-danger-hover-bg: #a40e26; 271 | --color-btn-danger-hover-border: rgba(31,35,40,0.15); 272 | --color-btn-danger-hover-shadow: 0 1px 0 rgba(31,35,40,0.1); 273 | --color-btn-danger-hover-inset-shadow: inset 0 1px 0 rgba(255,255,255,0.03); 274 | --color-btn-danger-hover-counter-bg: rgba(255,255,255,0.2); 275 | --color-btn-danger-selected-text: #ffffff; 276 | --color-btn-danger-selected-bg: hsla(356,72%,44%,1); 277 | --color-btn-danger-selected-border: rgba(31,35,40,0.15); 278 | --color-btn-danger-selected-shadow: inset 0 1px 0 rgba(76,0,20,0.2); 279 | --color-btn-danger-disabled-text: rgba(207,34,46,0.5); 280 | --color-btn-danger-disabled-bg: #f6f8fa; 281 | --color-btn-danger-disabled-counter-bg: rgba(207,34,46,0.05); 282 | --color-btn-danger-counter-bg: rgba(207,34,46,0.1); 283 | --color-btn-danger-icon: #cf222e; 284 | --color-btn-danger-hover-icon: #ffffff; 285 | --color-underlinenav-icon: #6e7781; 286 | --color-underlinenav-border-hover: rgba(175,184,193,0.2); 287 | --color-action-list-item-inline-divider: rgba(208,215,222,0.48); 288 | --color-action-list-item-default-hover-bg: rgba(208,215,222,0.32); 289 | --color-action-list-item-default-hover-border: rgba(0,0,0,0); 290 | --color-action-list-item-default-active-bg: rgba(208,215,222,0.48); 291 | --color-action-list-item-default-active-border: rgba(0,0,0,0); 292 | --color-action-list-item-default-selected-bg: rgba(208,215,222,0.24); 293 | --color-action-list-item-danger-hover-bg: rgba(255,235,233,0.64); 294 | --color-action-list-item-danger-active-bg: #ffebe9; 295 | --color-action-list-item-danger-hover-text: #d1242f; 296 | --color-switch-track-bg: #eaeef2; 297 | --color-switch-track-hover-bg: hsla(210,24%,90%,1); 298 | --color-switch-track-active-bg: hsla(210,24%,88%,1); 299 | --color-switch-track-disabled-bg: #8c959f; 300 | --color-switch-track-fg: #656d76; 301 | --color-switch-track-disabled-fg: #ffffff; 302 | --color-switch-track-border: rgba(0,0,0,0); 303 | --color-switch-track-checked-bg: #0969da; 304 | --color-switch-track-checked-hover-bg: #0860CA; 305 | --color-switch-track-checked-active-bg: #0757BA; 306 | --color-switch-track-checked-fg: #ffffff; 307 | --color-switch-track-checked-disabled-fg: #ffffff; 308 | --color-switch-track-checked-border: rgba(0,0,0,0); 309 | --color-switch-knob-bg: #ffffff; 310 | --color-switch-knob-disabled-bg: #f6f8fa; 311 | --color-switch-knob-border: #858F99; 312 | --color-switch-knob-checked-bg: #ffffff; 313 | --color-switch-knob-checked-disabled-bg: #f6f8fa; 314 | --color-switch-knob-checked-border: #0969da; 315 | --color-segmented-control-bg: #eaeef2; 316 | --color-segmented-control-button-bg: #ffffff; 317 | --color-segmented-control-button-hover-bg: rgba(175,184,193,0.2); 318 | --color-segmented-control-button-active-bg: rgba(175,184,193,0.4); 319 | --color-segmented-control-button-selected-border: #8c959f; 320 | --color-tree-view-item-chevron-hover-bg: rgba(208,215,222,0.32); 321 | --color-tree-view-item-directory-fill: #54aeff; 322 | --color-fg-default: #1F2328; 323 | --color-fg-muted: #656d76; 324 | --color-fg-subtle: #6e7781; 325 | --color-fg-on-emphasis: #ffffff; 326 | --color-canvas-default: #ffffff; 327 | --color-canvas-overlay: #ffffff; 328 | --color-canvas-inset: #f6f8fa; 329 | --color-canvas-subtle: #f6f8fa; 330 | --color-border-default: #d0d7de; 331 | --color-border-muted: hsla(210,18%,87%,1); 332 | --color-border-subtle: rgba(31,35,40,0.15); 333 | --color-shadow-small: 0 1px 0 rgba(31,35,40,0.04); 334 | --color-shadow-medium: 0 3px 6px rgba(140,149,159,0.15); 335 | --color-shadow-large: 0 8px 24px rgba(140,149,159,0.2); 336 | --color-shadow-extra-large: 0 12px 28px rgba(140,149,159,0.3); 337 | --color-neutral-emphasis-plus: #24292f; 338 | --color-neutral-emphasis: #6e7781; 339 | --color-neutral-muted: rgba(175,184,193,0.2); 340 | --color-neutral-subtle: rgba(234,238,242,0.5); 341 | --color-accent-fg: #0969da; 342 | --color-accent-emphasis: #0969da; 343 | --color-accent-muted: rgba(84,174,255,0.4); 344 | --color-accent-subtle: #ddf4ff; 345 | --color-success-fg: #1a7f37; 346 | --color-success-emphasis: #1f883d; 347 | --color-success-muted: rgba(74,194,107,0.4); 348 | --color-success-subtle: #dafbe1; 349 | --color-attention-fg: #9a6700; 350 | --color-attention-emphasis: #9a6700; 351 | --color-attention-muted: rgba(212,167,44,0.4); 352 | --color-attention-subtle: #fff8c5; 353 | --color-severe-fg: #bc4c00; 354 | --color-severe-emphasis: #bc4c00; 355 | --color-severe-muted: rgba(251,143,68,0.4); 356 | --color-severe-subtle: #fff1e5; 357 | --color-danger-fg: #d1242f; 358 | --color-danger-emphasis: #cf222e; 359 | --color-danger-muted: rgba(255,129,130,0.4); 360 | --color-danger-subtle: #ffebe9; 361 | --color-open-fg: #1a7f37; 362 | --color-open-emphasis: #1f883d; 363 | --color-open-muted: rgba(74,194,107,0.4); 364 | --color-open-subtle: #dafbe1; 365 | --color-closed-fg: #d1242f; 366 | --color-closed-emphasis: #cf222e; 367 | --color-closed-muted: rgba(255,129,130,0.4); 368 | --color-closed-subtle: #ffebe9; 369 | --color-done-fg: #8250df; 370 | --color-done-emphasis: #8250df; 371 | --color-done-muted: rgba(194,151,255,0.4); 372 | --color-done-subtle: #fbefff; 373 | --color-sponsors-fg: #bf3989; 374 | --color-sponsors-emphasis: #bf3989; 375 | --color-sponsors-muted: rgba(255,128,200,0.4); 376 | --color-sponsors-subtle: #ffeff7; 377 | --color-primer-fg-disabled: #8c959f; 378 | --color-primer-canvas-backdrop: rgba(31,35,40,0.5); 379 | --color-primer-canvas-sticky: rgba(255,255,255,0.95); 380 | --color-primer-border-active: #fd8c73; 381 | --color-primer-border-contrast: rgba(31,35,40,0.1); 382 | --color-primer-shadow-highlight: inset 0 1px 0 rgba(255,255,255,0.25); 383 | --color-primer-shadow-inset: inset 0 1px 0 rgba(208,215,222,0.2); 384 | --color-scale-black: #1F2328; 385 | --color-scale-white: #ffffff; 386 | --color-scale-gray-0: #f6f8fa; 387 | --color-scale-gray-1: #eaeef2; 388 | --color-scale-gray-2: #d0d7de; 389 | --color-scale-gray-3: #afb8c1; 390 | --color-scale-gray-4: #8c959f; 391 | --color-scale-gray-5: #6e7781; 392 | --color-scale-gray-6: #57606a; 393 | --color-scale-gray-7: #424a53; 394 | --color-scale-gray-8: #32383f; 395 | --color-scale-gray-9: #24292f; 396 | --color-scale-blue-0: #ddf4ff; 397 | --color-scale-blue-1: #b6e3ff; 398 | --color-scale-blue-2: #80ccff; 399 | --color-scale-blue-3: #54aeff; 400 | --color-scale-blue-4: #218bff; 401 | --color-scale-blue-5: #0969da; 402 | --color-scale-blue-6: #0550ae; 403 | --color-scale-blue-7: #033d8b; 404 | --color-scale-blue-8: #0a3069; 405 | --color-scale-blue-9: #002155; 406 | --color-scale-green-0: #dafbe1; 407 | --color-scale-green-1: #aceebb; 408 | --color-scale-green-2: #6fdd8b; 409 | --color-scale-green-3: #4ac26b; 410 | --color-scale-green-4: #2da44e; 411 | --color-scale-green-5: #1a7f37; 412 | --color-scale-green-6: #116329; 413 | --color-scale-green-7: #044f1e; 414 | --color-scale-green-8: #003d16; 415 | --color-scale-green-9: #002d11; 416 | --color-scale-yellow-0: #fff8c5; 417 | --color-scale-yellow-1: #fae17d; 418 | --color-scale-yellow-2: #eac54f; 419 | --color-scale-yellow-3: #d4a72c; 420 | --color-scale-yellow-4: #bf8700; 421 | --color-scale-yellow-5: #9a6700; 422 | --color-scale-yellow-6: #7d4e00; 423 | --color-scale-yellow-7: #633c01; 424 | --color-scale-yellow-8: #4d2d00; 425 | --color-scale-yellow-9: #3b2300; 426 | --color-scale-orange-0: #fff1e5; 427 | --color-scale-orange-1: #ffd8b5; 428 | --color-scale-orange-2: #ffb77c; 429 | --color-scale-orange-3: #fb8f44; 430 | --color-scale-orange-4: #e16f24; 431 | --color-scale-orange-5: #bc4c00; 432 | --color-scale-orange-6: #953800; 433 | --color-scale-orange-7: #762c00; 434 | --color-scale-orange-8: #5c2200; 435 | --color-scale-orange-9: #471700; 436 | --color-scale-red-0: #ffebe9; 437 | --color-scale-red-1: #ffcecb; 438 | --color-scale-red-2: #ffaba8; 439 | --color-scale-red-3: #ff8182; 440 | --color-scale-red-4: #fa4549; 441 | --color-scale-red-5: #cf222e; 442 | --color-scale-red-6: #a40e26; 443 | --color-scale-red-7: #82071e; 444 | --color-scale-red-8: #660018; 445 | --color-scale-red-9: #4c0014; 446 | --color-scale-purple-0: #fbefff; 447 | --color-scale-purple-1: #ecd8ff; 448 | --color-scale-purple-2: #d8b9ff; 449 | --color-scale-purple-3: #c297ff; 450 | --color-scale-purple-4: #a475f9; 451 | --color-scale-purple-5: #8250df; 452 | --color-scale-purple-6: #6639ba; 453 | --color-scale-purple-7: #512a97; 454 | --color-scale-purple-8: #3e1f79; 455 | --color-scale-purple-9: #2e1461; 456 | --color-scale-pink-0: #ffeff7; 457 | --color-scale-pink-1: #ffd3eb; 458 | --color-scale-pink-2: #ffadda; 459 | --color-scale-pink-3: #ff80c8; 460 | --color-scale-pink-4: #e85aad; 461 | --color-scale-pink-5: #bf3989; 462 | --color-scale-pink-6: #99286e; 463 | --color-scale-pink-7: #772057; 464 | --color-scale-pink-8: #611347; 465 | --color-scale-pink-9: #4d0336; 466 | --color-scale-coral-0: #fff0eb; 467 | --color-scale-coral-1: #ffd6cc; 468 | --color-scale-coral-2: #ffb4a1; 469 | --color-scale-coral-3: #fd8c73; 470 | --color-scale-coral-4: #ec6547; 471 | --color-scale-coral-5: #c4432b; 472 | --color-scale-coral-6: #9e2f1c; 473 | --color-scale-coral-7: #801f0f; 474 | --color-scale-coral-8: #691105; 475 | --color-scale-coral-9: #510901; 476 | } 477 | -------------------------------------------------------------------------------- /test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "pixelmatch": "^5.3.0", 9 | "pngjs": "^7.0.0", 10 | "puppeteer": "^22.0.0" 11 | } 12 | }, 13 | "node_modules/@babel/code-frame": { 14 | "version": "7.23.5", 15 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", 16 | "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", 17 | "dependencies": { 18 | "@babel/highlight": "^7.23.4", 19 | "chalk": "^2.4.2" 20 | }, 21 | "engines": { 22 | "node": ">=6.9.0" 23 | } 24 | }, 25 | "node_modules/@babel/helper-validator-identifier": { 26 | "version": "7.22.20", 27 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", 28 | "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", 29 | "engines": { 30 | "node": ">=6.9.0" 31 | } 32 | }, 33 | "node_modules/@babel/highlight": { 34 | "version": "7.23.4", 35 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", 36 | "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", 37 | "dependencies": { 38 | "@babel/helper-validator-identifier": "^7.22.20", 39 | "chalk": "^2.4.2", 40 | "js-tokens": "^4.0.0" 41 | }, 42 | "engines": { 43 | "node": ">=6.9.0" 44 | } 45 | }, 46 | "node_modules/@puppeteer/browsers": { 47 | "version": "2.0.0", 48 | "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.0.0.tgz", 49 | "integrity": "sha512-3PS82/5+tnpEaUWonjAFFvlf35QHF15xqyGd34GBa5oP5EPVfFXRsbSxIGYf1M+vZlqBZ3oxT1kRg9OYhtt8ng==", 50 | "dependencies": { 51 | "debug": "4.3.4", 52 | "extract-zip": "2.0.1", 53 | "progress": "2.0.3", 54 | "proxy-agent": "6.3.1", 55 | "tar-fs": "3.0.4", 56 | "unbzip2-stream": "1.4.3", 57 | "yargs": "17.7.2" 58 | }, 59 | "bin": { 60 | "browsers": "lib/cjs/main-cli.js" 61 | }, 62 | "engines": { 63 | "node": ">=18" 64 | } 65 | }, 66 | "node_modules/@tootallnate/quickjs-emscripten": { 67 | "version": "0.23.0", 68 | "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", 69 | "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" 70 | }, 71 | "node_modules/@types/node": { 72 | "version": "20.11.19", 73 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", 74 | "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", 75 | "optional": true, 76 | "dependencies": { 77 | "undici-types": "~5.26.4" 78 | } 79 | }, 80 | "node_modules/@types/yauzl": { 81 | "version": "2.10.3", 82 | "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", 83 | "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", 84 | "optional": true, 85 | "dependencies": { 86 | "@types/node": "*" 87 | } 88 | }, 89 | "node_modules/agent-base": { 90 | "version": "7.1.0", 91 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", 92 | "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", 93 | "dependencies": { 94 | "debug": "^4.3.4" 95 | }, 96 | "engines": { 97 | "node": ">= 14" 98 | } 99 | }, 100 | "node_modules/ansi-regex": { 101 | "version": "5.0.1", 102 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 103 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 104 | "engines": { 105 | "node": ">=8" 106 | } 107 | }, 108 | "node_modules/ansi-styles": { 109 | "version": "3.2.1", 110 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 111 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 112 | "dependencies": { 113 | "color-convert": "^1.9.0" 114 | }, 115 | "engines": { 116 | "node": ">=4" 117 | } 118 | }, 119 | "node_modules/argparse": { 120 | "version": "2.0.1", 121 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 122 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" 123 | }, 124 | "node_modules/ast-types": { 125 | "version": "0.13.4", 126 | "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", 127 | "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", 128 | "dependencies": { 129 | "tslib": "^2.0.1" 130 | }, 131 | "engines": { 132 | "node": ">=4" 133 | } 134 | }, 135 | "node_modules/b4a": { 136 | "version": "1.6.6", 137 | "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", 138 | "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" 139 | }, 140 | "node_modules/bare-events": { 141 | "version": "2.2.0", 142 | "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz", 143 | "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==", 144 | "optional": true 145 | }, 146 | "node_modules/base64-js": { 147 | "version": "1.5.1", 148 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 149 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 150 | "funding": [ 151 | { 152 | "type": "github", 153 | "url": "https://github.com/sponsors/feross" 154 | }, 155 | { 156 | "type": "patreon", 157 | "url": "https://www.patreon.com/feross" 158 | }, 159 | { 160 | "type": "consulting", 161 | "url": "https://feross.org/support" 162 | } 163 | ] 164 | }, 165 | "node_modules/basic-ftp": { 166 | "version": "5.0.4", 167 | "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", 168 | "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", 169 | "engines": { 170 | "node": ">=10.0.0" 171 | } 172 | }, 173 | "node_modules/buffer": { 174 | "version": "5.7.1", 175 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 176 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 177 | "funding": [ 178 | { 179 | "type": "github", 180 | "url": "https://github.com/sponsors/feross" 181 | }, 182 | { 183 | "type": "patreon", 184 | "url": "https://www.patreon.com/feross" 185 | }, 186 | { 187 | "type": "consulting", 188 | "url": "https://feross.org/support" 189 | } 190 | ], 191 | "dependencies": { 192 | "base64-js": "^1.3.1", 193 | "ieee754": "^1.1.13" 194 | } 195 | }, 196 | "node_modules/buffer-crc32": { 197 | "version": "0.2.13", 198 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 199 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 200 | "engines": { 201 | "node": "*" 202 | } 203 | }, 204 | "node_modules/callsites": { 205 | "version": "3.1.0", 206 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 207 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 208 | "engines": { 209 | "node": ">=6" 210 | } 211 | }, 212 | "node_modules/chalk": { 213 | "version": "2.4.2", 214 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 215 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 216 | "dependencies": { 217 | "ansi-styles": "^3.2.1", 218 | "escape-string-regexp": "^1.0.5", 219 | "supports-color": "^5.3.0" 220 | }, 221 | "engines": { 222 | "node": ">=4" 223 | } 224 | }, 225 | "node_modules/chromium-bidi": { 226 | "version": "0.5.8", 227 | "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.8.tgz", 228 | "integrity": "sha512-blqh+1cEQbHBKmok3rVJkBlBxt9beKBgOsxbFgs7UJcoVbbeZ+K7+6liAsjgpc8l1Xd55cQUy14fXZdGSb4zIw==", 229 | "dependencies": { 230 | "mitt": "3.0.1", 231 | "urlpattern-polyfill": "10.0.0" 232 | }, 233 | "peerDependencies": { 234 | "devtools-protocol": "*" 235 | } 236 | }, 237 | "node_modules/cliui": { 238 | "version": "8.0.1", 239 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 240 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 241 | "dependencies": { 242 | "string-width": "^4.2.0", 243 | "strip-ansi": "^6.0.1", 244 | "wrap-ansi": "^7.0.0" 245 | }, 246 | "engines": { 247 | "node": ">=12" 248 | } 249 | }, 250 | "node_modules/color-convert": { 251 | "version": "1.9.3", 252 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 253 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 254 | "dependencies": { 255 | "color-name": "1.1.3" 256 | } 257 | }, 258 | "node_modules/color-name": { 259 | "version": "1.1.3", 260 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 261 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 262 | }, 263 | "node_modules/cosmiconfig": { 264 | "version": "9.0.0", 265 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", 266 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", 267 | "dependencies": { 268 | "env-paths": "^2.2.1", 269 | "import-fresh": "^3.3.0", 270 | "js-yaml": "^4.1.0", 271 | "parse-json": "^5.2.0" 272 | }, 273 | "engines": { 274 | "node": ">=14" 275 | }, 276 | "funding": { 277 | "url": "https://github.com/sponsors/d-fischer" 278 | }, 279 | "peerDependencies": { 280 | "typescript": ">=4.9.5" 281 | }, 282 | "peerDependenciesMeta": { 283 | "typescript": { 284 | "optional": true 285 | } 286 | } 287 | }, 288 | "node_modules/cross-fetch": { 289 | "version": "4.0.0", 290 | "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", 291 | "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", 292 | "dependencies": { 293 | "node-fetch": "^2.6.12" 294 | } 295 | }, 296 | "node_modules/data-uri-to-buffer": { 297 | "version": "6.0.2", 298 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", 299 | "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", 300 | "engines": { 301 | "node": ">= 14" 302 | } 303 | }, 304 | "node_modules/debug": { 305 | "version": "4.3.4", 306 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 307 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 308 | "dependencies": { 309 | "ms": "2.1.2" 310 | }, 311 | "engines": { 312 | "node": ">=6.0" 313 | }, 314 | "peerDependenciesMeta": { 315 | "supports-color": { 316 | "optional": true 317 | } 318 | } 319 | }, 320 | "node_modules/degenerator": { 321 | "version": "5.0.1", 322 | "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", 323 | "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", 324 | "dependencies": { 325 | "ast-types": "^0.13.4", 326 | "escodegen": "^2.1.0", 327 | "esprima": "^4.0.1" 328 | }, 329 | "engines": { 330 | "node": ">= 14" 331 | } 332 | }, 333 | "node_modules/devtools-protocol": { 334 | "version": "0.0.1232444", 335 | "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", 336 | "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==" 337 | }, 338 | "node_modules/emoji-regex": { 339 | "version": "8.0.0", 340 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 341 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 342 | }, 343 | "node_modules/end-of-stream": { 344 | "version": "1.4.4", 345 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 346 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 347 | "dependencies": { 348 | "once": "^1.4.0" 349 | } 350 | }, 351 | "node_modules/env-paths": { 352 | "version": "2.2.1", 353 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", 354 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", 355 | "engines": { 356 | "node": ">=6" 357 | } 358 | }, 359 | "node_modules/error-ex": { 360 | "version": "1.3.2", 361 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 362 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 363 | "dependencies": { 364 | "is-arrayish": "^0.2.1" 365 | } 366 | }, 367 | "node_modules/escalade": { 368 | "version": "3.1.2", 369 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", 370 | "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", 371 | "engines": { 372 | "node": ">=6" 373 | } 374 | }, 375 | "node_modules/escape-string-regexp": { 376 | "version": "1.0.5", 377 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 378 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 379 | "engines": { 380 | "node": ">=0.8.0" 381 | } 382 | }, 383 | "node_modules/escodegen": { 384 | "version": "2.1.0", 385 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", 386 | "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", 387 | "dependencies": { 388 | "esprima": "^4.0.1", 389 | "estraverse": "^5.2.0", 390 | "esutils": "^2.0.2" 391 | }, 392 | "bin": { 393 | "escodegen": "bin/escodegen.js", 394 | "esgenerate": "bin/esgenerate.js" 395 | }, 396 | "engines": { 397 | "node": ">=6.0" 398 | }, 399 | "optionalDependencies": { 400 | "source-map": "~0.6.1" 401 | } 402 | }, 403 | "node_modules/esprima": { 404 | "version": "4.0.1", 405 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 406 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 407 | "bin": { 408 | "esparse": "bin/esparse.js", 409 | "esvalidate": "bin/esvalidate.js" 410 | }, 411 | "engines": { 412 | "node": ">=4" 413 | } 414 | }, 415 | "node_modules/estraverse": { 416 | "version": "5.3.0", 417 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 418 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 419 | "engines": { 420 | "node": ">=4.0" 421 | } 422 | }, 423 | "node_modules/esutils": { 424 | "version": "2.0.3", 425 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 426 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 427 | "engines": { 428 | "node": ">=0.10.0" 429 | } 430 | }, 431 | "node_modules/extract-zip": { 432 | "version": "2.0.1", 433 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", 434 | "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", 435 | "dependencies": { 436 | "debug": "^4.1.1", 437 | "get-stream": "^5.1.0", 438 | "yauzl": "^2.10.0" 439 | }, 440 | "bin": { 441 | "extract-zip": "cli.js" 442 | }, 443 | "engines": { 444 | "node": ">= 10.17.0" 445 | }, 446 | "optionalDependencies": { 447 | "@types/yauzl": "^2.9.1" 448 | } 449 | }, 450 | "node_modules/fast-fifo": { 451 | "version": "1.3.2", 452 | "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", 453 | "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" 454 | }, 455 | "node_modules/fd-slicer": { 456 | "version": "1.1.0", 457 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 458 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", 459 | "dependencies": { 460 | "pend": "~1.2.0" 461 | } 462 | }, 463 | "node_modules/fs-extra": { 464 | "version": "11.2.0", 465 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", 466 | "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", 467 | "dependencies": { 468 | "graceful-fs": "^4.2.0", 469 | "jsonfile": "^6.0.1", 470 | "universalify": "^2.0.0" 471 | }, 472 | "engines": { 473 | "node": ">=14.14" 474 | } 475 | }, 476 | "node_modules/get-caller-file": { 477 | "version": "2.0.5", 478 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 479 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 480 | "engines": { 481 | "node": "6.* || 8.* || >= 10.*" 482 | } 483 | }, 484 | "node_modules/get-stream": { 485 | "version": "5.2.0", 486 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 487 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 488 | "dependencies": { 489 | "pump": "^3.0.0" 490 | }, 491 | "engines": { 492 | "node": ">=8" 493 | }, 494 | "funding": { 495 | "url": "https://github.com/sponsors/sindresorhus" 496 | } 497 | }, 498 | "node_modules/get-uri": { 499 | "version": "6.0.3", 500 | "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", 501 | "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", 502 | "dependencies": { 503 | "basic-ftp": "^5.0.2", 504 | "data-uri-to-buffer": "^6.0.2", 505 | "debug": "^4.3.4", 506 | "fs-extra": "^11.2.0" 507 | }, 508 | "engines": { 509 | "node": ">= 14" 510 | } 511 | }, 512 | "node_modules/graceful-fs": { 513 | "version": "4.2.11", 514 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 515 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" 516 | }, 517 | "node_modules/has-flag": { 518 | "version": "3.0.0", 519 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 520 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 521 | "engines": { 522 | "node": ">=4" 523 | } 524 | }, 525 | "node_modules/http-proxy-agent": { 526 | "version": "7.0.2", 527 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", 528 | "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", 529 | "dependencies": { 530 | "agent-base": "^7.1.0", 531 | "debug": "^4.3.4" 532 | }, 533 | "engines": { 534 | "node": ">= 14" 535 | } 536 | }, 537 | "node_modules/https-proxy-agent": { 538 | "version": "7.0.4", 539 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", 540 | "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", 541 | "dependencies": { 542 | "agent-base": "^7.0.2", 543 | "debug": "4" 544 | }, 545 | "engines": { 546 | "node": ">= 14" 547 | } 548 | }, 549 | "node_modules/ieee754": { 550 | "version": "1.2.1", 551 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 552 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 553 | "funding": [ 554 | { 555 | "type": "github", 556 | "url": "https://github.com/sponsors/feross" 557 | }, 558 | { 559 | "type": "patreon", 560 | "url": "https://www.patreon.com/feross" 561 | }, 562 | { 563 | "type": "consulting", 564 | "url": "https://feross.org/support" 565 | } 566 | ] 567 | }, 568 | "node_modules/import-fresh": { 569 | "version": "3.3.0", 570 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 571 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 572 | "dependencies": { 573 | "parent-module": "^1.0.0", 574 | "resolve-from": "^4.0.0" 575 | }, 576 | "engines": { 577 | "node": ">=6" 578 | }, 579 | "funding": { 580 | "url": "https://github.com/sponsors/sindresorhus" 581 | } 582 | }, 583 | "node_modules/ip-address": { 584 | "version": "9.0.5", 585 | "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", 586 | "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", 587 | "dependencies": { 588 | "jsbn": "1.1.0", 589 | "sprintf-js": "^1.1.3" 590 | }, 591 | "engines": { 592 | "node": ">= 12" 593 | } 594 | }, 595 | "node_modules/is-arrayish": { 596 | "version": "0.2.1", 597 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 598 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" 599 | }, 600 | "node_modules/is-fullwidth-code-point": { 601 | "version": "3.0.0", 602 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 603 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 604 | "engines": { 605 | "node": ">=8" 606 | } 607 | }, 608 | "node_modules/js-tokens": { 609 | "version": "4.0.0", 610 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 611 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 612 | }, 613 | "node_modules/js-yaml": { 614 | "version": "4.1.0", 615 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 616 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 617 | "dependencies": { 618 | "argparse": "^2.0.1" 619 | }, 620 | "bin": { 621 | "js-yaml": "bin/js-yaml.js" 622 | } 623 | }, 624 | "node_modules/jsbn": { 625 | "version": "1.1.0", 626 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", 627 | "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" 628 | }, 629 | "node_modules/json-parse-even-better-errors": { 630 | "version": "2.3.1", 631 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 632 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" 633 | }, 634 | "node_modules/jsonfile": { 635 | "version": "6.1.0", 636 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 637 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 638 | "dependencies": { 639 | "universalify": "^2.0.0" 640 | }, 641 | "optionalDependencies": { 642 | "graceful-fs": "^4.1.6" 643 | } 644 | }, 645 | "node_modules/lines-and-columns": { 646 | "version": "1.2.4", 647 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 648 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" 649 | }, 650 | "node_modules/lru-cache": { 651 | "version": "7.18.3", 652 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", 653 | "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", 654 | "engines": { 655 | "node": ">=12" 656 | } 657 | }, 658 | "node_modules/mitt": { 659 | "version": "3.0.1", 660 | "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", 661 | "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" 662 | }, 663 | "node_modules/mkdirp-classic": { 664 | "version": "0.5.3", 665 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 666 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" 667 | }, 668 | "node_modules/ms": { 669 | "version": "2.1.2", 670 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 671 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 672 | }, 673 | "node_modules/netmask": { 674 | "version": "2.0.2", 675 | "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", 676 | "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", 677 | "engines": { 678 | "node": ">= 0.4.0" 679 | } 680 | }, 681 | "node_modules/node-fetch": { 682 | "version": "2.7.0", 683 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 684 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 685 | "dependencies": { 686 | "whatwg-url": "^5.0.0" 687 | }, 688 | "engines": { 689 | "node": "4.x || >=6.0.0" 690 | }, 691 | "peerDependencies": { 692 | "encoding": "^0.1.0" 693 | }, 694 | "peerDependenciesMeta": { 695 | "encoding": { 696 | "optional": true 697 | } 698 | } 699 | }, 700 | "node_modules/once": { 701 | "version": "1.4.0", 702 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 703 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 704 | "dependencies": { 705 | "wrappy": "1" 706 | } 707 | }, 708 | "node_modules/pac-proxy-agent": { 709 | "version": "7.0.1", 710 | "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", 711 | "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", 712 | "dependencies": { 713 | "@tootallnate/quickjs-emscripten": "^0.23.0", 714 | "agent-base": "^7.0.2", 715 | "debug": "^4.3.4", 716 | "get-uri": "^6.0.1", 717 | "http-proxy-agent": "^7.0.0", 718 | "https-proxy-agent": "^7.0.2", 719 | "pac-resolver": "^7.0.0", 720 | "socks-proxy-agent": "^8.0.2" 721 | }, 722 | "engines": { 723 | "node": ">= 14" 724 | } 725 | }, 726 | "node_modules/pac-resolver": { 727 | "version": "7.0.1", 728 | "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", 729 | "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", 730 | "dependencies": { 731 | "degenerator": "^5.0.0", 732 | "netmask": "^2.0.2" 733 | }, 734 | "engines": { 735 | "node": ">= 14" 736 | } 737 | }, 738 | "node_modules/parent-module": { 739 | "version": "1.0.1", 740 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 741 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 742 | "dependencies": { 743 | "callsites": "^3.0.0" 744 | }, 745 | "engines": { 746 | "node": ">=6" 747 | } 748 | }, 749 | "node_modules/parse-json": { 750 | "version": "5.2.0", 751 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 752 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 753 | "dependencies": { 754 | "@babel/code-frame": "^7.0.0", 755 | "error-ex": "^1.3.1", 756 | "json-parse-even-better-errors": "^2.3.0", 757 | "lines-and-columns": "^1.1.6" 758 | }, 759 | "engines": { 760 | "node": ">=8" 761 | }, 762 | "funding": { 763 | "url": "https://github.com/sponsors/sindresorhus" 764 | } 765 | }, 766 | "node_modules/pend": { 767 | "version": "1.2.0", 768 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 769 | "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" 770 | }, 771 | "node_modules/pixelmatch": { 772 | "version": "5.3.0", 773 | "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", 774 | "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", 775 | "dependencies": { 776 | "pngjs": "^6.0.0" 777 | }, 778 | "bin": { 779 | "pixelmatch": "bin/pixelmatch" 780 | } 781 | }, 782 | "node_modules/pixelmatch/node_modules/pngjs": { 783 | "version": "6.0.0", 784 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", 785 | "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", 786 | "engines": { 787 | "node": ">=12.13.0" 788 | } 789 | }, 790 | "node_modules/pngjs": { 791 | "version": "7.0.0", 792 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", 793 | "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", 794 | "engines": { 795 | "node": ">=14.19.0" 796 | } 797 | }, 798 | "node_modules/progress": { 799 | "version": "2.0.3", 800 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 801 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 802 | "engines": { 803 | "node": ">=0.4.0" 804 | } 805 | }, 806 | "node_modules/proxy-agent": { 807 | "version": "6.3.1", 808 | "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", 809 | "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", 810 | "dependencies": { 811 | "agent-base": "^7.0.2", 812 | "debug": "^4.3.4", 813 | "http-proxy-agent": "^7.0.0", 814 | "https-proxy-agent": "^7.0.2", 815 | "lru-cache": "^7.14.1", 816 | "pac-proxy-agent": "^7.0.1", 817 | "proxy-from-env": "^1.1.0", 818 | "socks-proxy-agent": "^8.0.2" 819 | }, 820 | "engines": { 821 | "node": ">= 14" 822 | } 823 | }, 824 | "node_modules/proxy-from-env": { 825 | "version": "1.1.0", 826 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 827 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 828 | }, 829 | "node_modules/pump": { 830 | "version": "3.0.0", 831 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 832 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 833 | "dependencies": { 834 | "end-of-stream": "^1.1.0", 835 | "once": "^1.3.1" 836 | } 837 | }, 838 | "node_modules/puppeteer": { 839 | "version": "22.0.0", 840 | "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.0.0.tgz", 841 | "integrity": "sha512-zYVnjwJngnSB4dbkWp7DHFSIc3nqHvZzrdHyo9+ugV1nq1Lm8obOMcmCFaGfR3PJs0EmYNz+/skBeO45yvASCQ==", 842 | "hasInstallScript": true, 843 | "dependencies": { 844 | "@puppeteer/browsers": "2.0.0", 845 | "cosmiconfig": "9.0.0", 846 | "puppeteer-core": "22.0.0" 847 | }, 848 | "bin": { 849 | "puppeteer": "lib/esm/puppeteer/node/cli.js" 850 | }, 851 | "engines": { 852 | "node": ">=18" 853 | } 854 | }, 855 | "node_modules/puppeteer-core": { 856 | "version": "22.0.0", 857 | "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.0.0.tgz", 858 | "integrity": "sha512-S3s91rLde0A86PWVeNY82h+P0fdS7CTiNWAicCVH/bIspRP4nS2PnO5j+VTFqCah0ZJizGzpVPAmxVYbLxTc9w==", 859 | "dependencies": { 860 | "@puppeteer/browsers": "2.0.0", 861 | "chromium-bidi": "0.5.8", 862 | "cross-fetch": "4.0.0", 863 | "debug": "4.3.4", 864 | "devtools-protocol": "0.0.1232444", 865 | "ws": "8.16.0" 866 | }, 867 | "engines": { 868 | "node": ">=18" 869 | } 870 | }, 871 | "node_modules/queue-tick": { 872 | "version": "1.0.1", 873 | "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", 874 | "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" 875 | }, 876 | "node_modules/require-directory": { 877 | "version": "2.1.1", 878 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 879 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 880 | "engines": { 881 | "node": ">=0.10.0" 882 | } 883 | }, 884 | "node_modules/resolve-from": { 885 | "version": "4.0.0", 886 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 887 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 888 | "engines": { 889 | "node": ">=4" 890 | } 891 | }, 892 | "node_modules/smart-buffer": { 893 | "version": "4.2.0", 894 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", 895 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", 896 | "engines": { 897 | "node": ">= 6.0.0", 898 | "npm": ">= 3.0.0" 899 | } 900 | }, 901 | "node_modules/socks": { 902 | "version": "2.7.3", 903 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", 904 | "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", 905 | "dependencies": { 906 | "ip-address": "^9.0.5", 907 | "smart-buffer": "^4.2.0" 908 | }, 909 | "engines": { 910 | "node": ">= 10.0.0", 911 | "npm": ">= 3.0.0" 912 | } 913 | }, 914 | "node_modules/socks-proxy-agent": { 915 | "version": "8.0.2", 916 | "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", 917 | "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", 918 | "dependencies": { 919 | "agent-base": "^7.0.2", 920 | "debug": "^4.3.4", 921 | "socks": "^2.7.1" 922 | }, 923 | "engines": { 924 | "node": ">= 14" 925 | } 926 | }, 927 | "node_modules/source-map": { 928 | "version": "0.6.1", 929 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 930 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 931 | "optional": true, 932 | "engines": { 933 | "node": ">=0.10.0" 934 | } 935 | }, 936 | "node_modules/sprintf-js": { 937 | "version": "1.1.3", 938 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", 939 | "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" 940 | }, 941 | "node_modules/streamx": { 942 | "version": "2.15.8", 943 | "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.8.tgz", 944 | "integrity": "sha512-6pwMeMY/SuISiRsuS8TeIrAzyFbG5gGPHFQsYjUr/pbBadaL1PCWmzKw+CHZSwainfvcF6Si6cVLq4XTEwswFQ==", 945 | "dependencies": { 946 | "fast-fifo": "^1.1.0", 947 | "queue-tick": "^1.0.1" 948 | }, 949 | "optionalDependencies": { 950 | "bare-events": "^2.2.0" 951 | } 952 | }, 953 | "node_modules/string-width": { 954 | "version": "4.2.3", 955 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 956 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 957 | "dependencies": { 958 | "emoji-regex": "^8.0.0", 959 | "is-fullwidth-code-point": "^3.0.0", 960 | "strip-ansi": "^6.0.1" 961 | }, 962 | "engines": { 963 | "node": ">=8" 964 | } 965 | }, 966 | "node_modules/strip-ansi": { 967 | "version": "6.0.1", 968 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 969 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 970 | "dependencies": { 971 | "ansi-regex": "^5.0.1" 972 | }, 973 | "engines": { 974 | "node": ">=8" 975 | } 976 | }, 977 | "node_modules/supports-color": { 978 | "version": "5.5.0", 979 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 980 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 981 | "dependencies": { 982 | "has-flag": "^3.0.0" 983 | }, 984 | "engines": { 985 | "node": ">=4" 986 | } 987 | }, 988 | "node_modules/tar-fs": { 989 | "version": "3.0.4", 990 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", 991 | "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", 992 | "dependencies": { 993 | "mkdirp-classic": "^0.5.2", 994 | "pump": "^3.0.0", 995 | "tar-stream": "^3.1.5" 996 | } 997 | }, 998 | "node_modules/tar-stream": { 999 | "version": "3.1.7", 1000 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", 1001 | "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", 1002 | "dependencies": { 1003 | "b4a": "^1.6.4", 1004 | "fast-fifo": "^1.2.0", 1005 | "streamx": "^2.15.0" 1006 | } 1007 | }, 1008 | "node_modules/through": { 1009 | "version": "2.3.8", 1010 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1011 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" 1012 | }, 1013 | "node_modules/tr46": { 1014 | "version": "0.0.3", 1015 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1016 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 1017 | }, 1018 | "node_modules/tslib": { 1019 | "version": "2.6.2", 1020 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 1021 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" 1022 | }, 1023 | "node_modules/unbzip2-stream": { 1024 | "version": "1.4.3", 1025 | "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", 1026 | "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", 1027 | "dependencies": { 1028 | "buffer": "^5.2.1", 1029 | "through": "^2.3.8" 1030 | } 1031 | }, 1032 | "node_modules/undici-types": { 1033 | "version": "5.26.5", 1034 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1035 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1036 | "optional": true 1037 | }, 1038 | "node_modules/universalify": { 1039 | "version": "2.0.1", 1040 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 1041 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 1042 | "engines": { 1043 | "node": ">= 10.0.0" 1044 | } 1045 | }, 1046 | "node_modules/urlpattern-polyfill": { 1047 | "version": "10.0.0", 1048 | "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", 1049 | "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==" 1050 | }, 1051 | "node_modules/webidl-conversions": { 1052 | "version": "3.0.1", 1053 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1054 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 1055 | }, 1056 | "node_modules/whatwg-url": { 1057 | "version": "5.0.0", 1058 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1059 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1060 | "dependencies": { 1061 | "tr46": "~0.0.3", 1062 | "webidl-conversions": "^3.0.0" 1063 | } 1064 | }, 1065 | "node_modules/wrap-ansi": { 1066 | "version": "7.0.0", 1067 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1068 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1069 | "dependencies": { 1070 | "ansi-styles": "^4.0.0", 1071 | "string-width": "^4.1.0", 1072 | "strip-ansi": "^6.0.0" 1073 | }, 1074 | "engines": { 1075 | "node": ">=10" 1076 | }, 1077 | "funding": { 1078 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1079 | } 1080 | }, 1081 | "node_modules/wrap-ansi/node_modules/ansi-styles": { 1082 | "version": "4.3.0", 1083 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1084 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1085 | "dependencies": { 1086 | "color-convert": "^2.0.1" 1087 | }, 1088 | "engines": { 1089 | "node": ">=8" 1090 | }, 1091 | "funding": { 1092 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1093 | } 1094 | }, 1095 | "node_modules/wrap-ansi/node_modules/color-convert": { 1096 | "version": "2.0.1", 1097 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1098 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1099 | "dependencies": { 1100 | "color-name": "~1.1.4" 1101 | }, 1102 | "engines": { 1103 | "node": ">=7.0.0" 1104 | } 1105 | }, 1106 | "node_modules/wrap-ansi/node_modules/color-name": { 1107 | "version": "1.1.4", 1108 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1109 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1110 | }, 1111 | "node_modules/wrappy": { 1112 | "version": "1.0.2", 1113 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1114 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 1115 | }, 1116 | "node_modules/ws": { 1117 | "version": "8.16.0", 1118 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", 1119 | "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", 1120 | "engines": { 1121 | "node": ">=10.0.0" 1122 | }, 1123 | "peerDependencies": { 1124 | "bufferutil": "^4.0.1", 1125 | "utf-8-validate": ">=5.0.2" 1126 | }, 1127 | "peerDependenciesMeta": { 1128 | "bufferutil": { 1129 | "optional": true 1130 | }, 1131 | "utf-8-validate": { 1132 | "optional": true 1133 | } 1134 | } 1135 | }, 1136 | "node_modules/y18n": { 1137 | "version": "5.0.8", 1138 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1139 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1140 | "engines": { 1141 | "node": ">=10" 1142 | } 1143 | }, 1144 | "node_modules/yargs": { 1145 | "version": "17.7.2", 1146 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1147 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1148 | "dependencies": { 1149 | "cliui": "^8.0.1", 1150 | "escalade": "^3.1.1", 1151 | "get-caller-file": "^2.0.5", 1152 | "require-directory": "^2.1.1", 1153 | "string-width": "^4.2.3", 1154 | "y18n": "^5.0.5", 1155 | "yargs-parser": "^21.1.1" 1156 | }, 1157 | "engines": { 1158 | "node": ">=12" 1159 | } 1160 | }, 1161 | "node_modules/yargs-parser": { 1162 | "version": "21.1.1", 1163 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1164 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1165 | "engines": { 1166 | "node": ">=12" 1167 | } 1168 | }, 1169 | "node_modules/yauzl": { 1170 | "version": "2.10.0", 1171 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 1172 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", 1173 | "dependencies": { 1174 | "buffer-crc32": "~0.2.3", 1175 | "fd-slicer": "~1.1.0" 1176 | } 1177 | } 1178 | } 1179 | } 1180 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "node test" 4 | }, 5 | "dependencies": { 6 | "pixelmatch": "^5.3.0", 7 | "pngjs": "^7.0.0", 8 | "puppeteer": "^22.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/sample/README.md: -------------------------------------------------------------------------------- 1 | # Header 2 | `inline code` 3 | 4 | ### Code block 5 | ```javascript 6 | // Line comment 7 | const foo = 'bar'; 8 | 9 | /** 10 | * Block comment 11 | */ 12 | function greetPerson(name) { 13 | return `Hello ${name}.`; // inline comment 14 | } 15 | 16 | const reallyLongFunctionNameToTestLineWrapping = reallyLongParameterNameToTestLineWrapping => console.log(`Hello ${reallyLongParameterNameToTestLineWrapping}`); 17 | ``` 18 | 19 | ### Image 20 | 21 | -------------------------------------------------------------------------------- /test/sample/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/test/sample/image.png -------------------------------------------------------------------------------- /test/screenshots/folder-root-expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/test/screenshots/folder-root-expected.png -------------------------------------------------------------------------------- /test/screenshots/project-root-expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/test/screenshots/project-root-expected.png -------------------------------------------------------------------------------- /test/screenshots/readme-file-expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/test/screenshots/readme-file-expected.png -------------------------------------------------------------------------------- /test/screenshots/wiki-expected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jerry1100/github-markdown-printer/8962d569bdc9d294084925b57c5ade3027831414/test/screenshots/wiki-expected.png -------------------------------------------------------------------------------- /test/test-case.js: -------------------------------------------------------------------------------- 1 | class TestCase { 2 | constructor(testName, urlToTest) { 3 | this.testName = testName; 4 | this.urlToTest = urlToTest; 5 | } 6 | } 7 | 8 | module.exports = TestCase; 9 | -------------------------------------------------------------------------------- /test/test-runner.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const puppeteer = require('puppeteer'); 4 | const { PNG } = require('pngjs'); 5 | const pixelMatch = require('pixelmatch'); 6 | 7 | const SCREENSHOTS_DIR = path.join(__dirname, 'screenshots'); 8 | const STYLE_CSS_PATH = path.join(__dirname, '..', 'src', 'style.css'); 9 | 10 | if (!fs.existsSync(SCREENSHOTS_DIR)) { 11 | fs.mkdirSync(SCREENSHOTS_DIR); 12 | } 13 | 14 | class TestRunner { 15 | constructor(testName, urlToTest) { 16 | this.urlToTest = urlToTest; 17 | 18 | const baseScreenshotName = testName.toLowerCase().replace(/\s+/g, '-'); 19 | this.expectedScreenshotPath = path.join( 20 | SCREENSHOTS_DIR, 21 | `${baseScreenshotName}-expected.png` 22 | ); 23 | this.actualScreenshotPath = path.join( 24 | SCREENSHOTS_DIR, 25 | `${baseScreenshotName}-actual.png` 26 | ); 27 | this.diffScreenshotPath = path.join( 28 | SCREENSHOTS_DIR, 29 | `${baseScreenshotName}-diff.png` 30 | ); 31 | } 32 | 33 | async takeScreenshotAndSaveToFs() { 34 | const browser = await puppeteer.launch({ 35 | args: ['--no-sandbox', '--disable-setuid-sandbox'], 36 | }); 37 | const page = await browser.newPage(); 38 | 39 | await page.setViewport({ width: 1200, height: 800 }); 40 | await page.goto(this.urlToTest); 41 | await page.addStyleTag({ path: STYLE_CSS_PATH }); 42 | await page.evaluate(this.replaceBodyHtmlWithMarkdown); 43 | await page.emulateMediaType('print'); 44 | await page.screenshot({ path: this.actualScreenshotPath }); 45 | await browser.close(); 46 | 47 | return this.actualScreenshotPath; 48 | } 49 | 50 | async replaceBodyHtmlWithMarkdown() { 51 | document.body.innerHTML = 52 | document.querySelector('.markdown-body').outerHTML; 53 | } 54 | 55 | async doesScreenshotMatchExpectedAndGenerateDiff(actualScreenshotPath) { 56 | const expectedScreenshot = this.getScreenshotData( 57 | this.expectedScreenshotPath 58 | ); 59 | const actualScreenshot = this.getScreenshotData(actualScreenshotPath); 60 | const numDiffPixels = this.generateDiffScreenshot( 61 | expectedScreenshot, 62 | actualScreenshot 63 | ); 64 | 65 | return numDiffPixels; 66 | } 67 | 68 | getScreenshotData(screenshotPath) { 69 | return PNG.sync.read(fs.readFileSync(screenshotPath)); 70 | } 71 | 72 | generateDiffScreenshot(expectedScreenshot, actualScreenshot) { 73 | const { width, height } = expectedScreenshot; 74 | const diffScreenshot = new PNG({ width, height }); 75 | const numDiffPixels = pixelMatch( 76 | expectedScreenshot.data, 77 | actualScreenshot.data, 78 | diffScreenshot.data, 79 | width, 80 | height, 81 | { threshold: 0.2 } 82 | ); 83 | 84 | fs.writeFileSync(this.diffScreenshotPath, PNG.sync.write(diffScreenshot)); 85 | 86 | return numDiffPixels; 87 | } 88 | } 89 | 90 | module.exports = TestRunner; 91 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const TestCase = require('./test-case'); 2 | const TestRunner = require('./test-runner'); 3 | 4 | const testCases = [ 5 | new TestCase( 6 | 'project root', 7 | 'https://github.com/jerry1100/messenger-dark-theme' 8 | ), 9 | new TestCase( 10 | 'folder root', 11 | 'https://github.com/jerry1100/github-markdown-printer/tree/master/test/sample' 12 | ), 13 | new TestCase( 14 | 'readme file', 15 | 'https://github.com/jerry1100/github-markdown-printer/blob/master/test/sample/README.md' 16 | ), 17 | new TestCase( 18 | 'wiki', 19 | 'https://github.com/jerry1100/github-markdown-printer/wiki' 20 | ), 21 | ]; 22 | 23 | (async () => { 24 | const testResults = await getTestResults(testCases); 25 | const didTestsPass = testResults.every((didPass) => didPass); 26 | 27 | process.exit(didTestsPass ? 0 : 1); 28 | })(); 29 | 30 | async function getTestResults(testCases) { 31 | const results = testCases.map( 32 | async ({ testName, urlToTest }) => await tryRunTest(testName, urlToTest) 33 | ); 34 | 35 | return await Promise.all(results); 36 | } 37 | 38 | async function tryRunTest(testName, urlToTest) { 39 | return new Promise(async (resolve) => { 40 | setTimeout(() => { 41 | console.error(`[${testName}] Test timed out`); 42 | resolve(false); 43 | }, 15000); 44 | 45 | try { 46 | resolve(await runTest(testName, urlToTest)); 47 | } catch (e) { 48 | console.error(`[${testName}] Exception during test: ${e}`); 49 | resolve(false); 50 | } 51 | }); 52 | } 53 | 54 | async function runTest(testName, urlToTest) { 55 | const testRunner = new TestRunner(testName, urlToTest); 56 | const actualScreenshotPath = await testRunner.takeScreenshotAndSaveToFs(); 57 | const numDiffPixels = 58 | await testRunner.doesScreenshotMatchExpectedAndGenerateDiff( 59 | actualScreenshotPath 60 | ); 61 | const didPass = numDiffPixels === 0; 62 | 63 | if (didPass) { 64 | console.log(`[${testName}] Passed`); 65 | } else { 66 | console.log( 67 | `[${testName}] Failed - actual screenshot differs from expected by ${numDiffPixels} pixels` 68 | ); 69 | } 70 | 71 | return didPass; 72 | } 73 | --------------------------------------------------------------------------------