├── .eslintignore ├── docs └── images │ ├── logo.png │ └── chatgpt-review-comment.png ├── src ├── index.ts ├── services │ ├── utils │ │ ├── concatenatePatchesToString.ts │ │ ├── extractFirstChangedLineFromPatch.ts │ │ ├── parseOpenAISuggestions.ts │ │ ├── divideFilesByTokenRange.ts │ │ └── getOpenAiSuggestions.ts │ ├── types.ts │ └── commentOnPullRequestService.ts └── config │ ├── promptsConfig.ts │ └── errorsConfig.ts ├── .prettierrc.json ├── tsconfig.json ├── .gitignore ├── action.yml ├── .eslintrc.json ├── LICENSE.md ├── package.json ├── CONTRIBUTING.md ├── README.md └── dist └── sourcemap-register.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | docs 4 | -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magnificode-ltd/chatgpt-code-reviewer/HEAD/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/chatgpt-review-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magnificode-ltd/chatgpt-code-reviewer/HEAD/docs/images/chatgpt-review-comment.png -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import CommentOnPullRequestService from './services/commentOnPullRequestService'; 2 | 3 | const commentOnPrService = new CommentOnPullRequestService(); 4 | 5 | commentOnPrService.addCommentToPr(); 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "trailingComma": "all", 5 | "singleQuote": true, 6 | "semi": true, 7 | "importOrder": ["^components/(.*)$", "^[./]"], 8 | "importOrderSeparation": true, 9 | "importOrderSortSpecifiers": true 10 | } 11 | -------------------------------------------------------------------------------- /src/services/utils/concatenatePatchesToString.ts: -------------------------------------------------------------------------------- 1 | import { FilenameWithPatch } from '../types'; 2 | 3 | const concatenatePatchesToString = (files: FilenameWithPatch[]) => 4 | files.map(({ filename, patch }) => `${filename}\n${patch}\n`).join(''); 5 | 6 | export default concatenatePatchesToString; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "./dist", 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "lib": ["es2015", "dom"] 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js dependencies 2 | node_modules/ 3 | 4 | # Buid files 5 | dist/* 6 | !dist/index.js 7 | !dist/sourcemap-register.js 8 | !dist/encoder.json 9 | !dist/vocab.bpe 10 | 11 | 12 | # TypeScript cache 13 | *.tsbuildinfo 14 | 15 | # Editor files 16 | .vscode/ 17 | .idea/ 18 | *.sublime-project 19 | *.sublime-workspace 20 | 21 | # Miscellaneous 22 | .DS_Store 23 | Thumbs.db -------------------------------------------------------------------------------- /src/services/types.ts: -------------------------------------------------------------------------------- 1 | import { getOctokit } from '@actions/github'; 2 | 3 | type Octokit = ReturnType; 4 | 5 | type FilenameWithPatch = { 6 | filename: string; 7 | patch: string; 8 | tokensUsed: number; 9 | }; 10 | 11 | type PullRequestInfo = { 12 | owner: string; 13 | repo: string; 14 | pullHeadRef: string; 15 | pullBaseRef: string; 16 | pullNumber: number; 17 | }; 18 | 19 | export type { Octokit, FilenameWithPatch, PullRequestInfo }; 20 | -------------------------------------------------------------------------------- /src/config/promptsConfig.ts: -------------------------------------------------------------------------------- 1 | enum Prompt { 2 | SYSTEM_PROMPT, 3 | } 4 | 5 | const promptsConfig: { [key in Prompt]: string } = { 6 | [Prompt.SYSTEM_PROMPT]: 7 | 'You now assume the role of a code reviewer. Based on the patch provide a list of suggestions how to improve the code with examples according to coding standards and best practices.\nStart every suggestion with path to the file. Path to the file should start with @@ and end with @@', 8 | }; 9 | 10 | export default promptsConfig; 11 | export { Prompt }; 12 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: chatgpt-code-reviewer 2 | description: GitHub action that adds ChatGPT code review comments to pull requests 3 | author: MagnifiCode (https://magnificode.net) 4 | inputs: 5 | model: 6 | description: 'OpenAI model' 7 | default: 'gpt-3.5-turbo' 8 | required: false 9 | max_tokens: 10 | description: 'max TPM for OpenAI' 11 | default: 4096 12 | required: false 13 | runs: 14 | using: node16 15 | main: dist/index.js 16 | branding: 17 | icon: 'message-circle' 18 | color: 'yellow' 19 | -------------------------------------------------------------------------------- /src/services/utils/extractFirstChangedLineFromPatch.ts: -------------------------------------------------------------------------------- 1 | const extractFirstChangedLineFromPatch = (patch: string) => { 2 | const lineHeaderRegExp = /^@@ -\d+,\d+ \+(\d+),(\d+) @@/; 3 | const lines = patch.split('\n'); 4 | const lineHeaderMatch = lines[0].match(lineHeaderRegExp); 5 | 6 | let firstChangedLine = 1; 7 | 8 | if (lineHeaderMatch) { 9 | firstChangedLine = parseInt(lineHeaderMatch[1], 10); 10 | } 11 | 12 | return firstChangedLine; 13 | }; 14 | 15 | export default extractFirstChangedLineFromPatch; 16 | -------------------------------------------------------------------------------- /src/services/utils/parseOpenAISuggestions.ts: -------------------------------------------------------------------------------- 1 | const parseOpenAISuggestions = (suggestionsText: string) => { 2 | const regex = /@@(.+?)@@\n([\s\S]*?)(?=\n@@|$)/g; 3 | const suggestionMatches = suggestionsText.matchAll(regex); 4 | const suggestions = []; 5 | 6 | for (const match of suggestionMatches) { 7 | const filename = match[1].trim(); 8 | const suggestionText = match[2].trim(); 9 | suggestions.push({ filename, suggestionText }); 10 | } 11 | 12 | return suggestions; 13 | }; 14 | 15 | export default parseOpenAISuggestions; 16 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb-base", "airbnb-typescript/base"], 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "rules": { 7 | "object-curly-newline": "off", 8 | "max-len": "off", 9 | "operator-linebreak": "off", 10 | "@typescript-eslint/lines-between-class-members": [ 11 | "error", 12 | "always", 13 | { "exceptAfterSingleLine": true } 14 | ], 15 | "implicit-arrow-linebreak": "off", 16 | "no-restricted-syntax": ["error", "WithStatement", "BinaryExpression[operator='in']"], 17 | "no-await-in-loop": "off", 18 | "comma-dangle": "off", 19 | "@typescript-eslint/comma-dangle": "off", 20 | "no-promise-executor-return": "off", 21 | "class-methods-use-this": "off", 22 | "no-console": "off" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2023, MagnifiCode LTD 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /src/services/utils/divideFilesByTokenRange.ts: -------------------------------------------------------------------------------- 1 | import { FilenameWithPatch } from '../types'; 2 | 3 | const divideFilesByTokenRange = ( 4 | tokensRange: number, 5 | files: FilenameWithPatch[], 6 | ) => { 7 | const result: FilenameWithPatch[][] = []; 8 | 9 | let currentArray: FilenameWithPatch[] = []; 10 | let currentTokensUsed = 0; 11 | 12 | for (const file of files) { 13 | if (currentTokensUsed + file.tokensUsed <= tokensRange) { 14 | currentArray.push(file); 15 | currentTokensUsed += file.tokensUsed; 16 | } else { 17 | result.push(currentArray); 18 | currentArray = [file]; 19 | currentTokensUsed = file.tokensUsed; 20 | } 21 | } 22 | 23 | if (currentArray.length > 0) { 24 | result.push(currentArray); 25 | } 26 | 27 | return result; 28 | }; 29 | 30 | export default divideFilesByTokenRange; 31 | -------------------------------------------------------------------------------- /src/config/errorsConfig.ts: -------------------------------------------------------------------------------- 1 | enum ErrorMessage { 2 | MISSING_GITHUB_TOKEN, 3 | MISSING_OPENAI_TOKEN, 4 | NO_PULLREQUEST_IN_CONTEXT, 5 | MISSING_PATCH_FOR_OPENAI_SUGGESTION, 6 | NO_CHANGED_FILES_IN_PULL_REQUEST, 7 | } 8 | 9 | const errorsConfig: { [key in ErrorMessage]: string } = { 10 | [ErrorMessage.MISSING_GITHUB_TOKEN]: 11 | 'A GitHub token must be provided to use the Octokit API.', 12 | [ErrorMessage.MISSING_OPENAI_TOKEN]: 13 | 'An OpenAI API token must be provided to use the OpenAI API. Make sure you have add a token with a name OPENAI_API_KEY in https://github.com/{user}/{repository}/settings/secrets/actions', 14 | [ErrorMessage.NO_PULLREQUEST_IN_CONTEXT]: 15 | 'Pull request data must be provided, check payload and try again.', 16 | [ErrorMessage.MISSING_PATCH_FOR_OPENAI_SUGGESTION]: 17 | 'The patch must be exist to provide a suggestions with Open AI', 18 | [ErrorMessage.NO_CHANGED_FILES_IN_PULL_REQUEST]: 19 | 'There are not any changed files in provided pull request', 20 | }; 21 | 22 | export default errorsConfig; 23 | export { ErrorMessage }; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-code-reviewer", 3 | "version": "0.0.8", 4 | "description": "GitHub action that provides a service for adding review comments to a pull request on GitHub.", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "package": "ncc build --source-map --minify", 9 | "lint": "eslint ./src", 10 | "build:package": "npm run build && npm run package", 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "prettier": "prettier -s -w ./src" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/magnificode-ltd/chatgpt-code-reviewer.git" 17 | }, 18 | "author": "", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/magnificode-ltd/chatgpt-code-reviewer/issues" 22 | }, 23 | "homepage": "https://github.com/magnificode-ltd/chatgpt-code-reviewer#readme", 24 | "dependencies": { 25 | "@actions/core": "^1.10.0", 26 | "@actions/github": "^5.1.1", 27 | "gpt-3-encoder": "^1.1.4", 28 | "node-fetch": "^3.3.1", 29 | "openai": "^3.2.1", 30 | "typescript": "5.0.4" 31 | }, 32 | "devDependencies": { 33 | "@trivago/prettier-plugin-sort-imports": "^4.1.1", 34 | "@types/node": "^20.1.0", 35 | "@typescript-eslint/eslint-plugin": "^5.59.5", 36 | "@typescript-eslint/parser": "^5.59.5", 37 | "@vercel/ncc": "^0.36.1", 38 | "eslint-config-airbnb": "^19.0.4", 39 | "eslint-config-airbnb-typescript": "^17.0.0", 40 | "prettier": "^2.8.8" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/services/utils/getOpenAiSuggestions.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from '@actions/core'; 2 | import fetch from 'node-fetch'; 3 | 4 | import errorsConfig, { ErrorMessage } from '../../config/errorsConfig'; 5 | import promptsConfig, { Prompt } from '../../config/promptsConfig'; 6 | 7 | const OPENAI_MODEL = getInput('model') || 'gpt-3.5-turbo'; 8 | 9 | const getOpenAiSuggestions = async (patch: string): Promise => { 10 | if (!patch) { 11 | throw new Error( 12 | errorsConfig[ErrorMessage.MISSING_PATCH_FOR_OPENAI_SUGGESTION], 13 | ); 14 | } 15 | 16 | try { 17 | const response = await fetch('https://api.openai.com/v1/chat/completions', { 18 | method: 'POST', 19 | headers: { 20 | 'Content-Type': 'application/json', 21 | Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, 22 | }, 23 | body: JSON.stringify({ 24 | model: OPENAI_MODEL, 25 | messages: [ 26 | { role: 'system', content: promptsConfig[Prompt.SYSTEM_PROMPT] }, 27 | { role: 'user', content: patch }, 28 | ], 29 | }), 30 | }); 31 | 32 | if (!response.ok) throw new Error('Failed to post data.'); 33 | 34 | const responseJson = (await response.json()) as any; 35 | 36 | const openAiSuggestion = 37 | responseJson.choices.shift()?.message?.content || ''; 38 | 39 | return openAiSuggestion; 40 | } catch (error) { 41 | console.error('Error posting data:', error); 42 | throw error; 43 | } 44 | }; 45 | 46 | export default getOpenAiSuggestions; 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to chatgpt-reviewer-github-action 2 | 3 | Thank you for considering contributing to chatgpt-reviewer-github-action. This document will guide you through the process of contributing to our project. We value the involvement of individuals like you and appreciate your efforts to help improve our software. 4 | 5 | ## Getting Started 6 | 7 | - Make sure you have a GitHub account. 8 | - Fork the repository on GitHub. 9 | - Clone the forked repository to your local machine. 10 | 11 | ## Issue Reporting 12 | 13 | If you encounter a bug, have a feature request, or want to suggest an improvement, please follow these steps: 14 | 15 | 1. Check the existing issues to avoid duplicates. 16 | 2. If the issue doesn't already exist, create a new one. 17 | 3. Provide a clear and descriptive title. 18 | 4. Describe the issue or request in detail, including steps to reproduce (if applicable). 19 | 5. Add any relevant screenshots or error messages. 20 | 21 | ## Making Changes 22 | 23 | To contribute code changes, follow these steps: 24 | 25 | 1. Create a new branch for your changes. 26 | 2. Ensure your code follows our coding conventions and style guidelines. 27 | 3. Write clear and concise commit messages. 28 | 4. Test your changes thoroughly. 29 | 5. Submit a pull request to the main repository, referencing the related issue (if applicable). 30 | 31 | ## Code Review 32 | 33 | All code changes require review before being merged. Follow these guidelines to help the review process: 34 | 35 | 1. Keep your pull request focused on a single issue or feature. 36 | 2. Be open to feedback and be prepared to make changes. 37 | 3. Respond to review comments promptly and engage in constructive discussions. 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chatgpt-code-reviewer 2 | 3 | GitHub action that adds ChatGPT code review comments to pull requests. This service uses the GitHub REST API and the OpenAI API to generate suggestions for pull request changes. 4 | 5 | Example: 6 | ChatGPT Review Example Comment 7 | 8 | ### A few notes on what to expect 9 | 10 | * This is not intended to replace an actual code review done by a developer. It's meant to spot things humans could miss, provide instantaneous feedback and fix immediately, before a peer has had time to review. 11 | * While in many of the cases we've seen the comments are great, it isn't always right, so be critical and decide for yourself what needs fixing and what does not. 12 | 13 | ### Before you start 14 | 15 | By using this repository you acknowledge and approve of the fact that: 16 | 17 | - Your code would be sent to OpenAI servers for generating code review suggestions. 18 | - Authors of this github action have no responsibility whatsoever to the consequences of the above, and they would not be liable for anything that happens as a result of using this action. 19 | 20 | --- 21 | 22 | ### Getting Started 23 | 24 | To use this github action, you will need to have a GitHub account and an OpenAI API key. Also you will need to configure a GitHub action workflow. 25 | 26 | 1. Visit https://platform.openai.com/account/api-keys to generate a new OpenAI API key. 27 | 2. Add new key with a name `OPENAI_API_KEY` as described [here](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository). As a value set generated OpenAi Api key from the step 1 28 | 3. In a repository you want to run this action, create a file: `.github/workflows/chatgpt-code-reviewer.yml` with the next content: 29 | 30 | ```yml 31 | name: chatgpt-code-reviewer 32 | run-name: chatgpt-code-reviewer 33 | on: [pull_request] 34 | jobs: 35 | chatgpt-code-reviewer: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: ChatGPT Review 39 | uses: magnificode-ltd/chatgpt-code-reviewer@v0.0.8 40 | # with: 41 | # model: gpt-3.5-turbo 42 | # max_tokens: 4096 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} 46 | ``` 47 | 48 | ### Parameters 49 | 50 | | Parameter | Description | Required | Default Value | 51 | | -------------- | ------------------------------------------------------------------------- | -------- | ------------- | 52 | | model | OpenAI model | false | gpt-3.5-turbo | 53 | | max_tokens | OpenAI TPM | false | 4096 | 54 | 55 | ### Environment Variables 56 | | Variable | Description | Required | Default Value | 57 | | -------------- | ------------------------------------------------------------------------- | -------- | ------------- | 58 | | GITHUB_TOKEN | provided to you automatically by GitHub, used to send out review comments | true | "" | 59 | | OPENAI_API_KEY | API key used to invoke OpenAI | true | "" | 60 | 61 | --- 62 | 63 | ### About 64 | 65 | 66 | MagnifiCode 67 | 68 | 69 | This repository was created & is maintained by MagnifiCode. We provide web development services. We specialize in React/Node/AWS (etc) and are available for [hire](https://bit.ly/3IcWXR3). Learn more about us on our [website](https://bit.ly/3nXn4EN). 70 | 71 | Follow us on [Twitter](https://twitter.com/magnificodehq) and [LinkedIn](https://www.linkedin.com/company/magnificode-software) for more updates. 72 | 73 | --- 74 | 75 | ### Known Issues 76 | 77 | Currently we add comments for a specific patch on the first line of the patch, so you may see a suggestion a bit higher on the file than it should be. 78 | In future versions we want to fix this. See our issues page for other issues. 79 | If you found any issue that's not in the issues area, feel free to create one and submit PRs. 80 | 81 | --- 82 | 83 | ### Dependencies 84 | 85 | - @actions/github: A GitHub Actions toolkit for interacting with the GitHub REST API. 86 | - openai: A library for interacting with the OpenAI API. 87 | -------------------------------------------------------------------------------- /src/services/commentOnPullRequestService.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from '@actions/core'; 2 | import { context, getOctokit } from '@actions/github'; 3 | import { encode } from 'gpt-3-encoder'; 4 | 5 | import errorsConfig, { ErrorMessage } from '../config/errorsConfig'; 6 | import { FilenameWithPatch, Octokit, PullRequestInfo } from './types'; 7 | import concatenatePatchesToString from './utils/concatenatePatchesToString'; 8 | import divideFilesByTokenRange from './utils/divideFilesByTokenRange'; 9 | import extractFirstChangedLineFromPatch from './utils/extractFirstChangedLineFromPatch'; 10 | import getOpenAiSuggestions from './utils/getOpenAiSuggestions'; 11 | import parseOpenAISuggestions from './utils/parseOpenAISuggestions'; 12 | 13 | const MAX_TOKENS = parseInt(getInput('max_tokens'), 10) || 4096; 14 | const OPENAI_TIMEOUT = 20000; 15 | 16 | class CommentOnPullRequestService { 17 | private readonly octokitApi: Octokit; 18 | private readonly pullRequest: PullRequestInfo; 19 | 20 | constructor() { 21 | if (!process.env.GITHUB_TOKEN) { 22 | throw new Error(errorsConfig[ErrorMessage.MISSING_GITHUB_TOKEN]); 23 | } 24 | 25 | if (!process.env.OPENAI_API_KEY) { 26 | throw new Error(errorsConfig[ErrorMessage.MISSING_OPENAI_TOKEN]); 27 | } 28 | 29 | if (!context.payload.pull_request) { 30 | throw new Error(errorsConfig[ErrorMessage.NO_PULLREQUEST_IN_CONTEXT]); 31 | } 32 | 33 | this.octokitApi = getOctokit(process.env.GITHUB_TOKEN); 34 | 35 | this.pullRequest = { 36 | owner: context.repo.owner, 37 | repo: context.repo.repo, 38 | pullHeadRef: context.payload?.pull_request.head.ref, 39 | pullBaseRef: context.payload?.pull_request.base.ref, 40 | pullNumber: context.payload?.pull_request.number, 41 | }; 42 | } 43 | 44 | private async getBranchDiff() { 45 | const { owner, repo, pullBaseRef, pullHeadRef } = this.pullRequest; 46 | 47 | const { data: branchDiff } = 48 | await this.octokitApi.rest.repos.compareCommits({ 49 | owner, 50 | repo, 51 | base: pullBaseRef, 52 | head: pullHeadRef, 53 | }); 54 | 55 | return branchDiff; 56 | } 57 | 58 | private async getLastCommit() { 59 | const { owner, repo, pullNumber } = this.pullRequest; 60 | 61 | const { data: commitsList } = await this.octokitApi.rest.pulls.listCommits({ 62 | owner, 63 | repo, 64 | per_page: 50, 65 | pull_number: pullNumber, 66 | }); 67 | 68 | return commitsList[commitsList.length - 1].sha; 69 | } 70 | 71 | private async createReviewComments(files: FilenameWithPatch[]) { 72 | const suggestionsListText = await getOpenAiSuggestions( 73 | concatenatePatchesToString(files), 74 | ); 75 | const suggestionsByFile = parseOpenAISuggestions(suggestionsListText); 76 | const { owner, repo, pullNumber } = this.pullRequest; 77 | const lastCommitId = await this.getLastCommit(); 78 | 79 | for (const file of files) { 80 | const firstChangedLine = extractFirstChangedLineFromPatch(file.patch); 81 | const suggestionForFile = suggestionsByFile.find( 82 | (suggestion) => suggestion.filename === file.filename, 83 | ); 84 | 85 | if (suggestionForFile) { 86 | try { 87 | const consoleTimeLabel = `Comment was created successfully for file: ${file.filename}`; 88 | console.time(consoleTimeLabel); 89 | 90 | await this.octokitApi.rest.pulls.createReviewComment({ 91 | owner, 92 | repo, 93 | pull_number: pullNumber, 94 | line: firstChangedLine, 95 | path: suggestionForFile.filename, 96 | body: `[ChatGPTReviewer]\n${suggestionForFile.suggestionText}`, 97 | commit_id: lastCommitId, 98 | }); 99 | 100 | console.timeEnd(consoleTimeLabel); 101 | } catch (error) { 102 | console.error( 103 | 'An error occurred while trying to add a comment', 104 | error, 105 | ); 106 | throw error; 107 | } 108 | } 109 | } 110 | } 111 | 112 | public async addCommentToPr() { 113 | const { files } = await this.getBranchDiff(); 114 | 115 | if (!files) { 116 | throw new Error( 117 | errorsConfig[ErrorMessage.NO_CHANGED_FILES_IN_PULL_REQUEST], 118 | ); 119 | } 120 | 121 | const patchesList: FilenameWithPatch[] = []; 122 | const filesTooLongToBeChecked: string[] = []; 123 | 124 | for (const file of files) { 125 | if (file.patch && encode(file.patch).length <= MAX_TOKENS / 2) { 126 | patchesList.push({ 127 | filename: file.filename, 128 | patch: file.patch, 129 | tokensUsed: encode(file.patch).length, 130 | }); 131 | } else { 132 | filesTooLongToBeChecked.push(file.filename); 133 | } 134 | } 135 | 136 | if (filesTooLongToBeChecked.length > 0) { 137 | console.log( 138 | `The changes for ${filesTooLongToBeChecked.join( 139 | ', ', 140 | )} is too long to be checked.`, 141 | ); 142 | } 143 | 144 | const listOfFilesByTokenRange = divideFilesByTokenRange( 145 | MAX_TOKENS / 2, 146 | patchesList, 147 | ); 148 | 149 | await this.createReviewComments(listOfFilesByTokenRange[0]); 150 | 151 | if (listOfFilesByTokenRange.length > 1) { 152 | let requestCount = 1; 153 | 154 | const intervalId = setInterval(async () => { 155 | if (requestCount >= listOfFilesByTokenRange.length) { 156 | clearInterval(intervalId); 157 | return; 158 | } 159 | 160 | await this.createReviewComments(listOfFilesByTokenRange[requestCount]); 161 | requestCount += 1; 162 | }, OPENAI_TIMEOUT); 163 | } 164 | } 165 | } 166 | 167 | export default CommentOnPullRequestService; 168 | -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},274:(e,r,n)=>{var t=n(339);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(190);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},680:(e,r,n)=>{var t=n(339);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},758:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(339);var i=n(345);var a=n(274).I;var u=n(449);var s=n(758).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){d.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(449);var o=n(339);var i=n(274).I;var a=n(680).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},351:(e,r,n)=>{var t;var o=n(591).h;var i=n(339);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},997:(e,r,n)=>{n(591).h;r.SourceMapConsumer=n(952).SourceMapConsumer;n(351)},284:(e,r,n)=>{e=n.nmd(e);var t=n(997).SourceMapConsumer;var o=n(17);var i;try{i=n(147);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(650);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var _=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){h.length=0}h.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){d.length=0}d.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=_.slice(0);v=handlerExec(d);m=handlerExec(h)}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};(()=>{__webpack_require__(284).install()})();module.exports=n})(); --------------------------------------------------------------------------------