diff --git a/.gitignore b/.gitignore index e76c2324..9ba7f7c9 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,7 @@ coverage.xml .hypothesis/ .pytest_cache/ cover/ +*/coverage @@ -221,6 +222,7 @@ env.bak/ venv.bak/ # End of https://www.toptal.com/developers/gitignore/api/node,java,python,go .idea +.run *.key *.pem *.pub @@ -239,3 +241,10 @@ venv.bak/ # Playwright playwright-report/ test-results/ + +# Ignoring all the extra files generated by openapi-generator-cli +frontend/src/service/recreation-resource/.gitignore +frontend/src/service/recreation-resource/.npmignore +frontend/src/service/recreation-resource/.openapi-generator-ignore +frontend/src/service/recreation-resource/git_push.sh +frontend/src/service/recreation-resource/.openapi-generator \ No newline at end of file diff --git a/README.md b/README.md index 66af31bb..5b7455b3 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,57 @@ npm install npm run dev ``` +### **OpenAPI/Swagger Documentation** + +The backend uses NestJS's built-in Swagger module (@nestjs/swagger) to +automatically generate OpenAPI documentation from TypeScript decorators. + +#### **Swagger Decorators** + +Decorators are used throughout the codebase to provide metadata for API +documentation: + +- @ApiTags() - Groups related endpoints together +- @ApiOperation() - Describes what an endpoint does +- @ApiResponse() - Documents possible response types +- @ApiProperty() - Documents DTO properties and their types + +Example usage in a controller: + +```tsx +@ApiTags("parks") +@Controller("parks") +export class ParksController { + @Get() + @ApiOperation({ summary: "Get all parks" }) + @ApiResponse({ + status: 200, + description: "List of parks returned", + type: [ParkDto], + }) + findAll(): Promise { + return this.parksService.findAll(); + } +} +``` + +#### **Accessing Generated Documentation** + +When running the backend server, Swagger UI is available at: + +`http://localhost:3000/api/docs` + +The raw OpenAPI specification can be accessed at: + +`http://localhost:3000/api/docs-json` + +This documentation is automatically generated from the TypeScript code and is +used to: + +- Provide interactive API documentation through Swagger UI +- Generate TypeScript client types using openapi-generator +- Ensure API consistency and type safety across the frontend and backend + ### Frontend Create an `.env` file in the `frontend` directory using the example in @@ -75,6 +126,32 @@ npm run dev Navigate to `http://localhost:3000` in your web browser to view the application. +### Generate Client Library + +#### Prerequisites + +Install Java Development Kit (JDK) 17: + +```bash +brew install openjdk@17 +``` + +#### Generate TypeScript Axios Client + +Run the following command to generate the TypeScript client library from your +OpenAPI specification: + +```bash +npx openapi-generator-cli generate -i http://localhost:3000/api/docs-json -g typescript-axios -o src/service/recreation-resource --skip-validate-spec +``` + +This command will: + +- Generate TypeScript client code using Axios +- Use the OpenAPI spec from your local NestJS server which should be running on + port **3000** +- Output the generated code to `src/service/recreation-resource` directory + ## Pre-commit hooks Pre-commit is set up to run checks for linting, formatting, and secrets. diff --git a/backend/package-lock.json b/backend/package-lock.json index 865ecb08..15bbbc14 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -4,7 +4,6 @@ "requires": true, "packages": { "": { - "name": "backend", "license": "Apache-2.0", "dependencies": { "@nestjs/cli": "^11.0.2", diff --git a/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.spec.ts b/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.spec.ts new file mode 100644 index 00000000..0b8a8f52 --- /dev/null +++ b/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.spec.ts @@ -0,0 +1,37 @@ +import { PaginatedRecreationResourceDto } from "./paginated-recreation-resouce.dto"; +import { RecreationResourceDto } from "./recreation-resource.dto"; + +const recResourceArrayResolved: RecreationResourceDto[] = [ + new RecreationResourceDto(), + new RecreationResourceDto(), + new RecreationResourceDto(), + new RecreationResourceDto(), +]; + +describe("PaginatedRecreationResourceDto", () => { + it("should validate the structure of paginated response", () => { + const paginatedResponse = new PaginatedRecreationResourceDto(); + paginatedResponse.data = recResourceArrayResolved; + paginatedResponse.total = 4; + paginatedResponse.page = 1; + paginatedResponse.limit = 10; + + expect(paginatedResponse).toHaveProperty("data"); + expect(paginatedResponse).toHaveProperty("total"); + expect(paginatedResponse).toHaveProperty("page"); + expect(Array.isArray(paginatedResponse.data)).toBe(true); + expect(typeof paginatedResponse.total).toBe("number"); + expect(typeof paginatedResponse.page).toBe("number"); + }); + + it("should handle empty data array", () => { + const emptyPaginatedResponse = new PaginatedRecreationResourceDto(); + emptyPaginatedResponse.data = []; + emptyPaginatedResponse.total = 0; + emptyPaginatedResponse.page = 1; + emptyPaginatedResponse.limit = 10; + + expect(emptyPaginatedResponse.data).toHaveLength(0); + expect(emptyPaginatedResponse.total).toBe(0); + }); +}); diff --git a/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.ts b/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.ts new file mode 100644 index 00000000..097b924b --- /dev/null +++ b/backend/src/recreation-resource/dto/paginated-recreation-resouce.dto.ts @@ -0,0 +1,16 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { RecreationResourceDto } from "./recreation-resource.dto"; + +export class PaginatedRecreationResourceDto { + @ApiProperty({ type: [RecreationResourceDto] }) + data: RecreationResourceDto[]; + + @ApiProperty() + total: number; + + @ApiProperty() + page: number; + + @ApiProperty() + limit: number; +} diff --git a/backend/src/recreation-resource/dto/recreation-resource.dto.spec.ts b/backend/src/recreation-resource/dto/recreation-resource.dto.spec.ts new file mode 100644 index 00000000..a424cc5c --- /dev/null +++ b/backend/src/recreation-resource/dto/recreation-resource.dto.spec.ts @@ -0,0 +1,87 @@ +import { + RecreationActivityDto, + RecreationStatusDto, + RecreationResourceDto, +} from "./recreation-resource.dto"; + +describe("Recreation DTOs", () => { + describe("RecreationActivityDto", () => { + it("should create a valid RecreationActivityDto instance", () => { + const activity = new RecreationActivityDto(); + activity.recreation_activity_code = "HIKING"; + activity.description = "Hiking trails available for all skill levels"; + + expect(activity instanceof RecreationActivityDto).toBeTruthy(); + expect(activity.recreation_activity_code).toBeDefined(); + expect(activity.description).toBeDefined(); + }); + }); + + describe("RecreationStatusDto", () => { + it("should create a valid RecreationStatusDto", () => { + const status = new RecreationStatusDto(); + status.status_code = "CLOSED"; + status.comment = "Temporary closure due to weather conditions"; + status.description = "The facility is currently closed to visitors"; + + expect(status.status_code).toBeDefined(); + expect(status.description).toBeDefined(); + }); + + it("should allow null comment", () => { + const status: RecreationStatusDto = { + status_code: "OPEN", + comment: null, + description: "The facility is open", + }; + + expect(status.comment).toBeNull(); + }); + }); + + describe("RecreationResourceDto", () => { + it("should create a valid RecreationResourceDto", () => { + const resource: RecreationResourceDto = { + rec_resource_id: "rec-123-abc", + name: "Evergreen Valley Campground", + description: + "A scenic campground nestled in the heart of Evergreen Valley", + site_location: "123 Forest Road, Mountain View, CA 94043", + recreation_activity: [ + { + recreation_activity_code: "HIKING", + description: "Hiking trails available for all skill levels", + }, + ], + recreation_status: { + status_code: "OPEN", + comment: null, + description: "The facility is open", + }, + }; + + expect(resource.rec_resource_id).toBeDefined(); + expect(resource.name.length).toBeGreaterThanOrEqual(1); + expect(resource.name.length).toBeLessThanOrEqual(100); + expect(Array.isArray(resource.recreation_activity)).toBeTruthy(); + expect(resource.recreation_status).toBeDefined(); + }); + + it("should allow null description", () => { + const resource: RecreationResourceDto = { + rec_resource_id: "rec-123-abc", + name: "Test Resource", + description: null, + site_location: "Test Location", + recreation_activity: [], + recreation_status: { + status_code: "OPEN", + comment: null, + description: "Open", + }, + }; + + expect(resource.description).toBeNull(); + }); + }); +}); diff --git a/backend/src/recreation-resource/dto/recreation-resource.dto.ts b/backend/src/recreation-resource/dto/recreation-resource.dto.ts index db8b1dfd..d14e07c3 100644 --- a/backend/src/recreation-resource/dto/recreation-resource.dto.ts +++ b/backend/src/recreation-resource/dto/recreation-resource.dto.ts @@ -1,40 +1,77 @@ import { ApiProperty } from "@nestjs/swagger"; +export class RecreationActivityDto { + @ApiProperty({ + description: "Unique code identifying the recreation activity", + example: "HIKING", + }) + recreation_activity_code: string; + + @ApiProperty({ + description: "Detailed description of the activity", + example: "Hiking trails available for all skill levels", + }) + description: string; +} + +export class RecreationStatusDto { + @ApiProperty({ + description: "Status code of the resource", + }) + status_code: string; + + @ApiProperty({ + description: "Additional status information", + example: "Temporary closure due to weather conditions", + nullable: true, + }) + comment: string; + + @ApiProperty({ + description: "Detailed status description", + example: "The facility is currently closed to visitors", + }) + description: string; +} + export class RecreationResourceDto { @ApiProperty({ - description: "The ID of the Recreation Resource", + description: "Unique identifier of the Recreation Resource", + example: "rec-123-abc", + format: "uuid", }) rec_resource_id: string; @ApiProperty({ - description: "The name of the Recreation Resource", + description: "Official name of the Recreation Resource", + example: "Evergreen Valley Campground", + minLength: 1, + maxLength: 100, }) name: string; @ApiProperty({ - description: "The description of the Recreation Resource", + description: "Detailed description of the Recreation Resource", + example: "A scenic campground nestled in the heart of Evergreen Valley", + nullable: true, }) description: string; @ApiProperty({ - description: "The location of the Recreation Resource", + description: "Physical location of the Recreation Resource", + example: "123 Forest Road, Mountain View, CA 94043", }) site_location: string; @ApiProperty({ - description: "The list of available activities at the Recreation Resource", + description: "List of recreational activities available at this resource", + type: [RecreationActivityDto], }) - recreation_activity: { - recreation_activity_code: string; - description: string; - }[]; + recreation_activity: RecreationActivityDto[]; @ApiProperty({ - description: "The status of the Recreation Resource", + description: "Current operational status of the Recreation Resource", + type: RecreationStatusDto, }) - recreation_status: { - status_code: string; - comment: string; - description: string; - }; + recreation_status: RecreationStatusDto; } diff --git a/backend/src/recreation-resource/recreation-resource.controller.spec.ts b/backend/src/recreation-resource/recreation-resource.controller.spec.ts index 82716632..f1561f98 100644 --- a/backend/src/recreation-resource/recreation-resource.controller.spec.ts +++ b/backend/src/recreation-resource/recreation-resource.controller.spec.ts @@ -69,4 +69,43 @@ describe("RecreationResourceController", () => { } }); }); + + describe("searchRecreationResources", () => { + it("should return paginated recreation resources", async () => { + const mockResult = { + data: [ + { + rec_resource_id: "REC0001", + name: "Rec site 1", + }, + ], + total: 1, + page: 1, + limit: 10, + }; + + vi.spyOn(recService, "searchRecreationResources").mockResolvedValue( + mockResult, + ); + + const result = await controller.searchRecreationResources("test", 10, 1); + expect(result).toBe(mockResult); + }); + + it("should handle empty search results", async () => { + const mockResult = { + data: [], + total: 0, + page: 1, + limit: 10, + }; + + vi.spyOn(recService, "searchRecreationResources").mockResolvedValue( + mockResult, + ); + + const result = await controller.searchRecreationResources("", 10, 1); + expect(result).toBe(mockResult); + }); + }); }); diff --git a/backend/src/recreation-resource/recreation-resource.controller.ts b/backend/src/recreation-resource/recreation-resource.controller.ts index 5a1292f4..8ff7e325 100644 --- a/backend/src/recreation-resource/recreation-resource.controller.ts +++ b/backend/src/recreation-resource/recreation-resource.controller.ts @@ -1,7 +1,8 @@ import { Controller, Get, HttpException, Param, Query } from "@nestjs/common"; -import { ApiTags } from "@nestjs/swagger"; +import { ApiOperation, ApiQuery, ApiResponse, ApiTags } from "@nestjs/swagger"; import { RecreationResourceService } from "./recreation-resource.service"; import { RecreationResourceDto } from "./dto/recreation-resource.dto"; +import { PaginatedRecreationResourceDto } from "./dto/paginated-recreation-resouce.dto"; @ApiTags("recreation-resource") @Controller({ path: "recreation-resource", version: "1" }) @@ -10,22 +11,56 @@ export class RecreationResourceController { private readonly recreationResourceService: RecreationResourceService, ) {} + @ApiOperation({ + summary: "Search recreation resources", + operationId: "searchRecreationResources", + }) + @ApiQuery({ + name: "filter", + required: false, + type: String, + description: "Search filter", + }) + @ApiQuery({ + name: "limit", + required: false, + type: Number, + description: "Number of items per page", + }) + @ApiQuery({ + name: "page", + required: false, + type: Number, + description: "Page number", + }) + @ApiResponse({ + status: 200, + description: "Resources found", + type: PaginatedRecreationResourceDto, + }) @Get("search") // it must be ahead Get(":id") to avoid conflict async searchRecreationResources( @Query("filter") filter: string = "", @Query("limit") limit?: number, @Query("page") page: number = 1, - ): Promise<{ data: RecreationResourceDto[]; total: number; page: number }> { - const response = - await this.recreationResourceService.searchRecreationResources( - page, - filter ?? "", - limit ? parseInt(String(limit)) : undefined, - ); - - return response; + ): Promise { + return await this.recreationResourceService.searchRecreationResources( + page, + filter ?? "", + limit ? parseInt(String(limit)) : undefined, + ); } + @ApiOperation({ + summary: "Find recreation resource by ID", + operationId: "getRecreationResourceById", + }) + @ApiResponse({ + status: 200, + description: "Resource found", + type: RecreationResourceDto, + }) + @ApiResponse({ status: 404, description: "Resource not found" }) @Get(":id") async findOne(@Param("id") id: string): Promise { const recResource = await this.recreationResourceService.findOne(id); diff --git a/backend/src/recreation-resource/recreation-resource.service.ts b/backend/src/recreation-resource/recreation-resource.service.ts index 5c61c36f..8f5cef78 100644 --- a/backend/src/recreation-resource/recreation-resource.service.ts +++ b/backend/src/recreation-resource/recreation-resource.service.ts @@ -2,6 +2,7 @@ import { Injectable } from "@nestjs/common"; import { Prisma } from "@prisma/client"; import { PrismaService } from "src/prisma.service"; import { RecreationResourceDto } from "./dto/recreation-resource.dto"; +import { PaginatedRecreationResourceDto } from "./dto/paginated-recreation-resouce.dto"; interface RecreationActivityWithDescription { with_description: { @@ -93,7 +94,7 @@ export class RecreationResourceService { page: number = 1, filter: string = "", limit?: number, - ): Promise { + ): Promise { // 10 page limit - max 100 records since if no limit we fetch page * limit if (page > 10 && !limit) { throw new Error("Maximum page limit is 10 when no limit is provided"); diff --git a/frontend/openapitools.json b/frontend/openapitools.json new file mode 100644 index 00000000..973a005e --- /dev/null +++ b/frontend/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.11.0" + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ce42ba71..1f122817 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -31,6 +31,7 @@ "@eslint/compat": "^1.2.4", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.17.0", + "@openapitools/openapi-generator-cli": "^2.16.3", "@playwright/test": "^1.49.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", @@ -1551,6 +1552,16 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@mswjs/interceptors": { "version": "0.37.1", "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.37.1.tgz", @@ -1569,6 +1580,113 @@ "node": ">=18" } }, + "node_modules/@nestjs/axios": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.1.3.tgz", + "integrity": "sha512-RZ/63c1tMxGLqyG3iOCVt7A72oy4x1eM6QEhd4KzCYpaVWW0igq0WSREeRoEZhIxRcZfDfIIkvsOMiM7yfVGZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "axios": "^1.3.1", + "rxjs": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/@nestjs/common": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.4.15.tgz", + "integrity": "sha512-vaLg1ZgwhG29BuLDxPA9OAcIlgqzp9/N8iG0wGapyUNTf4IY4O6zAHgN6QalwLhFxq7nOI021vdRojR1oF3bqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/core": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.4.15.tgz", + "integrity": "sha512-UBejmdiYwaH6fTsz2QFBlC1cJHM+3UDeLZN+CiP9I1fRv2KlBZsmozGLbV5eS1JAVWJB4T5N5yQ0gjN8ZvcS2w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.3.0", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nestjs/core/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nuxtjs/opencollective": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, "node_modules/@open-draft/deferred-promise": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", @@ -1594,6 +1712,109 @@ "dev": true, "license": "MIT" }, + "node_modules/@openapitools/openapi-generator-cli": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.16.3.tgz", + "integrity": "sha512-HUpxQW45MLoWruXPvwnS2p6PkbnEIeWuDq4AembALRNGbIbg158k3peBCIbnn4PzGura9TnhaPPjOl3BF5PinQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@nestjs/axios": "3.1.3", + "@nestjs/common": "10.4.15", + "@nestjs/core": "10.4.15", + "@nuxtjs/opencollective": "0.3.2", + "axios": "1.7.9", + "chalk": "4.1.2", + "commander": "8.3.0", + "compare-versions": "4.1.4", + "concurrently": "6.5.1", + "console.table": "0.10.0", + "fs-extra": "10.1.0", + "glob": "9.3.5", + "inquirer": "8.2.6", + "lodash": "4.17.21", + "proxy-agent": "6.5.0", + "reflect-metadata": "0.1.13", + "rxjs": "7.8.1", + "tslib": "2.8.1" + }, + "bin": { + "openapi-generator-cli": "main.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/openapi_generator" + } + }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", @@ -2357,6 +2578,13 @@ "node": ">= 6" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -3349,6 +3577,19 @@ "node": ">=12" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -3477,6 +3718,68 @@ "integrity": "sha512-BQQZftaO48FcE1Kof9CmXMFaAdqkcNorgc8CxesZv9nMbbTF1EFyQe89UOuh//QMmdtfUDXyO8rgUalemL5ODA==", "dev": true }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bootstrap": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", @@ -3721,6 +4024,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -3771,6 +4081,32 @@ "node": ">=6" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -3814,6 +4150,16 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3865,6 +4211,13 @@ "dev": true, "peer": true }, + "node_modules/compare-versions": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==", + "dev": true, + "license": "MIT" + }, "node_modules/compress-commons": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", @@ -3888,6 +4241,144 @@ "dev": true, "license": "MIT" }, + "node_modules/concurrently": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz", + "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "bin": { + "concurrently": "bin/concurrently.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/concurrently/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/concurrently/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/concurrently/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/console.table": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", + "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "easy-table": "1.1.0" + }, + "engines": { + "node": "> 0.10" + } + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -3983,6 +4474,16 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -4048,6 +4549,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -4088,6 +4606,19 @@ "dev": true, "license": "MIT" }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -4124,6 +4655,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4282,6 +4828,16 @@ "dev": true, "license": "MIT" }, + "node_modules/easy-table": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", + "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "wcwidth": ">=1.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.63", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", @@ -4880,6 +5436,34 @@ "node": ">=12.0.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4907,6 +5491,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", @@ -4921,6 +5512,32 @@ "dev": true, "license": "MIT" }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5059,7 +5676,32 @@ "mime-types": "^2.1.12" }, "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" } }, "node_modules/fs.realpath": { @@ -5195,6 +5837,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -6013,6 +6670,50 @@ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/inquirer/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -6036,6 +6737,20 @@ "loose-envify": "^1.0.0" } }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -6229,6 +6944,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -6386,6 +7111,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -6496,6 +7234,16 @@ "node": ">=8" } }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=6" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -6594,6 +7342,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, "node_modules/jsdom": { "version": "26.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", @@ -6687,6 +7442,29 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -6829,6 +7607,23 @@ "dev": true, "license": "MIT" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6969,6 +7764,16 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -7118,6 +7923,16 @@ "dev": true, "peer": true }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -7301,6 +8116,22 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7319,6 +8150,40 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/outvariant": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", @@ -7405,6 +8270,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pac-proxy-agent": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz", + "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -7813,6 +8712,36 @@ "react": ">=0.14.0" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -8094,6 +9023,13 @@ "node": ">=8" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -8184,6 +9120,27 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -8253,6 +9210,16 @@ "dev": true, "license": "MIT" }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -9019,6 +9986,47 @@ "node": ">=18" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9047,6 +10055,19 @@ "source-map": "^0.6.0" } }, + "node_modules/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -9520,6 +10541,13 @@ "b4a": "^1.6.4" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -9626,6 +10654,19 @@ "dev": true, "license": "MIT" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9675,6 +10716,16 @@ "node": ">=18" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/tsconfck": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz", @@ -9821,6 +10872,19 @@ "node": ">=14.17" } }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -10179,6 +11243,16 @@ "node": ">=10.13.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 86a17846..12d97e2a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,8 @@ "e2e:ui": "npx happo-e2e -- npx playwright test --ui", "preview": "vite preview", "test": "vitest --mode test", - "test:cov": "vitest run --mode test --coverage" + "test:cov": "vitest run --mode test --coverage", + "generate-api": "npx openapi-generator-cli generate -i http://localhost:3000/api/docs-json -g typescript-axios -o src/service/recreation-resource --skip-validate-spec" }, "dependencies": { "@bcgov/bc-sans": "^2.1.0", @@ -39,6 +40,7 @@ "@eslint/compat": "^1.2.4", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.17.0", + "@openapitools/openapi-generator-cli": "^2.16.3", "@playwright/test": "^1.49.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", diff --git a/frontend/src/components/rec-resource/RecResourcePage.test.tsx b/frontend/src/components/rec-resource/RecResourcePage.test.tsx index 7f2faa85..4b46adfe 100644 --- a/frontend/src/components/rec-resource/RecResourcePage.test.tsx +++ b/frontend/src/components/rec-resource/RecResourcePage.test.tsx @@ -2,33 +2,35 @@ import { vi } from 'vitest'; import { act, render, screen } from '@testing-library/react'; import RecResourcePage from '@/components/rec-resource/RecResourcePage'; import { BrowserRouter as Router } from 'react-router-dom'; -import apiService from '@/service/api-service'; +import { useRecreationResourceApi } from '@/service/hooks/useRecreationResourceApi'; +import * as routerDom from 'react-router-dom'; +// Mock data const mockResource = { rec_resource_id: 'REC1234', name: 'Resource Name', description: 'Resource Description', site_location: 'Resource Location', recreation_activity: [ - { - recreation_activity_code: '01', - description: 'Activity Description', - }, + { recreation_activity_code: '01', description: 'Activity Description' }, ], - recreation_status: { - status_code: '01', - description: 'Open', - }, + recreation_status: { status_code: '01', description: 'Open' }, }; +// Setup mocks +vi.mock('@/service/hooks/useRecreationResourceApi'); +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + useParams: vi.fn(), +})); + describe('RecResourcePage', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - it('renders the not found message when the resource is not found', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue(null), - }); + const renderComponent = async (mockApiResponse: any) => { + const mockApi = { + getRecreationResourceById: vi.fn().mockResolvedValue(mockApiResponse), + }; + (useRecreationResourceApi as any).mockReturnValue(mockApi); + await act(async () => { render( @@ -36,182 +38,104 @@ describe('RecResourcePage', () => { , ); }); - const notFoundElement = screen.getByText(/Resource not found/i); + }; - expect(notFoundElement).toBeInTheDocument(); + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(routerDom.useParams).mockReturnValue({ id: 'REC1234' }); }); - it('renders the resource when the resource is found', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ - data: mockResource, - }), + describe('Error handling', () => { + it('displays not found message on error', async () => { + const mockApi = { + getRecreationResourceById: vi + .fn() + .mockRejectedValue(new Error('Not found')), + }; + (useRecreationResourceApi as any).mockReturnValue(mockApi); + + await act(async () => { + render( + + + , + ); + }); + + expect(screen.getByText(/Resource not found/i)).toBeInTheDocument(); }); - await act(async () => { - render( - - - , - ); - }); - const nameElement = screen.getByText(/Resource Name/i); - const descriptionElement = screen.getByText(/Resource Description/i); - const locationElement = screen.getByText(/Resource Location/i); - - expect(nameElement).toBeInTheDocument(); - expect(descriptionElement).toBeInTheDocument(); - expect(locationElement).toBeInTheDocument(); }); - it('renders the Things to Do section when recreation_activity is present', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ - data: mockResource, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const thingsToDoElement = screen.getByRole('heading', { - name: /Things to Do/i, + describe('Activities section', () => { + it('shows activities when present', async () => { + await renderComponent({ data: mockResource }); + + expect( + screen.getByRole('heading', { name: /Things to Do/i }), + ).toBeInTheDocument(); + expect(screen.getByText(/Activity Description/i)).toBeInTheDocument(); }); - const activityElement = screen.getByText(/Activity Description/i); - expect(thingsToDoElement).toBeInTheDocument(); - expect(activityElement).toBeInTheDocument(); - }); + it('hides activities when empty', async () => { + await renderComponent({ + data: { ...mockResource, recreation_activity: [] }, + }); - it('does not render the Things to Do section when recreation_activity is not present', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ - data: { - ...mockResource, - recreation_activity: [], - }, - }), + expect( + screen.queryByRole('heading', { name: /Things to Do/i }), + ).toBeNull(); + expect(screen.queryByText(/Activity Description/i)).toBeNull(); }); - await act(async () => { - render( - - - , - ); - }); - const thingsToDoElement = screen.queryByRole('heading', { - name: /Things to Do/i, - }); - const activityElement = screen.queryByText(/Activity Description/i); - - expect(thingsToDoElement).toBeNull(); - expect(activityElement).toBeNull(); }); - it('renders the Open status when recreation_status is present', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ - data: mockResource, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const statusIcon = screen.getByAltText(/Site Open status icon/i); - const statusDescription = screen.getByText(/Open/i); + describe('Status handling', () => { + it('displays open status correctly', async () => { + await renderComponent({ data: mockResource }); - expect(statusIcon).toBeInTheDocument(); - expect(statusDescription).toBeInTheDocument(); - }); + expect(screen.getByAltText(/Site Open status icon/i)).toBeInTheDocument(); + expect(screen.getByText(/Open/i)).toBeInTheDocument(); + }); - it('renders the Closed status when recreation_status is present', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ + it('displays closed status correctly', async () => { + await renderComponent({ data: { ...mockResource, - recreation_status: { - status_code: '02', - description: 'Closed', - }, + recreation_status: { status_code: '02', description: 'Closed' }, }, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const statusIcon = screen.getByAltText(/Site Closed status icon/i); - const statusDescription = screen.getByText(/Closed/i); + }); - expect(statusIcon).toBeInTheDocument(); - expect(statusDescription).toBeInTheDocument(); - }); + expect( + screen.getByAltText(/Site Closed status icon/i), + ).toBeInTheDocument(); + expect(screen.getByText(/Closed/i)).toBeInTheDocument(); + }); - it('does not render the status when recreation_status is not present', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ + it('handles missing status gracefully', async () => { + await renderComponent({ data: { ...mockResource, - recreation_status: { - status_code: undefined, - description: undefined, - comment: undefined, - }, + recreation_status: { status_code: undefined, description: undefined }, }, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const statusIcon = screen.queryByAltText(/Site Open status icon/i); - const statusDescription = screen.queryByText(/Open/i); + }); - expect(statusIcon).toBeNull(); - expect(statusDescription).toBeNull(); - }); + expect(screen.queryByAltText(/Site.*status icon/i)).toBeNull(); + }); - it('does not render an unknown status when the status code is not recognized', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ + it('ignores unknown status codes', async () => { + await renderComponent({ data: { ...mockResource, - recreation_status: { - status_code: '03', - description: 'Unknown', - }, + recreation_status: { status_code: '03', description: 'Unknown' }, }, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const statusIcon = screen.queryByAltText(/Site Unknown status icon/i); - const statusDescription = screen.queryByText(/Unknown/i); + }); - expect(statusIcon).toBeNull(); - expect(statusDescription).toBeNull(); + expect(screen.queryByAltText(/Site.*status icon/i)).toBeNull(); + }); }); - it('renders the Closures section when recreation_status is closed', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ + describe('Closures section', () => { + it('shows closure information when closed', async () => { + await renderComponent({ data: { ...mockResource, recreation_status: { @@ -220,27 +144,16 @@ describe('RecResourcePage', () => { comment: 'This site is closed', }, }, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const closuresElement = screen.getByRole('heading', { - name: /Closures/i, - }); - const commentElement = screen.getByText(/This site is closed/i); + }); - expect(closuresElement).toBeInTheDocument(); - expect(commentElement).toBeInTheDocument(); - }); + expect( + screen.getByRole('heading', { name: /Closures/i }), + ).toBeInTheDocument(); + expect(screen.getByText(/This site is closed/i)).toBeInTheDocument(); + }); - it('does not render the Closures section when recreation_status is open', async () => { - vi.spyOn(apiService as any, 'getAxiosInstance').mockReturnValue({ - get: vi.fn().mockResolvedValue({ + it('hides closure information when open', async () => { + await renderComponent({ data: { ...mockResource, recreation_status: { @@ -249,21 +162,10 @@ describe('RecResourcePage', () => { comment: 'This site is open', }, }, - }), - }); - await act(async () => { - render( - - - , - ); - }); - const closuresElement = screen.queryByRole('heading', { - name: /Closures/i, - }); - const commentElement = screen.queryByText(/This site is open/i); + }); - expect(closuresElement).toBeNull(); - expect(commentElement).toBeNull(); + expect(screen.queryByRole('heading', { name: /Closures/i })).toBeNull(); + expect(screen.queryByText(/This site is open/i)).toBeNull(); + }); }); }); diff --git a/frontend/src/components/rec-resource/RecResourcePage.tsx b/frontend/src/components/rec-resource/RecResourcePage.tsx index 1af2bac3..fd5d0f43 100644 --- a/frontend/src/components/rec-resource/RecResourcePage.tsx +++ b/frontend/src/components/rec-resource/RecResourcePage.tsx @@ -1,8 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import useScrollSpy from 'react-use-scrollspy'; -import apiService from '@/service/api-service'; -import type { AxiosResponse } from '~/axios'; import BreadCrumbs from '@/components/layout/BreadCrumbs'; import { Camping, @@ -16,8 +14,9 @@ import { import Status from '@/components/rec-resource/Status'; import PageMenu from '@/components/layout/PageMenu'; import locationDot from '@/images/fontAwesomeIcons/location-dot.svg'; -import { RecreationResource } from '@/components/rec-resource/types'; import '@/components/rec-resource/RecResource.scss'; +import { RecreationResourceDto } from '@/service/recreation-resource'; +import { useRecreationResourceApi } from '@/service/hooks/useRecreationResourceApi'; export const photosExample = [ { @@ -47,26 +46,28 @@ export const photosExample = [ ]; const RecResourcePage = () => { - const [recResource, setRecResource] = useState(); + const [recResource, setRecResource] = useState(); const [notFound, setNotFound] = useState(false); const { id } = useParams(); + const recreationResourceApi = useRecreationResourceApi(); + useEffect(() => { // Get a single recreation resource by forest file ID - apiService - .getAxiosInstance() - .get(`/v1/recreation-resource/${id}`) - .then((response: AxiosResponse) => { - setRecResource(response.data); - return response.data; - }) - .catch((error) => { - console.error(error); - setNotFound(true); - }); - // eslint-disable-next-line - }, []); + if (id) { + recreationResourceApi + .getRecreationResourceById(id) + .then((response) => { + setRecResource(response.data); + return response.data; + }) + .catch((error) => { + console.error(error); + setNotFound(true); + }); + } + }, [id]); const { recreation_activity, diff --git a/frontend/src/service/hooks/useRecreationResourceApi.test.ts b/frontend/src/service/hooks/useRecreationResourceApi.test.ts new file mode 100644 index 00000000..d1710172 --- /dev/null +++ b/frontend/src/service/hooks/useRecreationResourceApi.test.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest'; +import { useRecreationResourceApi } from './useRecreationResourceApi'; +import { RecreationResourceApi } from '@/service/recreation-resource'; + +describe('useRecreationResourceApi', () => { + it('should return RecreationResourceApi instance with empty basePath', () => { + const api = useRecreationResourceApi(); + + expect(api).toBeInstanceOf(RecreationResourceApi); + }); +}); diff --git a/frontend/src/service/hooks/useRecreationResourceApi.ts b/frontend/src/service/hooks/useRecreationResourceApi.ts new file mode 100644 index 00000000..5806159b --- /dev/null +++ b/frontend/src/service/hooks/useRecreationResourceApi.ts @@ -0,0 +1,12 @@ +import { + Configuration, + RecreationResourceApi, +} from '@/service/recreation-resource'; + +export const useRecreationResourceApi = () => { + const configuration = new Configuration({ + basePath: '', + }); + + return new RecreationResourceApi(configuration); +}; diff --git a/frontend/src/service/recreation-resource/api.ts b/frontend/src/service/recreation-resource/api.ts new file mode 100644 index 00000000..8c84b69b --- /dev/null +++ b/frontend/src/service/recreation-resource/api.ts @@ -0,0 +1,919 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Recreation Sites and Trails BC API + * RST API documentation + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { Configuration } from './configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { + DUMMY_BASE_URL, + assertParamExists, + setApiKeyToObject, + setBasicAuthToObject, + setBearerAuthToObject, + setOAuthToObject, + setSearchParams, + serializeDataIfNeeded, + toPathString, + createRequestFunction, +} from './common'; +import type { RequestArgs } from './base'; +// @ts-ignore +import { + BASE_PATH, + COLLECTION_FORMATS, + BaseAPI, + RequiredError, + operationServerMap, +} from './base'; + +/** + * + * @export + * @interface HealthControllerCheck200Response + */ +export interface HealthControllerCheck200Response { + /** + * + * @type {string} + * @memberof HealthControllerCheck200Response + */ + status?: string; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck200Response + */ + info?: { [key: string]: HealthControllerCheck200ResponseInfoValue } | null; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck200Response + */ + error?: { [key: string]: HealthControllerCheck200ResponseInfoValue } | null; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck200Response + */ + details?: { [key: string]: HealthControllerCheck200ResponseInfoValue }; +} +/** + * + * @export + * @interface HealthControllerCheck200ResponseInfoValue + */ +export interface HealthControllerCheck200ResponseInfoValue { + [key: string]: any; + + /** + * + * @type {string} + * @memberof HealthControllerCheck200ResponseInfoValue + */ + status: string; +} +/** + * + * @export + * @interface HealthControllerCheck503Response + */ +export interface HealthControllerCheck503Response { + /** + * + * @type {string} + * @memberof HealthControllerCheck503Response + */ + status?: string; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck503Response + */ + info?: { [key: string]: HealthControllerCheck200ResponseInfoValue } | null; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck503Response + */ + error?: { [key: string]: HealthControllerCheck200ResponseInfoValue } | null; + /** + * + * @type {{ [key: string]: HealthControllerCheck200ResponseInfoValue; }} + * @memberof HealthControllerCheck503Response + */ + details?: { [key: string]: HealthControllerCheck200ResponseInfoValue }; +} +/** + * + * @export + * @interface PaginatedRecreationResourceDto + */ +export interface PaginatedRecreationResourceDto { + /** + * + * @type {Array} + * @memberof PaginatedRecreationResourceDto + */ + data: Array; + /** + * + * @type {number} + * @memberof PaginatedRecreationResourceDto + */ + total: number; + /** + * + * @type {number} + * @memberof PaginatedRecreationResourceDto + */ + page: number; + /** + * + * @type {number} + * @memberof PaginatedRecreationResourceDto + */ + limit: number; +} +/** + * + * @export + * @interface RecreationActivityDto + */ +export interface RecreationActivityDto { + /** + * Unique code identifying the recreation activity + * @type {string} + * @memberof RecreationActivityDto + */ + recreation_activity_code: string; + /** + * Detailed description of the activity + * @type {string} + * @memberof RecreationActivityDto + */ + description: string; +} +/** + * + * @export + * @interface RecreationResourceDto + */ +export interface RecreationResourceDto { + /** + * Unique identifier of the Recreation Resource + * @type {string} + * @memberof RecreationResourceDto + */ + rec_resource_id: string; + /** + * Official name of the Recreation Resource + * @type {string} + * @memberof RecreationResourceDto + */ + name: string; + /** + * Detailed description of the Recreation Resource + * @type {string} + * @memberof RecreationResourceDto + */ + description: string | null; + /** + * Physical location of the Recreation Resource + * @type {string} + * @memberof RecreationResourceDto + */ + site_location: string; + /** + * List of recreational activities available at this resource + * @type {Array} + * @memberof RecreationResourceDto + */ + recreation_activity: Array; + /** + * Current operational status of the Recreation Resource + * @type {RecreationStatusDto} + * @memberof RecreationResourceDto + */ + recreation_status: RecreationStatusDto; +} +/** + * + * @export + * @interface RecreationStatusDto + */ +export interface RecreationStatusDto { + /** + * Status code of the resource + * @type {string} + * @memberof RecreationStatusDto + */ + status_code: string; + /** + * Additional status information + * @type {string} + * @memberof RecreationStatusDto + */ + comment: string | null; + /** + * Detailed status description + * @type {string} + * @memberof RecreationStatusDto + */ + description: string; +} + +/** + * AppApi - axios parameter creator + * @export + */ +export const AppApiAxiosParamCreator = function ( + configuration?: Configuration, +) { + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + appControllerGetHello: async ( + options: RawAxiosRequestConfig = {}, + ): Promise => { + const localVarPath = `/api`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { + method: 'GET', + ...baseOptions, + ...options, + }; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = + baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = { + ...localVarHeaderParameter, + ...headersFromBaseOptions, + ...options.headers, + }; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + }; +}; + +/** + * AppApi - functional programming interface + * @export + */ +export const AppApiFp = function (configuration?: Configuration) { + const localVarAxiosParamCreator = AppApiAxiosParamCreator(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async appControllerGetHello( + options?: RawAxiosRequestConfig, + ): Promise< + (axios?: AxiosInstance, basePath?: string) => AxiosPromise + > { + const localVarAxiosArgs = + await localVarAxiosParamCreator.appControllerGetHello(options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = + operationServerMap['AppApi.appControllerGetHello']?.[ + localVarOperationServerIndex + ]?.url; + return (axios, basePath) => + createRequestFunction( + localVarAxiosArgs, + globalAxios, + BASE_PATH, + configuration, + )(axios, localVarOperationServerBasePath || basePath); + }, + }; +}; + +/** + * AppApi - factory interface + * @export + */ +export const AppApiFactory = function ( + configuration?: Configuration, + basePath?: string, + axios?: AxiosInstance, +) { + const localVarFp = AppApiFp(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + appControllerGetHello(options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp + .appControllerGetHello(options) + .then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * AppApi - object-oriented interface + * @export + * @class AppApi + * @extends {BaseAPI} + */ +export class AppApi extends BaseAPI { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof AppApi + */ + public appControllerGetHello(options?: RawAxiosRequestConfig) { + return AppApiFp(this.configuration) + .appControllerGetHello(options) + .then((request) => request(this.axios, this.basePath)); + } +} + +/** + * HealthApi - axios parameter creator + * @export + */ +export const HealthApiAxiosParamCreator = function ( + configuration?: Configuration, +) { + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + healthControllerCheck: async ( + options: RawAxiosRequestConfig = {}, + ): Promise => { + const localVarPath = `/api/health`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { + method: 'GET', + ...baseOptions, + ...options, + }; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = + baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = { + ...localVarHeaderParameter, + ...headersFromBaseOptions, + ...options.headers, + }; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + }; +}; + +/** + * HealthApi - functional programming interface + * @export + */ +export const HealthApiFp = function (configuration?: Configuration) { + const localVarAxiosParamCreator = HealthApiAxiosParamCreator(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async healthControllerCheck( + options?: RawAxiosRequestConfig, + ): Promise< + ( + axios?: AxiosInstance, + basePath?: string, + ) => AxiosPromise + > { + const localVarAxiosArgs = + await localVarAxiosParamCreator.healthControllerCheck(options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = + operationServerMap['HealthApi.healthControllerCheck']?.[ + localVarOperationServerIndex + ]?.url; + return (axios, basePath) => + createRequestFunction( + localVarAxiosArgs, + globalAxios, + BASE_PATH, + configuration, + )(axios, localVarOperationServerBasePath || basePath); + }, + }; +}; + +/** + * HealthApi - factory interface + * @export + */ +export const HealthApiFactory = function ( + configuration?: Configuration, + basePath?: string, + axios?: AxiosInstance, +) { + const localVarFp = HealthApiFp(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + healthControllerCheck( + options?: RawAxiosRequestConfig, + ): AxiosPromise { + return localVarFp + .healthControllerCheck(options) + .then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * HealthApi - object-oriented interface + * @export + * @class HealthApi + * @extends {BaseAPI} + */ +export class HealthApi extends BaseAPI { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof HealthApi + */ + public healthControllerCheck(options?: RawAxiosRequestConfig) { + return HealthApiFp(this.configuration) + .healthControllerCheck(options) + .then((request) => request(this.axios, this.basePath)); + } +} + +/** + * MetricsApi - axios parameter creator + * @export + */ +export const MetricsApiAxiosParamCreator = function ( + configuration?: Configuration, +) { + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + metricsControllerGetMetrics: async ( + options: RawAxiosRequestConfig = {}, + ): Promise => { + const localVarPath = `/api/metrics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { + method: 'GET', + ...baseOptions, + ...options, + }; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = + baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = { + ...localVarHeaderParameter, + ...headersFromBaseOptions, + ...options.headers, + }; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + }; +}; + +/** + * MetricsApi - functional programming interface + * @export + */ +export const MetricsApiFp = function (configuration?: Configuration) { + const localVarAxiosParamCreator = MetricsApiAxiosParamCreator(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async metricsControllerGetMetrics( + options?: RawAxiosRequestConfig, + ): Promise< + (axios?: AxiosInstance, basePath?: string) => AxiosPromise + > { + const localVarAxiosArgs = + await localVarAxiosParamCreator.metricsControllerGetMetrics(options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = + operationServerMap['MetricsApi.metricsControllerGetMetrics']?.[ + localVarOperationServerIndex + ]?.url; + return (axios, basePath) => + createRequestFunction( + localVarAxiosArgs, + globalAxios, + BASE_PATH, + configuration, + )(axios, localVarOperationServerBasePath || basePath); + }, + }; +}; + +/** + * MetricsApi - factory interface + * @export + */ +export const MetricsApiFactory = function ( + configuration?: Configuration, + basePath?: string, + axios?: AxiosInstance, +) { + const localVarFp = MetricsApiFp(configuration); + return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + metricsControllerGetMetrics( + options?: RawAxiosRequestConfig, + ): AxiosPromise { + return localVarFp + .metricsControllerGetMetrics(options) + .then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * MetricsApi - object-oriented interface + * @export + * @class MetricsApi + * @extends {BaseAPI} + */ +export class MetricsApi extends BaseAPI { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MetricsApi + */ + public metricsControllerGetMetrics(options?: RawAxiosRequestConfig) { + return MetricsApiFp(this.configuration) + .metricsControllerGetMetrics(options) + .then((request) => request(this.axios, this.basePath)); + } +} + +/** + * RecreationResourceApi - axios parameter creator + * @export + */ +export const RecreationResourceApiAxiosParamCreator = function ( + configuration?: Configuration, +) { + return { + /** + * + * @summary Find recreation resource by ID + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getRecreationResourceById: async ( + id: string, + options: RawAxiosRequestConfig = {}, + ): Promise => { + // verify required parameter 'id' is not null or undefined + assertParamExists('getRecreationResourceById', 'id', id); + const localVarPath = `/api/v1/recreation-resource/{id}`.replace( + `{${'id'}}`, + encodeURIComponent(String(id)), + ); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { + method: 'GET', + ...baseOptions, + ...options, + }; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = + baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = { + ...localVarHeaderParameter, + ...headersFromBaseOptions, + ...options.headers, + }; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Search recreation resources + * @param {string} [filter] Search filter + * @param {number} [limit] Number of items per page + * @param {number} [page] Page number + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + searchRecreationResources: async ( + filter?: string, + limit?: number, + page?: number, + options: RawAxiosRequestConfig = {}, + ): Promise => { + const localVarPath = `/api/v1/recreation-resource/search`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { + method: 'GET', + ...baseOptions, + ...options, + }; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + if (filter !== undefined) { + localVarQueryParameter['filter'] = filter; + } + + if (limit !== undefined) { + localVarQueryParameter['limit'] = limit; + } + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = + baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = { + ...localVarHeaderParameter, + ...headersFromBaseOptions, + ...options.headers, + }; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + }; +}; + +/** + * RecreationResourceApi - functional programming interface + * @export + */ +export const RecreationResourceApiFp = function ( + configuration?: Configuration, +) { + const localVarAxiosParamCreator = + RecreationResourceApiAxiosParamCreator(configuration); + return { + /** + * + * @summary Find recreation resource by ID + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getRecreationResourceById( + id: string, + options?: RawAxiosRequestConfig, + ): Promise< + ( + axios?: AxiosInstance, + basePath?: string, + ) => AxiosPromise + > { + const localVarAxiosArgs = + await localVarAxiosParamCreator.getRecreationResourceById(id, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = + operationServerMap['RecreationResourceApi.getRecreationResourceById']?.[ + localVarOperationServerIndex + ]?.url; + return (axios, basePath) => + createRequestFunction( + localVarAxiosArgs, + globalAxios, + BASE_PATH, + configuration, + )(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Search recreation resources + * @param {string} [filter] Search filter + * @param {number} [limit] Number of items per page + * @param {number} [page] Page number + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async searchRecreationResources( + filter?: string, + limit?: number, + page?: number, + options?: RawAxiosRequestConfig, + ): Promise< + ( + axios?: AxiosInstance, + basePath?: string, + ) => AxiosPromise + > { + const localVarAxiosArgs = + await localVarAxiosParamCreator.searchRecreationResources( + filter, + limit, + page, + options, + ); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = + operationServerMap['RecreationResourceApi.searchRecreationResources']?.[ + localVarOperationServerIndex + ]?.url; + return (axios, basePath) => + createRequestFunction( + localVarAxiosArgs, + globalAxios, + BASE_PATH, + configuration, + )(axios, localVarOperationServerBasePath || basePath); + }, + }; +}; + +/** + * RecreationResourceApi - factory interface + * @export + */ +export const RecreationResourceApiFactory = function ( + configuration?: Configuration, + basePath?: string, + axios?: AxiosInstance, +) { + const localVarFp = RecreationResourceApiFp(configuration); + return { + /** + * + * @summary Find recreation resource by ID + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getRecreationResourceById( + id: string, + options?: RawAxiosRequestConfig, + ): AxiosPromise { + return localVarFp + .getRecreationResourceById(id, options) + .then((request) => request(axios, basePath)); + }, + /** + * + * @summary Search recreation resources + * @param {string} [filter] Search filter + * @param {number} [limit] Number of items per page + * @param {number} [page] Page number + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + searchRecreationResources( + filter?: string, + limit?: number, + page?: number, + options?: RawAxiosRequestConfig, + ): AxiosPromise { + return localVarFp + .searchRecreationResources(filter, limit, page, options) + .then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * RecreationResourceApi - object-oriented interface + * @export + * @class RecreationResourceApi + * @extends {BaseAPI} + */ +export class RecreationResourceApi extends BaseAPI { + /** + * + * @summary Find recreation resource by ID + * @param {string} id + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof RecreationResourceApi + */ + public getRecreationResourceById( + id: string, + options?: RawAxiosRequestConfig, + ) { + return RecreationResourceApiFp(this.configuration) + .getRecreationResourceById(id, options) + .then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Search recreation resources + * @param {string} [filter] Search filter + * @param {number} [limit] Number of items per page + * @param {number} [page] Page number + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof RecreationResourceApi + */ + public searchRecreationResources( + filter?: string, + limit?: number, + page?: number, + options?: RawAxiosRequestConfig, + ) { + return RecreationResourceApiFp(this.configuration) + .searchRecreationResources(filter, limit, page, options) + .then((request) => request(this.axios, this.basePath)); + } +} diff --git a/frontend/src/service/recreation-resource/base.ts b/frontend/src/service/recreation-resource/base.ts new file mode 100644 index 00000000..4170c669 --- /dev/null +++ b/frontend/src/service/recreation-resource/base.ts @@ -0,0 +1,91 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Recreation Sites and Trails BC API + * RST API documentation + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { Configuration } from './configuration'; +// Some imports not used depending on template conditions +// @ts-ignore +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; + +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ',', + ssv: ' ', + tsv: '\t', + pipes: '|', +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: RawAxiosRequestConfig; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor( + configuration?: Configuration, + protected basePath: string = BASE_PATH, + protected axios: AxiosInstance = globalAxios, + ) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath ?? basePath; + } + } +} + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + constructor( + public field: string, + msg?: string, + ) { + super(msg); + this.name = 'RequiredError'; + } +} + +interface ServerMap { + [key: string]: { + url: string; + description: string; + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = {}; diff --git a/frontend/src/service/recreation-resource/common.ts b/frontend/src/service/recreation-resource/common.ts new file mode 100644 index 00000000..72abbca4 --- /dev/null +++ b/frontend/src/service/recreation-resource/common.ts @@ -0,0 +1,202 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Recreation Sites and Trails BC API + * RST API documentation + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { Configuration } from './configuration'; +import type { RequestArgs } from './base'; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { RequiredError } from './base'; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com'; + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function ( + functionName: string, + paramName: string, + paramValue: unknown, +) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError( + paramName, + `Required parameter ${paramName} was null or undefined when calling ${functionName}.`, + ); + } +}; + +/** + * + * @export + */ +export const setApiKeyToObject = async function ( + object: any, + keyParamName: string, + configuration?: Configuration, +) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = + typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +}; + +/** + * + * @export + */ +export const setBasicAuthToObject = function ( + object: any, + configuration?: Configuration, +) { + if (configuration && (configuration.username || configuration.password)) { + object['auth'] = { + username: configuration.username, + password: configuration.password, + }; + } +}; + +/** + * + * @export + */ +export const setBearerAuthToObject = async function ( + object: any, + configuration?: Configuration, +) { + if (configuration && configuration.accessToken) { + const accessToken = + typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object['Authorization'] = 'Bearer ' + accessToken; + } +}; + +/** + * + * @export + */ +export const setOAuthToObject = async function ( + object: any, + name: string, + scopes: string[], + configuration?: Configuration, +) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = + typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object['Authorization'] = 'Bearer ' + localVarAccessTokenValue; + } +}; + +function setFlattenedQueryParams( + urlSearchParams: URLSearchParams, + parameter: any, + key: string = '', +): void { + if (parameter == null) return; + if (typeof parameter === 'object') { + if (Array.isArray(parameter)) { + (parameter as any[]).forEach((item) => + setFlattenedQueryParams(urlSearchParams, item, key), + ); + } else { + Object.keys(parameter).forEach((currentKey) => + setFlattenedQueryParams( + urlSearchParams, + parameter[currentKey], + `${key}${key !== '' ? '.' : ''}${currentKey}`, + ), + ); + } + } else { + if (urlSearchParams.has(key)) { + urlSearchParams.append(key, parameter); + } else { + urlSearchParams.set(key, parameter); + } + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + setFlattenedQueryParams(searchParams, objects); + url.search = searchParams.toString(); +}; + +/** + * + * @export + */ +export const serializeDataIfNeeded = function ( + value: any, + requestOptions: any, + configuration?: Configuration, +) { + const nonString = typeof value !== 'string'; + const needsSerialization = + nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : value || ''; +}; + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash; +}; + +/** + * + * @export + */ +export const createRequestFunction = function ( + axiosArgs: RequestArgs, + globalAxios: AxiosInstance, + BASE_PATH: string, + configuration?: Configuration, +) { + return >( + axios: AxiosInstance = globalAxios, + basePath: string = BASE_PATH, + ) => { + const axiosRequestArgs = { + ...axiosArgs.options, + url: + (axios.defaults.baseURL ? '' : (configuration?.basePath ?? basePath)) + + axiosArgs.url, + }; + return axios.request(axiosRequestArgs); + }; +}; diff --git a/frontend/src/service/recreation-resource/configuration.ts b/frontend/src/service/recreation-resource/configuration.ts new file mode 100644 index 00000000..aa4630c3 --- /dev/null +++ b/frontend/src/service/recreation-resource/configuration.ts @@ -0,0 +1,138 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Recreation Sites and Trails BC API + * RST API documentation + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +export interface ConfigurationParameters { + apiKey?: + | string + | Promise + | ((name: string) => string) + | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string) + | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + serverIndex?: number; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: + | string + | Promise + | ((name: string) => string) + | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string) + | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.serverIndex = param.serverIndex; + this.baseOptions = { + headers: { + ...param.baseOptions?.headers, + 'User-Agent': 'OpenAPI-Generator/typescript-axios', + }, + ...param.baseOptions, + }; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp( + '^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', + 'i', + ); + return ( + mime !== null && + (jsonMime.test(mime) || + mime.toLowerCase() === 'application/json-patch+json') + ); + } +} diff --git a/frontend/src/service/recreation-resource/index.ts b/frontend/src/service/recreation-resource/index.ts new file mode 100644 index 00000000..3b72028f --- /dev/null +++ b/frontend/src/service/recreation-resource/index.ts @@ -0,0 +1,16 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Recreation Sites and Trails BC API + * RST API documentation + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +export * from './api'; +export * from './configuration'; diff --git a/frontend/vitest.config.mts b/frontend/vitest.config.mts index f20ad215..2903b3e0 100644 --- a/frontend/vitest.config.mts +++ b/frontend/vitest.config.mts @@ -15,6 +15,7 @@ export default defineConfig({ coverage: { provider: 'v8', reporter: ['lcov'], + exclude: ['src/service/recreation-resource/**'], }, }, }); diff --git a/package.json b/package.json index b1c48bfc..fbd66069 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,7 @@ { + "scripts": { + "prettier-fix": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"" + }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.15.0",