diff --git a/.env.example b/.env.example index ee78008..521453b 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,4 @@ # Replace ghp_xxx with your GitHub PAT token -GH_TOKEN=ghp_xxx +GH_TOKEN_1=ghp_xxx +GH_TOKEN_2=ghp_xxx +GH_TOKEN_3=ghp_xxx diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..122b047 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "env": { + "browser": true, + "es2021": true, + "jest": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/explicit-module-boundary-types": "on", + "@typescript-eslint/no-explicit-any": "error" + } +} diff --git a/.github/mergify.yml b/.github/mergify.yml index ebb96c8..b8a4c77 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -1,8 +1,6 @@ queue_rules: - # If you have other queues defined, add this at the end so it is processed last - name: dep-update batch_size: 10 - # Wait for up to 30 minutes for the batch to fill up batch_max_wait_time: 30 min queue_conditions: - author = dependabot[bot] @@ -20,8 +18,15 @@ pull_request_rules: - "#approved-reviews-by>=1" actions: queue: + - name: Automatic approve for GitHub Actions pull requests + conditions: + - author = github-actions[bot] + actions: + review: + type: APPROVE - name: Automatic merge for GitHub Actions pull requests conditions: - author = github-actions[bot] + - "#approved-reviews-by>=1" actions: merge: diff --git a/.github/workflows/auto-build-pkg.yml b/.github/workflows/auto-build-pkg.yml index e970af8..0f13498 100644 --- a/.github/workflows/auto-build-pkg.yml +++ b/.github/workflows/auto-build-pkg.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ matrix.node-version }} cache: npm diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fda6093..f9daa60 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -64,7 +64,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -77,6 +77,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/generate-locale-doc.yml b/.github/workflows/generate-locale-doc.yml index 30be507..4beefe3 100644 --- a/.github/workflows/generate-locale-doc.yml +++ b/.github/workflows/generate-locale-doc.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ matrix.node-version }} cache: npm @@ -58,7 +58,7 @@ jobs: - name: Push commit to a new branch and create prs run: | branch="auto_update_locale_readme" - message="docs(translation): auto update translation readme" + message="docs(i18n): auto update translation readme" body=$(printf "## Changes File\n\n\`\`\`diff\n$(git diff)\n\`\`\`\n\n> Co-authored-by: github-actions[bot] ") if [[ "$(git status --porcelain)" != "" ]]; then git branch -D ${branch} || true diff --git a/.github/workflows/generate-theme-doc.yml b/.github/workflows/generate-theme-doc.yml index b99faea..0474451 100644 --- a/.github/workflows/generate-theme-doc.yml +++ b/.github/workflows/generate-theme-doc.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ matrix.node-version }} cache: npm diff --git a/.github/workflows/setup-package.yml b/.github/workflows/setup-package.yml index f09849b..fb65ce1 100644 --- a/.github/workflows/setup-package.yml +++ b/.github/workflows/setup-package.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v4 # Setup .npmrc file to publish to GitHub Packages - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4.0.1 with: node-version: '20.x' registry-url: 'https://npm.pkg.github.com' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4f2db6..ca11478 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: ${{ matrix.node-version }} cache: npm diff --git a/.github/workflows/top-issues-dashboard.yml b/.github/workflows/top-issues-dashboard.yml index 9bdf214..b679134 100644 --- a/.github/workflows/top-issues-dashboard.yml +++ b/.github/workflows/top-issues-dashboard.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Run top issues action - uses: rickstaa/top-issues-action@8c70898862d1e7808bd5ce009405ac44f461044d # v1.3.77 + uses: rickstaa/top-issues-action@fa1b14384871ebbc2f341f953a728e8370788992 # v1.3.87 env: github_token: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.npmignore b/.npmignore index 483dbe0..2700ad8 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,9 @@ +coverage.yml +jest.config.json + .github/ +tests/ scripts/ +node_modules/ +coverage/ +public/ diff --git a/README.md b/README.md index 24b48cd..c05549c 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,10 @@

Report Bugs · Request Feature · Ask Question

