├── .eslintignore ├── .prettierignore ├── .prettierrc ├── .swiftlint.yml ├── nodemon.json ├── src ├── extensions │ ├── trpc.ts │ └── zod.ts ├── types.ts ├── index.ts ├── utility.ts ├── cli.ts └── generators │ ├── router.ts │ └── models.ts ├── .npmignore ├── .vscode ├── settings.json └── launch.json ├── tsconfig.json ├── .eslintrc.cjs ├── LICENSE ├── package.json ├── .gitignore ├── README.md ├── templates └── TRPCClient.swift └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /out 5 | yarn.lock 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /out 5 | yarn.lock 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "trailingComma": "es5", 4 | "printWidth": 140 5 | } 6 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - identifier_name 3 | - type_name 4 | - nesting 5 | line_length: 240 6 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src", "dist"], 3 | "ext": "*", 4 | "exec": "yarn run start || exit 1" 5 | } 6 | -------------------------------------------------------------------------------- /src/extensions/trpc.ts: -------------------------------------------------------------------------------- 1 | export type TRPCSwiftMeta = { 2 | swift?: { 3 | description?: string; 4 | }; 5 | }; 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | ios 3 | node_modules 4 | src 5 | .eslintignore 6 | .eslintrc.cjs 7 | .gitignore 8 | .prettierrc 9 | .prettierignore 10 | .swiftlint.yml 11 | nodemon.json 12 | tsconfig.tsbuildinfo 13 | yarn.lock 14 | *.map -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": "explicit" 4 | }, 5 | "editor.defaultFormatter": "esbenp.prettier-vscode", 6 | "editor.formatOnSave": true, 7 | "eslint.validate": ["javascript", "typescript"], 8 | "swiftlint.configSearchPaths": ["${workspaceFolder}"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "NodeNext", 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "forceConsistentCasingInFileNames": true, 8 | "skipLibCheck": true, 9 | "strict": true, 10 | "sourceMap": true, 11 | "incremental": true, 12 | "declaration": true 13 | }, 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], 4 | parser: "@typescript-eslint/parser", 5 | plugins: ["@typescript-eslint"], 6 | parserOptions: { 7 | sourceType: "module", 8 | ecmaVersion: "latest", 9 | }, 10 | env: { 11 | es2021: true, 12 | node: true, 13 | }, 14 | rules: { 15 | semi: ["error", "always"], 16 | "@typescript-eslint/no-explicit-any": "warn", 17 | "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Generator", 6 | "request": "launch", 7 | "type": "node", 8 | "runtimeExecutable": "nodemon" 9 | }, 10 | { 11 | "name": "Compile Generator", 12 | "type": "node", 13 | "request": "launch", 14 | "runtimeExecutable": "yarn", 15 | "runtimeArgs": ["run", "watch"], 16 | "console": "integratedTerminal" 17 | } 18 | ], 19 | "compounds": [ 20 | { 21 | "name": "TRPC-Swift", 22 | "configurations": ["Generator", "Compile Generator"] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/extensions/zod.ts: -------------------------------------------------------------------------------- 1 | import { ZodTypeAny, z } from "zod"; 2 | 3 | type ZodSwiftMetadata = { 4 | name?: string; 5 | description?: string; 6 | global?: boolean; 7 | }; 8 | 9 | declare module "zod" { 10 | interface ZodTypeDef { 11 | swift?: ZodSwiftMetadata; 12 | } 13 | 14 | interface ZodType { 15 | swift(this: T, metadata: ZodSwiftMetadata): T; 16 | } 17 | } 18 | 19 | export const extendZodWithSwift = (zod: typeof z) => { 20 | zod.ZodType.prototype.swift = function (metadata: ZodSwiftMetadata) { 21 | this._def.swift = { 22 | name: metadata.name ?? this._def.swift?.name, 23 | description: metadata.description, 24 | }; 25 | return this; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Marko Calasan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trpc-swift", 3 | "version": "0.1.35", 4 | "description": "Generates Swift clients and models from tRPC routers.", 5 | "repository": "https://github.com/calasanmarko/trpc-swift.git", 6 | "author": "Marko Calasan ", 7 | "main": "dist/index.js", 8 | "bin": { 9 | "trpc-swift": "dist/cli.js" 10 | }, 11 | "license": "MIT", 12 | "type": "module", 13 | "scripts": { 14 | "start": "node ./dist/index.js", 15 | "watch": "tsc --watch", 16 | "build": "tsc && cp -rf ./templates ./dist", 17 | "clean": "rimraf tsconfig.tsbuildinfo && rimraf -g dist/*", 18 | "lint": "prettier --check . && eslint .", 19 | "format": "prettier --write . **/*.{js,ts,json}" 20 | }, 21 | "devDependencies": { 22 | "zod": "^3.22.4", 23 | "@trpc/server": "^10.43.3", 24 | "@types/node": "^20.9.0", 25 | "@typescript-eslint/eslint-plugin": "^6.11.0", 26 | "@typescript-eslint/parser": "^6.11.0", 27 | "eslint": "^8.53.0", 28 | "eslint-config-prettier": "^9.0.0", 29 | "prettier": "^3.1.0", 30 | "typescript": "^5.2.2" 31 | }, 32 | "keywords": [ 33 | "typescript", 34 | "ts", 35 | "trpc", 36 | "rpc", 37 | "generator", 38 | "swift", 39 | "ios" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { AnyRootConfig, Procedure, ProcedureParams, ProcedureRouterRecord, RootConfig } from "@trpc/server"; 2 | import { RouterDef } from "../node_modules/@trpc/server/src/core/router.js"; 3 | import { TRPCSwiftMeta } from "./extensions/trpc.js"; 4 | 5 | export type TRPCSwiftGlobalMode = "all" | "top" | "none"; 6 | 7 | export type TRPCSwiftFlags = { 8 | createTypeAliases: boolean; 9 | createShared: boolean; 10 | publicAccess: boolean; 11 | conformance: string; 12 | globalMode: "all" | "top" | "none"; 13 | quiet: boolean; 14 | }; 15 | 16 | export type TRPCStructure = { 17 | [key: string]: TRPCStructure | GenericProcedure; 18 | }; 19 | 20 | export type GenericProcedure = Procedure< 21 | "query" | "mutation" | "subscription", 22 | ProcedureParams 23 | >; 24 | 25 | export type SwiftTRPCRouterDef = RouterDef< 26 | RootConfig<{ 27 | transformer: unknown; 28 | errorShape: unknown; 29 | ctx: never; 30 | meta: TRPCSwiftMeta; 31 | }>, 32 | ProcedureRouterRecord, 33 | never 34 | >; 35 | 36 | export type SwiftModelGenerationData = { 37 | swiftCode: string; 38 | names: Set; 39 | }; 40 | 41 | export type SwiftTypeGenerationData = { 42 | swiftTypeSignature: string; 43 | swiftLocalModel?: string; 44 | }; 45 | 46 | export type TRPCSwiftRouteState = { 47 | routeDepth: number; 48 | globalModels: SwiftModelGenerationData; 49 | visibleModelNames: Set; 50 | flags: TRPCSwiftFlags; 51 | }; 52 | 53 | export type TRPCSwiftModelState = TRPCSwiftRouteState & { 54 | modelDepth: number; 55 | isAlreadyOptional: boolean; 56 | }; 57 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from "fs"; 2 | import { getTRPCStructure, trpcStructureToSwiftClass } from "./generators/router.js"; 3 | import { indentSwiftCode, processTypeName } from "./utility.js"; 4 | import { SwiftModelGenerationData, SwiftTRPCRouterDef, TRPCSwiftFlags } from "./types.js"; 5 | import path from "path"; 6 | import { fileURLToPath } from "url"; 7 | 8 | export { TRPCSwiftMeta } from "./extensions/trpc.js"; 9 | export { extendZodWithSwift } from "./extensions/zod.js"; 10 | 11 | export const trpcRouterToSwiftClient = (name: string, routerDef: SwiftTRPCRouterDef, flags: TRPCSwiftFlags): string => { 12 | const __filename = fileURLToPath(import.meta.url); 13 | const __dirname = path.dirname(__filename); 14 | 15 | const trpcStructure = getTRPCStructure(routerDef); 16 | const globalModels: SwiftModelGenerationData = { 17 | swiftCode: "", 18 | names: new Set(), 19 | }; 20 | const swiftClass = trpcStructureToSwiftClass(name, trpcStructure, { 21 | routeDepth: 0, 22 | globalModels, 23 | visibleModelNames: new Set(), 24 | flags, 25 | }); 26 | 27 | let swiftClient = readFileSync(path.join(__dirname, "templates/TRPCClient.swift")).toString("utf-8"); 28 | swiftClient += swiftClass; 29 | 30 | if (flags.createTypeAliases) { 31 | globalModels.names.forEach((modelName) => { 32 | if (flags.publicAccess) { 33 | swiftClient += "public "; 34 | } 35 | swiftClient += `typealias ${modelName} = ${processTypeName(name)}.${modelName}\n`; 36 | }); 37 | } 38 | 39 | return indentSwiftCode(swiftClient); 40 | }; 41 | 42 | export const trpcRouterToSwiftFile = (name: string, routerDef: SwiftTRPCRouterDef, flags: TRPCSwiftFlags, outFile: string) => { 43 | const generated = trpcRouterToSwiftClient(name, routerDef, flags); 44 | writeFileSync(outFile, generated); 45 | }; 46 | -------------------------------------------------------------------------------- /src/utility.ts: -------------------------------------------------------------------------------- 1 | export const processTypeName = (name: string) => { 2 | const reservedTypes = ["Type"]; 3 | 4 | let processedName = snakeToCamelCase(name); 5 | processedName = processedName.charAt(0).toUpperCase() + processedName.slice(1); 6 | if (reservedTypes.includes(processedName)) { 7 | return `_${processedName}`; 8 | } 9 | 10 | return processedName; 11 | }; 12 | 13 | export const processFieldName = (name: string): string => { 14 | const reservedFields = ["internal", "public", "private"]; 15 | 16 | let processedName = snakeToCamelCase(name); 17 | processedName = processedName.charAt(0).toLowerCase() + processedName.slice(1); 18 | if (reservedFields.includes(processedName)) { 19 | return `_${name}`; 20 | } 21 | 22 | return processedName; 23 | }; 24 | 25 | export const snakeToCamelCase = (name: string): string => { 26 | return ( 27 | name 28 | // First, replace any sequence of non-alphanumeric characters with a single underscore 29 | .replace(/[^a-zA-Z0-9]+/g, "_") 30 | // Then, convert to camelCase by capitalizing the character following an underscore 31 | .replace(/_([a-z])/gi, ($1) => $1.toUpperCase().replace("_", "")) 32 | // Ensure the first character is lowercase 33 | .replace(/^([A-Z])/, ($1) => $1.toLowerCase()) 34 | ); 35 | }; 36 | 37 | export const indentSwiftCode = (code: string, spaces: number = 4): string => { 38 | const lines = code.split("\n"); 39 | let indentLevel = 0; 40 | 41 | for (let i = 0; i < lines.length; i++) { 42 | if (lines[i].includes("}")) { 43 | indentLevel--; 44 | } 45 | 46 | if (!lines[i].startsWith(" ")) { 47 | lines[i] = 48 | Array(indentLevel * spaces) 49 | .fill(" ") 50 | .join("") + lines[i]; 51 | } 52 | 53 | if (lines[i].includes("{")) { 54 | indentLevel++; 55 | } 56 | } 57 | 58 | return lines.join("\n"); 59 | }; 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debug 2 | release 3 | dist 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | .cache 110 | 111 | # Docusaurus cache and generated files 112 | .docusaurus 113 | 114 | # Serverless directories 115 | .serverless/ 116 | 117 | # FuseBox cache 118 | .fusebox/ 119 | 120 | # DynamoDB Local files 121 | .dynamodb/ 122 | 123 | # TernJS port file 124 | .tern-port 125 | 126 | # Stores VSCode versions used for testing VSCode extensions 127 | .vscode-test 128 | 129 | # yarn v2 130 | .yarn/cache 131 | .yarn/unplugged 132 | .yarn/build-state.yml 133 | .yarn/install-state.gz 134 | .pnp.* 135 | 136 | UserInterfaceState.xcuserstate 137 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # trpc-swift 2 | 3 | Generates native Swift clients for tRPC apps. 4 | 5 | # Installation 6 | 7 | Available as a npm package. 8 | 9 | ``` 10 | npm install --save-dev trpc-swift 11 | ``` 12 | 13 | # Usage 14 | 15 | ``` 16 | Usage: trpc-swift -r [routerName] -i [routerPath] -o [outputPath] 17 | Options: 18 | -r, --router-name Set the router name that should be found in the input file 19 | -i, --input Set the path where the tRPC input tRPC router is located 20 | -o, --output Set the output path for the generated Swift client 21 | -g, --global-mode Control which models are placed by default in the global scope. 22 | all All named models will be placed in the global scope by default. 23 | top Only named models directly referenced by routes will be placed in the global scope by default. 24 | none No models will be placed in the global scope by default. 25 | -p, --public Assign the public access modifier for all generated Swift models and routes. 26 | -a, --alias Create public type aliases for all models in the global scope. 27 | -s, --shared Create a shared singleton instance of the generated Swift client. 28 | -h, --help Display this help message 29 | -q, --quiet Run in quiet mode (no output except for fatal errors) 30 | ``` 31 | 32 | # Generation 33 | 34 | All routes in the input router are automatically detected and converted into Swift classes. Nested routers create nested Swift classes, tRPC procedures get converted into Swift methods. All referenced Zod input/output schemas, as well as their children get converted into Swift structures. 35 | 36 | For instance, the following tRPC router and Zod schemas: 37 | 38 | ``` 39 | extendZodWithSwift(z); 40 | 41 | const userSchema = z 42 | .object({ 43 | id: z.string().uuid(), 44 | name: z.object({ 45 | first: z.string(), 46 | middle: z.string().optional(), 47 | last: z.string(), 48 | }), 49 | email: z.string().optional(), 50 | dateCreated: z.date(), 51 | }) 52 | .swift({ 53 | name: "User", 54 | }); 55 | 56 | export const appRouter = router({ 57 | user: router({ 58 | get: authClientProcedure 59 | .meta({ 60 | swift: { 61 | description: "Fetches a user by ID.", 62 | }, 63 | }) 64 | .input( 65 | z.object({ 66 | id: userSchema.shape.id, 67 | }) 68 | ) 69 | .output(userSchema) 70 | .query(/** some implementation */), 71 | }), 72 | }); 73 | ``` 74 | 75 | will result in the following generated Swift client: 76 | 77 | ``` 78 | class AppRouter: TRPCClientData { 79 | lazy var user = UserRoute(clientData: self) 80 | 81 | // Scaffolding omitted 82 | 83 | init(baseUrl: URL? = nil, middlewares: [TRPCMiddleware] = []) { 84 | self.baseUrl = baseUrl 85 | self.baseMiddlewares = middlewares 86 | } 87 | 88 | struct User: Codable, Equatable { 89 | var id: String 90 | struct Name: Codable, Equatable { 91 | var first: String 92 | var middle: String? 93 | var last: String 94 | } 95 | var name: Name 96 | var email: String? 97 | var dateCreated: Date 98 | } 99 | 100 | class UserRoute: TRPCClientData { 101 | let clientData: TRPCClientData 102 | 103 | // Scaffolding omitted... 104 | 105 | struct GetInputType: Codable, Equatable { 106 | var id: String 107 | } 108 | 109 | /// Fetches a user by ID. 110 | func get(input: GetInputType) async throws -> User { 111 | return try await TRPCClient.shared.sendQuery(url: url.appendingPathExtension("get"), middlewares: middlewares, input: input) 112 | } 113 | } 114 | } 115 | ``` 116 | 117 | The generated Swift class is self-contained, handles networking and routing. All you need to do is add it to your Swift project. 118 | 119 | # License 120 | 121 | Made by Marko Calasan, 2023. 122 | 123 | This product is licensed under the MIT License. 124 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { writeFileSync } from "fs"; 3 | import { trpcRouterToSwiftClient } from "./index.js"; 4 | import { TRPCSwiftFlags } from "./types.js"; 5 | import path from "path"; 6 | import os from "os"; 7 | 8 | const timerLabel = "Done in"; 9 | console.time(timerLabel); 10 | 11 | const args = process.argv.slice(2); 12 | 13 | const showHelp = () => { 14 | console.log("Usage: trpc-swift -r [routerName] -i [routerPath] -o [outputPath]"); 15 | console.log("Options:"); 16 | console.log(" -r, --router-name Set the router name that should be found in the input file"); 17 | console.log(" -i, --input Set the path where the tRPC input tRPC router is located"); 18 | console.log(" -o, --output Set the output path for the generated Swift client"); 19 | console.log(" -c --conformance Set the conformance for the generated Swift models (default: Equatable)"); 20 | console.log(" -g, --global-mode Control which models are placed by default in the global scope."); 21 | console.log(" all All named models will be placed in the global scope by default."); 22 | console.log(" top Only named models directly referenced by routes will be placed in the global scope by default."); 23 | console.log(" none No models will be placed in the global scope by default."); 24 | console.log(" -p, --public Assign the public access modifier for all generated Swift models and routes."); 25 | console.log(" -a, --alias Create public type aliases for all models in the global scope."); 26 | console.log(" -s, --shared Create a shared singleton instance of the generated Swift client."); 27 | console.log(" -h, --help Display this help message"); 28 | console.log(" -q, --quiet Run in quiet mode (no output except for fatal errors)"); 29 | }; 30 | 31 | if (args.length < 2) { 32 | showHelp(); 33 | process.exit(1); 34 | } 35 | 36 | const flags: TRPCSwiftFlags = { 37 | createTypeAliases: false, 38 | createShared: false, 39 | publicAccess: false, 40 | globalMode: "top", 41 | conformance: "Equatable", 42 | quiet: false, 43 | }; 44 | 45 | const options = { 46 | routerName: "", 47 | routerPath: "", 48 | outputPath: "", 49 | flags, 50 | }; 51 | 52 | for (let i = 0; i < args.length; i++) { 53 | const arg = args[i]; 54 | const value = args.at(i + 1); 55 | 56 | switch (arg) { 57 | case "--help": 58 | case "-h": 59 | showHelp(); 60 | process.exit(0); 61 | // eslint-disable-next-line no-fallthrough 62 | case "--quiet": 63 | case "-q": 64 | flags.quiet = true; 65 | break; 66 | case "--router-name": 67 | case "-r": 68 | options.routerName = value!; 69 | i++; 70 | break; 71 | case "--input": 72 | case "-i": 73 | options.routerPath = value!; 74 | i++; 75 | break; 76 | case "--output": 77 | case "-o": 78 | options.outputPath = value!; 79 | i++; 80 | break; 81 | case "--global-mode": 82 | case "-g": 83 | switch (value) { 84 | case "all": 85 | case "top": 86 | case "none": 87 | flags.globalMode = value; 88 | break; 89 | default: 90 | console.error(`Unknown global mode: ${value}`); 91 | console.log(); 92 | showHelp(); 93 | process.exit(1); 94 | } 95 | i++; 96 | break; 97 | case "--conformance": 98 | case "-c": 99 | flags.conformance = value!.replace(/['"]/g, "").replace(/,(?!\s)/g, ", "); 100 | i++; 101 | break; 102 | case "--alias": 103 | case "-a": 104 | flags.createTypeAliases = true; 105 | break; 106 | case "--shared": 107 | case "-s": 108 | flags.createShared = true; 109 | break; 110 | case "--public": 111 | case "-p": 112 | flags.publicAccess = true; 113 | break; 114 | default: 115 | console.error(`Unknown argument: ${arg}`); 116 | console.log(); 117 | showHelp(); 118 | process.exit(1); 119 | } 120 | } 121 | 122 | if (!options.routerName || !options.routerPath || !options.outputPath) { 123 | console.error("--router-name, --router-path, --outputh-path are required."); 124 | console.log(); 125 | showHelp(); 126 | process.exit(1); 127 | } 128 | 129 | let fullRouterPath = path.join(process.cwd(), options.routerPath); 130 | if (os.platform() === "win32") { 131 | fullRouterPath = "file:///" + fullRouterPath; 132 | } 133 | 134 | const module = await import(fullRouterPath); 135 | const router = module[options.routerName]; 136 | if (!router) { 137 | console.error(`Could not find router ${options.routerName} in ${options.routerPath}`); 138 | process.exit(1); 139 | } 140 | 141 | const generatedCode = trpcRouterToSwiftClient(options.routerName, router._def, flags); 142 | writeFileSync(options.outputPath, generatedCode); 143 | 144 | if (!flags.quiet) { 145 | console.log(`Generated TRPC Swift client for ${options.routerName} in ${options.outputPath}`); 146 | console.timeEnd(timerLabel); 147 | } 148 | -------------------------------------------------------------------------------- /templates/TRPCClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TRPCClient.swift 3 | // Generated by trpc-swift 4 | // Library Author: Marko Calasan 5 | // 6 | 7 | import Foundation 8 | 9 | public enum DecodableValue: Decodable { 10 | case string(String) 11 | case int(Int) 12 | case double(Double) 13 | case bool(Bool) 14 | case dictionary([String: DecodableValue]) 15 | 16 | public init(from decoder: Decoder) throws { 17 | let container = try decoder.singleValueContainer() 18 | if let str = try? container.decode(String.self) { 19 | self = .string(str) 20 | } else if let int = try? container.decode(Int.self) { 21 | self = .int(int) 22 | } else if let dbl = try? container.decode(Double.self) { 23 | self = .double(dbl) 24 | } else if let bool = try? container.decode(Bool.self) { 25 | self = .bool(bool) 26 | } else { 27 | let dict = try container.decode([String: DecodableValue].self) 28 | self = .dictionary(dict) 29 | } 30 | } 31 | } 32 | 33 | public enum TRPCErrorCode: Int, Codable { 34 | // tRPC Defined 35 | case parseError = -32700 36 | case badRequest = -32600 37 | case internalServerError = -32603 38 | case unauthorized = -32001 39 | case forbidden = -32003 40 | case notFound = -32004 41 | case methodNotSupported = -32005 42 | case timeout = -32008 43 | case conflict = -32009 44 | case preconditionFailed = -32012 45 | case payloadTooLarge = -32013 46 | case unprocessableContent = -32022 47 | case tooManyRequests = -32029 48 | case clientClosedRequest = -32099 49 | 50 | // Application Defined 51 | case unknown = -1 52 | case missingOutputPayload = -2 53 | case errorParsingUrl = -3 54 | case errorParsingUrlComponents = -4 55 | } 56 | 57 | public struct TRPCError: Error, Decodable { 58 | public let code: TRPCErrorCode 59 | public let message: String? 60 | public let data: DecodableValue? 61 | 62 | init(code: TRPCErrorCode, message: String? = nil, data: DecodableValue? = nil) { 63 | self.code = code 64 | self.message = message 65 | self.data = data 66 | } 67 | } 68 | 69 | struct TRPCRequest: Encodable { 70 | struct DataContainer: Encodable { 71 | let json: T? 72 | } 73 | 74 | let zero: DataContainer 75 | 76 | enum CodingKeys: String, CodingKey { 77 | case zero = "0" 78 | } 79 | } 80 | 81 | struct TRPCResponse: Decodable { 82 | struct Result: Decodable { 83 | struct DataContainer: Decodable { 84 | let json: T 85 | } 86 | 87 | let data: DataContainer 88 | } 89 | 90 | struct ErrorContainer: Decodable { 91 | let json: TRPCError 92 | } 93 | 94 | let result: Result? 95 | let error: ErrorContainer? 96 | } 97 | 98 | public typealias TRPCMiddleware = (URLRequest) async throws -> URLRequest 99 | 100 | class TRPCClient { 101 | struct EmptyObject: Codable {} 102 | 103 | static let shared = TRPCClient() 104 | 105 | lazy var dateFormatter: DateFormatter = { 106 | let formatter = DateFormatter() 107 | formatter.locale = Locale(identifier: "en_US_POSIX") 108 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 109 | formatter.timeZone = TimeZone(secondsFromGMT: 0) 110 | 111 | return formatter 112 | }() 113 | 114 | func sendQuery(url: URL, middlewares: [TRPCMiddleware], input: Request) async throws -> Response { 115 | guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { 116 | throw TRPCError(code: .errorParsingUrl, message: "Could not create URLComponents from the given url: \(url)") 117 | } 118 | 119 | let encoder = JSONEncoder() 120 | encoder.dateEncodingStrategy = .formatted(dateFormatter) 121 | let data = try encoder.encode(TRPCRequest(zero: .init(json: Request.self == EmptyObject.self ? nil : input))) 122 | 123 | components.queryItems = [ 124 | URLQueryItem(name: "batch", value: "1"), 125 | URLQueryItem(name: "input", value: String(data: data, encoding: .utf8)!) 126 | ] 127 | 128 | let characterSet = CharacterSet(charactersIn: "/+").inverted 129 | guard let oldPercentEncodedQuery = components.percentEncodedQuery else { 130 | throw TRPCError(code: .errorParsingUrlComponents, message: "Could not retreive percent encoded URL query.") 131 | } 132 | components.percentEncodedQuery = oldPercentEncodedQuery.addingPercentEncoding(withAllowedCharacters: characterSet) 133 | 134 | guard let url = components.url else { 135 | throw TRPCError(code: .errorParsingUrlComponents, message: "Could not generate final URL after including parameters.") 136 | } 137 | 138 | return try await send(url: url, httpMethod: "GET", middlewares: middlewares, bodyData: nil) 139 | } 140 | 141 | func sendMutation(url: URL, middlewares: [TRPCMiddleware], input: Request) async throws -> Response { 142 | var components = URLComponents(url: url, resolvingAgainstBaseURL: false) 143 | 144 | let encoder = JSONEncoder() 145 | encoder.dateEncodingStrategy = .formatted(dateFormatter) 146 | let data = try encoder.encode(TRPCRequest(zero: .init(json: Request.self == EmptyObject.self ? nil : input))) 147 | 148 | components?.queryItems = [ 149 | URLQueryItem(name: "batch", value: "1") 150 | ] 151 | 152 | guard let url = components?.url else { 153 | throw NSError(domain: "", code: -1, userInfo: nil) 154 | } 155 | 156 | return try await send(url: url, httpMethod: "POST", middlewares: middlewares, bodyData: data) 157 | } 158 | 159 | private func send(url: URL, httpMethod: String, middlewares: [TRPCMiddleware], bodyData: Data?) async throws -> Response { 160 | var request = URLRequest(url: url) 161 | request.httpMethod = httpMethod 162 | request.httpBody = bodyData 163 | request.addValue("application/json", forHTTPHeaderField: "Content-Type") 164 | 165 | for middleware in middlewares { 166 | request = try await middleware(request) 167 | } 168 | 169 | request.httpMethod = httpMethod 170 | request.httpBody = bodyData 171 | 172 | let response = try await URLSession.shared.data(for: request) 173 | 174 | let decoder = JSONDecoder() 175 | decoder.dateDecodingStrategy = .formatted(dateFormatter) 176 | let decoded = try decoder.decode([TRPCResponse].self, from: response.0)[0] 177 | 178 | if let error = decoded.error { 179 | throw error.json 180 | } 181 | 182 | if let result = decoded.result { 183 | return result.data.json 184 | } 185 | 186 | if Response.self == EmptyObject.self { 187 | guard let emptyResult = EmptyObject() as? Response else { 188 | throw TRPCError(code: .missingOutputPayload, message: "Cannot cast empty object to \(Response.self).", data: nil) 189 | } 190 | 191 | return emptyResult 192 | } 193 | 194 | throw TRPCError(code: .missingOutputPayload, message: "Missing output payload.", data: nil) 195 | } 196 | } 197 | 198 | private protocol TRPCClientData: AnyObject { 199 | var url: URL { get } 200 | var middlewares: [TRPCMiddleware] { get } 201 | } 202 | 203 | -------------------------------------------------------------------------------- /src/generators/router.ts: -------------------------------------------------------------------------------- 1 | import { GenericProcedure, SwiftTRPCRouterDef, TRPCStructure, TRPCSwiftRouteState } from "../types.js"; 2 | import { ZodType, z } from "zod"; 3 | import { processFieldName, processTypeName } from "../utility.js"; 4 | import { zodSchemaToSwiftType } from "./models.js"; 5 | import { extendZodWithSwift } from "../extensions/zod.js"; 6 | 7 | extendZodWithSwift(z); 8 | 9 | export const getTRPCStructure = (routerDef: SwiftTRPCRouterDef): TRPCStructure => { 10 | const structure: TRPCStructure = {}; 11 | Object.entries(routerDef.procedures).forEach(([key, procedure]) => { 12 | const pathParts = key.split("."); 13 | 14 | let currentStructure: TRPCStructure = structure; 15 | pathParts.forEach((part, index) => { 16 | if (index === pathParts.length - 1) { 17 | currentStructure[part] = procedure as GenericProcedure; 18 | } 19 | currentStructure[part] ||= {}; 20 | currentStructure = currentStructure[part] as TRPCStructure; 21 | }); 22 | }); 23 | 24 | return structure; 25 | }; 26 | 27 | export const trpcStructureToSwiftClass = (name: string, structure: TRPCStructure, state: TRPCSwiftRouteState): string => { 28 | const className = processTypeName(name) + (state.routeDepth ? "Route" : ""); 29 | let swiftClass = `${state.flags.publicAccess ? "public " : ""}class ${className}: TRPCClientData {\n`; 30 | 31 | let innerSwiftCode = ""; 32 | const childStructureNames: string[] = []; 33 | 34 | Object.entries(structure).forEach(([key, value]) => { 35 | if (isProcedure(value)) { 36 | innerSwiftCode += trpcProcedureToSwiftMethodAndLocalModels(key, value, state); 37 | } else { 38 | innerSwiftCode += trpcStructureToSwiftClass(key, value, { 39 | ...state, 40 | routeDepth: state.routeDepth + 1, 41 | visibleModelNames: new Set(state.visibleModelNames), 42 | }); 43 | childStructureNames.push(key); 44 | } 45 | }); 46 | 47 | childStructureNames.forEach((child) => { 48 | const fieldName = processFieldName(child); 49 | const typeName = processTypeName(child) + "Route"; 50 | 51 | swiftClass += `private lazy var _${fieldName} = ${typeName}(clientData: self)\n`; 52 | swiftClass += `${state.flags.publicAccess ? "public " : ""}var ${fieldName}: ${typeName} {\n_${fieldName}\n}\n`; 53 | }); 54 | 55 | if (childStructureNames.length > 0) { 56 | swiftClass += "\n"; 57 | } 58 | 59 | if (state.routeDepth === 0) { 60 | if (state.flags.createShared) { 61 | swiftClass += `${state.flags.publicAccess ? "public " : ""}static let shared = ${className}()\n\n`; 62 | } 63 | swiftClass += `private var baseUrl: URL${state.flags.createShared ? "!" : ""}\n`; 64 | swiftClass += "private var baseMiddlewares: [TRPCMiddleware] = []\n\n"; 65 | swiftClass += "fileprivate var url: URL {\n"; 66 | swiftClass += "baseUrl\n"; 67 | swiftClass += "}\n\n"; 68 | swiftClass += "fileprivate var middlewares: [TRPCMiddleware] {\n"; 69 | swiftClass += "baseMiddlewares\n"; 70 | swiftClass += "}\n\n"; 71 | swiftClass += `${state.flags.publicAccess ? "public " : ""}init(baseUrl: URL${ 72 | state.flags.createShared ? "? = nil" : "" 73 | }, middlewares: [TRPCMiddleware] = []) {\n`; 74 | swiftClass += "self.baseUrl = baseUrl\n"; 75 | swiftClass += "self.baseMiddlewares = middlewares\n"; 76 | swiftClass += "}\n"; 77 | } else { 78 | swiftClass += "fileprivate let clientData: TRPCClientData\n\n"; 79 | swiftClass += "fileprivate var url: URL {\n"; 80 | if (state.routeDepth === 1) { 81 | swiftClass += `clientData.url.appendingPathComponent("${name}")\n`; 82 | } else { 83 | swiftClass += `clientData.url.appendingPathExtension("${name}")\n`; 84 | } 85 | swiftClass += "}\n\n"; 86 | swiftClass += "fileprivate var middlewares: [TRPCMiddleware] {\n"; 87 | swiftClass += "clientData.middlewares\n"; 88 | swiftClass += "}\n\n"; 89 | swiftClass += "fileprivate init(clientData: TRPCClientData) {\n"; 90 | swiftClass += "self.clientData = clientData\n"; 91 | swiftClass += "}\n"; 92 | } 93 | 94 | swiftClass += "\n"; 95 | 96 | if (state.routeDepth === 0 && state.globalModels.swiftCode) { 97 | swiftClass += state.globalModels.swiftCode + "\n"; 98 | } 99 | 100 | swiftClass += innerSwiftCode; 101 | swiftClass += "}\n"; 102 | 103 | return swiftClass; 104 | }; 105 | 106 | const trpcProcedureToSwiftMethodAndLocalModels = (name: string, procedure: GenericProcedure, state: TRPCSwiftRouteState): string => { 107 | try { 108 | let swiftLocalModels = ""; 109 | let swiftMethod = ""; 110 | 111 | const description = procedure._def.meta?.swift?.description; 112 | if (description) { 113 | swiftMethod += `/// ${description}\n`; 114 | } 115 | 116 | if (state.flags.publicAccess) { 117 | swiftMethod += "public "; 118 | } 119 | 120 | swiftMethod += `func ${name}(`; 121 | 122 | if (procedure._def.inputs.length > 1) { 123 | throw new Error("Multiple inputs not supported."); 124 | } 125 | 126 | const input = procedure._def.inputs.at(0); 127 | let addedInput = false; 128 | if (input) { 129 | const schemaType = zodSchemaToSwiftType( 130 | input as ZodType, 131 | { 132 | ...state, 133 | modelDepth: 0, 134 | isAlreadyOptional: false, 135 | }, 136 | processTypeName(name + "InputType") 137 | ); 138 | 139 | if (schemaType) { 140 | if (schemaType.swiftTypeSignature) { 141 | const swiftParam = `input: ${schemaType.swiftTypeSignature}`; 142 | 143 | if (schemaType.swiftLocalModel) { 144 | swiftLocalModels += schemaType.swiftLocalModel + "\n"; 145 | } 146 | 147 | swiftMethod += swiftParam; 148 | addedInput = true; 149 | } 150 | } 151 | } 152 | 153 | swiftMethod += ") async throws"; 154 | 155 | const emptyOutputType = "TRPCClient.EmptyObject"; 156 | let outputType = emptyOutputType; 157 | if (procedure._def.output) { 158 | const output = procedure._def.output; 159 | const schemaType = zodSchemaToSwiftType( 160 | output as ZodType, 161 | { 162 | ...state, 163 | modelDepth: 0, 164 | isAlreadyOptional: false, 165 | }, 166 | processTypeName(name + "OutputType") 167 | ); 168 | 169 | if (schemaType) { 170 | if (schemaType.swiftTypeSignature) { 171 | if (schemaType.swiftLocalModel) { 172 | swiftLocalModels += schemaType.swiftLocalModel + "\n"; 173 | } 174 | 175 | outputType = schemaType.swiftTypeSignature; 176 | } 177 | } 178 | } 179 | 180 | const hasOutput = outputType !== emptyOutputType; 181 | if (hasOutput) { 182 | swiftMethod += ` -> ${outputType} {\n`; 183 | } else { 184 | swiftMethod += " {\n"; 185 | } 186 | 187 | const pathMethod = state.routeDepth === 0 ? "appendingPathComponent" : "appendingPathExtension"; 188 | if (procedure._def.query) { 189 | swiftMethod += `${ 190 | hasOutput ? "return" : "let _: TRPCClient.EmptyObject =" 191 | } try await TRPCClient.shared.sendQuery(url: url.${pathMethod}("${name}"), middlewares: middlewares, input: ${ 192 | addedInput ? "input" : "TRPCClient.EmptyObject()" 193 | })\n`; 194 | } else if (procedure._def.mutation) { 195 | swiftMethod += `${ 196 | hasOutput ? "return" : "let _: TRPCClient.EmptyObject =" 197 | } try await TRPCClient.shared.sendMutation(url: url.${pathMethod}("${name}"), middlewares: middlewares, input: ${ 198 | addedInput ? "input" : "TRPCClient.EmptyObject()" 199 | })\n`; 200 | } else { 201 | throw new Error("Unsupported procedure type."); 202 | } 203 | 204 | swiftMethod += "}\n"; 205 | 206 | return swiftLocalModels + "\n" + swiftMethod; 207 | } catch (e) { 208 | if (!state.flags.quiet) { 209 | console.error(`Error while processing procedure ${name}: ${(e as Error).message}`); 210 | } 211 | return ""; 212 | } 213 | }; 214 | 215 | const isProcedure = (trpcStructureValue: TRPCStructure | GenericProcedure): trpcStructureValue is GenericProcedure => { 216 | return "_def" in trpcStructureValue; 217 | }; 218 | -------------------------------------------------------------------------------- /src/generators/models.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AnyZodObject, 3 | ZodArray, 4 | ZodEffects, 5 | ZodEnum, 6 | ZodFirstPartyTypeKind, 7 | ZodLiteral, 8 | ZodNullable, 9 | ZodNumber, 10 | ZodOptional, 11 | ZodRecord, 12 | ZodSet, 13 | ZodType, 14 | ZodTypeAny, 15 | ZodUnion, 16 | z, 17 | } from "zod"; 18 | import { SwiftTypeGenerationData, TRPCSwiftModelState } from "../types.js"; 19 | import { processFieldName, processTypeName } from "../utility.js"; 20 | import { extendZodWithSwift } from "../extensions/zod.js"; 21 | 22 | extendZodWithSwift(z); 23 | 24 | export const zodSchemaToSwiftType = (schema: ZodType, state: TRPCSwiftModelState, fallbackName: string): SwiftTypeGenerationData | null => { 25 | if ("typeName" in schema._def) { 26 | switch (schema._def.typeName as ZodFirstPartyTypeKind) { 27 | case ZodFirstPartyTypeKind.ZodUnion: 28 | return zodUnionToSwiftType(schema as ZodUnion<[ZodTypeAny, ...ZodTypeAny[]]>, state, fallbackName); 29 | case ZodFirstPartyTypeKind.ZodObject: 30 | return zodObjectToSwiftType(schema as AnyZodObject, state, fallbackName); 31 | case ZodFirstPartyTypeKind.ZodEnum: 32 | return zodEnumToSwiftType(schema as ZodEnum<[string, ...string[]]>, state, fallbackName); 33 | case ZodFirstPartyTypeKind.ZodOptional: 34 | case ZodFirstPartyTypeKind.ZodNullable: 35 | return zodOptionalOrNullableToSwiftType(schema as ZodOptional | ZodNullable, state, fallbackName); 36 | case ZodFirstPartyTypeKind.ZodArray: 37 | return zodCollectionToSwiftType(schema as ZodArray, state, fallbackName); 38 | case ZodFirstPartyTypeKind.ZodRecord: 39 | return zodCollectionToSwiftType(schema as ZodRecord, state, fallbackName); 40 | case ZodFirstPartyTypeKind.ZodSet: 41 | return zodCollectionToSwiftType(schema as ZodSet, state, fallbackName); 42 | case ZodFirstPartyTypeKind.ZodEffects: 43 | return zodEffectsToSwiftType(schema as ZodEffects, state, fallbackName); 44 | case ZodFirstPartyTypeKind.ZodVoid: 45 | case ZodFirstPartyTypeKind.ZodUndefined: 46 | return null; 47 | case ZodFirstPartyTypeKind.ZodBigInt: 48 | return { swiftTypeSignature: "Int" }; 49 | case ZodFirstPartyTypeKind.ZodNumber: 50 | return { swiftTypeSignature: (schema as ZodNumber).isInt ? "Int" : "Double" }; 51 | case ZodFirstPartyTypeKind.ZodBoolean: 52 | return { swiftTypeSignature: "Bool" }; 53 | case ZodFirstPartyTypeKind.ZodDate: 54 | return { swiftTypeSignature: "Date" }; 55 | case ZodFirstPartyTypeKind.ZodString: 56 | return { swiftTypeSignature: "String" }; 57 | case ZodFirstPartyTypeKind.ZodLiteral: 58 | return zodEnumToSwiftType(z.enum((schema as ZodLiteral)._def.value), state, fallbackName); 59 | default: 60 | break; 61 | } 62 | } 63 | 64 | throw new Error("Unsupported schema type: " + (schema._def as { typeName: ZodFirstPartyTypeKind }).typeName); 65 | }; 66 | 67 | const zodUnionToSwiftType = ( 68 | schema: ZodUnion<[ZodTypeAny, ...ZodTypeAny[]]>, 69 | state: TRPCSwiftModelState, 70 | fallbackName: string 71 | ): SwiftTypeGenerationData | null => { 72 | return wrapZodSchemaWithModels(schema, state, fallbackName, (name) => { 73 | let swiftModel = ""; 74 | 75 | const description = schema._def.swift?.description; 76 | if (description) { 77 | swiftModel += `/// ${description}\n`; 78 | } 79 | 80 | if (state.flags.publicAccess) { 81 | swiftModel += "public "; 82 | } 83 | 84 | swiftModel += `struct ${name}: Codable, ${state.flags.conformance} {\n`; 85 | schema._def.options.forEach((option, index) => { 86 | const optionType = zodSchemaToSwiftType( 87 | option, 88 | { 89 | ...state, 90 | isAlreadyOptional: false, 91 | }, 92 | processTypeName("Option" + (index + 1)) 93 | ); 94 | 95 | if (optionType) { 96 | if (optionType.swiftLocalModel) { 97 | swiftModel += optionType.swiftLocalModel; 98 | } 99 | 100 | const optionFieldSignature = processFieldName(optionType.swiftTypeSignature); 101 | let optionTypeSignature = optionType.swiftTypeSignature; 102 | if (!optionTypeSignature.endsWith("?")) { 103 | optionTypeSignature += "?"; 104 | } 105 | 106 | if (state.flags.publicAccess) { 107 | swiftModel += "public "; 108 | } 109 | swiftModel += `var ${optionFieldSignature}: ${optionTypeSignature}\n`; 110 | } 111 | }); 112 | swiftModel += "}\n"; 113 | 114 | return swiftModel; 115 | }); 116 | }; 117 | 118 | const zodObjectToSwiftType = (schema: AnyZodObject, state: TRPCSwiftModelState, fallbackName: string): SwiftTypeGenerationData => { 119 | return wrapZodSchemaWithModels(schema, state, fallbackName, (name) => { 120 | let swiftModel = ""; 121 | 122 | const description = schema._def.swift?.description; 123 | if (description) { 124 | swiftModel += `/// ${description}\n`; 125 | } 126 | 127 | const publicInitArgs: string[] = []; 128 | 129 | if (state.flags.publicAccess) { 130 | swiftModel += "public "; 131 | } 132 | 133 | swiftModel += `struct ${name}: Codable, ${state.flags.conformance} {\n`; 134 | Object.entries(schema.shape).forEach(([key, value]) => { 135 | const childType = zodSchemaToSwiftType( 136 | value as ZodType, 137 | { 138 | ...state, 139 | modelDepth: state.modelDepth + 1, 140 | visibleModelNames: new Set(state.visibleModelNames), 141 | isAlreadyOptional: false, 142 | }, 143 | processTypeName(key) 144 | ); 145 | if (childType) { 146 | if (childType.swiftLocalModel) { 147 | swiftModel += childType.swiftLocalModel; 148 | } 149 | 150 | const childDescription = (value as ZodType)._def.swift?.description; 151 | if (childDescription) { 152 | swiftModel += `/// ${childDescription}\n`; 153 | } 154 | 155 | if (state.flags.publicAccess) { 156 | swiftModel += "public "; 157 | } 158 | swiftModel += `var ${key}: ${childType.swiftTypeSignature}\n`; 159 | 160 | if (state.flags.publicAccess) { 161 | const isArgOptional = childType.swiftTypeSignature.endsWith("?"); 162 | publicInitArgs.push(`${key}: ${childType.swiftTypeSignature}${isArgOptional ? " = nil" : ""}`); 163 | } 164 | } 165 | }); 166 | if (state.flags.publicAccess) { 167 | swiftModel += `\npublic init(${publicInitArgs.join(", ")}) {\n`; 168 | Object.keys(schema.shape).forEach((key) => { 169 | swiftModel += `self.${key} = ${key}\n`; 170 | }); 171 | swiftModel += "}\n"; 172 | } 173 | swiftModel += "}\n"; 174 | 175 | return swiftModel; 176 | })!; 177 | }; 178 | 179 | const zodEnumToSwiftType = ( 180 | schema: ZodEnum<[string, ...string[]]>, 181 | state: TRPCSwiftModelState, 182 | fallbackName: string 183 | ): SwiftTypeGenerationData | null => { 184 | return wrapZodSchemaWithModels( 185 | schema, 186 | { 187 | ...state, 188 | modelDepth: state.modelDepth + 1, 189 | visibleModelNames: new Set(state.visibleModelNames), 190 | isAlreadyOptional: false, 191 | }, 192 | fallbackName, 193 | (name) => { 194 | if (!schema._def.values) { 195 | return null; 196 | } 197 | 198 | let swiftModel = ""; 199 | const description = schema._def.swift?.description; 200 | if (description) { 201 | swiftModel += `/// ${description}\n`; 202 | } 203 | 204 | if (state.flags.publicAccess) { 205 | swiftModel += "public "; 206 | } 207 | 208 | swiftModel += `enum ${name}: String, Codable, ${state.flags.conformance} {\n`; 209 | schema._def.values.forEach((value) => { 210 | swiftModel += `case ${processFieldName(value)} = "${value}"\n`; 211 | }); 212 | swiftModel += "}\n"; 213 | 214 | return swiftModel; 215 | } 216 | ); 217 | }; 218 | 219 | const zodOptionalOrNullableToSwiftType = ( 220 | schema: ZodOptional | ZodNullable, 221 | state: TRPCSwiftModelState, 222 | fallbackName: string 223 | ): SwiftTypeGenerationData | null => { 224 | const unwrappedResult = zodSchemaToSwiftType( 225 | schema._def.innerType, 226 | { 227 | ...state, 228 | modelDepth: state.modelDepth + 1, 229 | isAlreadyOptional: true, 230 | }, 231 | fallbackName 232 | ); 233 | if (!unwrappedResult) { 234 | return null; 235 | } 236 | 237 | return { 238 | swiftTypeSignature: `${unwrappedResult.swiftTypeSignature}${state.isAlreadyOptional ? "" : "?"}`, 239 | swiftLocalModel: unwrappedResult.swiftLocalModel, 240 | }; 241 | }; 242 | 243 | const zodCollectionToSwiftType = ( 244 | schema: ZodArray | ZodSet | ZodRecord, 245 | state: TRPCSwiftModelState, 246 | fallbackName: string 247 | ): SwiftTypeGenerationData | null => { 248 | const unwrappedResult = zodSchemaToSwiftType( 249 | schema._def.typeName === ZodFirstPartyTypeKind.ZodArray ? schema._def.type : schema._def.valueType, 250 | { 251 | ...state, 252 | isAlreadyOptional: false, 253 | }, 254 | fallbackName 255 | ); 256 | if (!unwrappedResult) { 257 | return null; 258 | } 259 | 260 | let swiftTypeSignature = ""; 261 | switch (schema._def.typeName) { 262 | case ZodFirstPartyTypeKind.ZodArray: 263 | swiftTypeSignature = `[${unwrappedResult.swiftTypeSignature}]`; 264 | break; 265 | case ZodFirstPartyTypeKind.ZodSet: 266 | swiftTypeSignature = `Set<${unwrappedResult.swiftTypeSignature}>`; 267 | break; 268 | case ZodFirstPartyTypeKind.ZodRecord: 269 | swiftTypeSignature = `[String: ${unwrappedResult.swiftTypeSignature}]`; 270 | break; 271 | default: 272 | break; 273 | } 274 | 275 | return { 276 | swiftTypeSignature, 277 | swiftLocalModel: unwrappedResult.swiftLocalModel, 278 | }; 279 | }; 280 | 281 | const zodEffectsToSwiftType = ( 282 | schema: ZodEffects, 283 | state: TRPCSwiftModelState, 284 | fallbackName: string 285 | ): SwiftTypeGenerationData | null => { 286 | return zodSchemaToSwiftType(schema._def.schema, state, fallbackName); 287 | }; 288 | 289 | const wrapZodSchemaWithModels = ( 290 | schema: AnyZodObject | ZodEnum<[string, ...string[]]> | ZodUnion<[ZodTypeAny, ...ZodTypeAny[]]>, 291 | state: TRPCSwiftModelState, 292 | fallbackName: string, 293 | modelGenerator: (name: string) => string | null 294 | ): SwiftTypeGenerationData | null => { 295 | const zodSwiftName = schema._def.swift?.name; 296 | const shouldBeGlobal = 297 | schema._def.swift?.name && 298 | (schema._def.swift.global || state.flags.globalMode === "all" || (state.flags.globalMode === "top" && state.modelDepth === 0)); 299 | const finalName = zodSwiftName ?? fallbackName; 300 | 301 | if (state.visibleModelNames.has(finalName) || state.globalModels.names.has(finalName)) { 302 | return { 303 | swiftTypeSignature: finalName, 304 | }; 305 | } 306 | 307 | const swiftTypeSignature = processTypeName(finalName); 308 | const swiftModel = modelGenerator(swiftTypeSignature); 309 | if (!swiftModel) { 310 | return null; 311 | } 312 | 313 | const swiftLocalModel = shouldBeGlobal ? undefined : swiftModel; 314 | if (shouldBeGlobal) { 315 | state.globalModels.names.add(finalName); 316 | state.globalModels.swiftCode += swiftModel; 317 | } 318 | 319 | state.visibleModelNames.add(finalName); 320 | 321 | return { 322 | swiftTypeSignature, 323 | swiftLocalModel, 324 | }; 325 | }; 326 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": 6 | version "4.4.0" 7 | resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" 8 | integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== 9 | dependencies: 10 | eslint-visitor-keys "^3.3.0" 11 | 12 | "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": 13 | version "4.11.0" 14 | resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" 15 | integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== 16 | 17 | "@eslint/eslintrc@^2.1.4": 18 | version "2.1.4" 19 | resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" 20 | integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== 21 | dependencies: 22 | ajv "^6.12.4" 23 | debug "^4.3.2" 24 | espree "^9.6.0" 25 | globals "^13.19.0" 26 | ignore "^5.2.0" 27 | import-fresh "^3.2.1" 28 | js-yaml "^4.1.0" 29 | minimatch "^3.1.2" 30 | strip-json-comments "^3.1.1" 31 | 32 | "@eslint/js@8.57.0": 33 | version "8.57.0" 34 | resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" 35 | integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== 36 | 37 | "@humanwhocodes/config-array@^0.11.14": 38 | version "0.11.14" 39 | resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" 40 | integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== 41 | dependencies: 42 | "@humanwhocodes/object-schema" "^2.0.2" 43 | debug "^4.3.1" 44 | minimatch "^3.0.5" 45 | 46 | "@humanwhocodes/module-importer@^1.0.1": 47 | version "1.0.1" 48 | resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" 49 | integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== 50 | 51 | "@humanwhocodes/object-schema@^2.0.2": 52 | version "2.0.3" 53 | resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" 54 | integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== 55 | 56 | "@nodelib/fs.scandir@2.1.5": 57 | version "2.1.5" 58 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 59 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 60 | dependencies: 61 | "@nodelib/fs.stat" "2.0.5" 62 | run-parallel "^1.1.9" 63 | 64 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 65 | version "2.0.5" 66 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 67 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 68 | 69 | "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": 70 | version "1.2.8" 71 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 72 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 73 | dependencies: 74 | "@nodelib/fs.scandir" "2.1.5" 75 | fastq "^1.6.0" 76 | 77 | "@trpc/server@^10.43.3": 78 | version "10.45.2" 79 | resolved "https://registry.yarnpkg.com/@trpc/server/-/server-10.45.2.tgz#5f2778c4810f93b5dc407146334f8da70a0b51fb" 80 | integrity sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg== 81 | 82 | "@types/json-schema@^7.0.12": 83 | version "7.0.15" 84 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" 85 | integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 86 | 87 | "@types/node@^20.9.0": 88 | version "20.14.15" 89 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.15.tgz#e59477ab7bc7db1f80c85540bfd192a0becc588b" 90 | integrity sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw== 91 | dependencies: 92 | undici-types "~5.26.4" 93 | 94 | "@types/semver@^7.5.0": 95 | version "7.5.8" 96 | resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" 97 | integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== 98 | 99 | "@typescript-eslint/eslint-plugin@^6.11.0": 100 | version "6.21.0" 101 | resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" 102 | integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== 103 | dependencies: 104 | "@eslint-community/regexpp" "^4.5.1" 105 | "@typescript-eslint/scope-manager" "6.21.0" 106 | "@typescript-eslint/type-utils" "6.21.0" 107 | "@typescript-eslint/utils" "6.21.0" 108 | "@typescript-eslint/visitor-keys" "6.21.0" 109 | debug "^4.3.4" 110 | graphemer "^1.4.0" 111 | ignore "^5.2.4" 112 | natural-compare "^1.4.0" 113 | semver "^7.5.4" 114 | ts-api-utils "^1.0.1" 115 | 116 | "@typescript-eslint/parser@^6.11.0": 117 | version "6.21.0" 118 | resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" 119 | integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== 120 | dependencies: 121 | "@typescript-eslint/scope-manager" "6.21.0" 122 | "@typescript-eslint/types" "6.21.0" 123 | "@typescript-eslint/typescript-estree" "6.21.0" 124 | "@typescript-eslint/visitor-keys" "6.21.0" 125 | debug "^4.3.4" 126 | 127 | "@typescript-eslint/scope-manager@6.21.0": 128 | version "6.21.0" 129 | resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" 130 | integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== 131 | dependencies: 132 | "@typescript-eslint/types" "6.21.0" 133 | "@typescript-eslint/visitor-keys" "6.21.0" 134 | 135 | "@typescript-eslint/type-utils@6.21.0": 136 | version "6.21.0" 137 | resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" 138 | integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== 139 | dependencies: 140 | "@typescript-eslint/typescript-estree" "6.21.0" 141 | "@typescript-eslint/utils" "6.21.0" 142 | debug "^4.3.4" 143 | ts-api-utils "^1.0.1" 144 | 145 | "@typescript-eslint/types@6.21.0": 146 | version "6.21.0" 147 | resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" 148 | integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== 149 | 150 | "@typescript-eslint/typescript-estree@6.21.0": 151 | version "6.21.0" 152 | resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" 153 | integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== 154 | dependencies: 155 | "@typescript-eslint/types" "6.21.0" 156 | "@typescript-eslint/visitor-keys" "6.21.0" 157 | debug "^4.3.4" 158 | globby "^11.1.0" 159 | is-glob "^4.0.3" 160 | minimatch "9.0.3" 161 | semver "^7.5.4" 162 | ts-api-utils "^1.0.1" 163 | 164 | "@typescript-eslint/utils@6.21.0": 165 | version "6.21.0" 166 | resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" 167 | integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== 168 | dependencies: 169 | "@eslint-community/eslint-utils" "^4.4.0" 170 | "@types/json-schema" "^7.0.12" 171 | "@types/semver" "^7.5.0" 172 | "@typescript-eslint/scope-manager" "6.21.0" 173 | "@typescript-eslint/types" "6.21.0" 174 | "@typescript-eslint/typescript-estree" "6.21.0" 175 | semver "^7.5.4" 176 | 177 | "@typescript-eslint/visitor-keys@6.21.0": 178 | version "6.21.0" 179 | resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" 180 | integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== 181 | dependencies: 182 | "@typescript-eslint/types" "6.21.0" 183 | eslint-visitor-keys "^3.4.1" 184 | 185 | "@ungap/structured-clone@^1.2.0": 186 | version "1.2.0" 187 | resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" 188 | integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== 189 | 190 | acorn-jsx@^5.3.2: 191 | version "5.3.2" 192 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 193 | integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 194 | 195 | acorn@^8.9.0: 196 | version "8.12.1" 197 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" 198 | integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== 199 | 200 | ajv@^6.12.4: 201 | version "6.12.6" 202 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 203 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 204 | dependencies: 205 | fast-deep-equal "^3.1.1" 206 | fast-json-stable-stringify "^2.0.0" 207 | json-schema-traverse "^0.4.1" 208 | uri-js "^4.2.2" 209 | 210 | ansi-regex@^5.0.1: 211 | version "5.0.1" 212 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 213 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 214 | 215 | ansi-styles@^4.1.0: 216 | version "4.3.0" 217 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 218 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 219 | dependencies: 220 | color-convert "^2.0.1" 221 | 222 | argparse@^2.0.1: 223 | version "2.0.1" 224 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 225 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 226 | 227 | array-union@^2.1.0: 228 | version "2.1.0" 229 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 230 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 231 | 232 | balanced-match@^1.0.0: 233 | version "1.0.2" 234 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 235 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 236 | 237 | brace-expansion@^1.1.7: 238 | version "1.1.11" 239 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 240 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 241 | dependencies: 242 | balanced-match "^1.0.0" 243 | concat-map "0.0.1" 244 | 245 | brace-expansion@^2.0.1: 246 | version "2.0.1" 247 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 248 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 249 | dependencies: 250 | balanced-match "^1.0.0" 251 | 252 | braces@^3.0.3: 253 | version "3.0.3" 254 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 255 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 256 | dependencies: 257 | fill-range "^7.1.1" 258 | 259 | callsites@^3.0.0: 260 | version "3.1.0" 261 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 262 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 263 | 264 | chalk@^4.0.0: 265 | version "4.1.2" 266 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 267 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 268 | dependencies: 269 | ansi-styles "^4.1.0" 270 | supports-color "^7.1.0" 271 | 272 | color-convert@^2.0.1: 273 | version "2.0.1" 274 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 275 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 276 | dependencies: 277 | color-name "~1.1.4" 278 | 279 | color-name@~1.1.4: 280 | version "1.1.4" 281 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 282 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 283 | 284 | concat-map@0.0.1: 285 | version "0.0.1" 286 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 287 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 288 | 289 | cross-spawn@^7.0.2: 290 | version "7.0.3" 291 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 292 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 293 | dependencies: 294 | path-key "^3.1.0" 295 | shebang-command "^2.0.0" 296 | which "^2.0.1" 297 | 298 | debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: 299 | version "4.3.6" 300 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" 301 | integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== 302 | dependencies: 303 | ms "2.1.2" 304 | 305 | deep-is@^0.1.3: 306 | version "0.1.4" 307 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 308 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 309 | 310 | dir-glob@^3.0.1: 311 | version "3.0.1" 312 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" 313 | integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== 314 | dependencies: 315 | path-type "^4.0.0" 316 | 317 | doctrine@^3.0.0: 318 | version "3.0.0" 319 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 320 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 321 | dependencies: 322 | esutils "^2.0.2" 323 | 324 | escape-string-regexp@^4.0.0: 325 | version "4.0.0" 326 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 327 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 328 | 329 | eslint-config-prettier@^9.0.0: 330 | version "9.1.0" 331 | resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" 332 | integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== 333 | 334 | eslint-scope@^7.2.2: 335 | version "7.2.2" 336 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" 337 | integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== 338 | dependencies: 339 | esrecurse "^4.3.0" 340 | estraverse "^5.2.0" 341 | 342 | eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: 343 | version "3.4.3" 344 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" 345 | integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== 346 | 347 | eslint@^8.53.0: 348 | version "8.57.0" 349 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" 350 | integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== 351 | dependencies: 352 | "@eslint-community/eslint-utils" "^4.2.0" 353 | "@eslint-community/regexpp" "^4.6.1" 354 | "@eslint/eslintrc" "^2.1.4" 355 | "@eslint/js" "8.57.0" 356 | "@humanwhocodes/config-array" "^0.11.14" 357 | "@humanwhocodes/module-importer" "^1.0.1" 358 | "@nodelib/fs.walk" "^1.2.8" 359 | "@ungap/structured-clone" "^1.2.0" 360 | ajv "^6.12.4" 361 | chalk "^4.0.0" 362 | cross-spawn "^7.0.2" 363 | debug "^4.3.2" 364 | doctrine "^3.0.0" 365 | escape-string-regexp "^4.0.0" 366 | eslint-scope "^7.2.2" 367 | eslint-visitor-keys "^3.4.3" 368 | espree "^9.6.1" 369 | esquery "^1.4.2" 370 | esutils "^2.0.2" 371 | fast-deep-equal "^3.1.3" 372 | file-entry-cache "^6.0.1" 373 | find-up "^5.0.0" 374 | glob-parent "^6.0.2" 375 | globals "^13.19.0" 376 | graphemer "^1.4.0" 377 | ignore "^5.2.0" 378 | imurmurhash "^0.1.4" 379 | is-glob "^4.0.0" 380 | is-path-inside "^3.0.3" 381 | js-yaml "^4.1.0" 382 | json-stable-stringify-without-jsonify "^1.0.1" 383 | levn "^0.4.1" 384 | lodash.merge "^4.6.2" 385 | minimatch "^3.1.2" 386 | natural-compare "^1.4.0" 387 | optionator "^0.9.3" 388 | strip-ansi "^6.0.1" 389 | text-table "^0.2.0" 390 | 391 | espree@^9.6.0, espree@^9.6.1: 392 | version "9.6.1" 393 | resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" 394 | integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== 395 | dependencies: 396 | acorn "^8.9.0" 397 | acorn-jsx "^5.3.2" 398 | eslint-visitor-keys "^3.4.1" 399 | 400 | esquery@^1.4.2: 401 | version "1.6.0" 402 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" 403 | integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== 404 | dependencies: 405 | estraverse "^5.1.0" 406 | 407 | esrecurse@^4.3.0: 408 | version "4.3.0" 409 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 410 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 411 | dependencies: 412 | estraverse "^5.2.0" 413 | 414 | estraverse@^5.1.0, estraverse@^5.2.0: 415 | version "5.3.0" 416 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 417 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 418 | 419 | esutils@^2.0.2: 420 | version "2.0.3" 421 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 422 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 423 | 424 | fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: 425 | version "3.1.3" 426 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 427 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 428 | 429 | fast-glob@^3.2.9: 430 | version "3.3.2" 431 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" 432 | integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== 433 | dependencies: 434 | "@nodelib/fs.stat" "^2.0.2" 435 | "@nodelib/fs.walk" "^1.2.3" 436 | glob-parent "^5.1.2" 437 | merge2 "^1.3.0" 438 | micromatch "^4.0.4" 439 | 440 | fast-json-stable-stringify@^2.0.0: 441 | version "2.1.0" 442 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 443 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 444 | 445 | fast-levenshtein@^2.0.6: 446 | version "2.0.6" 447 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 448 | integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 449 | 450 | fastq@^1.6.0: 451 | version "1.17.1" 452 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" 453 | integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== 454 | dependencies: 455 | reusify "^1.0.4" 456 | 457 | file-entry-cache@^6.0.1: 458 | version "6.0.1" 459 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 460 | integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== 461 | dependencies: 462 | flat-cache "^3.0.4" 463 | 464 | fill-range@^7.1.1: 465 | version "7.1.1" 466 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 467 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 468 | dependencies: 469 | to-regex-range "^5.0.1" 470 | 471 | find-up@^5.0.0: 472 | version "5.0.0" 473 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 474 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 475 | dependencies: 476 | locate-path "^6.0.0" 477 | path-exists "^4.0.0" 478 | 479 | flat-cache@^3.0.4: 480 | version "3.2.0" 481 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" 482 | integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== 483 | dependencies: 484 | flatted "^3.2.9" 485 | keyv "^4.5.3" 486 | rimraf "^3.0.2" 487 | 488 | flatted@^3.2.9: 489 | version "3.3.1" 490 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" 491 | integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== 492 | 493 | fs.realpath@^1.0.0: 494 | version "1.0.0" 495 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 496 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 497 | 498 | glob-parent@^5.1.2: 499 | version "5.1.2" 500 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 501 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 502 | dependencies: 503 | is-glob "^4.0.1" 504 | 505 | glob-parent@^6.0.2: 506 | version "6.0.2" 507 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 508 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 509 | dependencies: 510 | is-glob "^4.0.3" 511 | 512 | glob@^7.1.3: 513 | version "7.2.3" 514 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 515 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 516 | dependencies: 517 | fs.realpath "^1.0.0" 518 | inflight "^1.0.4" 519 | inherits "2" 520 | minimatch "^3.1.1" 521 | once "^1.3.0" 522 | path-is-absolute "^1.0.0" 523 | 524 | globals@^13.19.0: 525 | version "13.24.0" 526 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" 527 | integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== 528 | dependencies: 529 | type-fest "^0.20.2" 530 | 531 | globby@^11.1.0: 532 | version "11.1.0" 533 | resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" 534 | integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== 535 | dependencies: 536 | array-union "^2.1.0" 537 | dir-glob "^3.0.1" 538 | fast-glob "^3.2.9" 539 | ignore "^5.2.0" 540 | merge2 "^1.4.1" 541 | slash "^3.0.0" 542 | 543 | graphemer@^1.4.0: 544 | version "1.4.0" 545 | resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" 546 | integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== 547 | 548 | has-flag@^4.0.0: 549 | version "4.0.0" 550 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 551 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 552 | 553 | ignore@^5.2.0, ignore@^5.2.4: 554 | version "5.3.2" 555 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" 556 | integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== 557 | 558 | import-fresh@^3.2.1: 559 | version "3.3.0" 560 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 561 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 562 | dependencies: 563 | parent-module "^1.0.0" 564 | resolve-from "^4.0.0" 565 | 566 | imurmurhash@^0.1.4: 567 | version "0.1.4" 568 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 569 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 570 | 571 | inflight@^1.0.4: 572 | version "1.0.6" 573 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 574 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 575 | dependencies: 576 | once "^1.3.0" 577 | wrappy "1" 578 | 579 | inherits@2: 580 | version "2.0.4" 581 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 582 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 583 | 584 | is-extglob@^2.1.1: 585 | version "2.1.1" 586 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 587 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 588 | 589 | is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: 590 | version "4.0.3" 591 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 592 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 593 | dependencies: 594 | is-extglob "^2.1.1" 595 | 596 | is-number@^7.0.0: 597 | version "7.0.0" 598 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 599 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 600 | 601 | is-path-inside@^3.0.3: 602 | version "3.0.3" 603 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 604 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 605 | 606 | isexe@^2.0.0: 607 | version "2.0.0" 608 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 609 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 610 | 611 | js-yaml@^4.1.0: 612 | version "4.1.0" 613 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 614 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 615 | dependencies: 616 | argparse "^2.0.1" 617 | 618 | json-buffer@3.0.1: 619 | version "3.0.1" 620 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 621 | integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== 622 | 623 | json-schema-traverse@^0.4.1: 624 | version "0.4.1" 625 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 626 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 627 | 628 | json-stable-stringify-without-jsonify@^1.0.1: 629 | version "1.0.1" 630 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 631 | integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== 632 | 633 | keyv@^4.5.3: 634 | version "4.5.4" 635 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 636 | integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== 637 | dependencies: 638 | json-buffer "3.0.1" 639 | 640 | levn@^0.4.1: 641 | version "0.4.1" 642 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" 643 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== 644 | dependencies: 645 | prelude-ls "^1.2.1" 646 | type-check "~0.4.0" 647 | 648 | locate-path@^6.0.0: 649 | version "6.0.0" 650 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 651 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 652 | dependencies: 653 | p-locate "^5.0.0" 654 | 655 | lodash.merge@^4.6.2: 656 | version "4.6.2" 657 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 658 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 659 | 660 | merge2@^1.3.0, merge2@^1.4.1: 661 | version "1.4.1" 662 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 663 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 664 | 665 | micromatch@^4.0.4: 666 | version "4.0.7" 667 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" 668 | integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== 669 | dependencies: 670 | braces "^3.0.3" 671 | picomatch "^2.3.1" 672 | 673 | minimatch@9.0.3: 674 | version "9.0.3" 675 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" 676 | integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== 677 | dependencies: 678 | brace-expansion "^2.0.1" 679 | 680 | minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: 681 | version "3.1.2" 682 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 683 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 684 | dependencies: 685 | brace-expansion "^1.1.7" 686 | 687 | ms@2.1.2: 688 | version "2.1.2" 689 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 690 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 691 | 692 | natural-compare@^1.4.0: 693 | version "1.4.0" 694 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 695 | integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== 696 | 697 | once@^1.3.0: 698 | version "1.4.0" 699 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 700 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 701 | dependencies: 702 | wrappy "1" 703 | 704 | optionator@^0.9.3: 705 | version "0.9.4" 706 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" 707 | integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== 708 | dependencies: 709 | deep-is "^0.1.3" 710 | fast-levenshtein "^2.0.6" 711 | levn "^0.4.1" 712 | prelude-ls "^1.2.1" 713 | type-check "^0.4.0" 714 | word-wrap "^1.2.5" 715 | 716 | p-limit@^3.0.2: 717 | version "3.1.0" 718 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 719 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 720 | dependencies: 721 | yocto-queue "^0.1.0" 722 | 723 | p-locate@^5.0.0: 724 | version "5.0.0" 725 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 726 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 727 | dependencies: 728 | p-limit "^3.0.2" 729 | 730 | parent-module@^1.0.0: 731 | version "1.0.1" 732 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 733 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 734 | dependencies: 735 | callsites "^3.0.0" 736 | 737 | path-exists@^4.0.0: 738 | version "4.0.0" 739 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 740 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 741 | 742 | path-is-absolute@^1.0.0: 743 | version "1.0.1" 744 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 745 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 746 | 747 | path-key@^3.1.0: 748 | version "3.1.1" 749 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 750 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 751 | 752 | path-type@^4.0.0: 753 | version "4.0.0" 754 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 755 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 756 | 757 | picomatch@^2.3.1: 758 | version "2.3.1" 759 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 760 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 761 | 762 | prelude-ls@^1.2.1: 763 | version "1.2.1" 764 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 765 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 766 | 767 | prettier@^3.1.0: 768 | version "3.3.3" 769 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" 770 | integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== 771 | 772 | punycode@^2.1.0: 773 | version "2.3.1" 774 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 775 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 776 | 777 | queue-microtask@^1.2.2: 778 | version "1.2.3" 779 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 780 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 781 | 782 | resolve-from@^4.0.0: 783 | version "4.0.0" 784 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 785 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 786 | 787 | reusify@^1.0.4: 788 | version "1.0.4" 789 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 790 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 791 | 792 | rimraf@^3.0.2: 793 | version "3.0.2" 794 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 795 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 796 | dependencies: 797 | glob "^7.1.3" 798 | 799 | run-parallel@^1.1.9: 800 | version "1.2.0" 801 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 802 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 803 | dependencies: 804 | queue-microtask "^1.2.2" 805 | 806 | semver@^7.5.4: 807 | version "7.6.3" 808 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" 809 | integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== 810 | 811 | shebang-command@^2.0.0: 812 | version "2.0.0" 813 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 814 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 815 | dependencies: 816 | shebang-regex "^3.0.0" 817 | 818 | shebang-regex@^3.0.0: 819 | version "3.0.0" 820 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 821 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 822 | 823 | slash@^3.0.0: 824 | version "3.0.0" 825 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 826 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 827 | 828 | strip-ansi@^6.0.1: 829 | version "6.0.1" 830 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 831 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 832 | dependencies: 833 | ansi-regex "^5.0.1" 834 | 835 | strip-json-comments@^3.1.1: 836 | version "3.1.1" 837 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 838 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 839 | 840 | supports-color@^7.1.0: 841 | version "7.2.0" 842 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 843 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 844 | dependencies: 845 | has-flag "^4.0.0" 846 | 847 | text-table@^0.2.0: 848 | version "0.2.0" 849 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 850 | integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== 851 | 852 | to-regex-range@^5.0.1: 853 | version "5.0.1" 854 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 855 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 856 | dependencies: 857 | is-number "^7.0.0" 858 | 859 | ts-api-utils@^1.0.1: 860 | version "1.3.0" 861 | resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" 862 | integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== 863 | 864 | type-check@^0.4.0, type-check@~0.4.0: 865 | version "0.4.0" 866 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" 867 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== 868 | dependencies: 869 | prelude-ls "^1.2.1" 870 | 871 | type-fest@^0.20.2: 872 | version "0.20.2" 873 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 874 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 875 | 876 | typescript@^5.2.2: 877 | version "5.5.4" 878 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" 879 | integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== 880 | 881 | undici-types@~5.26.4: 882 | version "5.26.5" 883 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" 884 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== 885 | 886 | uri-js@^4.2.2: 887 | version "4.4.1" 888 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 889 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 890 | dependencies: 891 | punycode "^2.1.0" 892 | 893 | which@^2.0.1: 894 | version "2.0.2" 895 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 896 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 897 | dependencies: 898 | isexe "^2.0.0" 899 | 900 | word-wrap@^1.2.5: 901 | version "1.2.5" 902 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" 903 | integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== 904 | 905 | wrappy@1: 906 | version "1.0.2" 907 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 908 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 909 | 910 | yocto-queue@^0.1.0: 911 | version "0.1.0" 912 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 913 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 914 | 915 | zod@^3.22.4: 916 | version "3.23.8" 917 | resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" 918 | integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== 919 | --------------------------------------------------------------------------------