├── ChatGPT ├── Assets.xcassets │ ├── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── ChatGPTApp.swift ├── ChatGPT.entitlements └── ContentView.swift ├── ChatGPT.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── adolfo.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ ├── ChatGPT.xcscheme │ │ └── ChatGPTExtension.xcscheme └── project.pbxproj ├── ChatGPTExtension ├── Domain │ ├── Model │ │ ├── Suggestion.swift │ │ └── ConverterError.swift │ ├── UseCase │ │ ├── AnalyzeUseCase.swift │ │ ├── Regex │ │ │ ├── RegexUseCase.swift │ │ │ └── DefaultRegexUseCase.swift │ │ ├── Comments │ │ │ ├── CommentUseCase.swift │ │ │ └── DefaultCommentUseCase.swift │ │ ├── ExplainCode │ │ │ ├── ExplainCodeUseCase.swift │ │ │ └── DefaultExplainCodeUseCase.swift │ │ ├── JSON2Swift │ │ │ ├── JSONConverterUseCase.swift │ │ │ └── DefaultJSONConverterUseCase.swift │ │ ├── UnitTest │ │ │ ├── UnitTestUseCase.swift │ │ │ └── DefaultUnitTestUseCase.swift │ │ └── CodeSmells │ │ │ ├── CodeSmellsUseCase.swift │ │ │ └── DefaultCodeSmellsUseCase.swift │ └── Repositories │ │ ├── CommentRepository.swift │ │ ├── JSONConverterRepository.swift │ │ ├── RegexRepository.swift │ │ ├── ExplainCodeRepository.swift │ │ ├── UnitTestRepository.swift │ │ └── CodeSmellsRepository.swift ├── ChatGPTExtension.entitlements ├── Data │ ├── Network │ │ └── OpenAI │ │ │ ├── Model │ │ │ ├── ChatGPTError.swift │ │ │ ├── Constants.swift │ │ │ ├── ChatGPTRequest.swift │ │ │ ├── ChatGPTResponse.swift │ │ │ └── NetworkRequest.swift │ │ │ ├── Extensions │ │ │ └── OpenAI+Localizable.swift │ │ │ ├── Resources │ │ │ ├── es.lproj │ │ │ │ └── Localizable.strings │ │ │ └── en.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── OpenAI+Operations.swift │ │ │ └── OpenAI.swift │ └── Repositories │ │ ├── BaseChatGPTRepository.swift │ │ ├── ChatGPTCommentRepository.swift │ │ ├── ChatGPTExplainCodeRepository.swift │ │ ├── ChatGPTJSONConverterRepository.swift │ │ ├── ChatGPTRegexRepository.swift │ │ ├── ChatGPTCodeSmellsRepository.swift │ │ └── ChatGPTUnitTestRepository.swift ├── Commands │ ├── SourceEditorExtension.swift │ ├── ExplainCode │ │ └── ExplainCodeCommand.swift │ ├── JSON2Swift │ │ └── JSON2SwiftEditorCommand.swift │ ├── UnitTest │ │ └── UnitTestEditorCommand.swift │ ├── CodeSmells │ │ └── CodeSmellsEditorCommand.swift │ ├── Comment │ │ └── CommentCommand.swift │ └── Regex │ │ └── RegexCommand.swift ├── Infrastructure │ └── Dependencies │ │ └── DependencyManager.swift └── Info.plist ├── .github └── workflows │ └── code-review.yml ├── README.md └── .gitignore /ChatGPT/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ChatGPT/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ChatGPT/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/xcuserdata/adolfo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Model/Suggestion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Suggestion.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Suggestion { 11 | let result: String 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/AnalyzeUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnalyzeUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol JSONConverterUseCase { 11 | func analyze(source code: [String]) async -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPT/ChatGPTApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTApp.swift 3 | // ChatGPT 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct ChatGPTApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/Regex/RegexUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegexUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 20/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol RegexUseCase { 11 | func generateRegexFor(string value: String) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/Comments/CommentUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 22/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol CommentUseCase { 11 | func comment(function code: [String]) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/CommentRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 22/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol CommentRepository { 11 | func comment(function code: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/JSONConverterRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnalyzeRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol JSONConverterRepository { 11 | func analyze(code: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/RegexRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegexRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 20/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol RegexRepository { 11 | func generateRegexFor(string value: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/ExplainCodeRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExplainCodeRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol ExplainCodeRepository { 11 | func explainMeThis(code: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/ExplainCode/ExplainCodeUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExplainCodeUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol ExplainCodeUseCase { 11 | func explainMeThis(code: String) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/JSON2Swift/JSONConverterUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnalyzeUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol JSONConverterUseCase { 11 | func analyze(source code: [String]) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/UnitTest/UnitTestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnitTestUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 19/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol UnitTestUseCase { 11 | func generateTestsFor(source code: [String]) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/UnitTestRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnitTestRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 19/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol UnitTestRepository { 11 | func generateTestsFor(source code: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/CodeSmells/CodeSmellsUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeSmellsUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol CodeSmellsUseCase { 11 | func searchForCodeSmells(in code: [String]) async throws -> Suggestion 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Repositories/CodeSmellsRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeSmellsRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol CodeSmellsRepository { 11 | func searchForCodeSmells(in code: String) async throws -> [Suggestion] 12 | } 13 | -------------------------------------------------------------------------------- /ChatGPTExtension/ChatGPTExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/Model/ConverterError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConverterError.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | enum ConverterError: Error { 11 | case emptyResults 12 | case authorization 13 | case rateLimit 14 | case serverStatus 15 | case unknownResponse 16 | } 17 | -------------------------------------------------------------------------------- /ChatGPT/ChatGPT.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Model/ChatGPTError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTError.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | enum ChatGPTError: Error { 11 | case malformedURL(value: String) 12 | case authentication 13 | case rateLimitReached 14 | case serverError 15 | case unknownServerResponse 16 | case malformedResponse 17 | } 18 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Extensions/OpenAI+Localizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenAI+Localizable.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | extension OpenAI { 11 | func localizedPrompt(_ key: String) -> String { 12 | let openAIBundle = Bundle(for: Self.self) 13 | 14 | return NSLocalizedString(key, bundle: openAIBundle, comment: "") 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChatGPT/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ChatGPT 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | Text("ChatGPT & Xcode") 13 | .font(.largeTitle) 14 | .fontWidth(.condensed) 15 | .frame(maxWidth: .infinity, alignment: .center) 16 | .padding() 17 | } 18 | } 19 | 20 | struct ContentView_Previews: PreviewProvider { 21 | static var previews: some View { 22 | ContentView() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/code-review.yml: -------------------------------------------------------------------------------- 1 | name: GlobantBot Code Review 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | 7 | on: 8 | pull_request: 9 | types: [opened, reopened] 10 | 11 | jobs: 12 | code-review: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: fitomad/github-chatgpt-integration@main 16 | with: 17 | openai-api-key: ${{ secrets.OPENAI_API_KEY }} 18 | github-token: ${{ secrets.GH_TOKEN }} 19 | github-pr-id: ${{ github.event.number }} 20 | dev-lang: Swift 21 | openai-max-tokens: 4096 22 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | ChatGPT 4 | 5 | Created by Adolfo Vera Blasco on 4/3/23. 6 | 7 | */ 8 | 9 | "PROMPT_JSON" = "Convierte este JSON a una estructura Swift Codable pero sin la implementación"; 10 | "PROMPT_CODE_SMELLS" = "Busca posibles Code Smells en este código escrito en Swift"; 11 | "PROMPT_EXPLAIN_CODE" = "¿Qué hace este código escrito en Swift?"; 12 | "PROMPT_GENERATE_UNIT_TEST" = "Genera las pruebas para este código usando el framework XCTest"; 13 | "PROMPT_REGEX" = "Genera una expresión regular en Swift que represente esta cadena de texto"; 14 | 15 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Model/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | enum Constants { 11 | static let baseURL = "https://api.openai.com/v1/chat/completions" 12 | 13 | static let contentTypeHeaderKey = "Content-Type" 14 | static let contentTypeHeaderValue = "application/json" 15 | 16 | static let authorizationHeaderKey = "Authorization" 17 | static let authorizationHeaderValue = "Bearer" 18 | 19 | static let modelChatpGPT = "gpt-3.5-turbo" 20 | static let modelChatGPTUser = "user" 21 | } 22 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Model/ChatGPTRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTRequest.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct ChatGPTRequest: Encodable { 11 | let model = Constants.modelChatpGPT 12 | let messages: [ChatGPTRequest.Message] 13 | 14 | init(prompt: String) { 15 | let message = ChatGPTRequest.Message(content: prompt) 16 | 17 | self.messages = [ 18 | message 19 | ] 20 | } 21 | } 22 | 23 | extension ChatGPTRequest { 24 | struct Message: Encodable { 25 | let role = Constants.modelChatGPTUser 26 | let content: String 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | ChatGPT 4 | 5 | Created by Adolfo Vera Blasco on 4/3/23. 6 | 7 | */ 8 | 9 | "PROMPT_JSON" = "Convert this JSON to a Swift Codable data structure only struct declaration"; 10 | "PROMPT_CODE_SMELLS" = "Check for Code Smells in this Swift code"; 11 | "PROMPT_EXPLAIN_CODE" = "What this Swift code does?"; 12 | "PROMPT_GENERATE_UNIT_TEST" = "Write the test cases in Swift for this code using the XCTest framework."; 13 | "PROMPT_REGEX" = "Generate a regular expression using Regex to match"; 14 | "PROMPT_COMMENT" = "Generate comments in Swift format for this function, indicating the parameters and return type, with a max line lenght of 80 characters"; 15 | 16 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/BaseChatGPTRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseChatGPTRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | class BaseChatGPTRepository { 11 | func fetchApiKey() -> String? { 12 | let currentBundle = Bundle(for: Self.self) 13 | 14 | guard let apiKeyURL = currentBundle.url(forResource: "openai", withExtension: "environment"), 15 | var apiKey = try? String(contentsOf: apiKeyURL, encoding: .utf8) 16 | else 17 | { 18 | return nil 19 | } 20 | 21 | apiKey = apiKey.trimmingCharacters(in: .whitespacesAndNewlines) 22 | 23 | return apiKey 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/Regex/DefaultRegexUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultRegexUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 20/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultRegexUseCase: RegexUseCase { 11 | private let repository: RegexRepository 12 | 13 | init(repository: RegexRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func generateRegexFor(string value: String) async throws -> Suggestion { 18 | let suggestions = try await self.repository.generateRegexFor(string: value) 19 | 20 | guard let suggestion = suggestions.first else { 21 | throw ConverterError.emptyResults 22 | } 23 | 24 | return suggestion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/ExplainCode/DefaultExplainCodeUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultExplainCodeUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultExplainCodeUseCase: ExplainCodeUseCase { 11 | private let repository: ExplainCodeRepository 12 | 13 | init(repository: ExplainCodeRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func explainMeThis(code: String) async throws -> Suggestion { 18 | let suggestions = try await self.repository.explainMeThis(code: code) 19 | 20 | guard let suggestion = suggestions.first else { 21 | throw ConverterError.emptyResults 22 | } 23 | 24 | return suggestion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/Comments/DefaultCommentUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCommentUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 22/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultCommentUseCase: CommentUseCase { 11 | private let repository: CommentRepository 12 | 13 | init(repository: CommentRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func comment(function code: [String]) async throws -> Suggestion { 18 | let preparedCode = code.reduce("") { $0 + $1 } 19 | 20 | let suggestions = try await self.repository.comment(function: preparedCode) 21 | 22 | guard let suggestion = suggestions.first else { 23 | throw ConverterError.emptyResults 24 | } 25 | 26 | return suggestion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/UnitTest/DefaultUnitTestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultUnitTestUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 19/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultUnitTestUseCase: UnitTestUseCase { 11 | private let repository: UnitTestRepository 12 | 13 | init(repository: UnitTestRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func generateTestsFor(source code: [String]) async throws -> Suggestion { 18 | let lines = code.reduce("") { $0 + $1 } 19 | 20 | let suggestions = try await self.repository.generateTestsFor(source: lines) 21 | 22 | guard let suggestion = suggestions.first else { 23 | throw ConverterError.emptyResults 24 | } 25 | 26 | return suggestion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/JSON2Swift/DefaultJSONConverterUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultAnalyzeUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultJSONConverterUseCase: JSONConverterUseCase { 11 | let repository: JSONConverterRepository 12 | 13 | init(repository: JSONConverterRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func analyze(source code: [String]) async throws -> Suggestion { 18 | let preparedCode = code.reduce("") { $0 + $1 } 19 | 20 | let suggestions = try await self.repository.analyze(code: preparedCode) 21 | 22 | guard let suggestion = suggestions.first else { 23 | throw ConverterError.emptyResults 24 | } 25 | 26 | return suggestion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatGPTExtension/Domain/UseCase/CodeSmells/DefaultCodeSmellsUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCodeSmellsUseCase.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DefaultCodeSmellsUseCase: CodeSmellsUseCase { 11 | let repository: CodeSmellsRepository 12 | 13 | init(repository: CodeSmellsRepository) { 14 | self.repository = repository 15 | } 16 | 17 | func searchForCodeSmells(in code: [String]) async throws -> Suggestion { 18 | let preparedCode = code.reduce("") { $0 + $1 } 19 | 20 | let suggestions = try await self.repository.searchForCodeSmells(in: preparedCode) 21 | 22 | guard let suggestion = suggestions.first else { 23 | throw ConverterError.emptyResults 24 | } 25 | 26 | return suggestion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/xcuserdata/adolfo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ChatGPT.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | ChatGPTExtension.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 91FFEE4C29B2822000B4DE2A 21 | 22 | primary 23 | 24 | 25 | 91FFEE6229B2824B00B4DE2A 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/SourceEditorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorExtension.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | class SourceEditorExtension: NSObject, XCSourceEditorExtension { 12 | 13 | /* 14 | func extensionDidFinishLaunching() { 15 | // If your extension needs to do any work at launch, implement this optional method. 16 | } 17 | */ 18 | 19 | /* 20 | var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { 21 | // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter. 22 | return [ 23 | [ 24 | .classNameKey : "SourceEditorCommand", 25 | .identifierKey : "SourceEditorCommand", 26 | .nameKey : "ChatGPT" 27 | ] 28 | ] 29 | } 30 | */ 31 | } 32 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/ExplainCode/ExplainCodeCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExplainCodeCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | final class ExplainCodeCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: ExplainCodeUseCase = DependencyManager.makeExplainCodeDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void) { 15 | Task { 16 | let fileSourceCode = invocation.buffer.completeBuffer 17 | 18 | do { 19 | let suggestion = try await self.useCase.explainMeThis(code: fileSourceCode) 20 | 21 | let insertedExplanation = "/**\n\(suggestion.result)\n*/" 22 | 23 | invocation.buffer.lines.add(insertedExplanation) 24 | } catch let error { 25 | print("🚨 Something goes wrong... \(error)") 26 | } 27 | 28 | completionHandler(nil) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/JSON2Swift/JSON2SwiftEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceEditorCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | class JSON2SwiftEditorCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: JSONConverterUseCase = DependencyManager.makeAnalyzeDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 15 | guard let codeLines = invocation.buffer.lines as? [String] else { 16 | completionHandler(nil) 17 | return 18 | } 19 | 20 | Task { 21 | do { 22 | let suggestion = try await self.useCase.analyze(source: codeLines) 23 | 24 | invocation.buffer.selections.removeAllObjects() 25 | invocation.buffer.selections.add(suggestion.result) 26 | } catch let error { 27 | print("🚨 Something goes wrong... \(error)") 28 | } 29 | 30 | completionHandler(nil) 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /ChatGPT/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/UnitTest/UnitTestEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnitTestEditorCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 19/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | final class UnitTestEditorCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: UnitTestUseCase = DependencyManager.makeUnitTestsDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void) { 15 | guard let codeLines = invocation.buffer.lines as? [String] else { 16 | completionHandler(nil) 17 | return 18 | } 19 | 20 | Task { 21 | do { 22 | let suggestion = try await self.useCase.generateTestsFor(source: codeLines) 23 | 24 | let insertedExplanation = "/**\n\(suggestion.result)\n*/" 25 | 26 | invocation.buffer.lines.add(insertedExplanation) 27 | } catch let error { 28 | print("🚨 Something goes wrong... \(error)") 29 | } 30 | 31 | completionHandler(nil) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/CodeSmells/CodeSmellsEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeSmellsEditorCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | final class CodeSmellsEditorCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: CodeSmellsUseCase = DependencyManager.makeCodeSmellsDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 15 | guard let codeLines = invocation.buffer.lines as? [String] else { 16 | completionHandler(nil) 17 | return 18 | } 19 | 20 | Task { 21 | do { 22 | let suggestion = try await self.useCase.searchForCodeSmells(in: codeLines) 23 | 24 | let insertedSuggestion = "/**\(suggestion.result)\n*/" 25 | 26 | invocation.buffer.lines.add(insertedSuggestion) 27 | } catch let error { 28 | print("🚨 Something goes wrong... \(error)") 29 | } 30 | 31 | completionHandler(nil) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Model/ChatGPTResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTResponse.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct ChatGPTResponse: Decodable, Identifiable { 11 | let id: String 12 | let object: String 13 | let model: String 14 | let usage: ChatGPTResponse.Usage 15 | let choices: [ChatGPTResponse.Choice] 16 | } 17 | 18 | extension ChatGPTResponse { 19 | struct Usage: Decodable { 20 | let promptTokenCount: Int 21 | let completionTokenCount: Int 22 | let totalTokens: Int 23 | 24 | private enum CodingKeys: String, CodingKey { 25 | case promptTokenCount = "prompt_tokens" 26 | case completionTokenCount = "completion_tokens" 27 | case totalTokens = "total_tokens" 28 | } 29 | } 30 | 31 | struct Message: Decodable { 32 | let role: String 33 | let content: String 34 | } 35 | 36 | struct Choice: Decodable { 37 | let message: ChatGPTResponse.Message 38 | let finishReason: String 39 | let index: Int 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case message 43 | case finishReason = "finish_reason" 44 | case index 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-Xcode 2 | 3 | This repository serves as the basis for the Medium article titled ["Integrating ChatGPT into Xcode: How to Improve Your Apps with AI."](https://medium.com/globant/chatgpt-integration-in-xcode-how-to-improve-your-apps-with-ai-3bdbc34bea48) 4 | 5 | Integrating ChatGPT into Xcode using an Xcode Source Editor Extension that solves three specific problems: 6 | 7 | * **Code conversion**. A command that converts a JSON document to a Swift struct. 8 | * **Code smells**. We ask ChatGPT to try to identify things that can be improved in our source code. 9 | * **Code explanation**. In this last case, we are interested in knowing what a particular code does. 10 | * **Unit testing**. Generate XCTest code for the current file. 11 | * **Regex**. Creates a regular expression based on the selected text string. 12 | 13 | ## OpenAI API Key 14 | 15 | To execute the extension commands, an OpenAI API key is required, which must be saved in a file called `openai.environment` and will only contain the key. 16 | 17 | This file must be included in the Xcode extension target. 18 | 19 | ## Disclaimer. Read carefully 20 | 21 | Usage of this Source Code Extension will **send your source code to ChatGPT**, please note that due to the nature of the internet, It does not guarantee the security of any information transmitted to OpenAI, including source code. 22 | 23 | Before using code that you don't own with this Source Code Extension, contact its owner to obtain the necessary permission. 24 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTCommentRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTCommentRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 22/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTCommentRepository: BaseChatGPTRepository, CommentRepository { 11 | func comment(function code: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.comment(function: code) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTExplainCodeRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTExplainCodeRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTExplainCodeRepository: BaseChatGPTRepository, ExplainCodeRepository { 11 | func explainMeThis(code: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.explain(source: code) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTJSONConverterRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTAnalyzeRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTJSONConverterRepository: BaseChatGPTRepository, JSONConverterRepository { 11 | func analyze(code: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.analyze(source: code) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTRegexRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTRegexRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 20/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTRegexRepository: BaseChatGPTRepository, RegexRepository { 11 | func generateRegexFor(string value: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.generateRegexFor(string: value) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTCodeSmellsRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTCodeSmellsRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTCodeSmellsRepository: BaseChatGPTRepository, CodeSmellsRepository { 11 | func searchForCodeSmells(in code: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.codeSmellsFor(code: code) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Repositories/ChatGPTUnitTestRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatGPTUnitTestRepository.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 19/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class ChatGPTUnitTestRepository: BaseChatGPTRepository, UnitTestRepository { 11 | func generateTestsFor(source code: String) async throws -> [Suggestion] { 12 | guard let apiKey = super.fetchApiKey() else { 13 | throw ConverterError.authorization 14 | } 15 | 16 | let openAI = OpenAI(key: apiKey) 17 | 18 | var suggestions: [Suggestion]? 19 | 20 | do { 21 | let chatpGPTResponse = try await openAI.generateTestsFor(source: code) 22 | 23 | suggestions = chatpGPTResponse.choices.map { choice in 24 | let suggestion = Suggestion(result: choice.message.content) 25 | 26 | return suggestion 27 | } 28 | } catch ChatGPTError.rateLimitReached { 29 | throw ConverterError.rateLimit 30 | } catch ChatGPTError.serverError { 31 | throw ConverterError.serverStatus 32 | } catch ChatGPTError.authentication { 33 | throw ConverterError.authorization 34 | } catch { 35 | throw ConverterError.unknownResponse 36 | } 37 | 38 | guard let suggestions else { 39 | throw ConverterError.emptyResults 40 | } 41 | 42 | return suggestions 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/OpenAI+Operations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenAI+Operations.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 5/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | extension OpenAI { 11 | func codeSmellsFor(code: String) async throws -> ChatGPTResponse { 12 | let smellsPrompt = "\(localizedPrompt("PROMPT_CODE_SMELLS")) \(code)" 13 | 14 | return try await processRequestFor(prompt: smellsPrompt) 15 | } 16 | 17 | func analyze(source code: String) async throws -> ChatGPTResponse { 18 | let jsonPrompt = "\(localizedPrompt("PROMPT_JSON")) \(code)" 19 | 20 | return try await processRequestFor(prompt: jsonPrompt) 21 | } 22 | 23 | func explain(source code: String) async throws -> ChatGPTResponse { 24 | let explainPrompt = "\(localizedPrompt("PROMPT_EXPLAIN_CODE")) \(code)" 25 | 26 | return try await processRequestFor(prompt: explainPrompt) 27 | } 28 | 29 | func generateTestsFor(source code: String) async throws -> ChatGPTResponse { 30 | let testsPrompt = "\(localizedPrompt("PROMPT_GENERATE_UNIT_TEST")) \(code)" 31 | 32 | return try await processRequestFor(prompt: testsPrompt) 33 | } 34 | 35 | func generateRegexFor(string value: String) async throws -> ChatGPTResponse { 36 | let regexPrompt = "\(localizedPrompt("PROMPT_REGEX")) \(value)" 37 | 38 | return try await processRequestFor(prompt: regexPrompt) 39 | } 40 | 41 | func comment(function code: String) async throws -> ChatGPTResponse { 42 | let commentPrompt = "\(localizedPrompt("PROMPT_COMMENT")) \(code)" 43 | 44 | return try await processRequestFor(prompt: commentPrompt) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/Comment/CommentCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 22/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | final class CommentCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: CommentUseCase = DependencyManager.makeCommentDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 15 | guard let codeLines = invocation.buffer.lines as? [String], 16 | let selections = invocation.buffer.selections as? [XCSourceTextRange], 17 | let xcodeSelection = selections.first 18 | else 19 | { 20 | completionHandler(nil) 21 | return 22 | } 23 | 24 | Task { 25 | do { 26 | let functionLines = extractSelectedTextFrom(selection: xcodeSelection, from: codeLines) 27 | let suggestion = try await self.useCase.comment(function: functionLines) 28 | 29 | let comment = "/**\(suggestion.result)\n*/" 30 | 31 | invocation.buffer.lines.insert(comment, at: xcodeSelection.start.line) 32 | } catch let error { 33 | print("🚨 Something goes wrong... \(error)") 34 | } 35 | 36 | completionHandler(nil) 37 | } 38 | } 39 | 40 | private func extractSelectedTextFrom(selection: XCSourceTextRange, from lines: [String]) -> [String] { 41 | let selectedLinesSlice = lines[selection.start.line..(selectedLinesSlice) 43 | 44 | return selectedLines 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ChatGPTExtension/Data/Network/OpenAI/Model/NetworkRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkRequest.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 3/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct NetworkRequest { 11 | // MARK: - HttpMethod enum 12 | /// HTTP Methods 13 | public enum HttpMethod: String { 14 | case get = "GET" 15 | case post = "POST" 16 | case put = "PUT" 17 | case patch = "PATCH" 18 | case delete = "DELETE" 19 | } 20 | 21 | // MARK: - Public properties 22 | /// HTTP headers 23 | public var headers: [String : String]? 24 | /// Information for the HTTP *body* 25 | public var payload: Data? 26 | /// HTTP verb 27 | public var method: NetworkRequest.HttpMethod = .post 28 | 29 | // MARK: - Initializer 30 | public init(httpHeaders: [String : String]? = nil, body payload: Data? = nil, httpMethod: NetworkRequest.HttpMethod = .post) { 31 | self.headers = httpHeaders 32 | self.payload = payload 33 | self.method = httpMethod 34 | } 35 | 36 | // MARK: - Functions 37 | /** 38 | Create an `URLRequest` based on the current parameters 39 | for an endpoint. 40 | 41 | - Parameter endpoint: URL to fetch 42 | - Returns: A new `URLRequest` 43 | */ 44 | func makeURLRequest(for endpoint: String) -> URLRequest? { 45 | guard let url = URL(string: endpoint) else { 46 | return nil 47 | } 48 | 49 | var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData) 50 | 51 | if let headers = headers { 52 | headers.forEach({ request.addValue($0.value, forHTTPHeaderField: $0.key) }) 53 | } 54 | 55 | if let body = payload { 56 | request.httpBody = body 57 | } 58 | 59 | request.httpMethod = self.method.rawValue 60 | 61 | return request 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ChatGPTExtension/Infrastructure/Dependencies/DependencyManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DependencyManager.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 4/3/23. 6 | // 7 | 8 | import Foundation 9 | 10 | final class DependencyManager { 11 | static func makeAnalyzeDependencies() -> JSONConverterUseCase { 12 | let jsonConverterRepository: JSONConverterRepository = ChatGPTJSONConverterRepository() 13 | let useCase: JSONConverterUseCase = DefaultJSONConverterUseCase(repository: jsonConverterRepository) 14 | 15 | return useCase 16 | } 17 | 18 | static func makeCodeSmellsDependencies() -> CodeSmellsUseCase { 19 | let codeSmellsRepository: CodeSmellsRepository = ChatGPTCodeSmellsRepository() 20 | let useCase: CodeSmellsUseCase = DefaultCodeSmellsUseCase(repository: codeSmellsRepository) 21 | 22 | return useCase 23 | } 24 | 25 | static func makeExplainCodeDependencies() -> ExplainCodeUseCase { 26 | let explainCodeRepository: ExplainCodeRepository = ChatGPTExplainCodeRepository() 27 | let useCase: ExplainCodeUseCase = DefaultExplainCodeUseCase(repository: explainCodeRepository) 28 | 29 | return useCase 30 | } 31 | 32 | static func makeUnitTestsDependencies() -> UnitTestUseCase { 33 | let unitTestRepository: UnitTestRepository = ChatGPTUnitTestRepository() 34 | let useCase: UnitTestUseCase = DefaultUnitTestUseCase(repository: unitTestRepository) 35 | 36 | return useCase 37 | } 38 | 39 | static func makeRegexDependencies() -> RegexUseCase { 40 | let regexRepository: RegexRepository = ChatGPTRegexRepository() 41 | let useCase: RegexUseCase = DefaultRegexUseCase(repository: regexRepository) 42 | 43 | return useCase 44 | } 45 | 46 | static func makeCommentDependencies() -> CommentUseCase { 47 | let commentRepository: CommentRepository = ChatGPTCommentRepository() 48 | let useCase: CommentUseCase = DefaultCommentUseCase(repository: commentRepository) 49 | 50 | return useCase 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /ChatGPTExtension/Commands/Regex/RegexCommand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegexCommand.swift 3 | // ChatGPTExtension 4 | // 5 | // Created by Adolfo Vera Blasco on 21/3/23. 6 | // 7 | 8 | import Foundation 9 | import XcodeKit 10 | 11 | final class RegexCommand: NSObject, XCSourceEditorCommand { 12 | let useCase: RegexUseCase = DependencyManager.makeRegexDependencies() 13 | 14 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void) { 15 | guard let selections = invocation.buffer.selections as? [XCSourceTextRange], 16 | let lines = invocation.buffer.lines as? [String] 17 | else 18 | { 19 | completionHandler(nil) 20 | return 21 | } 22 | 23 | Task { 24 | do { 25 | let selectedTexts = extractSelections(selections, fromText: lines) 26 | 27 | for selectedText in selectedTexts { 28 | let suggestion = try await self.useCase.generateRegexFor(string: selectedText) 29 | 30 | let suggestedRegex = "/**\(suggestion.result)\n*/" 31 | 32 | invocation.buffer.lines.add(suggestedRegex) 33 | } 34 | } catch let error { 35 | print("🚨 Something goes wrong... \(error)") 36 | } 37 | 38 | completionHandler(nil) 39 | } 40 | } 41 | 42 | private func extractSelections(_ selections: [XCSourceTextRange], fromText lines: [String]) -> [String] { 43 | var selectedLines = [String]() 44 | 45 | for selection in selections where selection.start.line == selection.end.line { 46 | let line = lines[selection.start.line] 47 | 48 | let startIndex = line.index(line.startIndex, offsetBy: selection.start.column) 49 | let endIndex = line.index(line.startIndex, offsetBy: selection.end.column) 50 | 51 | let selectedText = String(line[startIndex.. ChatGPTResponse { 24 | let chatGRTRequest = ChatGPTRequest(prompt: prompt) 25 | let data = try? JSONEncoder().encode(chatGRTRequest) 26 | 27 | let request = NetworkRequest(httpHeaders: commonHeaders, body: data) 28 | 29 | guard let openaiURLRequest = request.makeURLRequest(for: Constants.baseURL) else { 30 | throw ChatGPTError.malformedURL(value: Constants.baseURL) 31 | } 32 | 33 | guard let (data, response) = try? await URLSession.shared.data(for: openaiURLRequest), 34 | let httpResponse = response as? HTTPURLResponse 35 | else 36 | { 37 | throw ChatGPTError.unknownServerResponse 38 | } 39 | 40 | switch httpResponse.statusCode { 41 | case 401: 42 | throw ChatGPTError.authentication 43 | case 429: 44 | throw ChatGPTError.rateLimitReached 45 | case 500: 46 | throw ChatGPTError.serverError 47 | case 200: 48 | let chatGPTResponse = try self.processResponse(data: data) 49 | return chatGPTResponse 50 | default: 51 | throw ChatGPTError.unknownServerResponse 52 | } 53 | } 54 | 55 | private func processResponse(data: Data) throws -> ChatGPTResponse { 56 | let jsonDecoder = JSONDecoder() 57 | 58 | do { 59 | let chatGPTResponse = try jsonDecoder.decode(ChatGPTResponse.self, from: data) 60 | return chatGPTResponse 61 | } catch { 62 | throw ChatGPTError.malformedResponse 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File system 2 | .DS_Store 3 | 4 | # Avoid environment files 5 | *.environment 6 | 7 | # Xcode 8 | # 9 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 10 | 11 | ## User settings 12 | xcuserdata/ 13 | 14 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 15 | *.xcscmblueprint 16 | *.xccheckout 17 | 18 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 19 | build/ 20 | DerivedData/ 21 | *.moved-aside 22 | *.pbxuser 23 | !default.pbxuser 24 | *.mode1v3 25 | !default.mode1v3 26 | *.mode2v3 27 | !default.mode2v3 28 | *.perspectivev3 29 | !default.perspectivev3 30 | 31 | ## Obj-C/Swift specific 32 | *.hmap 33 | 34 | ## App packaging 35 | *.ipa 36 | *.dSYM.zip 37 | *.dSYM 38 | 39 | ## Playgrounds 40 | timeline.xctimeline 41 | playground.xcworkspace 42 | 43 | # Swift Package Manager 44 | # 45 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 46 | # Packages/ 47 | # Package.pins 48 | # Package.resolved 49 | # *.xcodeproj 50 | # 51 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 52 | # hence it is not needed unless you have added a package configuration file to your project 53 | # .swiftpm 54 | 55 | .build/ 56 | 57 | # CocoaPods 58 | # 59 | # We recommend against adding the Pods directory to your .gitignore. However 60 | # you should judge for yourself, the pros and cons are mentioned at: 61 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 62 | # 63 | # Pods/ 64 | # 65 | # Add this line if you want to avoid checking in source code from the Xcode workspace 66 | # *.xcworkspace 67 | 68 | # Carthage 69 | # 70 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 71 | # Carthage/Checkouts 72 | 73 | Carthage/Build/ 74 | 75 | # Accio dependency management 76 | Dependencies/ 77 | .accio/ 78 | 79 | # fastlane 80 | # 81 | # It is recommended to not store the screenshots in the git repo. 82 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 83 | # For more information about the recommended setup visit: 84 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 85 | 86 | fastlane/report.xml 87 | fastlane/Preview.html 88 | fastlane/screenshots/**/*.png 89 | fastlane/test_output 90 | 91 | # Code Injection 92 | # 93 | # After new code Injection tools there's a generated folder /iOSInjectionProject 94 | # https://github.com/johnno1962/injectionforxcode 95 | 96 | iOSInjectionProject/ 97 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/xcshareddata/xcschemes/ChatGPT.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /ChatGPTExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | XCSourceEditorCommandDefinitions 10 | 11 | 12 | XCSourceEditorCommandClassName 13 | $(PRODUCT_MODULE_NAME).JSON2SwiftEditorCommand 14 | XCSourceEditorCommandIdentifier 15 | $(PRODUCT_BUNDLE_IDENTIFIER).JSON2SwiftEditorCommand 16 | XCSourceEditorCommandName 17 | JSON to Swift 18 | 19 | 20 | 21 | XCSourceEditorCommandClassName 22 | $(PRODUCT_MODULE_NAME).CodeSmellsEditorCommand 23 | XCSourceEditorCommandIdentifier 24 | $(PRODUCT_BUNDLE_IDENTIFIER).CodeSmellsEditorCommand 25 | XCSourceEditorCommandName 26 | Check for Code Smells 27 | 28 | 29 | 30 | XCSourceEditorCommandClassName 31 | $(PRODUCT_MODULE_NAME).ExplainCodeCommand 32 | XCSourceEditorCommandIdentifier 33 | $(PRODUCT_BUNDLE_IDENTIFIER).ExplainCodeCommand 34 | XCSourceEditorCommandName 35 | Explain me this code 36 | 37 | 38 | 39 | XCSourceEditorCommandClassName 40 | $(PRODUCT_MODULE_NAME).UnitTestEditorCommand 41 | XCSourceEditorCommandIdentifier 42 | $(PRODUCT_BUNDLE_IDENTIFIER).UnitTestEditorCommand 43 | XCSourceEditorCommandName 44 | Generate tests for this function 45 | 46 | 47 | 48 | XCSourceEditorCommandClassName 49 | $(PRODUCT_MODULE_NAME).RegexCommand 50 | XCSourceEditorCommandIdentifier 51 | $(PRODUCT_BUNDLE_IDENTIFIER).RegexCommand 52 | XCSourceEditorCommandName 53 | Generate regular expression based on a sample string 54 | 55 | 56 | 57 | XCSourceEditorCommandClassName 58 | $(PRODUCT_MODULE_NAME).CommentCommand 59 | XCSourceEditorCommandIdentifier 60 | $(PRODUCT_BUNDLE_IDENTIFIER).CommentCommand 61 | XCSourceEditorCommandName 62 | Add Swift comments 63 | 64 | 65 | 66 | XCSourceEditorExtensionPrincipalClass 67 | $(PRODUCT_MODULE_NAME).SourceEditorExtension 68 | 69 | NSExtensionPointIdentifier 70 | com.apple.dt.Xcode.extension.source-editor 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/xcshareddata/xcschemes/ChatGPTExtension.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 60 | 64 | 65 | 66 | 72 | 73 | 74 | 75 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ChatGPT.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 911729AD29B32E780066F46E /* DependencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911729AC29B32E780066F46E /* DependencyManager.swift */; }; 11 | 911729AF29B32FFB0066F46E /* ChatGPTResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911729AE29B32FFB0066F46E /* ChatGPTResponse.swift */; }; 12 | 9126724629B350320076A294 /* ChatGPTError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9126724529B350320076A294 /* ChatGPTError.swift */; }; 13 | 9126724829B359CA0076A294 /* JSONConverterRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9126724729B359CA0076A294 /* JSONConverterRepository.swift */; }; 14 | 9126724A29B35A000076A294 /* ChatGPTJSONConverterRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9126724929B35A000076A294 /* ChatGPTJSONConverterRepository.swift */; }; 15 | 9134BA4D29CA1E8200784AF2 /* RegexCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9134BA4C29CA1E8200784AF2 /* RegexCommand.swift */; }; 16 | 913C1D9229C8D2F300EE95B6 /* RegexRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913C1D9129C8D2F300EE95B6 /* RegexRepository.swift */; }; 17 | 913C1D9429C8D32400EE95B6 /* ChatGPTRegexRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913C1D9329C8D32400EE95B6 /* ChatGPTRegexRepository.swift */; }; 18 | 91893E8B29C7BE8E00AFF495 /* UnitTestEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91893E8A29C7BE8E00AFF495 /* UnitTestEditorCommand.swift */; }; 19 | 91893E8E29C7BFD000AFF495 /* UnitTestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91893E8D29C7BFD000AFF495 /* UnitTestUseCase.swift */; }; 20 | 91893E9029C7C01800AFF495 /* DefaultUnitTestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91893E8F29C7C01800AFF495 /* DefaultUnitTestUseCase.swift */; }; 21 | 91893E9229C7C07500AFF495 /* UnitTestRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91893E9129C7C07500AFF495 /* UnitTestRepository.swift */; }; 22 | 91893E9429C7C0AC00AFF495 /* ChatGPTUnitTestRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91893E9329C7C0AC00AFF495 /* ChatGPTUnitTestRepository.swift */; }; 23 | 91A043D629B48CB60077238E /* OpenAI+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91A043D529B48CB60077238E /* OpenAI+Operations.swift */; }; 24 | 91B2577329C8D7C900E11003 /* RegexUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B2577229C8D7C900E11003 /* RegexUseCase.swift */; }; 25 | 91B2577529C8D85600E11003 /* DefaultRegexUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B2577429C8D85600E11003 /* DefaultRegexUseCase.swift */; }; 26 | 91BCF70629B3C18E00C022E9 /* XcodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91FFEE6729B2824B00B4DE2A /* XcodeKit.framework */; }; 27 | 91BCF70729B3C18E00C022E9 /* XcodeKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 91FFEE6729B2824B00B4DE2A /* XcodeKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 28 | 91CD167A29B3F1EF0018CA5A /* CodeSmellsEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD167929B3F1EF0018CA5A /* CodeSmellsEditorCommand.swift */; }; 29 | 91CD167C29B3F35B0018CA5A /* CodeSmellsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD167B29B3F35B0018CA5A /* CodeSmellsUseCase.swift */; }; 30 | 91CD167E29B3F39C0018CA5A /* DefaultCodeSmellsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD167D29B3F39C0018CA5A /* DefaultCodeSmellsUseCase.swift */; }; 31 | 91CD168029B3F50C0018CA5A /* CodeSmellsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD167F29B3F50C0018CA5A /* CodeSmellsRepository.swift */; }; 32 | 91CD168229B3F5410018CA5A /* ChatGPTCodeSmellsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD168129B3F5410018CA5A /* ChatGPTCodeSmellsRepository.swift */; }; 33 | 91CD168429B3F7970018CA5A /* BaseChatGPTRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CD168329B3F7970018CA5A /* BaseChatGPTRepository.swift */; }; 34 | 91E2684A29B39ACC0098BBB5 /* JSONConverterUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2684929B39ACC0098BBB5 /* JSONConverterUseCase.swift */; }; 35 | 91E2684C29B39B6F0098BBB5 /* DefaultJSONConverterUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2684B29B39B6F0098BBB5 /* DefaultJSONConverterUseCase.swift */; }; 36 | 91E2684E29B3A7510098BBB5 /* Suggestion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2684D29B3A7510098BBB5 /* Suggestion.swift */; }; 37 | 91E2685329B3AA2C0098BBB5 /* ChatGPTRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2685229B3AA2C0098BBB5 /* ChatGPTRequest.swift */; }; 38 | 91E2685629B3AC820098BBB5 /* OpenAI+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2685529B3AC820098BBB5 /* OpenAI+Localizable.swift */; }; 39 | 91E2685729B3ADDE0098BBB5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 91E2685929B3ADDE0098BBB5 /* Localizable.strings */; }; 40 | 91E2685C29B3B3C50098BBB5 /* ConverterError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91E2685B29B3B3C50098BBB5 /* ConverterError.swift */; }; 41 | 91FAD36E29B4784800917E35 /* ExplainCodeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FAD36D29B4784800917E35 /* ExplainCodeCommand.swift */; }; 42 | 91FAD37029B478A000917E35 /* ExplainCodeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FAD36F29B478A000917E35 /* ExplainCodeUseCase.swift */; }; 43 | 91FAD37229B478FD00917E35 /* DefaultExplainCodeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FAD37129B478FD00917E35 /* DefaultExplainCodeUseCase.swift */; }; 44 | 91FAD37429B4796600917E35 /* ExplainCodeRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FAD37329B4796600917E35 /* ExplainCodeRepository.swift */; }; 45 | 91FAD37629B47AEA00917E35 /* ChatGPTExplainCodeRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FAD37529B47AEA00917E35 /* ChatGPTExplainCodeRepository.swift */; }; 46 | 91FFEE5129B2822000B4DE2A /* ChatGPTApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE5029B2822000B4DE2A /* ChatGPTApp.swift */; }; 47 | 91FFEE5329B2822000B4DE2A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE5229B2822000B4DE2A /* ContentView.swift */; }; 48 | 91FFEE5529B2822100B4DE2A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 91FFEE5429B2822100B4DE2A /* Assets.xcassets */; }; 49 | 91FFEE5829B2822100B4DE2A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 91FFEE5729B2822100B4DE2A /* Preview Assets.xcassets */; }; 50 | 91FFEE6629B2824B00B4DE2A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91FFEE6529B2824B00B4DE2A /* Cocoa.framework */; }; 51 | 91FFEE6B29B2824B00B4DE2A /* SourceEditorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE6A29B2824B00B4DE2A /* SourceEditorExtension.swift */; }; 52 | 91FFEE6D29B2824B00B4DE2A /* JSON2SwiftEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE6C29B2824B00B4DE2A /* JSON2SwiftEditorCommand.swift */; }; 53 | 91FFEE7229B2824B00B4DE2A /* ChatGPTExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 91FFEE6329B2824B00B4DE2A /* ChatGPTExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 54 | 91FFEE7C29B2838000B4DE2A /* OpenAI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE7B29B2838000B4DE2A /* OpenAI.swift */; }; 55 | 91FFEE7F29B2854200B4DE2A /* NetworkRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE7E29B2854200B4DE2A /* NetworkRequest.swift */; }; 56 | 91FFEE8329B288F000B4DE2A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFEE8229B288F000B4DE2A /* Constants.swift */; }; 57 | D8E6234C29CB93690072A861 /* openai.environment in Resources */ = {isa = PBXBuildFile; fileRef = D8E6234B29CB93690072A861 /* openai.environment */; }; 58 | D8E6234F29CBA0530072A861 /* CommentRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E6234E29CBA0530072A861 /* CommentRepository.swift */; }; 59 | D8E6235129CBA08C0072A861 /* ChatGPTCommentRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E6235029CBA08C0072A861 /* ChatGPTCommentRepository.swift */; }; 60 | D8E6235429CBA1120072A861 /* CommentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E6235329CBA1120072A861 /* CommentUseCase.swift */; }; 61 | D8E6235629CBA1580072A861 /* DefaultCommentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E6235529CBA1580072A861 /* DefaultCommentUseCase.swift */; }; 62 | D8E6235929CBA20E0072A861 /* CommentCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E6235829CBA20E0072A861 /* CommentCommand.swift */; }; 63 | /* End PBXBuildFile section */ 64 | 65 | /* Begin PBXContainerItemProxy section */ 66 | 91FFEE7029B2824B00B4DE2A /* PBXContainerItemProxy */ = { 67 | isa = PBXContainerItemProxy; 68 | containerPortal = 91FFEE4529B2822000B4DE2A /* Project object */; 69 | proxyType = 1; 70 | remoteGlobalIDString = 91FFEE6229B2824B00B4DE2A; 71 | remoteInfo = ChatGPTExtension; 72 | }; 73 | /* End PBXContainerItemProxy section */ 74 | 75 | /* Begin PBXCopyFilesBuildPhase section */ 76 | 91BCF70829B3C18E00C022E9 /* Embed Frameworks */ = { 77 | isa = PBXCopyFilesBuildPhase; 78 | buildActionMask = 2147483647; 79 | dstPath = ""; 80 | dstSubfolderSpec = 10; 81 | files = ( 82 | 91BCF70729B3C18E00C022E9 /* XcodeKit.framework in Embed Frameworks */, 83 | ); 84 | name = "Embed Frameworks"; 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | 91FFEE7629B2824B00B4DE2A /* Embed Foundation Extensions */ = { 88 | isa = PBXCopyFilesBuildPhase; 89 | buildActionMask = 2147483647; 90 | dstPath = ""; 91 | dstSubfolderSpec = 13; 92 | files = ( 93 | 91FFEE7229B2824B00B4DE2A /* ChatGPTExtension.appex in Embed Foundation Extensions */, 94 | ); 95 | name = "Embed Foundation Extensions"; 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXCopyFilesBuildPhase section */ 99 | 100 | /* Begin PBXFileReference section */ 101 | 911729AC29B32E780066F46E /* DependencyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyManager.swift; sourceTree = ""; }; 102 | 911729AE29B32FFB0066F46E /* ChatGPTResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTResponse.swift; sourceTree = ""; }; 103 | 9126724529B350320076A294 /* ChatGPTError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTError.swift; sourceTree = ""; }; 104 | 9126724729B359CA0076A294 /* JSONConverterRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONConverterRepository.swift; sourceTree = ""; }; 105 | 9126724929B35A000076A294 /* ChatGPTJSONConverterRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTJSONConverterRepository.swift; sourceTree = ""; }; 106 | 9134BA4C29CA1E8200784AF2 /* RegexCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegexCommand.swift; sourceTree = ""; }; 107 | 913C1D9129C8D2F300EE95B6 /* RegexRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegexRepository.swift; sourceTree = ""; }; 108 | 913C1D9329C8D32400EE95B6 /* ChatGPTRegexRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTRegexRepository.swift; sourceTree = ""; }; 109 | 91893E8A29C7BE8E00AFF495 /* UnitTestEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitTestEditorCommand.swift; sourceTree = ""; }; 110 | 91893E8D29C7BFD000AFF495 /* UnitTestUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitTestUseCase.swift; sourceTree = ""; }; 111 | 91893E8F29C7C01800AFF495 /* DefaultUnitTestUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultUnitTestUseCase.swift; sourceTree = ""; }; 112 | 91893E9129C7C07500AFF495 /* UnitTestRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitTestRepository.swift; sourceTree = ""; }; 113 | 91893E9329C7C0AC00AFF495 /* ChatGPTUnitTestRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTUnitTestRepository.swift; sourceTree = ""; }; 114 | 91A043D529B48CB60077238E /* OpenAI+Operations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenAI+Operations.swift"; sourceTree = ""; }; 115 | 91B2577229C8D7C900E11003 /* RegexUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegexUseCase.swift; sourceTree = ""; }; 116 | 91B2577429C8D85600E11003 /* DefaultRegexUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultRegexUseCase.swift; sourceTree = ""; }; 117 | 91CD167929B3F1EF0018CA5A /* CodeSmellsEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSmellsEditorCommand.swift; sourceTree = ""; }; 118 | 91CD167B29B3F35B0018CA5A /* CodeSmellsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSmellsUseCase.swift; sourceTree = ""; }; 119 | 91CD167D29B3F39C0018CA5A /* DefaultCodeSmellsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultCodeSmellsUseCase.swift; sourceTree = ""; }; 120 | 91CD167F29B3F50C0018CA5A /* CodeSmellsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSmellsRepository.swift; sourceTree = ""; }; 121 | 91CD168129B3F5410018CA5A /* ChatGPTCodeSmellsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTCodeSmellsRepository.swift; sourceTree = ""; }; 122 | 91CD168329B3F7970018CA5A /* BaseChatGPTRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseChatGPTRepository.swift; sourceTree = ""; }; 123 | 91E2684929B39ACC0098BBB5 /* JSONConverterUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONConverterUseCase.swift; sourceTree = ""; }; 124 | 91E2684B29B39B6F0098BBB5 /* DefaultJSONConverterUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultJSONConverterUseCase.swift; sourceTree = ""; }; 125 | 91E2684D29B3A7510098BBB5 /* Suggestion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Suggestion.swift; sourceTree = ""; }; 126 | 91E2685229B3AA2C0098BBB5 /* ChatGPTRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTRequest.swift; sourceTree = ""; }; 127 | 91E2685529B3AC820098BBB5 /* OpenAI+Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenAI+Localizable.swift"; sourceTree = ""; }; 128 | 91E2685829B3ADDE0098BBB5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 129 | 91E2685A29B3ADE30098BBB5 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 130 | 91E2685B29B3B3C50098BBB5 /* ConverterError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConverterError.swift; sourceTree = ""; }; 131 | 91FAD36D29B4784800917E35 /* ExplainCodeCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplainCodeCommand.swift; sourceTree = ""; }; 132 | 91FAD36F29B478A000917E35 /* ExplainCodeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplainCodeUseCase.swift; sourceTree = ""; }; 133 | 91FAD37129B478FD00917E35 /* DefaultExplainCodeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultExplainCodeUseCase.swift; sourceTree = ""; }; 134 | 91FAD37329B4796600917E35 /* ExplainCodeRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplainCodeRepository.swift; sourceTree = ""; }; 135 | 91FAD37529B47AEA00917E35 /* ChatGPTExplainCodeRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTExplainCodeRepository.swift; sourceTree = ""; }; 136 | 91FFEE4D29B2822000B4DE2A /* ChatGPT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChatGPT.app; sourceTree = BUILT_PRODUCTS_DIR; }; 137 | 91FFEE5029B2822000B4DE2A /* ChatGPTApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTApp.swift; sourceTree = ""; }; 138 | 91FFEE5229B2822000B4DE2A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 139 | 91FFEE5429B2822100B4DE2A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 140 | 91FFEE5729B2822100B4DE2A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 141 | 91FFEE5929B2822100B4DE2A /* ChatGPT.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ChatGPT.entitlements; sourceTree = ""; }; 142 | 91FFEE6329B2824B00B4DE2A /* ChatGPTExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ChatGPTExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 143 | 91FFEE6529B2824B00B4DE2A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 144 | 91FFEE6729B2824B00B4DE2A /* XcodeKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XcodeKit.framework; path = Library/Frameworks/XcodeKit.framework; sourceTree = DEVELOPER_DIR; }; 145 | 91FFEE6A29B2824B00B4DE2A /* SourceEditorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorExtension.swift; sourceTree = ""; }; 146 | 91FFEE6C29B2824B00B4DE2A /* JSON2SwiftEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON2SwiftEditorCommand.swift; sourceTree = ""; }; 147 | 91FFEE6E29B2824B00B4DE2A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 148 | 91FFEE6F29B2824B00B4DE2A /* ChatGPTExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ChatGPTExtension.entitlements; sourceTree = ""; }; 149 | 91FFEE7B29B2838000B4DE2A /* OpenAI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAI.swift; sourceTree = ""; }; 150 | 91FFEE7E29B2854200B4DE2A /* NetworkRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRequest.swift; sourceTree = ""; }; 151 | 91FFEE8229B288F000B4DE2A /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 152 | D8E6234B29CB93690072A861 /* openai.environment */ = {isa = PBXFileReference; lastKnownFileType = text; path = openai.environment; sourceTree = ""; }; 153 | D8E6234E29CBA0530072A861 /* CommentRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentRepository.swift; sourceTree = ""; }; 154 | D8E6235029CBA08C0072A861 /* ChatGPTCommentRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatGPTCommentRepository.swift; sourceTree = ""; }; 155 | D8E6235329CBA1120072A861 /* CommentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentUseCase.swift; sourceTree = ""; }; 156 | D8E6235529CBA1580072A861 /* DefaultCommentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultCommentUseCase.swift; sourceTree = ""; }; 157 | D8E6235829CBA20E0072A861 /* CommentCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentCommand.swift; sourceTree = ""; }; 158 | /* End PBXFileReference section */ 159 | 160 | /* Begin PBXFrameworksBuildPhase section */ 161 | 91FFEE4A29B2822000B4DE2A /* Frameworks */ = { 162 | isa = PBXFrameworksBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | 91FFEE6029B2824B00B4DE2A /* Frameworks */ = { 169 | isa = PBXFrameworksBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | 91FFEE6629B2824B00B4DE2A /* Cocoa.framework in Frameworks */, 173 | 91BCF70629B3C18E00C022E9 /* XcodeKit.framework in Frameworks */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXFrameworksBuildPhase section */ 178 | 179 | /* Begin PBXGroup section */ 180 | 911729A629B32E0D0066F46E /* Domain */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | 911729A929B32E2C0066F46E /* Repositories */, 184 | 911729A829B32E230066F46E /* UseCase */, 185 | 911729A729B32E180066F46E /* Model */, 186 | ); 187 | path = Domain; 188 | sourceTree = ""; 189 | }; 190 | 911729A729B32E180066F46E /* Model */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 91E2684D29B3A7510098BBB5 /* Suggestion.swift */, 194 | 91E2685B29B3B3C50098BBB5 /* ConverterError.swift */, 195 | ); 196 | path = Model; 197 | sourceTree = ""; 198 | }; 199 | 911729A829B32E230066F46E /* UseCase */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | D8E6235229CBA0FE0072A861 /* Comments */, 203 | 91B2577129C8D7B700E11003 /* Regex */, 204 | 91893E8C29C7BFB500AFF495 /* UnitTest */, 205 | 91AE7F6F29B48BB20037466B /* ExplainCode */, 206 | 91AE7F6E29B48BA70037466B /* CodeSmells */, 207 | 91AE7F6D29B48B970037466B /* JSON2Swift */, 208 | ); 209 | path = UseCase; 210 | sourceTree = ""; 211 | }; 212 | 911729A929B32E2C0066F46E /* Repositories */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 9126724729B359CA0076A294 /* JSONConverterRepository.swift */, 216 | 91CD167F29B3F50C0018CA5A /* CodeSmellsRepository.swift */, 217 | 91FAD37329B4796600917E35 /* ExplainCodeRepository.swift */, 218 | 91893E9129C7C07500AFF495 /* UnitTestRepository.swift */, 219 | 913C1D9129C8D2F300EE95B6 /* RegexRepository.swift */, 220 | D8E6234E29CBA0530072A861 /* CommentRepository.swift */, 221 | ); 222 | path = Repositories; 223 | sourceTree = ""; 224 | }; 225 | 911729AA29B32E580066F46E /* Infrastructure */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 911729AB29B32E670066F46E /* Dependencies */, 229 | ); 230 | path = Infrastructure; 231 | sourceTree = ""; 232 | }; 233 | 911729AB29B32E670066F46E /* Dependencies */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | 911729AC29B32E780066F46E /* DependencyManager.swift */, 237 | ); 238 | path = Dependencies; 239 | sourceTree = ""; 240 | }; 241 | 9134BA4B29CA1C9100784AF2 /* Regex */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 9134BA4C29CA1E8200784AF2 /* RegexCommand.swift */, 245 | ); 246 | path = Regex; 247 | sourceTree = ""; 248 | }; 249 | 91893E8929C7BE3D00AFF495 /* UnitTest */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | 91893E8A29C7BE8E00AFF495 /* UnitTestEditorCommand.swift */, 253 | ); 254 | path = UnitTest; 255 | sourceTree = ""; 256 | }; 257 | 91893E8C29C7BFB500AFF495 /* UnitTest */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | 91893E8D29C7BFD000AFF495 /* UnitTestUseCase.swift */, 261 | 91893E8F29C7C01800AFF495 /* DefaultUnitTestUseCase.swift */, 262 | ); 263 | path = UnitTest; 264 | sourceTree = ""; 265 | }; 266 | 91AE7F6D29B48B970037466B /* JSON2Swift */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | 91E2684929B39ACC0098BBB5 /* JSONConverterUseCase.swift */, 270 | 91E2684B29B39B6F0098BBB5 /* DefaultJSONConverterUseCase.swift */, 271 | ); 272 | path = JSON2Swift; 273 | sourceTree = ""; 274 | }; 275 | 91AE7F6E29B48BA70037466B /* CodeSmells */ = { 276 | isa = PBXGroup; 277 | children = ( 278 | 91CD167B29B3F35B0018CA5A /* CodeSmellsUseCase.swift */, 279 | 91CD167D29B3F39C0018CA5A /* DefaultCodeSmellsUseCase.swift */, 280 | ); 281 | path = CodeSmells; 282 | sourceTree = ""; 283 | }; 284 | 91AE7F6F29B48BB20037466B /* ExplainCode */ = { 285 | isa = PBXGroup; 286 | children = ( 287 | 91FAD36F29B478A000917E35 /* ExplainCodeUseCase.swift */, 288 | 91FAD37129B478FD00917E35 /* DefaultExplainCodeUseCase.swift */, 289 | ); 290 | path = ExplainCode; 291 | sourceTree = ""; 292 | }; 293 | 91B2577129C8D7B700E11003 /* Regex */ = { 294 | isa = PBXGroup; 295 | children = ( 296 | 91B2577229C8D7C900E11003 /* RegexUseCase.swift */, 297 | 91B2577429C8D85600E11003 /* DefaultRegexUseCase.swift */, 298 | ); 299 | path = Regex; 300 | sourceTree = ""; 301 | }; 302 | 91BCF70529B3C0D700C022E9 /* Commands */ = { 303 | isa = PBXGroup; 304 | children = ( 305 | D8E6235729CBA1F80072A861 /* Comment */, 306 | 9134BA4B29CA1C9100784AF2 /* Regex */, 307 | 91893E8929C7BE3D00AFF495 /* UnitTest */, 308 | 91FAD36C29B4782E00917E35 /* ExplainCode */, 309 | 91CD167829B3F1A00018CA5A /* CodeSmells */, 310 | 91CD167729B3F1860018CA5A /* JSON2Swift */, 311 | 91FFEE6A29B2824B00B4DE2A /* SourceEditorExtension.swift */, 312 | ); 313 | path = Commands; 314 | sourceTree = ""; 315 | }; 316 | 91CD167729B3F1860018CA5A /* JSON2Swift */ = { 317 | isa = PBXGroup; 318 | children = ( 319 | 91FFEE6C29B2824B00B4DE2A /* JSON2SwiftEditorCommand.swift */, 320 | ); 321 | path = JSON2Swift; 322 | sourceTree = ""; 323 | }; 324 | 91CD167829B3F1A00018CA5A /* CodeSmells */ = { 325 | isa = PBXGroup; 326 | children = ( 327 | 91CD167929B3F1EF0018CA5A /* CodeSmellsEditorCommand.swift */, 328 | ); 329 | path = CodeSmells; 330 | sourceTree = ""; 331 | }; 332 | 91E2684F29B3A8E40098BBB5 /* Resources */ = { 333 | isa = PBXGroup; 334 | children = ( 335 | 91E2685929B3ADDE0098BBB5 /* Localizable.strings */, 336 | ); 337 | path = Resources; 338 | sourceTree = ""; 339 | }; 340 | 91E2685429B3AC4C0098BBB5 /* Extensions */ = { 341 | isa = PBXGroup; 342 | children = ( 343 | 91E2685529B3AC820098BBB5 /* OpenAI+Localizable.swift */, 344 | ); 345 | path = Extensions; 346 | sourceTree = ""; 347 | }; 348 | 91FAD36C29B4782E00917E35 /* ExplainCode */ = { 349 | isa = PBXGroup; 350 | children = ( 351 | 91FAD36D29B4784800917E35 /* ExplainCodeCommand.swift */, 352 | ); 353 | path = ExplainCode; 354 | sourceTree = ""; 355 | }; 356 | 91FFEE4429B2822000B4DE2A = { 357 | isa = PBXGroup; 358 | children = ( 359 | 91FFEE4F29B2822000B4DE2A /* ChatGPT */, 360 | 91FFEE6929B2824B00B4DE2A /* ChatGPTExtension */, 361 | 91FFEE6429B2824B00B4DE2A /* Frameworks */, 362 | 91FFEE4E29B2822000B4DE2A /* Products */, 363 | ); 364 | sourceTree = ""; 365 | }; 366 | 91FFEE4E29B2822000B4DE2A /* Products */ = { 367 | isa = PBXGroup; 368 | children = ( 369 | 91FFEE4D29B2822000B4DE2A /* ChatGPT.app */, 370 | 91FFEE6329B2824B00B4DE2A /* ChatGPTExtension.appex */, 371 | ); 372 | name = Products; 373 | sourceTree = ""; 374 | }; 375 | 91FFEE4F29B2822000B4DE2A /* ChatGPT */ = { 376 | isa = PBXGroup; 377 | children = ( 378 | 91FFEE5029B2822000B4DE2A /* ChatGPTApp.swift */, 379 | 91FFEE5229B2822000B4DE2A /* ContentView.swift */, 380 | 91FFEE5429B2822100B4DE2A /* Assets.xcassets */, 381 | 91FFEE5929B2822100B4DE2A /* ChatGPT.entitlements */, 382 | 91FFEE5629B2822100B4DE2A /* Preview Content */, 383 | ); 384 | path = ChatGPT; 385 | sourceTree = ""; 386 | }; 387 | 91FFEE5629B2822100B4DE2A /* Preview Content */ = { 388 | isa = PBXGroup; 389 | children = ( 390 | 91FFEE5729B2822100B4DE2A /* Preview Assets.xcassets */, 391 | ); 392 | path = "Preview Content"; 393 | sourceTree = ""; 394 | }; 395 | 91FFEE6429B2824B00B4DE2A /* Frameworks */ = { 396 | isa = PBXGroup; 397 | children = ( 398 | 91FFEE6529B2824B00B4DE2A /* Cocoa.framework */, 399 | 91FFEE6729B2824B00B4DE2A /* XcodeKit.framework */, 400 | ); 401 | name = Frameworks; 402 | sourceTree = ""; 403 | }; 404 | 91FFEE6929B2824B00B4DE2A /* ChatGPTExtension */ = { 405 | isa = PBXGroup; 406 | children = ( 407 | 91FFEE6E29B2824B00B4DE2A /* Info.plist */, 408 | 91FFEE6F29B2824B00B4DE2A /* ChatGPTExtension.entitlements */, 409 | 911729AA29B32E580066F46E /* Infrastructure */, 410 | 91FFEE7729B2828E00B4DE2A /* Data */, 411 | 911729A629B32E0D0066F46E /* Domain */, 412 | 91BCF70529B3C0D700C022E9 /* Commands */, 413 | ); 414 | path = ChatGPTExtension; 415 | sourceTree = ""; 416 | }; 417 | 91FFEE7729B2828E00B4DE2A /* Data */ = { 418 | isa = PBXGroup; 419 | children = ( 420 | D8E6234D29CB9D1A0072A861 /* Settings */, 421 | 91FFEE7A29B282B700B4DE2A /* Repositories */, 422 | 91FFEE7829B2829900B4DE2A /* Network */, 423 | ); 424 | path = Data; 425 | sourceTree = ""; 426 | }; 427 | 91FFEE7829B2829900B4DE2A /* Network */ = { 428 | isa = PBXGroup; 429 | children = ( 430 | 91FFEE7929B282A700B4DE2A /* OpenAI */, 431 | ); 432 | path = Network; 433 | sourceTree = ""; 434 | }; 435 | 91FFEE7929B282A700B4DE2A /* OpenAI */ = { 436 | isa = PBXGroup; 437 | children = ( 438 | 91E2685429B3AC4C0098BBB5 /* Extensions */, 439 | 91E2684F29B3A8E40098BBB5 /* Resources */, 440 | 91FFEE7D29B2853400B4DE2A /* Model */, 441 | 91FFEE7B29B2838000B4DE2A /* OpenAI.swift */, 442 | 91A043D529B48CB60077238E /* OpenAI+Operations.swift */, 443 | ); 444 | path = OpenAI; 445 | sourceTree = ""; 446 | }; 447 | 91FFEE7A29B282B700B4DE2A /* Repositories */ = { 448 | isa = PBXGroup; 449 | children = ( 450 | 9126724929B35A000076A294 /* ChatGPTJSONConverterRepository.swift */, 451 | 91CD168129B3F5410018CA5A /* ChatGPTCodeSmellsRepository.swift */, 452 | 91CD168329B3F7970018CA5A /* BaseChatGPTRepository.swift */, 453 | 91FAD37529B47AEA00917E35 /* ChatGPTExplainCodeRepository.swift */, 454 | 91893E9329C7C0AC00AFF495 /* ChatGPTUnitTestRepository.swift */, 455 | 913C1D9329C8D32400EE95B6 /* ChatGPTRegexRepository.swift */, 456 | D8E6235029CBA08C0072A861 /* ChatGPTCommentRepository.swift */, 457 | ); 458 | path = Repositories; 459 | sourceTree = ""; 460 | }; 461 | 91FFEE7D29B2853400B4DE2A /* Model */ = { 462 | isa = PBXGroup; 463 | children = ( 464 | 9126724529B350320076A294 /* ChatGPTError.swift */, 465 | 91E2685229B3AA2C0098BBB5 /* ChatGPTRequest.swift */, 466 | 911729AE29B32FFB0066F46E /* ChatGPTResponse.swift */, 467 | 91FFEE8229B288F000B4DE2A /* Constants.swift */, 468 | 91FFEE7E29B2854200B4DE2A /* NetworkRequest.swift */, 469 | ); 470 | path = Model; 471 | sourceTree = ""; 472 | }; 473 | D8E6234D29CB9D1A0072A861 /* Settings */ = { 474 | isa = PBXGroup; 475 | children = ( 476 | D8E6234B29CB93690072A861 /* openai.environment */, 477 | ); 478 | path = Settings; 479 | sourceTree = ""; 480 | }; 481 | D8E6235229CBA0FE0072A861 /* Comments */ = { 482 | isa = PBXGroup; 483 | children = ( 484 | D8E6235329CBA1120072A861 /* CommentUseCase.swift */, 485 | D8E6235529CBA1580072A861 /* DefaultCommentUseCase.swift */, 486 | ); 487 | path = Comments; 488 | sourceTree = ""; 489 | }; 490 | D8E6235729CBA1F80072A861 /* Comment */ = { 491 | isa = PBXGroup; 492 | children = ( 493 | D8E6235829CBA20E0072A861 /* CommentCommand.swift */, 494 | ); 495 | path = Comment; 496 | sourceTree = ""; 497 | }; 498 | /* End PBXGroup section */ 499 | 500 | /* Begin PBXNativeTarget section */ 501 | 91FFEE4C29B2822000B4DE2A /* ChatGPT */ = { 502 | isa = PBXNativeTarget; 503 | buildConfigurationList = 91FFEE5C29B2822100B4DE2A /* Build configuration list for PBXNativeTarget "ChatGPT" */; 504 | buildPhases = ( 505 | 91FFEE4929B2822000B4DE2A /* Sources */, 506 | 91FFEE4A29B2822000B4DE2A /* Frameworks */, 507 | 91FFEE4B29B2822000B4DE2A /* Resources */, 508 | 91FFEE7629B2824B00B4DE2A /* Embed Foundation Extensions */, 509 | ); 510 | buildRules = ( 511 | ); 512 | dependencies = ( 513 | 91FFEE7129B2824B00B4DE2A /* PBXTargetDependency */, 514 | ); 515 | name = ChatGPT; 516 | productName = ChatGPT; 517 | productReference = 91FFEE4D29B2822000B4DE2A /* ChatGPT.app */; 518 | productType = "com.apple.product-type.application"; 519 | }; 520 | 91FFEE6229B2824B00B4DE2A /* ChatGPTExtension */ = { 521 | isa = PBXNativeTarget; 522 | buildConfigurationList = 91FFEE7329B2824B00B4DE2A /* Build configuration list for PBXNativeTarget "ChatGPTExtension" */; 523 | buildPhases = ( 524 | 91FFEE5F29B2824B00B4DE2A /* Sources */, 525 | 91FFEE6029B2824B00B4DE2A /* Frameworks */, 526 | 91FFEE6129B2824B00B4DE2A /* Resources */, 527 | 91BCF70829B3C18E00C022E9 /* Embed Frameworks */, 528 | ); 529 | buildRules = ( 530 | ); 531 | dependencies = ( 532 | ); 533 | name = ChatGPTExtension; 534 | productName = ChatGPTExtension; 535 | productReference = 91FFEE6329B2824B00B4DE2A /* ChatGPTExtension.appex */; 536 | productType = "com.apple.product-type.xcode-extension"; 537 | }; 538 | /* End PBXNativeTarget section */ 539 | 540 | /* Begin PBXProject section */ 541 | 91FFEE4529B2822000B4DE2A /* Project object */ = { 542 | isa = PBXProject; 543 | attributes = { 544 | BuildIndependentTargetsInParallel = 1; 545 | LastSwiftUpdateCheck = 1420; 546 | LastUpgradeCheck = 1420; 547 | TargetAttributes = { 548 | 91FFEE4C29B2822000B4DE2A = { 549 | CreatedOnToolsVersion = 14.2; 550 | }; 551 | 91FFEE6229B2824B00B4DE2A = { 552 | CreatedOnToolsVersion = 14.2; 553 | }; 554 | }; 555 | }; 556 | buildConfigurationList = 91FFEE4829B2822000B4DE2A /* Build configuration list for PBXProject "ChatGPT" */; 557 | compatibilityVersion = "Xcode 14.0"; 558 | developmentRegion = en; 559 | hasScannedForEncodings = 0; 560 | knownRegions = ( 561 | en, 562 | Base, 563 | es, 564 | ); 565 | mainGroup = 91FFEE4429B2822000B4DE2A; 566 | productRefGroup = 91FFEE4E29B2822000B4DE2A /* Products */; 567 | projectDirPath = ""; 568 | projectRoot = ""; 569 | targets = ( 570 | 91FFEE4C29B2822000B4DE2A /* ChatGPT */, 571 | 91FFEE6229B2824B00B4DE2A /* ChatGPTExtension */, 572 | ); 573 | }; 574 | /* End PBXProject section */ 575 | 576 | /* Begin PBXResourcesBuildPhase section */ 577 | 91FFEE4B29B2822000B4DE2A /* Resources */ = { 578 | isa = PBXResourcesBuildPhase; 579 | buildActionMask = 2147483647; 580 | files = ( 581 | 91FFEE5829B2822100B4DE2A /* Preview Assets.xcassets in Resources */, 582 | 91FFEE5529B2822100B4DE2A /* Assets.xcassets in Resources */, 583 | ); 584 | runOnlyForDeploymentPostprocessing = 0; 585 | }; 586 | 91FFEE6129B2824B00B4DE2A /* Resources */ = { 587 | isa = PBXResourcesBuildPhase; 588 | buildActionMask = 2147483647; 589 | files = ( 590 | D8E6234C29CB93690072A861 /* openai.environment in Resources */, 591 | 91E2685729B3ADDE0098BBB5 /* Localizable.strings in Resources */, 592 | ); 593 | runOnlyForDeploymentPostprocessing = 0; 594 | }; 595 | /* End PBXResourcesBuildPhase section */ 596 | 597 | /* Begin PBXSourcesBuildPhase section */ 598 | 91FFEE4929B2822000B4DE2A /* Sources */ = { 599 | isa = PBXSourcesBuildPhase; 600 | buildActionMask = 2147483647; 601 | files = ( 602 | 91FFEE5329B2822000B4DE2A /* ContentView.swift in Sources */, 603 | 91FFEE5129B2822000B4DE2A /* ChatGPTApp.swift in Sources */, 604 | ); 605 | runOnlyForDeploymentPostprocessing = 0; 606 | }; 607 | 91FFEE5F29B2824B00B4DE2A /* Sources */ = { 608 | isa = PBXSourcesBuildPhase; 609 | buildActionMask = 2147483647; 610 | files = ( 611 | 91FAD37029B478A000917E35 /* ExplainCodeUseCase.swift in Sources */, 612 | D8E6235429CBA1120072A861 /* CommentUseCase.swift in Sources */, 613 | 913C1D9229C8D2F300EE95B6 /* RegexRepository.swift in Sources */, 614 | 91FFEE8329B288F000B4DE2A /* Constants.swift in Sources */, 615 | 91FAD37629B47AEA00917E35 /* ChatGPTExplainCodeRepository.swift in Sources */, 616 | 91E2685C29B3B3C50098BBB5 /* ConverterError.swift in Sources */, 617 | 91CD167A29B3F1EF0018CA5A /* CodeSmellsEditorCommand.swift in Sources */, 618 | 91FFEE7C29B2838000B4DE2A /* OpenAI.swift in Sources */, 619 | 913C1D9429C8D32400EE95B6 /* ChatGPTRegexRepository.swift in Sources */, 620 | 91893E9029C7C01800AFF495 /* DefaultUnitTestUseCase.swift in Sources */, 621 | 91CD168029B3F50C0018CA5A /* CodeSmellsRepository.swift in Sources */, 622 | 91893E8E29C7BFD000AFF495 /* UnitTestUseCase.swift in Sources */, 623 | 9126724A29B35A000076A294 /* ChatGPTJSONConverterRepository.swift in Sources */, 624 | 91CD167E29B3F39C0018CA5A /* DefaultCodeSmellsUseCase.swift in Sources */, 625 | 91A043D629B48CB60077238E /* OpenAI+Operations.swift in Sources */, 626 | 9126724629B350320076A294 /* ChatGPTError.swift in Sources */, 627 | 9134BA4D29CA1E8200784AF2 /* RegexCommand.swift in Sources */, 628 | 91E2684E29B3A7510098BBB5 /* Suggestion.swift in Sources */, 629 | 91FAD37429B4796600917E35 /* ExplainCodeRepository.swift in Sources */, 630 | 91B2577329C8D7C900E11003 /* RegexUseCase.swift in Sources */, 631 | 91CD168229B3F5410018CA5A /* ChatGPTCodeSmellsRepository.swift in Sources */, 632 | D8E6234F29CBA0530072A861 /* CommentRepository.swift in Sources */, 633 | 91E2685329B3AA2C0098BBB5 /* ChatGPTRequest.swift in Sources */, 634 | D8E6235629CBA1580072A861 /* DefaultCommentUseCase.swift in Sources */, 635 | 91FFEE6B29B2824B00B4DE2A /* SourceEditorExtension.swift in Sources */, 636 | 91FAD36E29B4784800917E35 /* ExplainCodeCommand.swift in Sources */, 637 | 91893E9229C7C07500AFF495 /* UnitTestRepository.swift in Sources */, 638 | 91FFEE6D29B2824B00B4DE2A /* JSON2SwiftEditorCommand.swift in Sources */, 639 | 911729AD29B32E780066F46E /* DependencyManager.swift in Sources */, 640 | 91CD168429B3F7970018CA5A /* BaseChatGPTRepository.swift in Sources */, 641 | 91FAD37229B478FD00917E35 /* DefaultExplainCodeUseCase.swift in Sources */, 642 | 9126724829B359CA0076A294 /* JSONConverterRepository.swift in Sources */, 643 | 91B2577529C8D85600E11003 /* DefaultRegexUseCase.swift in Sources */, 644 | D8E6235929CBA20E0072A861 /* CommentCommand.swift in Sources */, 645 | 91E2684C29B39B6F0098BBB5 /* DefaultJSONConverterUseCase.swift in Sources */, 646 | 91E2684A29B39ACC0098BBB5 /* JSONConverterUseCase.swift in Sources */, 647 | 91CD167C29B3F35B0018CA5A /* CodeSmellsUseCase.swift in Sources */, 648 | 91893E8B29C7BE8E00AFF495 /* UnitTestEditorCommand.swift in Sources */, 649 | 91FFEE7F29B2854200B4DE2A /* NetworkRequest.swift in Sources */, 650 | 911729AF29B32FFB0066F46E /* ChatGPTResponse.swift in Sources */, 651 | 91893E9429C7C0AC00AFF495 /* ChatGPTUnitTestRepository.swift in Sources */, 652 | 91E2685629B3AC820098BBB5 /* OpenAI+Localizable.swift in Sources */, 653 | D8E6235129CBA08C0072A861 /* ChatGPTCommentRepository.swift in Sources */, 654 | ); 655 | runOnlyForDeploymentPostprocessing = 0; 656 | }; 657 | /* End PBXSourcesBuildPhase section */ 658 | 659 | /* Begin PBXTargetDependency section */ 660 | 91FFEE7129B2824B00B4DE2A /* PBXTargetDependency */ = { 661 | isa = PBXTargetDependency; 662 | target = 91FFEE6229B2824B00B4DE2A /* ChatGPTExtension */; 663 | targetProxy = 91FFEE7029B2824B00B4DE2A /* PBXContainerItemProxy */; 664 | }; 665 | /* End PBXTargetDependency section */ 666 | 667 | /* Begin PBXVariantGroup section */ 668 | 91E2685929B3ADDE0098BBB5 /* Localizable.strings */ = { 669 | isa = PBXVariantGroup; 670 | children = ( 671 | 91E2685829B3ADDE0098BBB5 /* en */, 672 | 91E2685A29B3ADE30098BBB5 /* es */, 673 | ); 674 | name = Localizable.strings; 675 | sourceTree = ""; 676 | }; 677 | /* End PBXVariantGroup section */ 678 | 679 | /* Begin XCBuildConfiguration section */ 680 | 91FFEE5A29B2822100B4DE2A /* Debug */ = { 681 | isa = XCBuildConfiguration; 682 | buildSettings = { 683 | ALWAYS_SEARCH_USER_PATHS = NO; 684 | CLANG_ANALYZER_NONNULL = YES; 685 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 686 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 687 | CLANG_ENABLE_MODULES = YES; 688 | CLANG_ENABLE_OBJC_ARC = YES; 689 | CLANG_ENABLE_OBJC_WEAK = YES; 690 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 691 | CLANG_WARN_BOOL_CONVERSION = YES; 692 | CLANG_WARN_COMMA = YES; 693 | CLANG_WARN_CONSTANT_CONVERSION = YES; 694 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 695 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 696 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 697 | CLANG_WARN_EMPTY_BODY = YES; 698 | CLANG_WARN_ENUM_CONVERSION = YES; 699 | CLANG_WARN_INFINITE_RECURSION = YES; 700 | CLANG_WARN_INT_CONVERSION = YES; 701 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 702 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 703 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 704 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 705 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 706 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 707 | CLANG_WARN_STRICT_PROTOTYPES = YES; 708 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 709 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 710 | CLANG_WARN_UNREACHABLE_CODE = YES; 711 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 712 | COPY_PHASE_STRIP = NO; 713 | DEBUG_INFORMATION_FORMAT = dwarf; 714 | ENABLE_STRICT_OBJC_MSGSEND = YES; 715 | ENABLE_TESTABILITY = YES; 716 | GCC_C_LANGUAGE_STANDARD = gnu11; 717 | GCC_DYNAMIC_NO_PIC = NO; 718 | GCC_NO_COMMON_BLOCKS = YES; 719 | GCC_OPTIMIZATION_LEVEL = 0; 720 | GCC_PREPROCESSOR_DEFINITIONS = ( 721 | "DEBUG=1", 722 | "$(inherited)", 723 | ); 724 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 725 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 726 | GCC_WARN_UNDECLARED_SELECTOR = YES; 727 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 728 | GCC_WARN_UNUSED_FUNCTION = YES; 729 | GCC_WARN_UNUSED_VARIABLE = YES; 730 | MACOSX_DEPLOYMENT_TARGET = 13.1; 731 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 732 | MTL_FAST_MATH = YES; 733 | ONLY_ACTIVE_ARCH = YES; 734 | SDKROOT = macosx; 735 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 736 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 737 | }; 738 | name = Debug; 739 | }; 740 | 91FFEE5B29B2822100B4DE2A /* Release */ = { 741 | isa = XCBuildConfiguration; 742 | buildSettings = { 743 | ALWAYS_SEARCH_USER_PATHS = NO; 744 | CLANG_ANALYZER_NONNULL = YES; 745 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 746 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 747 | CLANG_ENABLE_MODULES = YES; 748 | CLANG_ENABLE_OBJC_ARC = YES; 749 | CLANG_ENABLE_OBJC_WEAK = YES; 750 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 751 | CLANG_WARN_BOOL_CONVERSION = YES; 752 | CLANG_WARN_COMMA = YES; 753 | CLANG_WARN_CONSTANT_CONVERSION = YES; 754 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 755 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 756 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 757 | CLANG_WARN_EMPTY_BODY = YES; 758 | CLANG_WARN_ENUM_CONVERSION = YES; 759 | CLANG_WARN_INFINITE_RECURSION = YES; 760 | CLANG_WARN_INT_CONVERSION = YES; 761 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 762 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 763 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 764 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 765 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 766 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 767 | CLANG_WARN_STRICT_PROTOTYPES = YES; 768 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 769 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 770 | CLANG_WARN_UNREACHABLE_CODE = YES; 771 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 772 | COPY_PHASE_STRIP = NO; 773 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 774 | ENABLE_NS_ASSERTIONS = NO; 775 | ENABLE_STRICT_OBJC_MSGSEND = YES; 776 | GCC_C_LANGUAGE_STANDARD = gnu11; 777 | GCC_NO_COMMON_BLOCKS = YES; 778 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 779 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 780 | GCC_WARN_UNDECLARED_SELECTOR = YES; 781 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 782 | GCC_WARN_UNUSED_FUNCTION = YES; 783 | GCC_WARN_UNUSED_VARIABLE = YES; 784 | MACOSX_DEPLOYMENT_TARGET = 13.1; 785 | MTL_ENABLE_DEBUG_INFO = NO; 786 | MTL_FAST_MATH = YES; 787 | SDKROOT = macosx; 788 | SWIFT_COMPILATION_MODE = wholemodule; 789 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 790 | }; 791 | name = Release; 792 | }; 793 | 91FFEE5D29B2822100B4DE2A /* Debug */ = { 794 | isa = XCBuildConfiguration; 795 | buildSettings = { 796 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 797 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 798 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 799 | CODE_SIGN_ENTITLEMENTS = ChatGPT/ChatGPT.entitlements; 800 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 801 | CODE_SIGN_STYLE = Automatic; 802 | COMBINE_HIDPI_IMAGES = YES; 803 | CURRENT_PROJECT_VERSION = 1; 804 | DEVELOPMENT_ASSET_PATHS = "\"ChatGPT/Preview Content\""; 805 | DEVELOPMENT_TEAM = P8RCF8HS85; 806 | ENABLE_HARDENED_RUNTIME = YES; 807 | ENABLE_PREVIEWS = YES; 808 | GENERATE_INFOPLIST_FILE = YES; 809 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 810 | LD_RUNPATH_SEARCH_PATHS = ( 811 | "$(inherited)", 812 | "@executable_path/../Frameworks", 813 | ); 814 | MARKETING_VERSION = 1.0; 815 | PRODUCT_BUNDLE_IDENTIFIER = com.desappstre.ChatGPT; 816 | PRODUCT_NAME = "$(TARGET_NAME)"; 817 | SWIFT_EMIT_LOC_STRINGS = YES; 818 | SWIFT_VERSION = 5.0; 819 | }; 820 | name = Debug; 821 | }; 822 | 91FFEE5E29B2822100B4DE2A /* Release */ = { 823 | isa = XCBuildConfiguration; 824 | buildSettings = { 825 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 826 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 827 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 828 | CODE_SIGN_ENTITLEMENTS = ChatGPT/ChatGPT.entitlements; 829 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 830 | CODE_SIGN_STYLE = Automatic; 831 | COMBINE_HIDPI_IMAGES = YES; 832 | CURRENT_PROJECT_VERSION = 1; 833 | DEVELOPMENT_ASSET_PATHS = "\"ChatGPT/Preview Content\""; 834 | DEVELOPMENT_TEAM = P8RCF8HS85; 835 | ENABLE_HARDENED_RUNTIME = YES; 836 | ENABLE_PREVIEWS = YES; 837 | GENERATE_INFOPLIST_FILE = YES; 838 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 839 | LD_RUNPATH_SEARCH_PATHS = ( 840 | "$(inherited)", 841 | "@executable_path/../Frameworks", 842 | ); 843 | MARKETING_VERSION = 1.0; 844 | PRODUCT_BUNDLE_IDENTIFIER = com.desappstre.ChatGPT; 845 | PRODUCT_NAME = "$(TARGET_NAME)"; 846 | SWIFT_EMIT_LOC_STRINGS = YES; 847 | SWIFT_VERSION = 5.0; 848 | }; 849 | name = Release; 850 | }; 851 | 91FFEE7429B2824B00B4DE2A /* Debug */ = { 852 | isa = XCBuildConfiguration; 853 | buildSettings = { 854 | CODE_SIGN_ENTITLEMENTS = ChatGPTExtension/ChatGPTExtension.entitlements; 855 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 856 | CODE_SIGN_STYLE = Automatic; 857 | COMBINE_HIDPI_IMAGES = YES; 858 | CURRENT_PROJECT_VERSION = 1; 859 | DEVELOPMENT_TEAM = P8RCF8HS85; 860 | ENABLE_HARDENED_RUNTIME = YES; 861 | GENERATE_INFOPLIST_FILE = YES; 862 | INFOPLIST_FILE = ChatGPTExtension/Info.plist; 863 | INFOPLIST_KEY_CFBundleDisplayName = ChatGPTExtension; 864 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 865 | LD_RUNPATH_SEARCH_PATHS = ( 866 | "$(inherited)", 867 | "@executable_path/../Frameworks", 868 | "@executable_path/../../../../Frameworks", 869 | ); 870 | MARKETING_VERSION = 1.0; 871 | PRODUCT_BUNDLE_IDENTIFIER = com.desappstre.ChatGPT.ChatGPTExtension; 872 | PRODUCT_NAME = "$(TARGET_NAME)"; 873 | SKIP_INSTALL = YES; 874 | SWIFT_EMIT_LOC_STRINGS = YES; 875 | SWIFT_VERSION = 5.0; 876 | }; 877 | name = Debug; 878 | }; 879 | 91FFEE7529B2824B00B4DE2A /* Release */ = { 880 | isa = XCBuildConfiguration; 881 | buildSettings = { 882 | CODE_SIGN_ENTITLEMENTS = ChatGPTExtension/ChatGPTExtension.entitlements; 883 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 884 | CODE_SIGN_STYLE = Automatic; 885 | COMBINE_HIDPI_IMAGES = YES; 886 | CURRENT_PROJECT_VERSION = 1; 887 | DEVELOPMENT_TEAM = P8RCF8HS85; 888 | ENABLE_HARDENED_RUNTIME = YES; 889 | GENERATE_INFOPLIST_FILE = YES; 890 | INFOPLIST_FILE = ChatGPTExtension/Info.plist; 891 | INFOPLIST_KEY_CFBundleDisplayName = ChatGPTExtension; 892 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 893 | LD_RUNPATH_SEARCH_PATHS = ( 894 | "$(inherited)", 895 | "@executable_path/../Frameworks", 896 | "@executable_path/../../../../Frameworks", 897 | ); 898 | MARKETING_VERSION = 1.0; 899 | PRODUCT_BUNDLE_IDENTIFIER = com.desappstre.ChatGPT.ChatGPTExtension; 900 | PRODUCT_NAME = "$(TARGET_NAME)"; 901 | SKIP_INSTALL = YES; 902 | SWIFT_EMIT_LOC_STRINGS = YES; 903 | SWIFT_VERSION = 5.0; 904 | }; 905 | name = Release; 906 | }; 907 | /* End XCBuildConfiguration section */ 908 | 909 | /* Begin XCConfigurationList section */ 910 | 91FFEE4829B2822000B4DE2A /* Build configuration list for PBXProject "ChatGPT" */ = { 911 | isa = XCConfigurationList; 912 | buildConfigurations = ( 913 | 91FFEE5A29B2822100B4DE2A /* Debug */, 914 | 91FFEE5B29B2822100B4DE2A /* Release */, 915 | ); 916 | defaultConfigurationIsVisible = 0; 917 | defaultConfigurationName = Release; 918 | }; 919 | 91FFEE5C29B2822100B4DE2A /* Build configuration list for PBXNativeTarget "ChatGPT" */ = { 920 | isa = XCConfigurationList; 921 | buildConfigurations = ( 922 | 91FFEE5D29B2822100B4DE2A /* Debug */, 923 | 91FFEE5E29B2822100B4DE2A /* Release */, 924 | ); 925 | defaultConfigurationIsVisible = 0; 926 | defaultConfigurationName = Release; 927 | }; 928 | 91FFEE7329B2824B00B4DE2A /* Build configuration list for PBXNativeTarget "ChatGPTExtension" */ = { 929 | isa = XCConfigurationList; 930 | buildConfigurations = ( 931 | 91FFEE7429B2824B00B4DE2A /* Debug */, 932 | 91FFEE7529B2824B00B4DE2A /* Release */, 933 | ); 934 | defaultConfigurationIsVisible = 0; 935 | defaultConfigurationName = Release; 936 | }; 937 | /* End XCConfigurationList section */ 938 | }; 939 | rootObject = 91FFEE4529B2822000B4DE2A /* Project object */; 940 | } 941 | --------------------------------------------------------------------------------