GitHub Readme Profile Version GitHub Readme Profile Code Quality - GitHub Readme Profile Issues - GitHub Readme Profile PRs + GitHub Readme Profile Issues + GitHub Readme Profile PRs + Join to Community
@@ -327,9 +328,10 @@ Step-by-step guide on setting up your own Vercel instance. 7. To import a project, click the `Add New...` or `+` button and select the `Project` option. 8. Click the Continue with GitHub button, search for the required Git Repository and import it by clicking the `Import` button. Alternatively, you can import a Third-Party Git Repository using the `Import Third-Party Git Repository` link at the bottom of the page. 9. Create a personal access token (PAT) [here](https://github.com/settings/tokens/new) and enable the `repo` and `user` permissions (this allows access to see private repo and user stats). -10. Add the PAT as an environment variable named `GH_TOKEN`. -11. In build and output settings, you set install command toggle and add command `npm install typescript`. -12. Click deploy, and you're good to go. See your domains to use the API! +10. Add the PAT as an environment variable named `GH_TOKEN_1`. +11. Repeat step number 9 and add PAT up to the `GH_TOKEN_3` environment variable. +12. In build and output settings, you set install command toggle and add command `npm install typescript`. +13. Click deploy, and you're good to go. See your domains to use the API! [![Deploy](https://raw.githubusercontent.com/FajarKim/FajarKim/master/images/deploy-on-vercel.svg)](https://vercel.com/import/project?template=https://github.com/FajarKim/github-readme-profile) @@ -367,7 +369,7 @@ Want to contribute? Please note our contribution guidelines [here](/CONTRIBUTING

Made with ❤️ and TypeScript

-

Copyright © 2023 Rangga Fajar Oktariansyah

+

Copyright © 2023-present Rangga Fajar Oktariansyah

GitHub Readme Profile License -
\ No newline at end of file + diff --git a/api/index.ts b/api/index.ts index 4ff2868..803b1ae 100644 --- a/api/index.ts +++ b/api/index.ts @@ -1,13 +1,32 @@ -// Importing necessary libraries and modules import escapeHTML from "escape-html"; import { Resvg } from "@resvg/resvg-js"; import getData from "../src/getData"; -import cardStyle from "../src/card"; +import card from "../src/card"; import { themes, Themes } from "../themes/index"; import { isValidHexColor, isValidGradient, parseBoolean } from "../src/common/utils"; -// User interface configuration type -export type UiConfig = { +/** + * Type representing the configuration for the card options. + * + * @typedef {Object} UiConfig + * @property {string} titleColor - Color for the title text. + * @property {string} textColor - Color for the main text. + * @property {string} iconColor - Color for icons. + * @property {string} borderColor - Color for borders. + * @property {string} strokeColor - Color for strokes. + * @property {string} usernameColor - Color for the username. + * @property {any} bgColor - Background color or gradient. + * @property {string} Locale - Locale setting. + * @property {number|string} borderWidth - Width of borders. + * @property {number|string} borderRadius - Radius of borders. + * @property {boolean|string} disabledAnimations - Toggle for disabling animations. + * @property {string} Format - Output format (e.g., "svg", "png", or "json"). + * @property {string|undefined} hiddenItems - Items to hide. + * @property {string|undefined} showItems - Items to show. + * @property {boolean|string} hideStroke - Toggle for hiding strokes. + * @property {boolean|string} hideBorder - Toggle for hiding borders. + */ +type UiConfig = { titleColor: string; textColor: string; iconColor: string; @@ -27,23 +46,20 @@ export type UiConfig = { }; /** - * Generates readme stats based on user input. + * Handles the generation card of a GitHub stats based on user data and specified options. * - * @param {any} req HTTP request object. - * @param {any} res HTTP response object. - * @returns {Promise} Promise representing the response. + * @param {any} req - The request object from the client. + * @param {any} res - The response object to send data back to the client. + * @returns {Promise} - A promise that resolves when the photo profile is generated and sent. */ -export default async function readmeStats(req: any, res: any): Promise { +async function readmeStats(req: any, res: any): Promise { try { - // Extracting and escaping username from the request const username = escapeHTML(req.query.username); - // Setting fallback and default themes const fallbackTheme = "default"; const defaultTheme: Themes[keyof Themes] = themes[fallbackTheme]; const selectTheme: Themes[keyof Themes] = themes[req.query.theme] || defaultTheme; - // Configuring UI based on request parameters or using default values const uiConfig: UiConfig = { titleColor: escapeHTML(req.query.title_color || selectTheme.title_color || defaultTheme.title_color), textColor: escapeHTML(req.query.text_color || selectTheme.text_color || defaultTheme.text_color), @@ -63,7 +79,6 @@ export default async function readmeStats(req: any, res: any): Promise { hideBorder: parseBoolean(escapeHTML(req.query.hide_border)) || false, }; - // Validating username and color codes if (!username) { throw new Error("Username is required"); } @@ -79,38 +94,35 @@ export default async function readmeStats(req: any, res: any): Promise { throw new Error("Enter a valid hex color code"); } - // Validating background color or gradient if (!isValidGradient(uiConfig.bgColor)) { if (!isValidHexColor(uiConfig.bgColor)) { throw new Error("Enter a valid hex color code"); } } - // Fetching user stats data const fetchStats = await getData(username); res.setHeader("Cache-Control", "s-maxage=3600, stale-while-revalidate"); - // Handling different response formats (JSON, PNG, SVG) if (uiConfig.Format === "json") { res.json(fetchStats); } else if (uiConfig.Format === "png") { - // Converting SVG to PNG using @resvg/resvg-js - const svgString = cardStyle(fetchStats, uiConfig); + const svgString = card(fetchStats, uiConfig); const resvg = new Resvg(svgString, { font: { defaultFontFamily: "Segoe UI" }}); const pngBuffer = await resvg.render().asPng(); - // Sending PNG in the response res.setHeader("Content-Type", "image/png"); res.send(pngBuffer); } else { - // Sending SVG in the response res.setHeader("Content-Type", "image/svg+xml"); - const svg = cardStyle(fetchStats, uiConfig); + const svg = card(fetchStats, uiConfig); res.send(svg); } } catch (error: any) { - // Handling and logging errors in the response + const message = error.message; res.setHeader("Cache-Control", "s-maxage=7200, stale-while-revalidate"); - res.status(500).send(escapeHTML(error.message)); + res.status(500).send(escapeHTML(message)); } } + +export { UiConfig, readmeStats }; +export default readmeStats; diff --git a/package-lock.json b/package-lock.json index 9dc5ad7..09df039 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@fajarkim/github-readme-profile", - "version": "1.0.8-beta.1", + "version": "1.0.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@fajarkim/github-readme-profile", - "version": "1.0.8-beta.1", + "version": "1.0.9", "license": "MIT", "dependencies": { "@actions/core": "^1.10.1", "@resvg/resvg-js": "^2.6.0", "@types/escape-html": "^1.0.4", "@types/express": "^4.17.21", - "axios": "^1.6.2", + "axios": "^1.6.3", "dotenv": "^16.3.1", "escape-html": "^1.0.3", "express": "^4.18.2", @@ -23,7 +23,10 @@ "devDependencies": { "@markdoc/markdoc": "^0.4.0", "@types/jest": "^29.5.11", - "@types/node": "^20.10.4", + "@types/node": "^20.10.6", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", + "eslint": "^8.56.0", "jest": "^29.7.0", "nodemon": "^3.0.2", "ts-jest": "^29.1.1", @@ -31,6 +34,15 @@ "typescript": "^5.3.3" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@actions/core": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", @@ -156,21 +168,21 @@ } }, "node_modules/@babel/core": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", - "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-compilation-targets": "^7.22.15", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.5", - "@babel/parser": "^7.23.5", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -209,12 +221,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", - "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.5", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -224,14 +236,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -365,14 +377,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", - "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", + "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5" + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" }, "engines": { "node": ">=6.9.0" @@ -464,9 +476,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", - "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -667,20 +679,20 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", - "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.5", - "@babel/types": "^7.23.5", - "debug": "^4.1.0", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -711,9 +723,9 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", - "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -752,6 +764,130 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@fastify/busboy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", @@ -760,6 +896,62 @@ "node": ">=14" } }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1135,6 +1327,41 @@ } } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@resvg/resvg-js": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.0.tgz", @@ -1399,9 +1626,9 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" @@ -1418,9 +1645,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -1518,6 +1745,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/linkify-it": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", @@ -1549,23 +1782,29 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/qs": { - "version": "6.9.10", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", - "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==" + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -1606,86 +1845,522 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", + "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "dev": true, "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/type-utils": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": ">= 0.6" + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "ms": "2.1.2" }, "engines": { - "node": ">=0.4.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/acorn-walk": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", - "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "type-fest": "^0.21.3" + "lru-cache": "^6.0.0" }, - "engines": { - "node": ">=8" + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", + "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4" }, "engines": { - "node": ">=8" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", + "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", + "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", + "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", + "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", + "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", + "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1715,15 +2390,24 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz", + "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -1996,9 +2680,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001566", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", - "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "version": "1.0.30001572", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001572.tgz", + "integrity": "sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==", "dev": true, "funding": [ { @@ -2251,6 +2935,12 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2325,6 +3015,30 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dotenv": { "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", @@ -2342,9 +3056,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.609", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.609.tgz", - "integrity": "sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==", + "version": "1.4.616", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.616.tgz", + "integrity": "sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==", "dev": true }, "node_modules/emittery": { @@ -2381,26 +3095,264 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -2416,6 +3368,48 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2513,12 +3507,49 @@ "node": ">= 0.10.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -2528,6 +3559,18 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2570,10 +3613,30 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "funding": [ { "type": "individual", @@ -2739,6 +3802,26 @@ "node": ">=4" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -2756,6 +3839,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2850,12 +3939,46 @@ "node": ">=0.10.0" } }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -2984,6 +4107,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3743,12 +4875,30 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -3761,6 +4911,15 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -3779,6 +4938,19 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -3803,6 +4975,12 @@ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3894,6 +5072,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -4213,6 +5400,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4264,6 +5468,18 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -4328,6 +5544,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4367,6 +5592,15 @@ "node": ">=8" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -4429,6 +5663,15 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -4459,6 +5702,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4554,6 +5817,54 @@ "node": ">=10" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4898,6 +6209,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -4945,6 +6262,18 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-jest": { "version": "29.1.1", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", @@ -5072,6 +6401,18 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -5178,6 +6519,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index f72bc1b..51726f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fajarkim/github-readme-profile", - "version": "1.0.8-beta.1", + "version": "1.0.9", "description": "🙀 Generate your Stats GitHub Profile in SVG", "main": "api/index.ts", "dependencies": { @@ -8,7 +8,7 @@ "@resvg/resvg-js": "^2.6.0", "@types/escape-html": "^1.0.4", "@types/express": "^4.17.21", - "axios": "^1.6.2", + "axios": "^1.6.3", "dotenv": "^16.3.1", "escape-html": "^1.0.3", "express": "^4.18.2", @@ -46,7 +46,10 @@ "devDependencies": { "@markdoc/markdoc": "^0.4.0", "@types/jest": "^29.5.11", - "@types/node": "^20.10.4", + "@types/node": "^20.10.6", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", + "eslint": "^8.56.0", "jest": "^29.7.0", "nodemon": "^3.0.2", "ts-jest": "^29.1.1", diff --git a/scripts/generate-theme-doc.ts b/scripts/generate-theme-doc.ts index e8ab605..f3f04a8 100644 --- a/scripts/generate-theme-doc.ts +++ b/scripts/generate-theme-doc.ts @@ -1,43 +1,20 @@ -// Importing necessary libraries and modules import fs from "fs"; -import { themes } from "../themes/index"; +import themes from "../themes/index"; const TARGET_FILE = "./themes/README.md"; -/** - * Generates the markdown for a theme. - * - * @param {string} theme Theme name. - * @returns {string} Theme markdown string. - */ function generateThemeMarkdown(theme: string): string { - // Creates a markdown string for a given theme return `\`${theme}\` ![${theme}][${theme}]`; } -/** - * Generates the link to the theme image for a username and theme. - * - * @param {string} username GitHub username. - * @param {string} theme Theme name. - * @returns {string} Theme link string. - */ function generateThemeLink(username: string, theme: string): string { - // Creates a link to the theme image for a specific username and theme return `[${theme}]: https://github-readme-profile-alpha.vercel.app/api?username=${username}&theme=${theme}`; } -/** - * Generates the content for the README file with available themes and preview links. - * - * @param {string} username GitHub username. - * @returns {string} README content string. - */ export function generateReadmeThemes(username: string): string { const availableThemes = Object.keys(themes); const itemsPerRow = 3; - // Generate table rows with theme markdown let themesPreviewTable = ""; for (let i = 0; i < availableThemes.length; i += itemsPerRow) { const themesSlice = availableThemes.slice(i, i + itemsPerRow); @@ -45,7 +22,6 @@ export function generateReadmeThemes(username: string): string { themesPreviewTable += `| ${row} |\n`; } - // Generate individual theme links let themesPreviewLink = ""; for (let i = 0; i < availableThemes.length; i += 1) { const themesSlice = availableThemes.slice(i, i + 1); @@ -53,7 +29,6 @@ export function generateReadmeThemes(username: string): string { themesPreviewLink += `${row}\n`; } - // Final README content with themes and links const readmeContent = ` ## Available Themes @@ -78,11 +53,8 @@ ${themesPreviewLink}`; return readmeContent; } -// GitHub username to generate the README const username = "FajarKim"; -// Generate the README content const generatedReadme = generateReadmeThemes(username); -// Write the README content to the specified file fs.writeFileSync(TARGET_FILE, generatedReadme); diff --git a/scripts/generate-translation-doc.ts b/scripts/generate-translation-doc.ts index 6dfc5fc..fdce7e5 100644 --- a/scripts/generate-translation-doc.ts +++ b/scripts/generate-translation-doc.ts @@ -1,30 +1,16 @@ -// Importing necessary libraries and modules import fs from "fs"; -import { locales } from "../src/translations"; -import { languageNames } from "./languageNames"; +import locales from "../src/translations"; +import languageNames from "./languageNames"; const TARGET_FILE = "./docs/translations.md"; -/** - * Generates the markdown for a locale. - * - * @param {string} locale Locale code. - * @returns {string} Locale markdown string. - */ function generateTranslationsMarkdown(locale: string): string { - // Returns the markdown string for a specific locale return `${locale}`; } -/** - * Generates the content for the README file with available locales and progress. - * - * @returns {string} README content string. - */ export function generateReadmeLocales(): string { const availableLocales = Object.keys(locales); - // Generate table rows with locale details let localesListTable = ""; for (let i = 0; i < availableLocales.length; i += 1) { const localesSlice = availableLocales.slice(i, i + 1); @@ -36,7 +22,6 @@ export function generateReadmeLocales(): string { \n`; } - // Final README content with locales and progress const readmeContent = ` ## Available Locales Use \`?locale=LOCALE_CODE\` parameter like so :- @@ -61,8 +46,6 @@ Want to add new translations? Consider reading the [contribution guidelines](htt return readmeContent; } -// Generate the README content const generatedReadme = generateReadmeLocales(); -// Write the README content to the specified file fs.writeFileSync(TARGET_FILE, generatedReadme); diff --git a/scripts/languageNames.ts b/scripts/languageNames.ts index 411a5d4..b2d7565 100644 --- a/scripts/languageNames.ts +++ b/scripts/languageNames.ts @@ -1,10 +1,20 @@ -// Represents the structure of localized code languages name in English -export type LanguageNames = { +/** + * Type representing a collection of language names based on language codes. + * + * @typedef {Object} LanguageNames + * @property {string} [key] - Language code. + * @property {string} [value] - Language name. + */ +type LanguageNames = { [key: string]: string; }; -// Object containing localized strings for different languages name in English -export const languageNames: LanguageNames = { +/** + * LanguageNames object stores language code and language name. + * + * @type {LanguageNames} + */ +const languageNames: LanguageNames = { "af": "Afrikaans", "af-NA": "Afrikaans (Namibia)", "af-ZA": "Afrikaans (South Africa)", @@ -810,4 +820,7 @@ export const languageNames: LanguageNames = { "zh-Hant-TW": "Chinese (Traditional, Taiwan)", "zu": "Zulu", "zu-ZA": "Zulu (South Africa)", -} +}; + +export { LanguageNames, languageNames }; +export default languageNames; diff --git a/src/card.ts b/src/card.ts index f126e63..4dc2615 100644 --- a/src/card.ts +++ b/src/card.ts @@ -1,95 +1,90 @@ -// Importing necessary types and modules import type { GetData } from "./getData"; import type { UiConfig } from "../api/index"; import { locales, Locales } from "./translations"; -import { icons } from "./icons"; +import icons from "./icons"; import { parseBoolean } from "./common/utils"; /** - * Generates the SVG code for the user's GitHub stats card based on provided data and UI configuration. + * Generates the SVG markup for the GitHub stats card. * - * @param {GetData} data User's GitHub stats data. - * @param {UiConfig} uiConfig User interface configuration. - * @returns {string} SVG code representing the GitHub stats card. + * @param {GetData} data - GitHub user data stats. + * @param {UiConfig} uiConfig - Configuration for the UI card options. + * @returns {string} - SVG markup for the GitHub stats card. */ -export default function cardStyle(data: GetData, uiConfig: UiConfig): string { - // Setting fallback and default locale +function card(data: GetData, uiConfig: UiConfig): string { const fallbackLocale = "en"; const defaultLocale: Locales[keyof Locales] = locales[fallbackLocale]; const selectLocale: Locales[keyof Locales] = locales[uiConfig.Locale] || defaultLocale; - // Determining text direction and animations based on UI configuration const isRtlDirection = parseBoolean(selectLocale.rtlDirection); const isDisabledAnimations = parseBoolean(uiConfig.disabledAnimations || uiConfig.Format === "png"); - // Setting angles and positions for SVG elements const direction = isRtlDirection ? "rtl" : "ltr"; - const titleXAngle = isDisabledAnimations ? (isRtlDirection ? 520 : 15) : (isRtlDirection ? 510 : 5); - const titleYAngle = isDisabledAnimations ? 0 : -10; - const textXAngle = isRtlDirection ? 215 : 25; - const dataXAngle = isRtlDirection ? 15 : 225; - const iconXAngle = isRtlDirection ? 225 : 0; - const imageXAngle = isDisabledAnimations ? 120 : 125; - const imageYAngle = isDisabledAnimations ? 70 : 65; - const userXAngle = isDisabledAnimations ? 119.9 : 109.9; - const userYAngle = isDisabledAnimations ? 140 : 130; - const follXAngle = isDisabledAnimations ? 120 : 110; - const follYAngle = isDisabledAnimations ? 161 : 151; - - // Setting styles for hiding stroke and border based on UI configuration + const angle = { + titleXAngle: isDisabledAnimations ? (isRtlDirection ? 520 : 15) : (isRtlDirection ? 510 : 5), + titleYAngle: isDisabledAnimations ? 0 : -10, + textXAngle: isRtlDirection ? 215 : 20, + dataXAngle: isRtlDirection ? 15 : 220, + iconXAngle: isRtlDirection ? 225 : -5, + imageXAngle: isDisabledAnimations ? 120 : 125, + imageYAngle: isDisabledAnimations ? 70 : 65, + userXAngle: isDisabledAnimations ? 119.9 : 109.9, + userYAngle: isDisabledAnimations ? 140 : 130, + follXAngle: isDisabledAnimations ? 120 : 110, + follYAngle: isDisabledAnimations ? 161 : 151, + }; + const hideStroke = parseBoolean(uiConfig.hideStroke) ? `` : `stroke="#${uiConfig.strokeColor}" stroke-width="5"`; const hideBorder = parseBoolean(uiConfig.hideBorder) ? `` : `stroke="#${uiConfig.borderColor}" stroke-opacity="1" stroke-width="${uiConfig.borderWidth}"`; - // CSS animations for SVG elements - const animations = parseBoolean(uiConfig.disabledAnimations || uiConfig.Format === "png") ? `` : ` /* Animations */ - @keyframes scaleInAnimation { - from { - transform: translate(-5px, 5px) scale(0); - } - to { - transform: translate(-5px, 5px) scale(1); - } - } - @keyframes fadeInAnimation { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - @keyframes fadeLeftInAnimation { - from { - opacity: 0; - transform: translate(-90px, 10px); - } - to { - opacity: 1; - transform: translate(10px, 10px); - } - } - - .div-animation { - animation: fadeLeftInAnimation 0.7s ease-in-out forwards; - } - - .image-profile-animation { - animation: scaleInAnimation 1.2s ease-in-out forwards; - transform-origin: ${imageXAngle}px ${imageYAngle}px; - } - - .single-item-animation { - opacity: 0; - animation: fadeInAnimation 0.3s ease-in-out forwards; - }`; - - // Extracting and formatting hidden and shown items based on UI configuration + const animations = parseBoolean(uiConfig.disabledAnimations || uiConfig.Format === "png") ? `` : ` + /* Animations */ + @keyframes scaleInAnimation { + from { + transform: translate(-5px, 5px) scale(0); + } + to { + transform: translate(-5px, 5px) scale(1); + } + } + @keyframes fadeInAnimation { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + @keyframes fadeLeftInAnimation { + from { + opacity: 0; + transform: translate(-90px, 10px); + } + to { + opacity: 1; + transform: translate(10px, 10px); + } + } + + .div-animation { + animation: fadeLeftInAnimation 0.7s ease-in-out forwards; + } + + .image-profile-animation { + animation: scaleInAnimation 1.2s ease-in-out forwards; + transform-origin: ${angle.imageXAngle}px ${angle.imageYAngle}px; + } + + .single-item-animation { + opacity: 0; + animation: fadeInAnimation 0.3s ease-in-out forwards; + }`; + const hiddenItems = uiConfig.hiddenItems || ""; const hiddenItemsArray = hiddenItems.split(","); const showItems = uiConfig.showItems || ""; const showItemsArray = showItems.split(","); - // Array containing information about different GitHub stats to be displayed on the card const cardItems = [ { text: selectLocale.totalReposText || defaultLocale.totalReposText, value: data.public_repos, icon: icons.repository, hidden: hiddenItemsArray.includes("repos") }, { text: selectLocale.starsCountText || defaultLocale.starsCountText, value: data.total_stars, icon: icons.star, hidden: hiddenItemsArray.includes("stars") }, @@ -105,27 +100,19 @@ export default function cardStyle(data: GetData, uiConfig: UiConfig): string { { text: selectLocale.contributedToText || defaultLocale.contributedToText, value: data.total_contributed_to, icon: icons.contributed_to, hidden: hiddenItemsArray.includes("contributed") }, ]; - // Filtering items based on hiddenItemsArray and showItemsArray const cardItemsToShow = cardItems.filter(item => !item.hidden); - // Generating SVG code for each visible card item const cardItemsSVG = cardItemsToShow.map((item, index) => ` - - - - ${item.icon} - - ${item.text}: - ${item.value} - - `).join("\n"); - - /** - * Generates a linear gradient SVG code based on an array of color stops. - * - * @param {string[]} colors Array of color codes for the gradient stops. - * @returns {string} SVG code representing the linear gradient. - */ + + + + ${item.icon} + + ${item.text}: + ${item.value} + + `).join("\n"); + function generateGradient(colors: string[]): string { const gradientId = "gradient"; const gradientAngle = colors[0]; @@ -135,16 +122,14 @@ export default function cardStyle(data: GetData, uiConfig: UiConfig): string { return ``; }).join(""); return ` - - - ${gradientStops} - - - - `; + + + ${gradientStops} + + + `; } - // Generating SVG code for the background based on background color or gradient let backgroundSVG; if (uiConfig.bgColor) { if (Array.isArray(uiConfig.bgColor)) { @@ -155,81 +140,79 @@ export default function cardStyle(data: GetData, uiConfig: UiConfig): string { const gradientColors = gradientHexArray.map(color => color.trim()); backgroundSVG = generateGradient(gradientColors); } else { - backgroundSVG = ``; + backgroundSVG = ` + `; } } } - // Final SVG code for the GitHub stats card - return ` - - ${selectLocale.titleCard.split("{name}").join(data.name) || defaultLocale.titleCard.split("{name}").join(data.name)} - - ${backgroundSVG} - - - ${selectLocale.titleCard.split("{name}").join(data.name) || defaultLocale.titleCard.split("{name}").join(data.name)} - - - - - - - - - - @${data.username} - - ${data.followers} ${selectLocale.followersText || defaultLocale.followersText} · ${data.following} ${selectLocale.followingText || defaultLocale.followingText} - - - - ${cardItemsSVG} - + return ` + + + ${selectLocale.titleCard.split("{name}").join(data.name) || defaultLocale.titleCard.split("{name}").join(data.name)} +${backgroundSVG} + + + ${selectLocale.titleCard.split("{name}").join(data.name) || defaultLocale.titleCard.split("{name}").join(data.name)} + + + + + + + + + @${data.username} + + ${data.followers} ${selectLocale.followersText || defaultLocale.followersText} · ${data.following} ${selectLocale.followingText || defaultLocale.followingText} + +${cardItemsSVG} + `; -} \ No newline at end of file +} + +export default card; diff --git a/src/common/utils.ts b/src/common/utils.ts index 3b8ffa5..61ea7e2 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,23 +1,23 @@ /** - * Checks if the provided value is a valid hexadecimal color code. + * Checks whether the provided value is a valid hexadecimal color. * - * @param {any} hexColor Value to be checked. - * @returns {boolean} True if the value is a valid hexadecimal color code, false otherwise. + * @param {any} hexColor - The input value to check for valid hexadecimal color. + * @returns {boolean} - True if the input is a valid hexadecimal color, false otherwise. */ -function isValidHexColor(hexColor: any): boolean { +function isValidHexColor(hexColor: string): boolean { return new RegExp( /^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/ ).test(hexColor); } /** - * Checks if the provided array of color codes represents a valid gradient. + * Checks whether the provided array of hexadecimal colors is a valid gradient. * - * @param {string[]} hexColors Array of color codes to be checked. - * @returns {boolean} True if the array represents a valid gradient, false otherwise. + * @param {string[]} hexColors - The array of hexadecimal colors to check for a valid gradient. + * @returns {boolean} - True if the array represents a valid gradient, false otherwise. */ -function isValidGradient(hexColors: string[]): boolean { - const colors = [hexColors]; +function isValidGradient(hexColors: string): boolean { + const colors = hexColors.split(","); for (let i = 1; i < colors.length; i++) { if (!isValidHexColor(colors[i])) { return false; @@ -27,10 +27,10 @@ function isValidGradient(hexColors: string[]): boolean { } /** - * Parses a boolean value or string representation of a boolean. + * Parses a boolean value from either a boolean or string representation. * - * @param {boolean | string} value Value to be parsed. - * @returns {boolean | undefined} Parsed boolean value or undefined if parsing fails. + * @param {boolean | string} value - The input value to parse as a boolean. + * @returns {boolean | undefined} - The parsed boolean value, or undefined if parsing fails. */ function parseBoolean(value: boolean | string): boolean | undefined { if (typeof value === "boolean") { @@ -51,4 +51,4 @@ export { isValidHexColor, isValidGradient, parseBoolean -} \ No newline at end of file +} diff --git a/src/fetcher/apiFetch.ts b/src/fetcher/apiFetch.ts deleted file mode 100644 index 475b1f5..0000000 --- a/src/fetcher/apiFetch.ts +++ /dev/null @@ -1,147 +0,0 @@ -// Importing necessary libraries and modules -import axios from "axios"; -import getRandomToken from "../getRandomToken"; - -// Represents the user data obtained from the GitHub GraphQL API -export interface User { - name: string; - login: string; - avatarUrl: string; - repositories: Repositories; - followers: Followers; - following: Following; - contributionsCollection: ContributionsCollection; - openedIssues: OpenedIssues; - closedIssues: ClosedIssues; - pullRequests: PullRequests; - mergedPullRequests: MergedPullRequests; - discussionStarted: DiscussionStarted; - discussionAnswered: DiscussionAnswered; - repositoriesContributedTo: RepositoriesContributedTo; -} - -// Represents the total count of repositories -export interface Repositories { - totalCount: number; -} - -// Represents the total count of followers -export interface Followers { - totalCount: number; -} - -// Represents the total count of following -export interface Following { - totalCount: number; -} - -// Represents contribution data -export interface ContributionsCollection { - totalCommitContributions: number; - restrictedContributionsCount: number; - totalPullRequestReviewContributions: number; -} - -// Represents the total count of opened issues -export interface OpenedIssues { - totalCount: number; -} - -// Represents the total count of closed issues -export interface ClosedIssues { - totalCount: number; -} - -// Represents the total count of pull requests -export interface PullRequests { - totalCount: number; -} - -// Represents the total count of merged pull requests -export interface MergedPullRequests { - totalCount: number; -} - -// Represents the total count of started discussions -export interface DiscussionStarted { - totalCount: number; -} - -// Represents the total count of answered discussions -export interface DiscussionAnswered { - totalCount: number; -} - -// Represents the total count of repositories contributed to -export interface RepositoriesContributedTo { - totalCount: number; -} - -/** - * Fetches user data from the GitHub GraphQL API. - * - * @param {string} username GitHub username. - * @returns {Promise} Promise representing the user data obtained from the GitHub Graphql API. - */ -export default async function apiFetch(username: string): Promise { - const data = await axios({ - method: "post", - url: "https://api.github.com/graphql", - headers: { - "User-Agent": "FajarKim/github-readme-profile", - Authorization: getRandomToken(true), - }, - data: { - query: `query userInfo($username: String!) { - user(login: $username) { - name - login - avatarUrl - repositories(ownerAffiliations: OWNER, privacy: PUBLIC) { - totalCount - } - followers { - totalCount - } - following { - totalCount - } - contributionsCollection { - totalCommitContributions - restrictedContributionsCount - totalPullRequestReviewContributions - } - openedIssues: issues(states: OPEN) { - totalCount - } - closedIssues: issues(states: CLOSED) { - totalCount - } - pullRequests(first: 1) { - totalCount - } - mergedPullRequests: pullRequests(states: MERGED) { - totalCount - } - discussionStarted: repositoryDiscussions { - totalCount - } - discussionAnswered: repositoryDiscussionComments(onlyAnswers: true) { - totalCount - } - repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { - totalCount - } - } - }`, - variables: { - username, - }, - }, - }); - - if (data.data.errors?.length > 0) - throw new Error(data.data.errors[0].message); - - return data.data.data.user; -} diff --git a/src/fetcher/repositoryFetch.ts b/src/fetcher/repositoryFetch.ts deleted file mode 100644 index 1eb4532..0000000 --- a/src/fetcher/repositoryFetch.ts +++ /dev/null @@ -1,87 +0,0 @@ -// Importing necessary libraries and modules -import axios from "axios"; -import getRandomToken from "../getRandomToken"; - -// Represents the structure returned: Promise containing the repository data -type RepositoryData = { - stars: number; - forks: number; - openedIssues: number; -}; - -/** - * Fetches repository data for the specified user. - * - * @param {string} username GitHub username. - * @param {number} totalpage Total pages of repositories to fetch. - * @returns {Promise} Promise containing the repository data. - */ -export default async function repositoryFetch( - username: string, - totalpage: number -): Promise { - let stars = 0; - let forks = 0; - let openedIssues = 0; - - // Fetch repository data for each page in parallel - await Promise.all( - Array.from( - { length: totalpage }, - async (_, i) => await getPerPageReposData(username, i + 1) - ) - ).then((data: object[]) => { - // Accumulate data from each page - data.forEach((repo: any) => { - stars += repo.stars; - forks += repo.forks; - openedIssues += repo.openedIssues; - }); - }); - - return { - stars, - forks, - openedIssues, - }; -} - -/** - * Fetches repository data for a specific page. - * - * @param {string} username GitHub username. - * @param {number} pageno Page number to fetch. - * @returns {Promise} Promise containing the repository data for the specified page. - */ -async function getPerPageReposData( - username: string, - pageno: number -): Promise { - const sanitizedUsername = encodeURIComponent(username); - // Fetch data for the specified page - const data = await axios({ - method: "get", - url: `https://api.github.com/users/${sanitizedUsername}/repos?page=${pageno}&per_page=100`, - headers: { - "User-Agent": "FajarKim/github-readme-profile", - Authorization: getRandomToken(true), - }, - }); - - let stars = 0; - let forks = 0; - let openedIssues = 0; - - // Accumulate data from each repository on the page - data.data.forEach((repo: any) => { - stars += repo.stargazers_count; - forks += repo.forks_count; - openedIssues += repo.open_issues; - }); - - return { - stars, - forks, - openedIssues, - }; -} diff --git a/src/fetcher/repositoryStats.ts b/src/fetcher/repositoryStats.ts new file mode 100644 index 0000000..20f965a --- /dev/null +++ b/src/fetcher/repositoryStats.ts @@ -0,0 +1,97 @@ +import axios from "axios"; +import { getToken3 } from "../getToken"; + +/** + * Type representing the data associated with a user's repository stats. + * + * @typedef {Object} RepositoryData + * @property {number} stars - The total count of stars across repositories. + * @property {number} forks - The total count of forks across repositories. + * @property {number} openedIssues - The total count of opened issues across repositories. + */ +type RepositoryData = { + stars: number; + forks: number; + openedIssues: number; +}; + +/** + * Retrieves and calculates repository statistics for a given user. + * + * @param {string} username - The username of the GitHub user. + * @param {number} totalpage - The total number of pages to retrieve data from. + * @returns {Promise} - A promise that resolves to the repository statistics. + */ +async function repositoryStats( + username: string, + totalpage: number +): Promise { + let stars = 0; + let forks = 0; + let openedIssues = 0; + + await Promise.all( + Array.from( + { length: totalpage }, + async (_, i) => await getPerPageRepositoryData(username, i + 1) + ) + ).then((data: object[]) => { + data.forEach((repo: any) => { + stars += repo.stars; + forks += repo.forks; + openedIssues += repo.openedIssues; + }); + }); + + return { + stars, + forks, + openedIssues, + }; +} + +/** + * Retrieves repository data for a specific page. + * + * @param {string} username - The username of the GitHub user. + * @param {number} pageno - The page number to retrieve data from. + * @returns {Promise} - A promise that resolves to the repository data for the specified page. + */ +async function getPerPageRepositoryData( + username: string, + pageno: number +): Promise { + const sanitizedUsername = encodeURIComponent(username); + + const data = await axios({ + method: "get", + url: `https://api.github.com/users/${sanitizedUsername}/repos?page=${pageno}&per_page=100`, + headers: { + "User-Agent": "FajarKim/github-readme-profile", + Authorization: getToken3(true), + }, + }); + + let stars = 0; + let forks = 0; + let openedIssues = 0; + + data.data.forEach((repo: any) => { + stars += repo.stargazers_count; + forks += repo.forks_count; + openedIssues += repo.open_issues; + }); + + return { + stars, + forks, + openedIssues, + }; +} + +export { + RepositoryData, + repositoryStats, + getPerPageRepositoryData +}; +export default repositoryStats; diff --git a/src/fetcher/stats.ts b/src/fetcher/stats.ts new file mode 100644 index 0000000..a0c76ce --- /dev/null +++ b/src/fetcher/stats.ts @@ -0,0 +1,359 @@ +import axios from "axios"; +import { getToken, getToken2, getToken3 } from "../getToken"; + +/** + * Represents a user's information and statistics. + * + * @interface User + * @property {string} name - The name of the user. + * @property {string} login - The login username of the user. + * @property {string} avatarUrl - The URL of the user's avatar. + * @property {Repositories} repositories - Information about user repositories. + * @property {Followers} followers - Information about user followers. + * @property {Following} following - Information about users being followed by the user. + * @property {OpenedIssues} openedIssues - Information about opened issues by the user. + * @property {ClosedIssues} closedIssues - Information about closed issues by the user. + * @property {PullRequests} pullRequests - Information about user pull requests. + * @property {MergedPullRequests} mergedPullRequests - Information about merged pull requests by the user. + * @property {DiscussionStarted} discussionStarted - Information about discussions started by the user. + * @property {DiscussionAnswered} discussionAnswered - Information about discussions answered by the user. + * @property {RepositoriesContributedTo} repositoriesContributedTo - Information about repositories contributed to by the user. + * @property {number} totalCommitContributions - The total count of commit contributions by the user. + * @property {number} restrictedContributionsCount - The count of restricted contributions by the user. + * @property {number} totalPullRequestReviewContributions - The total count of pull request review contributions by the user. + */ +interface User { + name: string; + login: string; + avatarUrl: string; + repositories: Repositories; + followers: Followers; + following: Following; + openedIssues: OpenedIssues; + closedIssues: ClosedIssues; + pullRequests: PullRequests; + mergedPullRequests: MergedPullRequests; + discussionStarted: DiscussionStarted; + discussionAnswered: DiscussionAnswered; + repositoriesContributedTo: RepositoriesContributedTo; + totalCommitContributions: number; + restrictedContributionsCount: number; + totalPullRequestReviewContributions: number; +} + +/** + * Represents information about user repositories. + * + * @interface Repositories + * @property {number} totalCount - The total count of repositories. + */ +interface Repositories { + totalCount: number; +} + +/** + * Represents information about user followers. + * + * @interface Followers + * @property {number} totalCount - The total count of followers. + */ +interface Followers { + totalCount: number; +} + +/** + * Represents information about user following. + * + * @interface Following + * @property {number} totalCount - The total count of following. + */ +interface Following { + totalCount: number; +} + +/** + * Represents contributions data collected over a specific time period. + * + * @interface ContributionsCollection + * @property {number} totalCommitContributions - The total count of commit contributions. + * @property {number} restrictedContributionsCount - The count of restricted contributions. + * @property {number} totalPullRequestReviewContributions - The total count of pull request review contributions. + */ +interface ContributionsCollection { + totalCommitContributions: number; + restrictedContributionsCount: number; + totalPullRequestReviewContributions: number; +} + +/** + * Represents information about user opened issues. + * + * @interface OpenedIssues + * @property {number} totalCount - The total count of opened issues. + */ +interface OpenedIssues { + totalCount: number; +} + +/** + * Represents information about user closed issues. + * + * @interface ClosedIssues + * @property {number} totalCount - The total count of closed issues. + */ +interface ClosedIssues { + totalCount: number; +} + +/** + * Represents information about user pull requests. + * + * @interface PullRequests + * @property {number} totalCount - The total count of pull requests. + */ +interface PullRequests { + totalCount: number; +} + +/** + * Represents information about user merged pull requests. + * + * @interface MergedPullRequests + * @property {number} totalCount - The total count of merged pull requests. + */ +interface MergedPullRequests { + totalCount: number; +} + +/** + * Represents information about user discussion started. + * + * @interface DiscussionStarted + * @property {number} totalCount - The total count of discussion started. + */ +interface DiscussionStarted { + totalCount: number; +} + +/** + * Represents information about user discussion answered. + * + * @interface DiscussionAnswered + * @property {number} totalCount - The total count of discussion answered. + */ +interface DiscussionAnswered { + totalCount: number; +} + +/** + * Represents information about user repositories contributed to. + * + * @interface RepositoriesContributedTo + * @property {number} totalCount - The total count of repositories contributed to. + */ +interface RepositoriesContributedTo { + totalCount: number; +} + +/** + * Fetches the user's join year based on the provided username. + * + * @param {string} username - The GitHub username of the user. + * @returns {Promise} - A promise that resolves with the user's join year. + */ +async function getUserJoinYear(username: string): Promise { + const data = await axios({ + method: "post", + url: "https://api.github.com/graphql", + headers: { + "User-Agent": "FajarKim/github-readme-profile", + Authorization: getToken3(true), + }, + data: { + query: `query userInfo($username: String!) { + user(login: $username) { + createdAt + } + }`, + variables: { + username, + }, + }, + }); + + if (data.data.errors?.length > 0) { + throw new Error(data.data.errors[0].message); + } + + const user = data.data.data.user; + if (!user || !user.createdAt) { + throw new Error("User data is missing."); + } + + const joinDate = new Date(user.createdAt); + return joinDate.getFullYear(); +} + +/** + * Fetches the contributions data for the specified year. + * + * @param {string} username - The GitHub username of the user. + * @param {number} year - The year for which contributions data is fetched. + * @returns {Promise} - A promise that resolves with contributions data. + */ +async function fetchContributions(username: string, year: number): Promise { + const from = `${year}-01-01T00:00:00Z`; + const to = `${year}-12-31T23:59:59Z`; + + const data = await axios({ + method: "post", + url: "https://api.github.com/graphql", + headers: { + "User-Agent": "FajarKim/github-readme-profile", + Authorization: getToken2(true), + }, + data: { + query: `query userInfo($username: String!, $from: DateTime!, $to: DateTime!) { + user(login: $username) { + contributionsCollection(from: $from, to: $to) { + totalCommitContributions + restrictedContributionsCount + totalPullRequestReviewContributions + } + } + }`, + variables: { + username, + from, + to, + }, + }, + }); + + if (data.data.errors?.length > 0) { + throw new Error(data.data.errors[0].message); + } + + const contributions = data.data.data.user.contributionsCollection; + return { + totalCommitContributions: contributions.totalCommitContributions, + restrictedContributionsCount: contributions.restrictedContributionsCount, + totalPullRequestReviewContributions: contributions.totalPullRequestReviewContributions, + }; +} + +/** + * Fetches various statistics and information about the user. + * + * @param {string} username - The GitHub username of the user. + * @returns {Promise} - A promise that resolves with the user's information and statistics. + */ +async function stats(username: string): Promise { + const startYear = await getUserJoinYear(username); + const endYear = new Date().getFullYear(); + + let TotalCommitContributions = 0; + let RestrictedContributionsCount = 0; + let TotalPullRequestReviewContributions = 0; + + for (let year = startYear; year <= endYear; year++) { + const contributions = await fetchContributions(username, year); + TotalCommitContributions += contributions.totalCommitContributions; + RestrictedContributionsCount += contributions.restrictedContributionsCount; + TotalPullRequestReviewContributions += contributions.totalPullRequestReviewContributions; + } + + const data = await axios({ + method: "post", + url: "https://api.github.com/graphql", + headers: { + "User-Agent": "FajarKim/github-readme-profile", + Authorization: getToken(true), + }, + data: { + query: `query userInfo($username: String!) { + user(login: $username) { + name + login + avatarUrl + repositories(ownerAffiliations: OWNER, privacy: PUBLIC) { + totalCount + } + followers { + totalCount + } + following { + totalCount + } + openedIssues: issues(states: OPEN) { + totalCount + } + closedIssues: issues(states: CLOSED) { + totalCount + } + pullRequests(first: 1) { + totalCount + } + mergedPullRequests: pullRequests(states: MERGED) { + totalCount + } + discussionStarted: repositoryDiscussions { + totalCount + } + discussionAnswered: repositoryDiscussionComments(onlyAnswers: true) { + totalCount + } + repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) { + totalCount + } + } + }`, + variables: { + username, + }, + }, + }); + + if (data.data.errors?.length > 0) + throw new Error(data.data.errors[0].message); + + const user = data.data.data.user; + + return { + name: user.name, + login: user.login, + avatarUrl: user.avatarUrl, + repositories: user.repositories, + followers: user.followers, + following: user.following, + openedIssues: user.openedIssues, + closedIssues: user.closedIssues, + pullRequests: user.pullRequests, + mergedPullRequests: user.mergedPullRequests, + discussionStarted: user.discussionStarted, + discussionAnswered: user.discussionAnswered, + repositoriesContributedTo: user.repositoriesContributedTo, + totalCommitContributions: TotalCommitContributions, + restrictedContributionsCount: RestrictedContributionsCount, + totalPullRequestReviewContributions: TotalPullRequestReviewContributions, + }; +} + +export { + User, + Repositories, + Followers, + Following, + ContributionsCollection, + OpenedIssues, + ClosedIssues, + PullRequests, + MergedPullRequests, + DiscussionStarted, + DiscussionAnswered, + RepositoriesContributedTo, + getUserJoinYear, + fetchContributions, + stats +}; +export default stats; diff --git a/src/getData.ts b/src/getData.ts index cd344d2..23e61d3 100644 --- a/src/getData.ts +++ b/src/getData.ts @@ -1,14 +1,34 @@ -// Importing necessary libraries and modules import millify from "millify"; -import apiFetch from "./fetcher/apiFetch"; -import repositoryFetch from "./fetcher/repositoryFetch"; +import stats from "./fetcher/stats"; +import repositoryStats from "./fetcher/repositoryStats"; const base64ImageFetcher = require("node-base64-image"); -// Represents the data structure returned by the getData function -export type GetData = { +/** + * Type representing GitHub user information. + * + * @typedef {Object} GetData + * @property {string} username - GitHub username. + * @property {string} name - GitHub user's name. + * @property {string|Buffer} picture - Base64-encoded image or Buffer representing the user's profile picture. + * @property {string|number} public_repos - Formatted count of public repositories. + * @property {string|number} followers - Formatted count of followers. + * @property {string|number} following - Formatted count of users being followed. + * @property {string|number} total_stars - Formatted count of total stars received on repositories. + * @property {string|number} total_forks - Formatted count of total forks received on repositories. + * @property {string|number} total_issues - Formatted count of total issues (both open and closed). + * @property {string|number} total_closed_issues - Formatted count of closed issues. + * @property {string|number} total_prs - Formatted count of total pull requests. + * @property {string|number} total_prs_merged - Formatted count of total merged pull requests. + * @property {string|number} total_commits - Formatted count of total commits. + * @property {string|number} total_review - Formatted count of pull request reviews. + * @property {string|number} total_discussion_answered - Formatted count of discussions answered. + * @property {string|number} total_discussion_started - Formatted count of discussions started. + * @property {string|number} total_contributed_to - Formatted count of repositories contributed to. + */ +type GetData = { username: string; name: string; - pic: string | Buffer; + picture: string | Buffer; public_repos: string | number; followers: string | number; following: string | number; @@ -26,24 +46,22 @@ export type GetData = { }; /** - * Fetches and processes data for a given GitHub user. + * Fetches and formats GitHub user data based on the provided username. * - * @param {string} username GitHub username. - * @returns Promise Promise representing the data structure returned. + * @param {string} username - GitHub username. + * @returns {Promise} - A promise that resolves with formatted GitHub user data. */ async function getData(username: string): Promise { - const user = await apiFetch(username); + const user = await stats(username); const totalRepoPages = Math.ceil(user.repositories.totalCount / 100); - const userRepositories = await repositoryFetch(username, totalRepoPages); + const userRepositories = await repositoryStats(username, totalRepoPages); - // If user.name is not available, use user.login as name if (!user.name) user.name = user.login; - // Creating output object const output = { username: user.login, name: user.name, - pic: await base64ImageFetcher.encode(`${user.avatarUrl}&s=200`, { + picture: await base64ImageFetcher.encode(`${user.avatarUrl}&s=200`, { string: true, }), public_repos: millify(user.repositories.totalCount), @@ -58,10 +76,9 @@ async function getData(username: string): Promise { total_prs: millify(user.pullRequests.totalCount), total_prs_merged: millify(user.mergedPullRequests.totalCount), total_commits: millify( - user.contributionsCollection.restrictedContributionsCount + - user.contributionsCollection.totalCommitContributions + user.restrictedContributionsCount + user.totalCommitContributions ), - total_review: millify(user.contributionsCollection.totalPullRequestReviewContributions), + total_review: millify(user.totalPullRequestReviewContributions), total_discussion_answered: millify(user.discussionAnswered.totalCount), total_discussion_started: millify(user.discussionStarted.totalCount), total_contributed_to: millify(user.repositoriesContributedTo.totalCount), @@ -70,4 +87,5 @@ async function getData(username: string): Promise { return output; } +export { GetData, getData }; export default getData; diff --git a/src/getRandomToken.ts b/src/getRandomToken.ts deleted file mode 100644 index 431a201..0000000 --- a/src/getRandomToken.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Importing necessary module -import dotenv from "dotenv"; -import { getInput } from "@actions/core"; - -// Loads environment variables from a .env file if present -dotenv.config(); - -/** - * Generates a random token based on the GH_ environment variables. - * - * @param {boolean} bearerHeader Indicates whether to include "Bearer " prefix for authorization header. - * @returns {string} A random token. - */ -function getRandomToken(bearerHeader: boolean): string { - const getEnvs: any = process.env; - let getGhEnv: any = Object.keys(getEnvs).filter((key) => - key.startsWith("GH_") - ); - getGhEnv = getGhEnv.map((key: string) => getEnvs[key]); - const getRandomEnv: string = - getGhEnv[Math.floor(Math.random() * getGhEnv.length)]; - - if (!getRandomEnv) { - // Use GitHub Actions core module to get the token - const getRandomEnv = getInput("github_token"); - - if (!getRandomEnv) { - throw new Error("Could not find github token"); - } - } - - if (bearerHeader) { - return `Bearer ${getRandomEnv}`; - } - - return getRandomEnv; -} - -export default getRandomToken; diff --git a/src/getToken.ts b/src/getToken.ts new file mode 100644 index 0000000..0be12a3 --- /dev/null +++ b/src/getToken.ts @@ -0,0 +1,102 @@ +import dotenv from "dotenv"; +import { getInput } from "@actions/core"; + +dotenv.config(); + +/** + * Retrieves the GitHub token 1 from the environment variables or GitHub Actions inputs. + * + * @param {boolean} bearerHeader - Flag indicating whether to return the token with 'Bearer' prefix. + * @returns {string} - The GitHub token. + */ +function getToken(bearerHeader: boolean): string { +const getEnvirontment: any = process.env; + let getGHEnvirontment: any = Object.keys(getEnvirontment).filter((key) => + key.startsWith("GH_TOKEN_1") + ); + getGHEnvirontment = getGHEnvirontment.map((key: string) => getEnvirontment[key]); + + // Select a random GitHub environment variable + let getGHToken: string = + getGHEnvirontment[Math.floor(Math.random() * getGHEnvirontment.length)]; + + // If no GitHub environment variable is found, get the token from GitHub Actions inputs + if (!getGHToken) { + getGHToken = getInput("github_token"); + + if (!getGHToken) { + throw new Error("Could not find github token"); + } + } + + if (bearerHeader) { + return `Bearer ${getGHToken}`; + } + + return getGHToken; +} + +/** + * Retrieves the GitHub token 2 from the environment variables or GitHub Actions inputs. + * + * @param {boolean} bearerHeader - Flag indicating whether to return the token with 'Bearer' prefix. + * @returns {string} - The GitHub token. + */ +function getToken2(bearerHeader: boolean): string { +const getEnvirontment: any = process.env; + let getGHEnvirontment: any = Object.keys(getEnvirontment).filter((key) => + key.startsWith("GH_TOKEN_2") + ); + getGHEnvirontment = getGHEnvirontment.map((key: string) => getEnvirontment[key]); + + // Select a random GitHub environment variable + let getGHToken: string = + getGHEnvirontment[Math.floor(Math.random() * getGHEnvirontment.length)]; + + // If no GitHub environment variable is found, get the token from GitHub Actions inputs + if (!getGHToken) { + getGHToken = getToken(false); + } + + if (bearerHeader) { + return `Bearer ${getGHToken}`; + } + + return getGHToken; +} + +/** + * Retrieves the GitHub token 3 from the environment variables or GitHub Actions inputs. + * + * @param {boolean} bearerHeader - Flag indicating whether to return the token with 'Bearer' prefix. + * @returns {string} - The GitHub token. + */ +function getToken3(bearerHeader: boolean): string { +const getEnvirontment: any = process.env; + let getGHEnvirontment: any = Object.keys(getEnvirontment).filter((key) => + key.startsWith("GH_TOKEN_3") + ); + getGHEnvirontment = getGHEnvirontment.map((key: string) => getEnvirontment[key]); + + // Select a random GitHub environment variable + let getGHToken: string = + getGHEnvirontment[Math.floor(Math.random() * getGHEnvirontment.length)]; + + // If no GitHub environment variable is found, get the token from GitHub Actions inputs + if (!getGHToken) { + getGHToken = getToken(false); + } + + if (bearerHeader) { + return `Bearer ${getGHToken}`; + } + + return getGHToken; +} + +export { + getToken, + getToken2, + getToken3 +}; +export default getToken; diff --git a/src/icons.ts b/src/icons.ts index 020c8d7..cb327c4 100644 --- a/src/icons.ts +++ b/src/icons.ts @@ -1,5 +1,21 @@ -// Represents the available icons for GitHub stats cards -export type Icons = { +/** + * Type representing an object storing SVG icons for various categories. + * + * @typedef {Object} Icons + * @property {string} repository - SVG icon for the repository category. + * @property {string} star - SVG icon for the star category. + * @property {string} fork - SVG icon for the fork category. + * @property {string} commit - SVG icon for the commit category. + * @property {string} review - SVG icon for the review category. + * @property {string} pull_request - SVG icon for the pull request category. + * @property {string} pull_request_merged - SVG icon for the merged pull request category. + * @property {string} issue - SVG icon for the issue category. + * @property {string} issue_closed - SVG icon for the closed issue category. + * @property {string} discussion_started - SVG icon for the started discussion category. + * @property {string} discussion_answered - SVG icon for the answered discussion category. + * @property {string} contributed_to - SVG icon for the contributed to category. + */ +type Icons = { repository: string; star: string; fork: string; @@ -14,8 +30,12 @@ export type Icons = { contributed_to: string; }; -// Object containing various SVG path data for different GitHub-related icons -export const icons = { +/** + * Icons object stores SVG icons for various categories. + * + * @type {Icons} + */ +const icons: Icons = { repository: ``, star: ``, fork: ``, @@ -28,4 +48,7 @@ export const icons = { discussion_started: ``, discussion_answered: ``, contributed_to: ``, -} +}; + +export { Icons, icons }; +export default icons; diff --git a/src/translations.ts b/src/translations.ts index 3fd0379..e5dd93b 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -1,5 +1,25 @@ -// Represents the structure of localized strings -export type Locales = { +/** + * Type representing for local translation card strings. + * + * @typedef {Object} Locales + * @property {string} titleCard - Title for the GitHub stats card. + * @property {string} [followersText] - Text for followers count. + * @property {string} [followingText] - Text for following count. + * @property {string} [totalReposText] - Text for total repository count. + * @property {string} [starsCountText] - Text for stars count. + * @property {string} [forksCountText] - Text for forks count. + * @property {string} [commitsCountText] - Text for commits count. + * @property {string} [totalPRText] - Text for total pull requests count. + * @property {string} [totalPRMergedText] - Text for total merged pull requests count. + * @property {string} [totalPRReviewedText] - Text for total pull requests reviewed count. + * @property {string} [totalIssuesText] - Text for total issues count. + * @property {string} [totalIssuesClosedText] - Text for total closed issues count. + * @property {string} [totalDiscussionStartedText] - Text for total discussions started count. + * @property {string} [totalDiscussionAnsweredText] - Text for total discussions answered count. + * @property {string} [contributedToText] - Text for contributed repositories (last year). + * @property {boolean|string} rtlDirection - Flag indicating right-to-left direction or a string specifying direction. + */ +type Locales = { [key: string]: { titleCard: string; followersText?: string; @@ -20,8 +40,12 @@ export type Locales = { }; }; -// Object containing localized strings for different languages -export const locales: Locales = { +/** + * Localization strings for different languages. + * + * @type {Locales} + */ +const locales: Locales = { en: { titleCard: "{name}'s GitHub Stats", followersText: "Followers", @@ -221,3 +245,6 @@ export const locales: Locales = { rtlDirection: false, }, } + +export { Locales, locales }; +export default locales; diff --git a/tests/card.test.ts b/tests/card.test.ts new file mode 100644 index 0000000..9b09cab --- /dev/null +++ b/tests/card.test.ts @@ -0,0 +1,138 @@ +import card from "../src/card"; +import locales from "../src/translations"; + +describe("Test card function", () => { + const mockData = { + username: "FajarKim", + name: "Rangga Fajar Oktariansyah", + picture: "avatar", + public_repos: 20, + followers: 20, + following: 10, + total_stars: 140, + total_forks: 90, + total_issues: 150, + total_closed_issues: 100, + total_prs: 530, + total_prs_merged: 490, + total_commits: 1330, + total_review: 340, + total_discussion_answered: 4, + total_discussion_started: 10, + total_contributed_to: 12, + }; + + const mockUiConfig = { + Locale: "en", + Format: "svg", + titleColor: "2f80ed", + textColor: "434d58", + iconColor: "4c71f2", + borderColor: "e4e2e2", + bgColor: "ffffff", + strokeColor: "e4e2e2", + usernameColor: "2f80ed", + borderRadius: 5, + borderWidth: 1, + hideBorder: false, + hideStroke: false, + disabledAnimations: false, + showItems: "reviews,issues_closed", + hiddenItems: "forks,commits", + }; + + it("should generate SVG markup with default values", () => { + const svgMarkup = card(mockData, mockUiConfig); + + expect(svgMarkup).toContain("