├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── assets ├── icons │ ├── icon_128.png │ ├── icon_16.png │ ├── icon_256.png │ └── icon_48.png └── promo │ ├── Large promo tile.jpg │ ├── Marquee promo tile.jpg │ ├── Small promo tile.jpg │ └── screenshot_1.jpg ├── bundle.ts ├── example.png ├── package.json ├── src └── index.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | 3 | dist/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Lasse Norfeldt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archive Notice ⚠️ 2 | 3 | > This project is no longer actively maintained and has been archived. Feel free to fork it and build upon it. Thank you for your interest and support! 4 | 5 | 6 | # Issue Reactions Chrome & Firefox Extension 7 | List reaction links on a Github issue or discussion page 8 | 9 | screenshot example 10 | 11 | See it in action 12 | 13 | [![Wes Bos Showing off this extension](http://img.youtube.com/vi/K4wc818iNDc/0.jpg)](http://www.youtube.com/watch?v=K4wc818iNDc "Video Title") 14 | 15 | ## Chrome 16 | 17 | Grab it from the chrome extensions: [Github Issue Reactions](https://chrome.google.com/webstore/detail/github-issue-reactions/enekincdenmmbpgkbhflknhaphpajnfd) 18 | 19 | ## Firefox 20 | 21 | Grab it from the firefox add-ons: [Github Issue Reactions](https://addons.mozilla.org/addon/github-issue-reactions/) 22 | 23 | ## Manual Setup 24 | 25 | 1. Clone this repo 26 | 2. `yarn install` 27 | 3. `yarn bundle` 28 | 4. Chrome: 29 | 1. Open Chrome Extensions 30 | 2. Enable Developer mode 31 | 3. Pick Load unpacked 32 | 5. Firefox: 33 | 1. Settings/Extension & Themes 34 | 2. Click the gear icon and select "Debug add-ons" 35 | 3. Load Temporary Add-on.. 36 | 6. Navigate to the relevant `/dist` directory 37 | 7. Enjoy! 👍 38 | 39 | ## Not Working Any More? 40 | 41 | Try to do a git pull to see if it has been fixed 42 | 43 | (**DO NOT FORGET go into your extensions and reload the lasted version**). 44 | -------------------------------------------------------------------------------- /assets/icons/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/icons/icon_128.png -------------------------------------------------------------------------------- /assets/icons/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/icons/icon_16.png -------------------------------------------------------------------------------- /assets/icons/icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/icons/icon_256.png -------------------------------------------------------------------------------- /assets/icons/icon_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/icons/icon_48.png -------------------------------------------------------------------------------- /assets/promo/Large promo tile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/promo/Large promo tile.jpg -------------------------------------------------------------------------------- /assets/promo/Marquee promo tile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/promo/Marquee promo tile.jpg -------------------------------------------------------------------------------- /assets/promo/Small promo tile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/promo/Small promo tile.jpg -------------------------------------------------------------------------------- /assets/promo/screenshot_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/assets/promo/screenshot_1.jpg -------------------------------------------------------------------------------- /bundle.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs' 2 | import * as path from 'path' 3 | import * as child_process from 'child_process' 4 | import * as archiver from 'archiver' 5 | 6 | import { version } from './package.json' 7 | 8 | console.log('Bundling started') 9 | 10 | type Browser = 'chrome' | 'firefox' 11 | 12 | function writeToDist(browser: Browser, fileName: string, content: any) { 13 | const dir = path.join(__dirname, 'dist', browser) 14 | if (!fs.existsSync(dir)) { 15 | fs.mkdirSync(dir, { recursive: true }) 16 | } 17 | fs.writeFileSync(path.join(dir, fileName), content) 18 | } 19 | 20 | // MANIFESTS 21 | const commonManifest = { 22 | name: 'Github Issue Reactions', 23 | version, 24 | description: 25 | 'List a link of reactions on a github issue and pull request page', 26 | content_scripts: [ 27 | { 28 | matches: ['*://*.github.com/*'], 29 | js: ['index.js'], 30 | run_at: 'document_end', 31 | }, 32 | ], 33 | permissions: ['storage'], 34 | icons: { 35 | '16': 'icon_16.png', 36 | '48': 'icon_48.png', 37 | '128': 'icon_128.png', 38 | '256': 'icon_256.png', 39 | }, 40 | host_permissions: ['https://www.github.com/', 'http://www.github.com/'], 41 | } 42 | 43 | // CHROME 44 | const chromeManifest = { 45 | manifest_version: 3, 46 | ...commonManifest, 47 | } 48 | writeToDist('chrome', 'manifest.json', JSON.stringify(chromeManifest, null, 2)) 49 | 50 | // FIREFOX 51 | const { host_permissions, ...firefoxManifest } = { 52 | manifest_version: 2, 53 | ...commonManifest, 54 | permissions: [ 55 | ...commonManifest.host_permissions, 56 | ...commonManifest.permissions, 57 | ], 58 | browser_specific_settings: { 59 | gecko: { 60 | id: '{f6ec3962-fd1d-4a7b-8dab-d211fbf91389}', 61 | strict_min_version: '57.0a1', 62 | }, 63 | }, 64 | } 65 | writeToDist( 66 | 'firefox', 67 | 'manifest.json', 68 | JSON.stringify(firefoxManifest, null, 2) 69 | ) 70 | 71 | // ICONS 72 | const iconFiles = fs.readdirSync(path.join(__dirname, 'assets', 'icons')) 73 | for (const iconFile of iconFiles) { 74 | const iconData = fs.readFileSync( 75 | path.join(__dirname, 'assets', 'icons', iconFile) 76 | ) 77 | writeToDist('chrome', iconFile, iconData) 78 | writeToDist('firefox', iconFile, iconData) 79 | } 80 | 81 | // CONTENT SCRIPT 82 | const tscCommand = (browser: Browser) => { 83 | const command = `yarn tsc src/index.ts --outDir dist/${browser}` 84 | console.log(command) 85 | 86 | return command 87 | } 88 | child_process.exec(tscCommand('chrome'), () => callBack('chrome')) 89 | child_process.exec(tscCommand('firefox'), () => callBack('firefox')) 90 | 91 | // If it should z(h)ip it when done 92 | function callBack(browser: Browser) { 93 | if (process.argv.includes('zip')) { 94 | const archive = archiver('zip', { 95 | zlib: { level: 9 }, 96 | }) 97 | const output = fs.createWriteStream( 98 | path.join(__dirname, `${browser}_${version}.zip`) 99 | ) 100 | archive.pipe(output) 101 | archive.directory(path.join(__dirname, 'dist', `${browser}`), false) 102 | archive.finalize() 103 | } 104 | } 105 | 106 | setTimeout(() => { 107 | const timeStampWithoutMs = new Date() 108 | .toISOString() 109 | .split('.')[0] 110 | .replace('T', ' ') 111 | console.log('Bundling finished', timeStampWithoutMs) 112 | }, 5000) 113 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Norfeldt/github-issue-reactions-browser-extension/0c853a2032b5d03edd34f52408bc64caac4e2164/example.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-issue-reactions-browser-extension", 3 | "version": "2.4.5", 4 | "repository": "git@github.com:Norfeldt/github-issue-reactions-browser-extension.git", 5 | "author": "Lasse Nørfeldt ", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "watch 'yarn bundle' src", 9 | "bundle": "ts-node bundle.ts", 10 | "zip": "ts-node bundle.ts --args zip" 11 | }, 12 | "devDependencies": { 13 | "@types/archiver": "^5.3.1", 14 | "@types/chrome": "^0.0.209", 15 | "@types/firefox-webext-browser": "^109.0.0", 16 | "@types/node": "^18.11.17", 17 | "archiver": "^5.3.1", 18 | "ts-node": "^10.9.1", 19 | "typescript": "^5.0.0-beta", 20 | "watch": "^1.0.2" 21 | }, 22 | "volta": { 23 | "node": "18.16.0", 24 | "yarn": "1.22.19" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | const primaryColor = 'var(--color-fg-default)' 2 | const backgroundColor = 'var(--color-social-reaction-bg-hover)' 3 | const DISPLAY = 'DISPLAY' 4 | 5 | const getBrowser = () => { 6 | if (navigator.userAgent.match(/Chrome/)) return chrome 7 | 8 | return browser 9 | } 10 | 11 | const [sideBarId, wrapperId] = [ 12 | '#partial-discussion-sidebar', 13 | '#reactions-wrapper', 14 | ] 15 | 16 | // INITIAL LOADING INDICATOR 17 | injectWrapper({ withLoadingSpinner: true }) 18 | 19 | // Create a sticking wrapper to place all reactions 20 | function injectWrapper({ withLoadingSpinner } = { withLoadingSpinner: false }) { 21 | if (document.querySelector('header')?.innerText.includes('Sign in')) { 22 | const header = document.querySelector(sideBarId) as HTMLDivElement 23 | if (header) { 24 | const notSignedInClass = 'not-signed-in' 25 | Array.from(document.querySelectorAll(`.${notSignedInClass}`)).forEach( 26 | (element) => element?.remove() 27 | ) 28 | const textHeader = document.createElement('div') 29 | textHeader.className = notSignedInClass 30 | textHeader.style.margin = '1.25rem 0 0.2rem 0' 31 | textHeader.style.fontWeight = 'bold' 32 | textHeader.appendChild( 33 | document.createTextNode('Sign in to list reactions') 34 | ) 35 | // add the text below "Github source code is different for signed out users and it is currently too much work to support both" 36 | const textReason = document.createElement('div') 37 | textReason.className = notSignedInClass 38 | textReason.style.margin = '1.25rem 0 0.5rem 0' 39 | textReason.style.fontStyle = 'italic' 40 | textReason.appendChild( 41 | document.createTextNode( 42 | 'Github source code is different for signed out users and it is currently too much work to support both - sorry! 🙈' 43 | ) 44 | ) 45 | textReason.appendChild( 46 | document.createTextNode( 47 | 'You are welcome to contribute to the project on Github 🙌' 48 | ) 49 | ) 50 | header.appendChild(textHeader) 51 | header.appendChild(textReason) 52 | 53 | Array.from(document.querySelectorAll(`.credits`)).forEach((element) => 54 | element?.remove() 55 | ) 56 | header.appendChild(Credits()) 57 | } 58 | return 59 | } 60 | 61 | const header = document.querySelector(sideBarId) as HTMLDivElement 62 | if (!header) return 63 | 64 | header.style.position = 'relative' 65 | header.style.height = '100%' 66 | 67 | const wrapper = document.createElement('div') 68 | wrapper.setAttribute('id', wrapperId.replace('#', '')) 69 | const top = 70 | document.querySelectorAll('.gh-header-sticky').length > 0 ? 70 : 10 71 | wrapper.style.position = 'sticky' 72 | wrapper.style.setProperty('position', '-webkit-sticky', 'important') 73 | wrapper.style.top = top + 'px' 74 | wrapper.innerHTML = '' 75 | 76 | wrapper.appendChild(Title('Reactions', true)) 77 | if (withLoadingSpinner) { 78 | wrapper.appendChild(LoadingSpinner()) 79 | } 80 | header.appendChild(wrapper) 81 | } 82 | 83 | function LoadingSpinner() { 84 | const loadingSpinner = document.createElement('div') 85 | const side = '25px' 86 | loadingSpinner.style.width = side 87 | loadingSpinner.style.height = side 88 | loadingSpinner.style.border = `2px solid ${backgroundColor}` 89 | loadingSpinner.style.borderTop = `2px solid ${primaryColor}` 90 | loadingSpinner.style.borderRadius = '50%' 91 | loadingSpinner.style.animation = 'spin 1s linear infinite' 92 | const style = document.createElement('style') 93 | document.head.appendChild(style) 94 | const keyframes = ` 95 | @keyframes spin { 96 | 0% { transform: rotate(0deg); } 97 | 100% { transform: rotate(360deg); } 98 | }` 99 | style.sheet?.insertRule(keyframes) 100 | 101 | return loadingSpinner 102 | } 103 | 104 | // OBSERVE FOR PAGE MUTATIONS 105 | function hasAncestorWithId(element: Element | null, id: string) { 106 | while (element) { 107 | if (element.id === id) { 108 | return true 109 | } 110 | element = element.parentElement 111 | } 112 | return false 113 | } 114 | 115 | const observer = new MutationObserver((mutations: MutationRecord[]) => { 116 | for (const mutation of mutations) { 117 | if ( 118 | hasAncestorWithId( 119 | mutation.target as Element | null, 120 | sideBarId.replace('#', '') 121 | ) || 122 | hasAncestorWithId( 123 | mutation.target as Element | null, 124 | wrapperId.replace('#', '') 125 | ) 126 | ) { 127 | continue 128 | } 129 | 130 | // Check if the URL contains /discussions/ or /issues/ 131 | if (/\/(discussions|issues|pull)\//.test(window.location.pathname)) { 132 | addReactionNav() 133 | } 134 | } 135 | }) 136 | 137 | // Start observing mutations on the whole document 138 | observer.observe(document, { 139 | childList: true, 140 | subtree: true, 141 | }) 142 | 143 | // Scan the site for reactions and stick it into the wrapper 144 | function addReactionNav() { 145 | document.querySelector(wrapperId)?.remove() 146 | injectWrapper() 147 | const wrapper = document.querySelector(wrapperId) 148 | if (!wrapper) { 149 | return 150 | } 151 | 152 | wrapper.appendChild(Reactions()) 153 | if (window.location.pathname.match(/\/discussions\//)) { 154 | wrapper.appendChild(Title('Discussion Votes')) 155 | wrapper.appendChild(DiscussionVotes()) 156 | } 157 | wrapper.appendChild(Credits()) 158 | } 159 | 160 | function Title(title: string, withSwitch = false) { 161 | const element = document.createElement('div') satisfies HTMLDivElement 162 | element.style.display = 'flex' 163 | element.style.justifyContent = 'space-between' 164 | element.style.alignItems = 'center' 165 | element.style.fontWeight = 'bold' 166 | element.style.margin = '1.25rem 0 0.5rem 0' 167 | 168 | element.appendChild(document.createTextNode(title)) 169 | 170 | if (withSwitch) { 171 | const switchDiv = document.createElement('div') 172 | switchDiv.appendChild(SvgBlockIcon()) 173 | switchDiv.appendChild(Switch()) 174 | switchDiv.appendChild(SvgInlineBlockIcon()) 175 | element.appendChild(switchDiv) 176 | } 177 | 178 | return element 179 | } 180 | 181 | const reactionClass = 'reaction-sidebar-link' 182 | 183 | function Reactions() { 184 | const all = document.createElement('div') 185 | 186 | const issueUrl = 187 | window.location.origin + window.location.pathname + window.location.search 188 | 189 | // Grabbing all reactions Reactions 👍 🚀 🎉 😄 ❤️ 😕 👎 👀 190 | const reactions = [ 191 | { emoji: '👍', name: '+1' }, 192 | { emoji: '🚀', name: 'rocket' }, 193 | { emoji: '🎉', name: 'tada' }, 194 | { emoji: '😄', name: 'smile' }, 195 | { emoji: '❤️', name: 'heart' }, 196 | { emoji: '😕', name: 'thinking_face' }, 197 | { emoji: '👎', name: '-1' }, 198 | { emoji: '👀', name: 'eyes' }, 199 | ] 200 | 201 | const findReaction = (node: Element) => (reaction: typeof reactions[number]) => 202 | node.textContent?.includes(reaction.emoji) || 203 | node.querySelector(`g-emoji[alias="${reaction.name}"]`) 204 | 205 | Array.from(document.querySelectorAll('.js-comment-reactions-options')) 206 | .filter((node) => reactions.some(findReaction(node))) 207 | .forEach((reactionSection) => { 208 | const combinedReactions = Array.from( 209 | reactionSection.querySelectorAll('button[class*="reaction"]') 210 | ) 211 | .map((btn) => ({ 212 | emoji: reactions.find(findReaction(btn))?.emoji, 213 | count: btn.textContent?.match(/\d+/)?.join(''), 214 | })) 215 | .filter((reaction) => reaction.emoji && reaction.count) 216 | .reduce((acc, { emoji, count }) => `${acc} ${emoji} ${count}`, '') 217 | 218 | const linkContainer = document.createElement('div') 219 | linkContainer.classList.add(reactionClass) 220 | 221 | const a = document.createElement('a') 222 | const linkText = document.createTextNode(' ' + combinedReactions) 223 | linkContainer.appendChild(a) 224 | a.appendChild(linkText) 225 | a.title = combinedReactions 226 | 227 | let id = null 228 | while (id == null) { 229 | if (reactionSection.tagName === 'A' && reactionSection.name) { 230 | id = reactionSection.name 231 | break 232 | } 233 | if (reactionSection.id) { 234 | id = reactionSection.id 235 | break 236 | } 237 | // @ts-expect-error 238 | reactionSection = reactionSection.parentNode 239 | } 240 | 241 | linkContainer.style.margin = '0.5rem 0' 242 | a.href = issueUrl + '#' + id 243 | a.style.border = '1px solid var(--borderColor-default, #d2dff0)' 244 | a.style.borderRadius = '100px' 245 | a.style.padding = '2px 7px' 246 | a.style.color = 'var(--color-fg-muted)' 247 | 248 | all.appendChild(linkContainer) 249 | }) 250 | 251 | getBrowser() 252 | .storage.sync.get([DISPLAY]) 253 | .then((result: { [x: string]: string }) => { 254 | const display = (result[DISPLAY] as Display) ?? 'block' 255 | const elements = Array.from( 256 | document.getElementsByClassName(reactionClass) 257 | ) as HTMLDivElement[] 258 | for (let element of elements) { 259 | element.style.display = display 260 | } 261 | }) 262 | 263 | if (all.childElementCount === 0) { 264 | const noReactions = document.createElement('div') 265 | noReactions.innerText = '🤷‍♂️ no reactions found' 266 | all.appendChild(noReactions) 267 | } 268 | 269 | return all 270 | } 271 | 272 | function DiscussionVotes() { 273 | const all = document.createElement('div') 274 | document.querySelectorAll('[data-url]').forEach((discussionComment) => { 275 | const defaultVote = discussionComment.querySelector( 276 | '.js-default-vote-count' 277 | ) 278 | const upvotedVote = discussionComment.querySelector( 279 | '.js-upvoted-vote-count' 280 | ) 281 | const isUpvote = !!discussionComment.querySelector('[data-upvoted="true"]') 282 | const vote = isUpvote ? upvotedVote : defaultVote 283 | let url = discussionComment.dataset?.url?.replace( 284 | '/comments/', 285 | '#discussioncomment-' 286 | ) 287 | if (!url) return 288 | 289 | if (url.match(/body$/)) { 290 | url = `${ 291 | window.location.origin + 292 | window.location.pathname + 293 | window.location.search 294 | }#${discussionComment.children[0].id}` 295 | } 296 | 297 | if (!vote || url.match(/votes$/)) return 298 | const votes = vote.textContent 299 | const a = document.createElement('a') 300 | const linkText = document.createTextNode( 301 | `\n⬆️ ${votes}${isUpvote ? ' 🫵' : ''}` 302 | ) 303 | a.appendChild(linkText) 304 | a.title = url 305 | a.href = url 306 | a.style.border = '1px solid var(--borderColor-default, #d2dff0)' 307 | a.style.borderRadius = '100px' 308 | a.style.padding = '2px 7px' 309 | a.style.margin = '0.5rem 0' 310 | const linkContainer = document.createElement('div') 311 | linkContainer.appendChild(a) 312 | linkContainer.classList.add(reactionClass) 313 | all.appendChild(linkContainer) 314 | }) 315 | 316 | return all 317 | } 318 | 319 | function Credits() { 320 | const credits = document.createElement('div') 321 | credits.classList.add('credits') 322 | credits.style.display = 'flex' 323 | credits.style.gap = '0.5rem' 324 | credits.style.alignItems = 'center' 325 | credits.style.margin = '1rem 0' 326 | credits.style.fontSize = '0.8rem' 327 | credits.style.color = '#777' 328 | 329 | const laptopEmojiSpan = document.createElement('span') 330 | laptopEmojiSpan.appendChild(document.createTextNode('💻')) 331 | 332 | const extensionLink = document.createElement('a') 333 | extensionLink.href = 334 | 'https://github.com/Norfeldt/github-issue-reactions-browser-extension' 335 | extensionLink.appendChild(document.createTextNode('Reactions Extension')) 336 | 337 | const madeBySpan = document.createElement('span') 338 | madeBySpan.appendChild(document.createTextNode(' by ')) 339 | 340 | const authorLink = document.createElement('a') 341 | authorLink.href = 'https://github.com/Norfeldt' 342 | authorLink.appendChild(document.createTextNode('Norfeldt')) 343 | 344 | credits.appendChild(laptopEmojiSpan) 345 | credits.appendChild(extensionLink) 346 | credits.appendChild(madeBySpan) 347 | credits.appendChild(authorLink) 348 | 349 | return credits 350 | } 351 | 352 | // Create the switch container, label, input, and handle elements 353 | function Switch() { 354 | const switchContainer = document.createElement('span') 355 | const switchLabel = document.createElement('label') 356 | const switchInput = document.createElement('span') 357 | switchLabel.appendChild(switchInput) 358 | const switchHandle = document.createElement('span') 359 | switchHandle.setAttribute('class', 'switch-handle-reactions-layout') 360 | switchLabel.appendChild(switchHandle) 361 | switchContainer.appendChild(switchLabel) 362 | 363 | // Add CSS styles to the switch container 364 | switchContainer.style.display = 'inline-block' 365 | switchContainer.style.position = 'relative' 366 | switchContainer.style.backgroundColor = backgroundColor 367 | switchContainer.style.borderRadius = '14px' 368 | switchContainer.style.width = '30px' 369 | switchContainer.style.height = '17px' 370 | 371 | // Add CSS styles to the switch label 372 | switchLabel.style.display = 'block' 373 | switchLabel.style.position = 'relative' 374 | switchLabel.style.width = '100%' 375 | switchLabel.style.height = '100%' 376 | switchLabel.style.cursor = 'pointer' 377 | 378 | // Add CSS styles to the switch input 379 | switchInput.style.display = 'none' 380 | 381 | // Add CSS styles to the switch handle 382 | switchHandle.style.display = 'block' 383 | switchHandle.style.position = 'absolute' 384 | switchHandle.style.top = '1px' 385 | switchHandle.style.width = '14px' 386 | switchHandle.style.height = '14px' 387 | switchHandle.style.borderRadius = '14px' 388 | switchHandle.style.backgroundColor = primaryColor 389 | switchHandle.style.boxShadow = '0 2px 4px 0 rgba(0, 0, 0, 0.1)' 390 | switchHandle.style.transition = 'left 0.2s ease-in-out' 391 | 392 | const toggle = (value: boolean) => { 393 | switchHandle.style.left = value ? '12px' : '2px' 394 | } 395 | 396 | getBrowser() 397 | .storage.sync?.get([DISPLAY]) 398 | ?.then((result) => { 399 | if (!result[DISPLAY]) return 400 | toggle(result[DISPLAY] === 'inline-block') 401 | }) 402 | 403 | // Add an event listener to the switch 404 | switchContainer.addEventListener('click', async function changeSwitch() { 405 | // Get Layout from storage and change it to the opposite (either block or inline-block) 406 | const settings = await getBrowser().storage.sync.get([DISPLAY]) 407 | const display: Display = 408 | settings[DISPLAY] === 'inline-block' ? 'block' : 'inline-block' 409 | getBrowser().storage.sync.set({ [DISPLAY]: display }) 410 | }) 411 | 412 | getBrowser().storage.onChanged.addListener(function (changes, _namespace) { 413 | for (const key in changes) { 414 | const storageChange = changes[key] 415 | if (key === DISPLAY) { 416 | toggle(storageChange.newValue === 'inline-block') 417 | } 418 | } 419 | }) 420 | 421 | return switchContainer 422 | } 423 | 424 | getBrowser().storage.onChanged.addListener(function (changes) { 425 | for (let key in changes) { 426 | if (key === DISPLAY) { 427 | const display = 428 | changes[key].newValue === 'block' ? 'block' : 'inline-block' 429 | const elements = Array.from( 430 | document.getElementsByClassName(reactionClass) 431 | ) as HTMLDivElement[] 432 | for (let element of elements) { 433 | element.style.display = display 434 | } 435 | } 436 | } 437 | }) 438 | 439 | function SvgBlockIcon() { 440 | const svg = ` 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | ` 451 | const span = document.createElement('span') 452 | span.innerHTML = svg 453 | 454 | return span 455 | } 456 | 457 | function SvgInlineBlockIcon() { 458 | const svg = ` 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | ` 469 | const span = document.createElement('span') 470 | span.innerHTML = svg 471 | 472 | return span 473 | } 474 | 475 | declare interface Element { 476 | dataset: DOMStringMap 477 | name: string 478 | } 479 | 480 | type Display = 'block' | 'inline-block' 481 | 482 | type Settings = { 483 | [DISPLAY]: Display 484 | } 485 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "CommonJS", 5 | "strict": true, 6 | "resolveJsonModule": true, 7 | "types": ["chrome", "firefox-webext-browser"] 8 | }, 9 | "include": ["src", "scripts", "bundle.ts"], 10 | "exclude": ["node_modules", "dist", "scripts"] 11 | } 12 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@cspotcode/source-map-support@^0.8.0": 6 | version "0.8.1" 7 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" 8 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== 9 | dependencies: 10 | "@jridgewell/trace-mapping" "0.3.9" 11 | 12 | "@jridgewell/resolve-uri@^3.0.3": 13 | version "3.1.0" 14 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" 15 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== 16 | 17 | "@jridgewell/sourcemap-codec@^1.4.10": 18 | version "1.4.14" 19 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" 20 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== 21 | 22 | "@jridgewell/trace-mapping@0.3.9": 23 | version "0.3.9" 24 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" 25 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== 26 | dependencies: 27 | "@jridgewell/resolve-uri" "^3.0.3" 28 | "@jridgewell/sourcemap-codec" "^1.4.10" 29 | 30 | "@tsconfig/node10@^1.0.7": 31 | version "1.0.9" 32 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" 33 | integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== 34 | 35 | "@tsconfig/node12@^1.0.7": 36 | version "1.0.11" 37 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" 38 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== 39 | 40 | "@tsconfig/node14@^1.0.0": 41 | version "1.0.3" 42 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" 43 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== 44 | 45 | "@tsconfig/node16@^1.0.2": 46 | version "1.0.3" 47 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" 48 | integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== 49 | 50 | "@types/archiver@^5.3.1": 51 | version "5.3.1" 52 | resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.1.tgz#02991e940a03dd1a32678fead4b4ca03d0e387ca" 53 | integrity sha512-wKYZaSXaDvTZuInAWjCeGG7BEAgTWG2zZW0/f7IYFcoHB2X2d9lkVFnrOlXl3W6NrvO6Ml3FLLu8Uksyymcpnw== 54 | dependencies: 55 | "@types/glob" "*" 56 | 57 | "@types/chrome@^0.0.209": 58 | version "0.0.209" 59 | resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.209.tgz#3c023bb9b4e51d317167b4459e2f58bbd1fbc49e" 60 | integrity sha512-YL3gz9cAKKym/b+u26p8BQuKAc3USsPRcOYZ1OWQmOw0kfYBXkxrh9ASvSRgwA8ywA4sIahio0z0chzmmLq2og== 61 | dependencies: 62 | "@types/filesystem" "*" 63 | "@types/har-format" "*" 64 | 65 | "@types/filesystem@*": 66 | version "0.0.32" 67 | resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.32.tgz#307df7cc084a2293c3c1a31151b178063e0a8edf" 68 | integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ== 69 | dependencies: 70 | "@types/filewriter" "*" 71 | 72 | "@types/filewriter@*": 73 | version "0.0.29" 74 | resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee" 75 | integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ== 76 | 77 | "@types/firefox-webext-browser@^109.0.0": 78 | version "109.0.0" 79 | resolved "https://registry.yarnpkg.com/@types/firefox-webext-browser/-/firefox-webext-browser-109.0.0.tgz#17120057a46985ec7659dfd33589655860419929" 80 | integrity sha512-tkEjBP/zZxaS5bv8MH/0kUs3WeUm8KU3Ew1B9BtQQdq5PwtG23SXvAbjxjMSQpoIzbxyWG4Yu4mi1uB2S8W7ng== 81 | 82 | "@types/glob@*": 83 | version "8.0.0" 84 | resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.0.0.tgz#321607e9cbaec54f687a0792b2d1d370739455d2" 85 | integrity sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA== 86 | dependencies: 87 | "@types/minimatch" "*" 88 | "@types/node" "*" 89 | 90 | "@types/har-format@*": 91 | version "1.2.10" 92 | resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.10.tgz#7b4e1e0ada4d17684ac3b05d601a4871cfab11fc" 93 | integrity sha512-o0J30wqycjF5miWDKYKKzzOU1ZTLuA42HZ4HE7/zqTOc/jTLdQ5NhYWvsRQo45Nfi1KHoRdNhteSI4BAxTF1Pg== 94 | 95 | "@types/minimatch@*": 96 | version "5.1.2" 97 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" 98 | integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== 99 | 100 | "@types/node@*", "@types/node@^18.11.17": 101 | version "18.11.18" 102 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" 103 | integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== 104 | 105 | acorn-walk@^8.1.1: 106 | version "8.2.0" 107 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" 108 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== 109 | 110 | acorn@^8.4.1: 111 | version "8.8.1" 112 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" 113 | integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== 114 | 115 | archiver-utils@^2.1.0: 116 | version "2.1.0" 117 | resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" 118 | integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== 119 | dependencies: 120 | glob "^7.1.4" 121 | graceful-fs "^4.2.0" 122 | lazystream "^1.0.0" 123 | lodash.defaults "^4.2.0" 124 | lodash.difference "^4.5.0" 125 | lodash.flatten "^4.4.0" 126 | lodash.isplainobject "^4.0.6" 127 | lodash.union "^4.6.0" 128 | normalize-path "^3.0.0" 129 | readable-stream "^2.0.0" 130 | 131 | archiver@^5.3.1: 132 | version "5.3.1" 133 | resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6" 134 | integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== 135 | dependencies: 136 | archiver-utils "^2.1.0" 137 | async "^3.2.3" 138 | buffer-crc32 "^0.2.1" 139 | readable-stream "^3.6.0" 140 | readdir-glob "^1.0.0" 141 | tar-stream "^2.2.0" 142 | zip-stream "^4.1.0" 143 | 144 | arg@^4.1.0: 145 | version "4.1.3" 146 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 147 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 148 | 149 | async@^3.2.3: 150 | version "3.2.4" 151 | resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" 152 | integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== 153 | 154 | balanced-match@^1.0.0: 155 | version "1.0.2" 156 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 157 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 158 | 159 | base64-js@^1.3.1: 160 | version "1.5.1" 161 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 162 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 163 | 164 | bl@^4.0.3: 165 | version "4.1.0" 166 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" 167 | integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== 168 | dependencies: 169 | buffer "^5.5.0" 170 | inherits "^2.0.4" 171 | readable-stream "^3.4.0" 172 | 173 | brace-expansion@^1.1.7: 174 | version "1.1.11" 175 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 176 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 177 | dependencies: 178 | balanced-match "^1.0.0" 179 | concat-map "0.0.1" 180 | 181 | brace-expansion@^2.0.1: 182 | version "2.0.1" 183 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 184 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 185 | dependencies: 186 | balanced-match "^1.0.0" 187 | 188 | buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: 189 | version "0.2.13" 190 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" 191 | integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== 192 | 193 | buffer@^5.5.0: 194 | version "5.7.1" 195 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 196 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 197 | dependencies: 198 | base64-js "^1.3.1" 199 | ieee754 "^1.1.13" 200 | 201 | compress-commons@^4.1.0: 202 | version "4.1.1" 203 | resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" 204 | integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== 205 | dependencies: 206 | buffer-crc32 "^0.2.13" 207 | crc32-stream "^4.0.2" 208 | normalize-path "^3.0.0" 209 | readable-stream "^3.6.0" 210 | 211 | concat-map@0.0.1: 212 | version "0.0.1" 213 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 214 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 215 | 216 | core-util-is@~1.0.0: 217 | version "1.0.3" 218 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 219 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 220 | 221 | crc-32@^1.2.0: 222 | version "1.2.2" 223 | resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" 224 | integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== 225 | 226 | crc32-stream@^4.0.2: 227 | version "4.0.2" 228 | resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" 229 | integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== 230 | dependencies: 231 | crc-32 "^1.2.0" 232 | readable-stream "^3.4.0" 233 | 234 | create-require@^1.1.0: 235 | version "1.1.1" 236 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 237 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 238 | 239 | diff@^4.0.1: 240 | version "4.0.2" 241 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 242 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 243 | 244 | end-of-stream@^1.4.1: 245 | version "1.4.4" 246 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 247 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 248 | dependencies: 249 | once "^1.4.0" 250 | 251 | exec-sh@^0.2.0: 252 | version "0.2.2" 253 | resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" 254 | integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== 255 | dependencies: 256 | merge "^1.2.0" 257 | 258 | fs-constants@^1.0.0: 259 | version "1.0.0" 260 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" 261 | integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== 262 | 263 | fs.realpath@^1.0.0: 264 | version "1.0.0" 265 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 266 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 267 | 268 | glob@^7.1.4: 269 | version "7.2.3" 270 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 271 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 272 | dependencies: 273 | fs.realpath "^1.0.0" 274 | inflight "^1.0.4" 275 | inherits "2" 276 | minimatch "^3.1.1" 277 | once "^1.3.0" 278 | path-is-absolute "^1.0.0" 279 | 280 | graceful-fs@^4.2.0: 281 | version "4.2.10" 282 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" 283 | integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 284 | 285 | ieee754@^1.1.13: 286 | version "1.2.1" 287 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 288 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 289 | 290 | inflight@^1.0.4: 291 | version "1.0.6" 292 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 293 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 294 | dependencies: 295 | once "^1.3.0" 296 | wrappy "1" 297 | 298 | inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: 299 | version "2.0.4" 300 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 301 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 302 | 303 | isarray@~1.0.0: 304 | version "1.0.0" 305 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 306 | integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== 307 | 308 | lazystream@^1.0.0: 309 | version "1.0.1" 310 | resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" 311 | integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== 312 | dependencies: 313 | readable-stream "^2.0.5" 314 | 315 | lodash.defaults@^4.2.0: 316 | version "4.2.0" 317 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" 318 | integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== 319 | 320 | lodash.difference@^4.5.0: 321 | version "4.5.0" 322 | resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" 323 | integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== 324 | 325 | lodash.flatten@^4.4.0: 326 | version "4.4.0" 327 | resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" 328 | integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== 329 | 330 | lodash.isplainobject@^4.0.6: 331 | version "4.0.6" 332 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 333 | integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== 334 | 335 | lodash.union@^4.6.0: 336 | version "4.6.0" 337 | resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" 338 | integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== 339 | 340 | make-error@^1.1.1: 341 | version "1.3.6" 342 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 343 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 344 | 345 | merge@^1.2.0: 346 | version "1.2.1" 347 | resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" 348 | integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== 349 | 350 | minimatch@^3.1.1: 351 | version "3.1.2" 352 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 353 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 354 | dependencies: 355 | brace-expansion "^1.1.7" 356 | 357 | minimatch@^5.1.0: 358 | version "5.1.2" 359 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.2.tgz#0939d7d6f0898acbd1508abe534d1929368a8fff" 360 | integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg== 361 | dependencies: 362 | brace-expansion "^2.0.1" 363 | 364 | minimist@^1.2.0: 365 | version "1.2.7" 366 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" 367 | integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== 368 | 369 | normalize-path@^3.0.0: 370 | version "3.0.0" 371 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 372 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 373 | 374 | once@^1.3.0, once@^1.4.0: 375 | version "1.4.0" 376 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 377 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 378 | dependencies: 379 | wrappy "1" 380 | 381 | path-is-absolute@^1.0.0: 382 | version "1.0.1" 383 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 384 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 385 | 386 | process-nextick-args@~2.0.0: 387 | version "2.0.1" 388 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 389 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 390 | 391 | readable-stream@^2.0.0, readable-stream@^2.0.5: 392 | version "2.3.7" 393 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 394 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 395 | dependencies: 396 | core-util-is "~1.0.0" 397 | inherits "~2.0.3" 398 | isarray "~1.0.0" 399 | process-nextick-args "~2.0.0" 400 | safe-buffer "~5.1.1" 401 | string_decoder "~1.1.1" 402 | util-deprecate "~1.0.1" 403 | 404 | readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: 405 | version "3.6.0" 406 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" 407 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== 408 | dependencies: 409 | inherits "^2.0.3" 410 | string_decoder "^1.1.1" 411 | util-deprecate "^1.0.1" 412 | 413 | readdir-glob@^1.0.0: 414 | version "1.1.2" 415 | resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.2.tgz#b185789b8e6a43491635b6953295c5c5e3fd224c" 416 | integrity sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA== 417 | dependencies: 418 | minimatch "^5.1.0" 419 | 420 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 421 | version "5.1.2" 422 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 423 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 424 | 425 | safe-buffer@~5.2.0: 426 | version "5.2.1" 427 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 428 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 429 | 430 | string_decoder@^1.1.1: 431 | version "1.3.0" 432 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 433 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 434 | dependencies: 435 | safe-buffer "~5.2.0" 436 | 437 | string_decoder@~1.1.1: 438 | version "1.1.1" 439 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 440 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 441 | dependencies: 442 | safe-buffer "~5.1.0" 443 | 444 | tar-stream@^2.2.0: 445 | version "2.2.0" 446 | resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" 447 | integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== 448 | dependencies: 449 | bl "^4.0.3" 450 | end-of-stream "^1.4.1" 451 | fs-constants "^1.0.0" 452 | inherits "^2.0.3" 453 | readable-stream "^3.1.1" 454 | 455 | ts-node@^10.9.1: 456 | version "10.9.1" 457 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" 458 | integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== 459 | dependencies: 460 | "@cspotcode/source-map-support" "^0.8.0" 461 | "@tsconfig/node10" "^1.0.7" 462 | "@tsconfig/node12" "^1.0.7" 463 | "@tsconfig/node14" "^1.0.0" 464 | "@tsconfig/node16" "^1.0.2" 465 | acorn "^8.4.1" 466 | acorn-walk "^8.1.1" 467 | arg "^4.1.0" 468 | create-require "^1.1.0" 469 | diff "^4.0.1" 470 | make-error "^1.1.1" 471 | v8-compile-cache-lib "^3.0.1" 472 | yn "3.1.1" 473 | 474 | typescript@^5.0.0-beta: 475 | version "5.0.0-beta" 476 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.0-beta.tgz#791fa95411d6ff64ee77d677ed1e6f32a2eaabaf" 477 | integrity sha512-+SSabbSXG5mtF+QGdV9uXXt9Saq1cSyI6hSG7znhaLoquleJpnmfkwSxFngK9c2fWWi1W/263TuzXQOsIcdjjA== 478 | 479 | util-deprecate@^1.0.1, util-deprecate@~1.0.1: 480 | version "1.0.2" 481 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 482 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 483 | 484 | v8-compile-cache-lib@^3.0.1: 485 | version "3.0.1" 486 | resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" 487 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== 488 | 489 | watch@^1.0.2: 490 | version "1.0.2" 491 | resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" 492 | integrity sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA== 493 | dependencies: 494 | exec-sh "^0.2.0" 495 | minimist "^1.2.0" 496 | 497 | wrappy@1: 498 | version "1.0.2" 499 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 500 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 501 | 502 | yn@3.1.1: 503 | version "3.1.1" 504 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 505 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 506 | 507 | zip-stream@^4.1.0: 508 | version "4.1.0" 509 | resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" 510 | integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== 511 | dependencies: 512 | archiver-utils "^2.1.0" 513 | compress-commons "^4.1.0" 514 | readable-stream "^3.6.0" 515 | --------------------------------------------------------------------------------