From 59e4b8defb07b78c3b6b511a2a9c59729fc82c87 Mon Sep 17 00:00:00 2001 From: jasonfoknxu Date: Sat, 6 May 2023 08:02:21 +0800 Subject: [PATCH] Version 1.0.5 --- .github/workflows/auto-update.yml | 82 ++-- .gitignore | 15 +- LICENSE | 42 +- changelog.md | 52 ++- config.json | 9 +- credits.md | 10 +- package.json | 44 +- src/app.ts | 417 ++++++++--------- src/interface/Config.ts | 5 + src/interface/Emoji.ts | 25 + .../{IGithubEmoji.ts => GithubEmoji.ts} | 6 +- src/interface/IConfig.ts | 4 - src/interface/IEmoji.ts | 25 - src/interface/{IUnicode.ts => Unicode.ts} | 36 +- src/utilities.ts | 430 +++++++++--------- tsconfig.json | 33 +- yarn.lock | 348 +++++++------- 17 files changed, 801 insertions(+), 782 deletions(-) create mode 100644 src/interface/Config.ts create mode 100644 src/interface/Emoji.ts rename src/interface/{IGithubEmoji.ts => GithubEmoji.ts} (55%) delete mode 100644 src/interface/IConfig.ts delete mode 100644 src/interface/IEmoji.ts rename src/interface/{IUnicode.ts => Unicode.ts} (59%) diff --git a/.github/workflows/auto-update.yml b/.github/workflows/auto-update.yml index cbda76c..66bff95 100644 --- a/.github/workflows/auto-update.yml +++ b/.github/workflows/auto-update.yml @@ -1,41 +1,41 @@ -name: Auto Update -on: - push: - branches: - - main - paths-ignore: - - 'README.md' - - 'github-emoji.json' - pull_request: - branches: - - main - schedule: - - cron: '0 0 * * 0' -jobs: - build: - runs-on: ubuntu-latest - env: - AUTO_COMMIT_MESSAGE: Auto Update by GitHub Actions - AUTO_COMMIT_AUTHOR: github-actions[bot] - AUTO_COMMIT_EMAIL: github-actions[bot]@users.noreply.github.com - AUTO_COMMIT_NO_UPDATE: No update, nothing to commit - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-node@v3 - with: - node-version: '16' - cache: 'yarn' - - name: Install Dependencies - run: yarn --frozen-lockfile - - name: Generate the GitHub Emoji Icon List Markdown - run: yarn start - - # Commit and push the README.md - - name: Update the README.md (Commit and Push) - run: | - git config --global user.name "${{ env.AUTO_COMMIT_AUTHOR }}" - git config --global user.email "${{ env.AUTO_COMMIT_EMAIL }}" - git add README.md github-emoji.json - git commit -m "${{ env.AUTO_COMMIT_MESSAGE }}" || echo "${{ env.AUTO_COMMIT_NO_UPDATE }}" - git push +name: Auto Update +on: + push: + branches: + - main + paths-ignore: + - 'README.md' + - 'github-emoji.json' + pull_request: + branches: + - main + schedule: + - cron: '0 0 * * *' +jobs: + build: + runs-on: ubuntu-latest + env: + AUTO_COMMIT_MESSAGE: Auto Update by GitHub Actions + AUTO_COMMIT_AUTHOR: github-actions[bot] + AUTO_COMMIT_EMAIL: github-actions[bot]@users.noreply.github.com + AUTO_COMMIT_NO_UPDATE: No update, nothing to commit + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: '16' + cache: 'yarn' + - name: Install Dependencies + run: yarn --frozen-lockfile + - name: Generate the GitHub Emoji Icon List Markdown + run: yarn start + + # Commit and push the README.md and Json file + - name: Update the README.md (Commit and Push) + run: | + git config --global user.name "${{ env.AUTO_COMMIT_AUTHOR }}" + git config --global user.email "${{ env.AUTO_COMMIT_EMAIL }}" + git add README.md github-emoji.json + git commit -m "${{ env.AUTO_COMMIT_MESSAGE }}" || echo "${{ env.AUTO_COMMIT_NO_UPDATE }}" + git push diff --git a/.gitignore b/.gitignore index c50c3df..1d47dce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ -# Dependency directories -node_modules/ - -# IDE config -.vscode/ -.idea/ +# Dependency directories +node_modules/ + +# IDE config +.vscode/ +.idea/ + +# Assets +banner.psd \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0d50027..1b89668 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2022 NXU - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2022 NXU + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/changelog.md b/changelog.md index 5cf090f..f10d2a3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,23 +1,29 @@ -# Changelog - -### Version 1.0.4 -- Fix GitHub Actions workflow `auto-update` (failed when no update) -- Add credits - -### Version 1.0.3b -- Quick fix minor bug - -### Version 1.0.3 -- Add GitHub emoji counter -- Add original Unicode -- Add JSON version - -### Version 1.0.2 -- Add GitHub Actions badge -- Fix minor visual bug of the markdown - -### Version 1.0.1 -- Fix the GitHub Actions workflow `auto-update` - -### Version 1.0.0 -- Initial version +# Changelog + +### Version 1.0.5 +- Configurable JSON file name +- Optimize Interface naming +- Add GitHub Image +- Change update interval to everyday + +### Version 1.0.4 +- Fix GitHub Actions workflow `auto-update` (failed when no update) +- Add credits + +### Version 1.0.3b +- Quick fix minor bug + +### Version 1.0.3 +- Add GitHub emoji counter +- Add original Unicode +- Add JSON version + +### Version 1.0.2 +- Add GitHub Actions badge +- Fix minor visual bug of the markdown + +### Version 1.0.1 +- Fix the GitHub Actions workflow `auto-update` + +### Version 1.0.0 +- Initial version diff --git a/config.json b/config.json index b3367c3..4271834 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,5 @@ -{ - "GitHub_Emojis_List": "https://api.github.com/emojis", - "Unicode_Emojis_Data": "https://unicode.org/Public/emoji/15.0/emoji-test.txt" -} +{ + "GitHub_Emojis_List": "https://api.github.com/emojis", + "Unicode_Emojis_Data": "https://unicode.org/Public/emoji/15.0/emoji-test.txt", + "Json_File_Name": "github-emoji.json" +} diff --git a/credits.md b/credits.md index a6a1d6e..04408c1 100644 --- a/credits.md +++ b/credits.md @@ -1,3 +1,7 @@ -# :star: Credits :sparkles: -- ts-node ([https://github.com/TypeStrong/ts-node](https://github.com/TypeStrong/ts-node)) -- axios ([https://github.com/axios/axios](https://github.com/axios/axios)) +# :star: Credits :sparkles: +- ts-node () +- axios () +- Node.js () +- TypeScript () +- GitHub () +- Unicode () \ No newline at end of file diff --git a/package.json b/package.json index 017e7ba..9b64f60 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,22 @@ -{ - "name": "github-emoji-icon-list", - "version": "1.0.3b", - "description": "Generate GitHub Emoji Icon list in Markdown format.", - "homepage": "https://github.com/jasonfoknxu/github-emoji-icon-list", - "author": "jasonfoknxu (https://nxuweb.net)", - "main": "src/app.ts", - "license": "MIT", - "repository": "github:jasonfoknxu/github-emoji-icon-list", - "private": false, - "scripts": { - "start": "ts-node --files src/app.ts" - }, - "devDependencies": { - "@types/node": "^18.11.12", - "typescript": "^4.9.3" - }, - "dependencies": { - "ts-node": "^10.9.1", - "axios": "^1.2.1" - } -} +{ + "name": "github-emoji-icon-list", + "version": "1.0.5", + "description": "Generate GitHub Emoji Icon list in Markdown format. Auto update by GitHub Actions.", + "homepage": "https://github.com/jasonfoknxu/github-emoji-icon-list", + "author": "jasonfoknxu (https://nxuweb.net)", + "main": "src/app.ts", + "license": "MIT", + "repository": "github:jasonfoknxu/github-emoji-icon-list", + "private": false, + "scripts": { + "start": "ts-node --files src/app.ts" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^4.9.3" + }, + "dependencies": { + "axios": "^1.2.1", + "ts-node": "^10.9.1" + } +} diff --git a/src/app.ts b/src/app.ts index 9890434..29b2b3b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,205 +1,212 @@ -/** - * GitHub Emoji Icon List Markdown Generator - * - Version: 1.0.4 - * - Developer: NXU (GitHub: @jasonfoknxu) - * - https://github.com/jasonfoknxu/github-emoji-icon-list - */ - -import * as Utils from './utilities'; - -(async () => { - // Get the config from config file - const config: IConfig = await Utils.getConfig(); - // Get the GitHub Emoji Icon List - const githubEmojisData: IGithubEmoji = await Utils.get(config.GitHub_Emojis_List); - // Get the Unicode Emoji Data - const unicodeEmojisData = await Utils.get(config.Unicode_Emojis_Data); - - // Stop if no GitHub emoji list or Unicode data - if (!githubEmojisData || !unicodeEmojisData) { - Utils.log('Failed to get the GitHub Emoji List or Unicode Emoji Data.', 'e'); - process.exit(1); - } - - // Count number of GitHub emoji - let numberOfEmoji = 0; - - // Handle the GitHub emoji from the GitHub Emoji Icon List - let githubEmojis: IGithubEmoji = {}; - for (const [shortcode, url] of Object.entries(githubEmojisData)) { - githubEmojis[shortcode] = Utils.base(url).toUpperCase(); - numberOfEmoji++; - } - - // Process the Unicode emoji data from the Unicode Emoji Data text - const unicodeEmojiLines = unicodeEmojisData.split(/\r?\n/); - let unicodeEmojis: IUnicodeEmojiData = {}; - let group = '', subgroup = '', emojiGroups = [], emojiSubgroups = [], emojiCount = 0; - for (let i = 0; i < unicodeEmojiLines.length; i++) { - const parseResult = Utils.parse(unicodeEmojiLines[i]); - if (!parseResult) { continue; } - if (parseResult.type === 'group') { - group = parseResult.name; - emojiGroups.push(group); - } else if (parseResult.type === 'subgroup') { - subgroup = parseResult.name; - emojiSubgroups.push(subgroup); - } else if (parseResult.type === 'emoji') { - if (!parseResult.unicode) { continue; } - unicodeEmojis[parseResult.unicode] = { - name: parseResult.name, - group: group ?? '', - subgroup: subgroup ?? '', - order: emojiCount++, - origUnicode: parseResult.original - }; - } - } - - // Group the GitHub emoji with the Unicode emoji information - let emojis: IEmojiGroup = {}, customGroup: ICustomEmoji[] = []; - for (const [shortcode, unicode] of Object.entries(githubEmojis)) { - const emojiData = unicodeEmojis[unicode]; - if (!emojiData || emojiData.group === '') { - customGroup.push({unicode: unicode, shortcode: shortcode}); - } else if (emojiData.group !== '') { - if (!emojis[emojiData.group]) { - emojis[emojiData.group] = {}; - } - if (emojiData.subgroup !== '') - if (!emojis[emojiData.group][emojiData.subgroup]) { - emojis[emojiData.group][emojiData.subgroup] = []; - } - const emojiToAdd = {unicode: unicode, shortcode: shortcode, name: emojiData.name, order: emojiData.order, origUnicode: emojiData.origUnicode }; - // Ordering the emoji within the subgroup - const index = emojis[emojiData.group][emojiData.subgroup].findIndex((emoji) => { - return (emoji.order ?? 0) > emojiToAdd.order; - }); - if (index > -1) { - emojis[emojiData.group][emojiData.subgroup].splice(index, 0, emojiToAdd); - } else { - emojis[emojiData.group][emojiData.subgroup].splice(emojis[emojiData.group][emojiData.subgroup].length, 0, emojiToAdd); - } - } - } - - // Export the emoji list to format the JSON - let exportEmoji: IEmojiGroup = {}; - for (const group in emojis) { - exportEmoji[group] = {}; - for (const subgroup in emojis[group]) { - exportEmoji[group][Utils.title(subgroup)] = emojis[group][subgroup].map((e) => ({ - unicode: Utils.toUnicode(e.origUnicode ?? e.unicode), - shortcode: `:${e.shortcode}:` ?? '', - name: e.name, - emoji: Utils.toEmoji(e.origUnicode ?? e.unicode) - })); - } - } - - // Write to a JSON file - await Utils.writeFile('github-emoji.json',JSON.stringify(exportEmoji)); - - // Sort the emoji from group and subgroup - let organizedEmoji: EmojiGroup[] = []; - for (const group in emojis) { - let sortedEmojiSubgroups: EmojiSubgroup[] = []; - for (const subgroup in emojis[group]) { - sortedEmojiSubgroups.push([emojiSubgroups.indexOf(subgroup), subgroup, emojis[group][subgroup]]); - } - sortedEmojiSubgroups = sortedEmojiSubgroups.sort((a, b) => { - return a[0] - b[0]; - }); - organizedEmoji.push([emojiGroups.indexOf(group), group, sortedEmojiSubgroups]); - } - organizedEmoji = organizedEmoji.sort((a, b) => { - return a[0] - b[0]; - }); - - // Create the Markdown - let markdown = '', tableOfContents = '## Table of Contents\n', tocColumns = []; - // Build the Markdown format - for (let i = 0; i < organizedEmoji.length; i++) { - const groupTitle = organizedEmoji[i][1]; - markdown += `## ${groupTitle}\n\n`; - - if (tocColumns.length > 0) { - tableOfContents += `|${tocColumns.join('|')}|\n`; - tocColumns = []; - } - tableOfContents += `\n- ${Utils.anchor(groupTitle)}\n\n`; - tableOfContents += `| | | | | |\n`; - tableOfContents += `|:-----:|:-----:|:-----:|:-----:|:-----:|\n`; - - const subgroups = organizedEmoji[i][2]; - for (let j = 0; j < subgroups.length; j++) { - const subgroupTitle = subgroups[j][1]; - markdown += `### ${Utils.title(subgroupTitle)}\n\n`; - markdown += `|Emoji|Shortcode|Description|\n`; - markdown += `|:---:|:-----:|:---|\n`; - - const emojiInGroup = subgroups[j][2]; - for (let k = 0; k < emojiInGroup.length; k++) { - const emoji = emojiInGroup[k]; - markdown += `|:${emoji.shortcode}:|\`:${emoji.shortcode}:\`|${emoji.name}|\n`; - } - markdown += `\n\n`; - markdown += Utils.anchor(':top: Back to Top', 'github-emoji-icon-list'); - markdown += `\n\n`; - - tocColumns.push(Utils.anchor(`:${emojiInGroup[0].shortcode}: ${Utils.title(subgroupTitle)}`, subgroupTitle)); - if (tocColumns.length > 4) { - tableOfContents += `|${tocColumns.join('|')}|\n`; - tocColumns = []; - } - } - - if (tocColumns.length > 0) { - tableOfContents += `|${tocColumns.join('|')}|\n`; - tocColumns = []; - } - } - - // Add GitHub Custom Emoji - tableOfContents += `\n- ${Utils.anchor('GitHub Custom Emoji')}\n\n`; - - markdown += `## GitHub Custom Emoji\n\n`; - markdown += `|Emoji|Shortcode|\n`; - markdown += `|:---:|:-----:|\n`; - for (let x = 0; x < customGroup.length; x++) { - const emoji = customGroup[x]; - markdown += `|:${emoji.shortcode}:|\`:${emoji.shortcode}:\`|\n`; - } - markdown += `\n\n`; - markdown += Utils.anchor(':top: Back to Top', 'github-emoji-icon-list'); - markdown += `\n`; - - // end - markdown += `\n\n`; - markdown += `:heart: :orange_heart: :yellow_heart: :green_heart: :blue_heart: :purple_heart: :brown_heart: :black_heart: :white_heart:`; - - // Add Table of Contents - markdown = tableOfContents + '\n\n' + markdown; - - // icon divider - markdown = ':red_circle: :orange_circle: :yellow_circle: :green_circle: :large_blue_circle: :purple_circle: :brown_circle: :black_circle: :white_circle: :red_square: :orange_square: :yellow_square: :green_square: :blue_square: :purple_square: :brown_square: :black_large_square: :white_large_square: \n\n' + markdown; - - // Add GitHub Actions badge (Auto Update) - markdown = `[![Auto Update by GitHub Actions](https://github.com/jasonfoknxu/github-emoji-icon-list/actions/workflows/auto-update.yml/badge.svg)](https://github.com/jasonfoknxu/github-emoji-icon-list/actions/workflows/auto-update.yml) :robot: Auto update by GitHub Actions every week.\n\n` + markdown; - - // Add the Json version info - markdown = `[:floppy_disk: JSON version](https://github.com/jasonfoknxu/github-emoji-icon-list/blob/main/github-emoji.json) is available. Feel free to use it for further development.\n\n` + markdown; - - // Add the Json version info - markdown = `:bar_chart: Number of GitHub Emoji Icon: ${Utils.numberIcon(numberOfEmoji)}\n\n` + markdown; - - // Introduction - markdown = `This list includes all the usable Emoji icon shortcodes in GitHub Markdown. The list is automatically generated from [:octocat: GitHub Emoji API](${config.GitHub_Emojis_List}) with the information from [Unicode Emoji data file](${config.Unicode_Emojis_Data}).\n\n> :information_source: *The emoji may be displayed in different result on various system or browser*\n\n` + markdown; - - // Heading - markdown = `# GitHub Emoji Icon List\n\n` + markdown; - - // Write to file README.md - await Utils.writeFile('README.md', markdown); - -})(); +/** + * GitHub Emoji Icon List Markdown Generator + * - Version: 1.0.5 + * - Developer: NXU (GitHub: @jasonfoknxu) + * - https://github.com/jasonfoknxu/github-emoji-icon-list + */ + +import * as Utils from './utilities'; + +(async () => { + // Get the config from config file + const config: Config = await Utils.getConfig(); + // Get the GitHub Emoji Icon List + const githubEmojisData: GithubEmoji = await Utils.get(config.GitHub_Emojis_List); + // Get the Unicode Emoji Data + const unicodeEmojisData = await Utils.get(config.Unicode_Emojis_Data); + + // Stop if no GitHub emoji list or Unicode data + if (!githubEmojisData || !unicodeEmojisData) { + Utils.log('Failed to get the GitHub Emoji List or Unicode Emoji Data.', 'e'); + process.exit(1); + } + + // Count number of GitHub emoji + let numberOfEmoji = 0; + + // Handle the GitHub emoji from the GitHub Emoji Icon List + let githubEmojis: GithubEmoji = {}, githubEmojiImage: GithubEmoji = {}; + for (const [shortcode, url] of Object.entries(githubEmojisData)) { + githubEmojis[shortcode] = Utils.base(url).toUpperCase(); + githubEmojiImage[shortcode] = url; + numberOfEmoji++; + } + + // Process the Unicode emoji data from the Unicode Emoji Data text + const unicodeEmojiLines = unicodeEmojisData.split(/\r?\n/); + let unicodeEmojis: UnicodeEmojiData = {}; + let group = '', subgroup = '', emojiGroups = [], emojiSubgroups = [], emojiCount = 0; + for (let i = 0; i < unicodeEmojiLines.length; i++) { + const parseResult = Utils.parse(unicodeEmojiLines[i]); + if (!parseResult) { continue; } + if (parseResult.type === 'group') { + group = parseResult.name; + emojiGroups.push(group); + } else if (parseResult.type === 'subgroup') { + subgroup = parseResult.name; + emojiSubgroups.push(subgroup); + } else if (parseResult.type === 'emoji') { + if (!parseResult.unicode) { continue; } + unicodeEmojis[parseResult.unicode] = { + name: parseResult.name, + group: group ?? '', + subgroup: subgroup ?? '', + order: emojiCount++, + origUnicode: parseResult.original + }; + } + } + + // Group the GitHub emoji with the Unicode emoji information + let emojis: EmojiGroup = {}, customGroup: CustomEmoji[] = []; + for (const [shortcode, unicode] of Object.entries(githubEmojis)) { + const emojiData = unicodeEmojis[unicode]; + if (!emojiData || emojiData.group === '') { + customGroup.push({ unicode: unicode, shortcode: shortcode }); + } else if (emojiData.group !== '') { + if (!emojis[emojiData.group]) { + emojis[emojiData.group] = {}; + } + if (emojiData.subgroup !== '') + if (!emojis[emojiData.group][emojiData.subgroup]) { + emojis[emojiData.group][emojiData.subgroup] = []; + } + const emojiToAdd = { unicode: unicode, shortcode: shortcode, name: emojiData.name, order: emojiData.order, origUnicode: emojiData.origUnicode }; + // Ordering the emoji within the subgroup + const index = emojis[emojiData.group][emojiData.subgroup].findIndex((emoji) => { + return (emoji.order ?? 0) > emojiToAdd.order; + }); + if (index > -1) { + emojis[emojiData.group][emojiData.subgroup].splice(index, 0, emojiToAdd); + } else { + emojis[emojiData.group][emojiData.subgroup].splice(emojis[emojiData.group][emojiData.subgroup].length, 0, emojiToAdd); + } + } + } + + // Export the emoji list to format the JSON + let exportEmoji: EmojiGroup = {}; + for (const group in emojis) { + exportEmoji[group] = {}; + for (const subgroup in emojis[group]) { + exportEmoji[group][Utils.title(subgroup)] = emojis[group][subgroup].map((e) => ({ + unicode: Utils.toUnicode(e.origUnicode ?? e.unicode), + shortcode: `:${e.shortcode}:`, + name: e.name, + emoji: Utils.toEmoji(e.origUnicode ?? e.unicode), + image: Utils.base(githubEmojiImage[e.shortcode], '') + })); + } + } + + // Write to a JSON file + await Utils.writeFile(config.Json_File_Name ?? 'github-emoji.json', JSON.stringify(exportEmoji)); + + // Sort the emoji from group and subgroup + let organizedEmoji: EmojiGroupData[] = []; + for (const group in emojis) { + let sortedEmojiSubgroups: EmojiSubgroupData[] = []; + for (const subgroup in emojis[group]) { + sortedEmojiSubgroups.push([emojiSubgroups.indexOf(subgroup), subgroup, emojis[group][subgroup]]); + } + sortedEmojiSubgroups = sortedEmojiSubgroups.sort((a, b) => { + return a[0] - b[0]; + }); + organizedEmoji.push([emojiGroups.indexOf(group), group, sortedEmojiSubgroups]); + } + organizedEmoji = organizedEmoji.sort((a, b) => { + return a[0] - b[0]; + }); + + // Create the Markdown + let markdown = '', tableOfContents = '## Table of Contents\n', tocColumns = []; + // Build the Markdown format + for (let i = 0; i < organizedEmoji.length; i++) { + const groupTitle = organizedEmoji[i][1]; + markdown += `## ${groupTitle}\n\n`; + + if (tocColumns.length > 0) { + tableOfContents += `|${tocColumns.join('|')}|\n`; + tocColumns = []; + } + tableOfContents += `\n- ${Utils.anchor(groupTitle)}\n\n`; + tableOfContents += `| | | | | |\n`; + tableOfContents += `|:-----:|:-----:|:-----:|:-----:|:-----:|\n`; + + const subgroups = organizedEmoji[i][2]; + for (let j = 0; j < subgroups.length; j++) { + const subgroupTitle = subgroups[j][1]; + markdown += `### ${Utils.title(subgroupTitle)}\n\n`; + markdown += `|Emoji|Image|Shortcode|Description|\n`; + markdown += `|:---:|:---:|:-----:|:---|\n`; + + const emojiInGroup = subgroups[j][2]; + for (let k = 0; k < emojiInGroup.length; k++) { + const emoji = emojiInGroup[k]; + // Image Markdown: ![${emoji.name}](${githubEmojiImage[emoji.shortcode]}) + // Use HTML instead, because we need to resize the image + markdown += `|:${emoji.shortcode}:|${emoji.name}|\`:${emoji.shortcode}:\`|${emoji.name}|\n`; + } + markdown += `\n\n`; + markdown += Utils.anchor(':top: Back to Top', 'github-emoji-icon-list'); + markdown += `\n\n`; + + tocColumns.push(Utils.anchor(`:${emojiInGroup[0].shortcode}: ${Utils.title(subgroupTitle)}`, subgroupTitle)); + if (tocColumns.length > 4) { + tableOfContents += `|${tocColumns.join('|')}|\n`; + tocColumns = []; + } + } + + if (tocColumns.length > 0) { + tableOfContents += `|${tocColumns.join('|')}|\n`; + tocColumns = []; + } + } + + // Add GitHub Custom Emoji + tableOfContents += `\n- ${Utils.anchor('GitHub Custom Emoji')}\n\n`; + + markdown += `## GitHub Custom Emoji\n\n`; + markdown += `|Emoji|Shortcode|\n`; + markdown += `|:---:|:-----:|\n`; + for (let x = 0; x < customGroup.length; x++) { + const emoji = customGroup[x]; + markdown += `|:${emoji.shortcode}:|\`:${emoji.shortcode}:\`|\n`; + } + markdown += `\n\n`; + markdown += Utils.anchor(':top: Back to Top', 'github-emoji-icon-list'); + markdown += `\n`; + + // end + markdown += `\n\n`; + markdown += `:heart: :orange_heart: :yellow_heart: :green_heart: :blue_heart: :purple_heart: :brown_heart: :black_heart: :white_heart:`; + + // Add Table of Contents + markdown = tableOfContents + '\n\n' + markdown; + + // Square icon divider + markdown = ':red_square: :orange_square: :yellow_square: :green_square: :blue_square: :purple_square: :brown_square: :black_large_square: :white_large_square: \n\n' + markdown; + + // Add GitHub Actions badge (Auto Update) + markdown = `[![Auto Update by GitHub Actions](https://github.com/jasonfoknxu/github-emoji-icon-list/actions/workflows/auto-update.yml/badge.svg)](https://github.com/jasonfoknxu/github-emoji-icon-list/actions/workflows/auto-update.yml)\n\n :robot: New icon checking & Auto update by GitHub Actions everyday.\n\n` + markdown; + + // Add the Json version info + markdown = `[:floppy_disk: JSON version](https://github.com/jasonfoknxu/github-emoji-icon-list/blob/main/github-emoji.json) is available. Feel free to use it for further development.\n\n` + markdown; + + // Add the Json version info + markdown = `:bar_chart: Number of GitHub Emoji Icon: ${Utils.numberIcon(numberOfEmoji)}\n\n` + markdown; + + // Circle icon divider + markdown = ':red_circle: :orange_circle: :yellow_circle: :green_circle: :large_blue_circle: :purple_circle: :brown_circle: :black_circle: :white_circle: \n\n' + markdown; + + // Introduction + markdown = `This list includes all the usable Emoji icon shortcodes in GitHub Markdown. The list is automatically generated from [:octocat: GitHub Emoji API](${config.GitHub_Emojis_List}) with the information from [Unicode Emoji data file](${config.Unicode_Emojis_Data}).\n\n> :information_source: *The emoji may be displayed in different result on various system or browser*\n\n` + markdown; + + // Heading + markdown = `# GitHub Emoji Icon List\n\n` + markdown; + + // Write to file README.md + await Utils.writeFile('README.md', markdown); + +})(); diff --git a/src/interface/Config.ts b/src/interface/Config.ts new file mode 100644 index 0000000..232f27e --- /dev/null +++ b/src/interface/Config.ts @@ -0,0 +1,5 @@ +interface Config { + GitHub_Emojis_List: string, + Unicode_Emojis_Data: string, + Json_File_Name?: string +} diff --git a/src/interface/Emoji.ts b/src/interface/Emoji.ts new file mode 100644 index 0000000..fa66ded --- /dev/null +++ b/src/interface/Emoji.ts @@ -0,0 +1,25 @@ +interface Emoji { + unicode: string, + shortcode: string, + name: string, + order?: number, + emoji?: string, + origUnicode?: string +} + +interface EmojiGroup { + [groupname: string]: EmojiSubgroup +} + +interface EmojiSubgroup { + [subgroupname: string]: Emoji[] +} + +interface CustomEmoji { + unicode: string, + shortcode: string +} + +type EmojiSubgroupData = [suborder: number, subgroup: string, emoji: Emoji[]]; + +type EmojiGroupData = [order: number, group: string, subgroups: EmojiSubgroupData[]]; diff --git a/src/interface/IGithubEmoji.ts b/src/interface/GithubEmoji.ts similarity index 55% rename from src/interface/IGithubEmoji.ts rename to src/interface/GithubEmoji.ts index 77b51e0..018e209 100644 --- a/src/interface/IGithubEmoji.ts +++ b/src/interface/GithubEmoji.ts @@ -1,3 +1,3 @@ -interface IGithubEmoji { - [shortcode: string]: string -} +interface GithubEmoji { + [shortcode: string]: string +} diff --git a/src/interface/IConfig.ts b/src/interface/IConfig.ts deleted file mode 100644 index 6e78e8b..0000000 --- a/src/interface/IConfig.ts +++ /dev/null @@ -1,4 +0,0 @@ -interface IConfig { - GitHub_Emojis_List: string, - Unicode_Emojis_Data: string -} diff --git a/src/interface/IEmoji.ts b/src/interface/IEmoji.ts deleted file mode 100644 index 83b12d3..0000000 --- a/src/interface/IEmoji.ts +++ /dev/null @@ -1,25 +0,0 @@ -interface IEmoji { - unicode: string, - shortcode?: string, - name: string, - order?: number, - emoji?: string, - origUnicode?: string -} - -interface IEmojiGroup { - [groupname: string]: IEmojiSubgroup -} - -interface IEmojiSubgroup { - [subgroupname: string]: IEmoji[] -} - -interface ICustomEmoji { - unicode: string, - shortcode: string -} - -type EmojiSubgroup = [suborder: number, subgroup: string, emoji: IEmoji[]]; - -type EmojiGroup = [order: number, group: string, subgroups: EmojiSubgroup[]]; diff --git a/src/interface/IUnicode.ts b/src/interface/Unicode.ts similarity index 59% rename from src/interface/IUnicode.ts rename to src/interface/Unicode.ts index 5f64c0b..b03fd33 100644 --- a/src/interface/IUnicode.ts +++ b/src/interface/Unicode.ts @@ -1,18 +1,18 @@ -interface IUnicode { - type: string, - name: string, - unicode?: string, - original?: string -} - -interface IUnicodeEmojiData { - [unicode: string]: IUnicodeEmoji -} - -interface IUnicodeEmoji { - name: string, - group: string, - subgroup: string, - order: number, - origUnicode?: string -} +interface Unicode { + type: string, + name: string, + unicode?: string, + original?: string +} + +interface UnicodeEmojiData { + [unicode: string]: UnicodeEmoji +} + +interface UnicodeEmoji { + name: string, + group: string, + subgroup: string, + order: number, + origUnicode?: string +} diff --git a/src/utilities.ts b/src/utilities.ts index a6ac1d8..92cea8d 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -1,215 +1,215 @@ -/** - * Utilities of GitHub Emoji Icon List Markdown Generator - */ - -import {promises as fs} from 'fs'; -import axios from 'axios'; -import path from 'path'; - -/** - * Get the config from the config file - * - * @param filename - The file name of the config file (in project root dir) - * @param format - The file extension of the config file (normally is JSON) - * - * @returns The parsed config from the JSON-formatted config file - */ -const getConfig = async (filename: string = 'config', format: string = 'json'): Promise => { - try { - const readConfig: string = await fs.readFile(path.join(__dirname, '../', `${filename}.${format}`), 'utf8'); - return JSON.parse(readConfig); - } catch (err) { - log('Failed to read the config file.', 'e'); - console.log(err); - process.exit(); - } -}; - -/** - * Perform a HTTP/HTTPS get request - * - * @param url - The URL of the request - * - * @returns The responsive result of the request - */ -const get = async (url: string) => { - return (await axios.get(url)).data ?? null; -}; - -/** - * Extract the unicode form the urls in the GitHub emoji icon list - * - * @param url - The URL of a GitHub emoji icon - * @param extension - The extension of the GitHUb emoji icon - * - * @returns The unicode of a GitHub emoji - */ -const base = (url: string, extension: string = '.png'): string => { - if (url.includes('?')) { - url = url.split('?')[0]; - } - return path.basename(url, extension); -}; - -/** - * Parser to extract the data from the Unicode Emojis Data text - * - * @param text - A line of the Unicode Emojis text - * - * @returns The parsed result of the line of Unicode Emoji text - */ -const parse = (text: string): IUnicode | null => { - // Format: {code points}; {status} # {emoji} E{emoji version} {name} - const dataRegex = /^(.+)\s+;.+#.+E[\d.]+\s+(.+)$/i; - const dataMatch = text.match(dataRegex); - if (dataMatch !== null) { - let unicode = dataMatch[1].trim(); - // \u200d is the joiner unicode which is not used in GitHub icon file naming - const originalUnicode = (unicode.includes(' 200D')) ? unicode.replace(/\s/g, '-').toUpperCase() : undefined; - unicode = unicode.replace(/\s200D/g, '').replace(/\s/g, '-').toUpperCase(); - return {type: 'emoji', name: dataMatch[2].trim(), unicode: unicode, original: originalUnicode }; - } - const subgroupRegex = /^#\s+subgroup:\s+(.+)$/i; - const subgroupMatch = text.match(subgroupRegex); - if (subgroupMatch !== null) { - return {type: 'subgroup', name: subgroupMatch[1].trim()}; - } - const groupRegex = /^#\s+group:\s+(.+)$/i; - const groupMatch = text.match(groupRegex); - if (groupMatch !== null) { - return {type: 'group', name: groupMatch[1].trim()}; - } - return null; -}; - -/** - * Formatting a title (Uppercase first character of each word) - * - * @param text - The original text for the title - * - * @returns The formatted title - */ -const title = (text: string): string => { - text = text.replace(/-/g, ' '); - if (text.includes(' ')) { - const words = text.split(' '); - return words.map((word) => { - return word[0].toUpperCase() + word.substring(1); - }).join(' '); - } - return text[0].toUpperCase() + text.substring(1); -}; - -/** - * Convert the unicode to Emoji symbol - * - * @param unicode - The Unicode - * - * @returns The Emoji symbol - */ -const toEmoji = (unicode: string): string => { - if (unicode.includes('-')) { - const codes = unicode.split('-'); - return codes.map((u) => { - return String.fromCodePoint(parseInt(u, 16)); - }).join(''); - } - return String.fromCodePoint(parseInt(unicode, 16)); -}; - -/** - * Convert the unicode text to Unicode - * - * @param unicodeText - The text of the Unicode - * - * @returns The Unicode formatted unicode - */ -const toUnicode = (unicodeText: string): string => { - if (unicodeText.includes('-')) { - const codes = unicodeText.split('-'); - return codes.map((u) => { - return ` U+${u}`; - }).join('').trim(); - } - return `U+${unicodeText}`; -}; - -/** - * Convert the number to icon - * - * @param num - The number text - * - * @returns The shortcodes of the number icon - */ -const numberIcon = (num: number | string): string => { - const mapping = ['zero','one','two','three','four','five','six','seven','eight','nine']; - let result = ''; - for (const n of num.toString()) { - result += `:${mapping[parseInt(n)]}:`; - } - return result; -}; - -/** - * Create a Markdown Anchor - * - * @param displayText - The text for the anchor - * @param anchorPoint - The named anchor point to be linked - * - * @returns The anchor point Markdown - */ -const anchor = (displayText: string, anchorPoint: string = '') => { - if (anchorPoint === '') { - anchorPoint = displayText; - } - return `[${displayText}](#${anchorPoint.toLowerCase().replace(/\s/g, '-').replace(/&/g, '')})`; -}; - -/** - * Write content to a file - * - * @param filepath - The path of the file (in project root directory) - * @param content - The content to be written to the file - * - */ -const writeFile = async (filepath: string, content: string) => { - await fs.writeFile(path.join(__dirname, '../', `${filepath}`), content); -}; - -/** - * Log for message (Display in the console only) - * - * @param message - The text to be logged - * @param type - The type of the log - * - */ -const log = (message: string, type: string = '') => { - let msgType; - switch (type.toLowerCase()) { - case 'i': - msgType = 'INFO'; - break; - case 'e': - msgType = 'ERROR'; - break; - case 'w': - msgType = 'WARNING'; - break; - default: - msgType = 'MESSAGE'; - } - console.log(`[${msgType}] ${timeNow()} | ${message}`); -}; - -/** - * Get current date time with format YYYY-MM-DD HH:mm:ss - * - * @returns The formatted datetime - */ -const timeNow = (): string => { - const d: Date = new Date(); - return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`; -}; - - -export {getConfig, get, base, parse, title, toEmoji, toUnicode, numberIcon, anchor, writeFile, log, timeNow}; +/** + * Utilities of GitHub Emoji Icon List Markdown Generator + */ + +import {promises as fs} from 'fs'; +import axios from 'axios'; +import path from 'path'; + +/** + * Get the config from the config file + * + * @param filename - The file name of the config file (in project root dir) + * @param format - The file extension of the config file (normally is JSON) + * + * @returns The parsed config from the JSON-formatted config file + */ +const getConfig = async (filename: string = 'config', format: string = 'json'): Promise => { + try { + const readConfig: string = await fs.readFile(path.join(__dirname, '../', `${filename}.${format}`), 'utf8'); + return JSON.parse(readConfig); + } catch (err) { + log('Failed to read the config file.', 'e'); + console.log(err); + process.exit(); + } +}; + +/** + * Perform a HTTP/HTTPS get request + * + * @param url - The URL of the request + * + * @returns The responsive result of the request + */ +const get = async (url: string) => { + return (await axios.get(url)).data ?? null; +}; + +/** + * Extract the unicode form the urls in the GitHub emoji icon list + * + * @param url - The URL of a GitHub emoji icon + * @param extension - The extension of the GitHUb emoji icon + * + * @returns The unicode of a GitHub emoji + */ +const base = (url: string, extension: string = '.png'): string => { + if (url.includes('?')) { + url = url.split('?')[0]; + } + return path.basename(url, extension); +}; + +/** + * Parser to extract the data from the Unicode Emojis Data text + * + * @param text - A line of the Unicode Emojis text + * + * @returns The parsed result of the line of Unicode Emoji text + */ +const parse = (text: string): Unicode | null => { + // Format: {code points}; {status} # {emoji} E{emoji version} {name} + const dataRegex = /^(.+)\s+;.+#.+E[\d.]+\s+(.+)$/i; + const dataMatch = text.match(dataRegex); + if (dataMatch !== null) { + let unicode = dataMatch[1].trim(); + // \u200d is the joiner unicode which is not used in GitHub icon file naming + const originalUnicode = (unicode.includes(' 200D')) ? unicode.replace(/\s/g, '-').toUpperCase() : undefined; + unicode = unicode.replace(/\s200D/g, '').replace(/\s/g, '-').toUpperCase(); + return {type: 'emoji', name: dataMatch[2].trim(), unicode: unicode, original: originalUnicode }; + } + const subgroupRegex = /^#\s+subgroup:\s+(.+)$/i; + const subgroupMatch = text.match(subgroupRegex); + if (subgroupMatch !== null) { + return {type: 'subgroup', name: subgroupMatch[1].trim()}; + } + const groupRegex = /^#\s+group:\s+(.+)$/i; + const groupMatch = text.match(groupRegex); + if (groupMatch !== null) { + return {type: 'group', name: groupMatch[1].trim()}; + } + return null; +}; + +/** + * Formatting a title (Uppercase first character of each word) + * + * @param text - The original text for the title + * + * @returns The formatted title + */ +const title = (text: string): string => { + text = text.replace(/-/g, ' '); + if (text.includes(' ')) { + const words = text.split(' '); + return words.map((word) => { + return word[0].toUpperCase() + word.substring(1); + }).join(' '); + } + return text[0].toUpperCase() + text.substring(1); +}; + +/** + * Convert the unicode to Emoji symbol + * + * @param unicode - The Unicode + * + * @returns The Emoji symbol + */ +const toEmoji = (unicode: string): string => { + if (unicode.includes('-')) { + const codes = unicode.split('-'); + return codes.map((u) => { + return String.fromCodePoint(parseInt(u, 16)); + }).join(''); + } + return String.fromCodePoint(parseInt(unicode, 16)); +}; + +/** + * Convert the unicode text to Unicode + * + * @param unicodeText - The text of the Unicode + * + * @returns The Unicode formatted unicode + */ +const toUnicode = (unicodeText: string): string => { + if (unicodeText.includes('-')) { + const codes = unicodeText.split('-'); + return codes.map((u) => { + return ` U+${u}`; + }).join('').trim(); + } + return `U+${unicodeText}`; +}; + +/** + * Convert the number to icon + * + * @param num - The number text + * + * @returns The shortcodes of the number icon + */ +const numberIcon = (num: number | string): string => { + const mapping = ['zero','one','two','three','four','five','six','seven','eight','nine']; + let result = ''; + for (const n of num.toString()) { + result += `:${mapping[parseInt(n)]}:`; + } + return result; +}; + +/** + * Create a Markdown Anchor + * + * @param displayText - The text for the anchor + * @param anchorPoint - The named anchor point to be linked + * + * @returns The anchor point Markdown + */ +const anchor = (displayText: string, anchorPoint: string = '') => { + if (anchorPoint === '') { + anchorPoint = displayText; + } + return `[${displayText}](#${anchorPoint.toLowerCase().replace(/\s/g, '-').replace(/&/g, '')})`; +}; + +/** + * Write content to a file + * + * @param filepath - The path of the file (in project root directory) + * @param content - The content to be written to the file + * + */ +const writeFile = async (filepath: string, content: string) => { + await fs.writeFile(path.join(__dirname, '../', `${filepath}`), content); +}; + +/** + * Log for message (Display in the console only) + * + * @param message - The text to be logged + * @param type - The type of the log + * + */ +const log = (message: string, type: string = '') => { + let msgType; + switch (type.toLowerCase()) { + case 'i': + msgType = 'INFO'; + break; + case 'e': + msgType = 'ERROR'; + break; + case 'w': + msgType = 'WARNING'; + break; + default: + msgType = 'MESSAGE'; + } + console.log(`[${msgType}] ${timeNow()} | ${message}`); +}; + +/** + * Get current date time with format YYYY-MM-DD HH:mm:ss + * + * @returns The formatted datetime + */ +const timeNow = (): string => { + const d: Date = new Date(); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`; +}; + + +export {getConfig, get, base, parse, title, toEmoji, toUnicode, numberIcon, anchor, writeFile, log, timeNow}; diff --git a/tsconfig.json b/tsconfig.json index 65e716f..24b67a4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,15 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "rootDir": "src", - "typeRoots": ["./src/interface"], - "types": ["node"], - "outDir": "dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true - }, - "include": [ - "src/*", - "src/*/*" - ] -} +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "rootDir": "src", + "typeRoots": ["./src/interface"], + "types": ["node"], + "outDir": "dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "include": ["src/*", "src/*/*"] +} diff --git a/yarn.lock b/yarn.lock index 8c5b53a..34ec290 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,174 +1,174 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== - -"@types/node@^18.11.12": - version "18.11.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.12.tgz#89e7f8aa8c88abf432f9bd594888144d7dba10aa" - integrity sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1: - version "8.8.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" - integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a" - integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -typescript@^4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" - integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@types/node@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.0.0.tgz#081d9afd28421be956c1a47ced1c9a0034b467e2" + integrity sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a" + integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +typescript@^4.9.3: + version "4.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" + integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==