@autoview/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +407 -0
- package/lib/AutoViewAgent.d.ts +109 -0
- package/lib/AutoViewAgent.js +123 -0
- package/lib/AutoViewAgent.js.map +1 -0
- package/lib/agent/emitMcpServer.d.ts +15 -0
- package/lib/agent/emitMcpServer.js +157 -0
- package/lib/agent/emitMcpServer.js.map +1 -0
- package/lib/agent/emitReport.d.ts +14 -0
- package/lib/agent/emitReport.js +85 -0
- package/lib/agent/emitReport.js.map +1 -0
- package/lib/agent/toolSurface.d.ts +130 -0
- package/lib/agent/toolSurface.js +342 -0
- package/lib/agent/toolSurface.js.map +1 -0
- package/lib/agent/verifyAgentTasks.d.ts +87 -0
- package/lib/agent/verifyAgentTasks.js +126 -0
- package/lib/agent/verifyAgentTasks.js.map +1 -0
- package/lib/cli/main.d.ts +2 -0
- package/lib/cli/main.js +295 -0
- package/lib/cli/main.js.map +1 -0
- package/lib/compiler/AutoViewInterfaceCompiler.d.ts +27 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js +68 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js.map +1 -0
- package/lib/constants/AutoViewFrontendTemplate.d.ts +1 -0
- package/lib/constants/AutoViewFrontendTemplate.js +46 -0
- package/lib/constants/AutoViewFrontendTemplate.js.map +1 -0
- package/lib/constants/AutoViewSystemPromptConstant.d.ts +5 -0
- package/lib/constants/AutoViewSystemPromptConstant.js +4 -0
- package/lib/constants/AutoViewSystemPromptConstant.js.map +1 -0
- package/lib/context/IAutoViewAgentContext.d.ts +60 -0
- package/lib/context/IAutoViewAgentContext.js +3 -0
- package/lib/context/IAutoViewAgentContext.js.map +1 -0
- package/lib/fromSwagger.d.ts +53 -0
- package/lib/fromSwagger.js +513 -0
- package/lib/fromSwagger.js.map +1 -0
- package/lib/generateDeterministic.d.ts +26 -0
- package/lib/generateDeterministic.js +75 -0
- package/lib/generateDeterministic.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoView.d.ts +17 -0
- package/lib/orchestrate/orchestrateAutoView.js +491 -0
- package/lib/orchestrate/orchestrateAutoView.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.d.ts +37 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js +109 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRender.d.ts +133 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js +943 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.d.ts +24 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js +92 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewReview.d.ts +48 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js +328 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.d.ts +45 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js +586 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.d.ts +26 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js +85 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.d.ts +96 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.d.ts +40 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.d.ts +63 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.d.ts +37 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js.map +1 -0
- package/lib/orchestrate/utils/HistoryMessage.d.ts +10 -0
- package/lib/orchestrate/utils/HistoryMessage.js +25 -0
- package/lib/orchestrate/utils/HistoryMessage.js.map +1 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.d.ts +53 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js +362 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.d.ts +4 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js +233 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.d.ts +22 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js +154 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js.map +1 -0
- package/lib/orchestrate/utils/cacheNodeModules.d.ts +31 -0
- package/lib/orchestrate/utils/cacheNodeModules.js +134 -0
- package/lib/orchestrate/utils/cacheNodeModules.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.d.ts +37 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js +192 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.d.ts +22 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js +29 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.d.ts +19 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js +30 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js.map +1 -0
- package/lib/orchestrate/utils/executeCachedBatch.d.ts +22 -0
- package/lib/orchestrate/utils/executeCachedBatch.js +64 -0
- package/lib/orchestrate/utils/executeCachedBatch.js.map +1 -0
- package/lib/orchestrate/utils/loadShoppingFixture.d.ts +33 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js +17 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js.map +1 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.d.ts +24 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js +77 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js.map +1 -0
- package/lib/orchestrate/utils/renderJsonSchema.d.ts +23 -0
- package/lib/orchestrate/utils/renderJsonSchema.js +122 -0
- package/lib/orchestrate/utils/renderJsonSchema.js.map +1 -0
- package/lib/orchestrate/utils/renderResourcePage.d.ts +36 -0
- package/lib/orchestrate/utils/renderResourcePage.js +1415 -0
- package/lib/orchestrate/utils/renderResourcePage.js.map +1 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.d.ts +109 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js +274 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js.map +1 -0
- package/lib/preview/renderPreview.d.ts +22 -0
- package/lib/preview/renderPreview.js +198 -0
- package/lib/preview/renderPreview.js.map +1 -0
- package/lib/typings/compiler.d.ts +39 -0
- package/lib/typings/compiler.js +3 -0
- package/lib/typings/compiler.js.map +1 -0
- package/lib/typings/events.d.ts +106 -0
- package/lib/typings/events.js +3 -0
- package/lib/typings/events.js.map +1 -0
- package/lib/typings/index.d.ts +10 -0
- package/lib/typings/index.js +27 -0
- package/lib/typings/index.js.map +1 -0
- package/lib/typings/misc.d.ts +78 -0
- package/lib/typings/misc.js +3 -0
- package/lib/typings/misc.js.map +1 -0
- package/lib/utils/ArrayUtil.d.ts +8 -0
- package/lib/utils/ArrayUtil.js +30 -0
- package/lib/utils/ArrayUtil.js.map +1 -0
- package/lib/utils/StringUtil.d.ts +11 -0
- package/lib/utils/StringUtil.js +28 -0
- package/lib/utils/StringUtil.js.map +1 -0
- package/lib/utils/classifyEndpoints.d.ts +62 -0
- package/lib/utils/classifyEndpoints.js +216 -0
- package/lib/utils/classifyEndpoints.js.map +1 -0
- package/lib/utils/endpointFilter.d.ts +26 -0
- package/lib/utils/endpointFilter.js +0 -0
- package/lib/utils/endpointFilter.js.map +1 -0
- package/lib/utils/extractFields.d.ts +85 -0
- package/lib/utils/extractFields.js +231 -0
- package/lib/utils/extractFields.js.map +1 -0
- package/lib/utils/index.d.ts +13 -0
- package/lib/utils/index.js +30 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/normalizeForNestia.d.ts +34 -0
- package/lib/utils/normalizeForNestia.js +133 -0
- package/lib/utils/normalizeForNestia.js.map +1 -0
- package/lib/utils/resourcePlan.d.ts +39 -0
- package/lib/utils/resourcePlan.js +95 -0
- package/lib/utils/resourcePlan.js.map +1 -0
- package/lib/utils/sliceDocument.d.ts +17 -0
- package/lib/utils/sliceDocument.js +114 -0
- package/lib/utils/sliceDocument.js.map +1 -0
- package/lib/utils/toEndpoints.d.ts +90 -0
- package/lib/utils/toEndpoints.js +227 -0
- package/lib/utils/toEndpoints.js.map +1 -0
- package/lib/verify/runWorkflows.d.ts +25 -0
- package/lib/verify/runWorkflows.js +366 -0
- package/lib/verify/runWorkflows.js.map +1 -0
- package/lib/verify/workflows.d.ts +53 -0
- package/lib/verify/workflows.js +107 -0
- package/lib/verify/workflows.js.map +1 -0
- package/package.json +82 -0
- package/prompts/AUTOVIEW_RENDER.md +398 -0
- package/prompts/AUTOVIEW_REVIEW.md +60 -0
- package/prompts/AUTOVIEW_SDK_STUDY.md +89 -0
- package/src/AutoViewAgent.ts +222 -0
- package/src/agent/emitMcpServer.integration.test.ts +168 -0
- package/src/agent/emitMcpServer.test.ts +51 -0
- package/src/agent/emitMcpServer.ts +178 -0
- package/src/agent/emitReport.ts +117 -0
- package/src/agent/toolSurface.test.ts +243 -0
- package/src/agent/toolSurface.ts +501 -0
- package/src/agent/verifyAgentTasks.test.ts +106 -0
- package/src/agent/verifyAgentTasks.ts +171 -0
- package/src/cli/main.ts +363 -0
- package/src/compiler/AutoViewInterfaceCompiler.ts +69 -0
- package/src/constants/AutoViewFrontendTemplate.ts +42 -0
- package/src/constants/AutoViewSystemPromptConstant.ts +6 -0
- package/src/context/IAutoViewAgentContext.ts +84 -0
- package/src/fromSwagger.test.ts +269 -0
- package/src/fromSwagger.ts +500 -0
- package/src/generateDeterministic.test.ts +39 -0
- package/src/generateDeterministic.ts +77 -0
- package/src/index.ts +30 -0
- package/src/orchestrate/orchestrateAutoView.ts +590 -0
- package/src/orchestrate/orchestrateAutoViewProductPlan.ts +121 -0
- package/src/orchestrate/orchestrateAutoViewRender.ts +1117 -0
- package/src/orchestrate/orchestrateAutoViewRenderDeterministic.ts +101 -0
- package/src/orchestrate/orchestrateAutoViewReview.ts +272 -0
- package/src/orchestrate/orchestrateAutoViewScaffold.ts +627 -0
- package/src/orchestrate/orchestrateAutoViewSdkStudy.ts +90 -0
- package/src/orchestrate/renderNavTs.test.ts +74 -0
- package/src/orchestrate/structures/IAutoViewProductPlan.ts +119 -0
- package/src/orchestrate/structures/IAutoViewProductPlanApplication.ts +41 -0
- package/src/orchestrate/structures/IAutoViewRenderApplication.ts +40 -0
- package/src/orchestrate/structures/IAutoViewReviewApplication.ts +42 -0
- package/src/orchestrate/structures/IAutoViewSdkMap.ts +72 -0
- package/src/orchestrate/structures/IAutoViewSdkStudyApplication.ts +40 -0
- package/src/orchestrate/utils/HistoryMessage.ts +41 -0
- package/src/orchestrate/utils/auditFrontendRuntime.test.ts +18 -0
- package/src/orchestrate/utils/auditFrontendRuntime.ts +454 -0
- package/src/orchestrate/utils/buildDeterministicPlan.test.ts +170 -0
- package/src/orchestrate/utils/buildDeterministicPlan.ts +289 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.test.ts +90 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.ts +169 -0
- package/src/orchestrate/utils/cacheNodeModules.ts +136 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.test.ts +86 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.ts +202 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.test.ts +87 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.ts +31 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.test.ts +70 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.ts +32 -0
- package/src/orchestrate/utils/executeCachedBatch.ts +59 -0
- package/src/orchestrate/utils/loadShoppingFixture.ts +52 -0
- package/src/orchestrate/utils/normalizeProductPlanPaths.ts +92 -0
- package/src/orchestrate/utils/renderJsonSchema.test.ts +162 -0
- package/src/orchestrate/utils/renderJsonSchema.ts +133 -0
- package/src/orchestrate/utils/renderResourcePage.test.ts +468 -0
- package/src/orchestrate/utils/renderResourcePage.ts +1624 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.test.ts +32 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.ts +335 -0
- package/src/preview/renderPreview.ts +273 -0
- package/src/typings/compiler.ts +47 -0
- package/src/typings/events.ts +155 -0
- package/src/typings/index.ts +10 -0
- package/src/typings/misc.ts +93 -0
- package/src/utils/ArrayUtil.ts +16 -0
- package/src/utils/StringUtil.ts +29 -0
- package/src/utils/classifyEndpoints.test.ts +86 -0
- package/src/utils/classifyEndpoints.ts +291 -0
- package/src/utils/endpointFilter.test.ts +50 -0
- package/src/utils/endpointFilter.ts +0 -0
- package/src/utils/extractFields.test.ts +82 -0
- package/src/utils/extractFields.ts +306 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/normalizeForNestia.test.ts +93 -0
- package/src/utils/normalizeForNestia.ts +139 -0
- package/src/utils/resourcePlan.test.ts +104 -0
- package/src/utils/resourcePlan.ts +180 -0
- package/src/utils/sliceDocument.test.ts +85 -0
- package/src/utils/sliceDocument.ts +119 -0
- package/src/utils/toEndpoints.test.ts +251 -0
- package/src/utils/toEndpoints.ts +343 -0
- package/src/verify/runWorkflows.ts +403 -0
- package/src/verify/workflows.test.ts +117 -0
- package/src/verify/workflows.ts +154 -0
- package/template/CLAUDE.md +140 -0
- package/template/Dockerfile +31 -0
- package/template/PROMPT.md +80 -0
- package/template/SANDBOX.md +70 -0
- package/template/app/api/health/route.ts +10 -0
- package/template/app/globals.css +97 -0
- package/template/app/layout.tsx +30 -0
- package/template/app/page.tsx +19 -0
- package/template/components/AppShell.tsx +114 -0
- package/template/components/auto/CatalogGrid.tsx +159 -0
- package/template/components/auto/ConfirmButton.tsx +67 -0
- package/template/components/auto/EmbeddedCollection.tsx +144 -0
- package/template/components/auto/ResourceDashboard.tsx +104 -0
- package/template/components/auto/ResourceDetail.tsx +93 -0
- package/template/components/auto/ResourceForm.tsx +235 -0
- package/template/components/auto/ResourceIcon.tsx +88 -0
- package/template/components/auto/ResourceLanding.tsx +155 -0
- package/template/components/auto/ResourceTable.tsx +223 -0
- package/template/components/auto/formatValue.tsx +186 -0
- package/template/components/auto/types.ts +42 -0
- package/template/components/ui/badge.tsx +40 -0
- package/template/components/ui/button.tsx +57 -0
- package/template/components/ui/card.tsx +86 -0
- package/template/components/ui/dialog.tsx +119 -0
- package/template/components/ui/input.tsx +23 -0
- package/template/components/ui/label.tsx +24 -0
- package/template/components/ui/pagination.tsx +117 -0
- package/template/components/ui/select.tsx +92 -0
- package/template/components/ui/sheet.tsx +135 -0
- package/template/components/ui/skeleton.tsx +15 -0
- package/template/components/ui/table.tsx +120 -0
- package/template/components/ui/tabs.tsx +55 -0
- package/template/lib/utils.ts +35 -0
- package/template/next.config.mjs +52 -0
- package/template/package.json +46 -0
- package/template/postcss.config.js +6 -0
- package/template/scripts/start-shopping-backend.sh +56 -0
- package/template/tailwind.config.ts +96 -0
- package/template/tsconfig.json +29 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { describeEndpointPropsShape } from "./describeEndpointPropsShape";
|
|
4
|
+
|
|
5
|
+
const stub = (
|
|
6
|
+
overrides: Partial<IAutoViewEndpoint>,
|
|
7
|
+
): IAutoViewEndpoint => ({
|
|
8
|
+
method: "patch",
|
|
9
|
+
path: "/things",
|
|
10
|
+
specification: "",
|
|
11
|
+
description: "",
|
|
12
|
+
authorizationType: null,
|
|
13
|
+
parameters: [],
|
|
14
|
+
requestBody: null,
|
|
15
|
+
responseBody: null,
|
|
16
|
+
authorizationActor: null,
|
|
17
|
+
name: "index",
|
|
18
|
+
prerequisites: [],
|
|
19
|
+
accessor: ["things", "index"],
|
|
20
|
+
...overrides,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("describeEndpointPropsShape", () => {
|
|
24
|
+
it("returns `{}` when there are no path params and no body", () => {
|
|
25
|
+
expect(describeEndpointPropsShape(stub({}))).toBe("{}");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("emits a single path parameter", () => {
|
|
29
|
+
expect(
|
|
30
|
+
describeEndpointPropsShape(
|
|
31
|
+
stub({
|
|
32
|
+
method: "get",
|
|
33
|
+
name: "at",
|
|
34
|
+
parameters: [
|
|
35
|
+
{ name: "id", description: "", schema: { type: "string" } },
|
|
36
|
+
],
|
|
37
|
+
}),
|
|
38
|
+
),
|
|
39
|
+
).toBe("{ id: string }");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("wraps the body type under `body` when no path params exist", () => {
|
|
43
|
+
expect(
|
|
44
|
+
describeEndpointPropsShape(
|
|
45
|
+
stub({
|
|
46
|
+
requestBody: { description: "", typeName: "IShoppingSale.IRequest" },
|
|
47
|
+
}),
|
|
48
|
+
),
|
|
49
|
+
).toBe("{ body: IShoppingSale.IRequest }");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("combines multiple path params with the body wrapper", () => {
|
|
53
|
+
expect(
|
|
54
|
+
describeEndpointPropsShape(
|
|
55
|
+
stub({
|
|
56
|
+
method: "post",
|
|
57
|
+
name: "create",
|
|
58
|
+
parameters: [
|
|
59
|
+
{ name: "saleId", description: "", schema: { type: "string" } },
|
|
60
|
+
{ name: "reviewId", description: "", schema: { type: "string" } },
|
|
61
|
+
],
|
|
62
|
+
requestBody: {
|
|
63
|
+
description: "",
|
|
64
|
+
typeName: "IShoppingSaleReviewComment.ICreate",
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
),
|
|
68
|
+
).toBe(
|
|
69
|
+
"{ saleId: string; reviewId: string; body: IShoppingSaleReviewComment.ICreate }",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("maps integer/number param schemas to `number`", () => {
|
|
74
|
+
expect(
|
|
75
|
+
describeEndpointPropsShape(
|
|
76
|
+
stub({
|
|
77
|
+
method: "get",
|
|
78
|
+
name: "at",
|
|
79
|
+
parameters: [
|
|
80
|
+
{ name: "index", description: "", schema: { type: "integer" } },
|
|
81
|
+
],
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
).toBe("{ index: number }");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { IAutoViewEndpoint } from "../../utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Derive the Nestia `(connection, props)` call shape for a single AutoBE
|
|
6
|
+
* operation as a one-line TypeScript signature string. Used by the Render phase
|
|
7
|
+
* to spoon-feed the LLM the exact `props` object shape it has to pass —
|
|
8
|
+
* otherwise the model routinely flattens body fields into the top level of
|
|
9
|
+
* `props`, which makes the simulator return a masked 400 and the page renders
|
|
10
|
+
* the empty state.
|
|
11
|
+
*
|
|
12
|
+
* Examples (matching the live shopping SDK):
|
|
13
|
+
*
|
|
14
|
+
* - `at` on `/sales/:id` → `{ id: string }`
|
|
15
|
+
* - `index` on `/sales` (PATCH) → `{ body: IShoppingSale.IRequest }`
|
|
16
|
+
* - `create` on `/sales/:saleId/reviews` → `{ saleId: string; body:
|
|
17
|
+
* IShoppingSaleReview.ICreate }`
|
|
18
|
+
*
|
|
19
|
+
* Pure. Does not mutate the operation.
|
|
20
|
+
*/
|
|
21
|
+
export function describeEndpointPropsShape(
|
|
22
|
+
op: IAutoViewEndpoint,
|
|
23
|
+
): string {
|
|
24
|
+
const fields: string[] = [];
|
|
25
|
+
for (const param of op.parameters) {
|
|
26
|
+
fields.push(`${param.name}: ${renderParamType(param.schema)}`);
|
|
27
|
+
}
|
|
28
|
+
// Query endpoints carry their query object under `props.query`. Omitting it
|
|
29
|
+
// here is exactly why the Render LLM passed `undefined` as props for
|
|
30
|
+
// findByStatus / login and broke typecheck — the props shape never told it a
|
|
31
|
+
// query existed.
|
|
32
|
+
if (op.query != null) {
|
|
33
|
+
fields.push(`query: ${renderQueryShape(op.query)}`);
|
|
34
|
+
}
|
|
35
|
+
if (op.requestBody !== null) {
|
|
36
|
+
fields.push(`body: ${op.requestBody.typeName}`);
|
|
37
|
+
}
|
|
38
|
+
if (fields.length === 0) return "{}";
|
|
39
|
+
return `{ ${fields.join("; ")} }`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Render a query schema: a named component (nestia emits `*.GetQuery`) or an
|
|
43
|
+
* inline object. The Render phase imports the named SDK type either way. */
|
|
44
|
+
function renderQueryShape(query: OpenApi.IJsonSchema): string {
|
|
45
|
+
if ("$ref" in query && typeof query.$ref === "string") {
|
|
46
|
+
return query.$ref.split("/").pop()!;
|
|
47
|
+
}
|
|
48
|
+
if ("properties" in query && query.properties) {
|
|
49
|
+
const required = new Set(query.required ?? []);
|
|
50
|
+
const fields = Object.entries(query.properties).map(([name, prop]) => {
|
|
51
|
+
const optional = required.has(name) ? "" : "?";
|
|
52
|
+
const type = "type" in prop ? String(prop.type) : "unknown";
|
|
53
|
+
return `${name}${optional}: ${type}`;
|
|
54
|
+
});
|
|
55
|
+
return fields.length > 0 ? `{ ${fields.join("; ")} }` : "{}";
|
|
56
|
+
}
|
|
57
|
+
return "Record<string, unknown>";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Inspect the document's component schemas and return a brief, machine-friendly
|
|
62
|
+
* line describing the operation's request body — what type it is, which fields
|
|
63
|
+
* are required, and a sample literal the LLM can copy verbatim into the page
|
|
64
|
+
* when no domain-specific filter applies.
|
|
65
|
+
*
|
|
66
|
+
* Returns an empty string when the operation has no request body, or when the
|
|
67
|
+
* referenced schema cannot be resolved (the prompt is then unchanged for that
|
|
68
|
+
* endpoint, no harm done).
|
|
69
|
+
*
|
|
70
|
+
* Format:
|
|
71
|
+
*
|
|
72
|
+
* body: IShoppingSale.IRequest — required: [page, limit]; example: { "page": 1, "limit": 24 }
|
|
73
|
+
*
|
|
74
|
+
* Pure. Does not mutate the document.
|
|
75
|
+
*/
|
|
76
|
+
export function describeRequestBodyHint(
|
|
77
|
+
op: IAutoViewEndpoint,
|
|
78
|
+
doc: OpenApi.IDocument,
|
|
79
|
+
): string {
|
|
80
|
+
if (op.requestBody === null) return "";
|
|
81
|
+
const schema = (doc.components?.schemas ?? {})[op.requestBody.typeName];
|
|
82
|
+
if (schema === undefined) return `body: ${op.requestBody.typeName}`;
|
|
83
|
+
const required = collectRequired(schema, doc);
|
|
84
|
+
const example = sampleLiteral(schema, doc, required);
|
|
85
|
+
const requiredPart =
|
|
86
|
+
required.length > 0
|
|
87
|
+
? ` — required: [${required.join(", ")}]`
|
|
88
|
+
: " — (no required fields)";
|
|
89
|
+
const examplePart = example !== null ? `; example: ${example}` : "";
|
|
90
|
+
return `body: ${op.requestBody.typeName}${requiredPart}${examplePart}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function renderParamType(schema: OpenApi.IJsonSchema): string {
|
|
94
|
+
if (!("type" in schema)) return "string";
|
|
95
|
+
switch (schema.type) {
|
|
96
|
+
case "integer":
|
|
97
|
+
case "number":
|
|
98
|
+
return "number";
|
|
99
|
+
case "boolean":
|
|
100
|
+
return "boolean";
|
|
101
|
+
default:
|
|
102
|
+
return "string";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Pull the `required[]` list out of an object schema, resolving a single level
|
|
108
|
+
* of `$ref` indirection when the type name points at a nested component.
|
|
109
|
+
* Returns an empty array for non-object schemas so callers can uniformly print
|
|
110
|
+
* "(no required fields)".
|
|
111
|
+
*/
|
|
112
|
+
function collectRequired(
|
|
113
|
+
schema: OpenApi.IJsonSchema,
|
|
114
|
+
doc: OpenApi.IDocument,
|
|
115
|
+
): string[] {
|
|
116
|
+
const resolved = resolveSchema(schema, doc);
|
|
117
|
+
if (resolved === null) return [];
|
|
118
|
+
if (!("type" in resolved) || resolved.type !== "object") return [];
|
|
119
|
+
return resolved.required ?? [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Best-effort literal that satisfies the schema's required fields. Used to give
|
|
124
|
+
* the LLM a concrete `{ "body": ... }` starting point instead of a bare type
|
|
125
|
+
* name. We do not try to be exhaustive — just enough to clear the typia
|
|
126
|
+
* validation gate (page/limit numbers, empty arrays for collections, null for
|
|
127
|
+
* nullable refs, etc.).
|
|
128
|
+
*/
|
|
129
|
+
function sampleLiteral(
|
|
130
|
+
schema: OpenApi.IJsonSchema,
|
|
131
|
+
doc: OpenApi.IDocument,
|
|
132
|
+
required: string[],
|
|
133
|
+
): string | null {
|
|
134
|
+
const resolved = resolveSchema(schema, doc);
|
|
135
|
+
if (resolved === null) return null;
|
|
136
|
+
if (!("type" in resolved) || resolved.type !== "object") return null;
|
|
137
|
+
const obj = resolved as OpenApi.IJsonSchema.IObject;
|
|
138
|
+
const entries: string[] = [];
|
|
139
|
+
for (const field of required) {
|
|
140
|
+
const childSchema = (obj.properties ?? {})[field];
|
|
141
|
+
if (childSchema === undefined) continue;
|
|
142
|
+
entries.push(
|
|
143
|
+
`${JSON.stringify(field)}: ${sampleValue(childSchema, doc, field)}`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return `{ ${entries.join(", ")} }`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function sampleValue(
|
|
150
|
+
schema: OpenApi.IJsonSchema,
|
|
151
|
+
doc: OpenApi.IDocument,
|
|
152
|
+
fieldHint: string,
|
|
153
|
+
): string {
|
|
154
|
+
const resolved = resolveSchema(schema, doc) ?? schema;
|
|
155
|
+
if ("const" in resolved) {
|
|
156
|
+
return JSON.stringify(
|
|
157
|
+
(resolved as OpenApi.IJsonSchema.IConstant).const,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if ("oneOf" in resolved) {
|
|
161
|
+
const branches = resolved.oneOf;
|
|
162
|
+
if (branches.length > 0) return sampleValue(branches[0]!, doc, fieldHint);
|
|
163
|
+
return "null";
|
|
164
|
+
}
|
|
165
|
+
if (!("type" in resolved)) return "null";
|
|
166
|
+
switch (resolved.type) {
|
|
167
|
+
case "boolean":
|
|
168
|
+
return "false";
|
|
169
|
+
case "integer":
|
|
170
|
+
case "number":
|
|
171
|
+
if (fieldHint === "page" || fieldHint === "current") return "1";
|
|
172
|
+
if (fieldHint === "limit") return "24";
|
|
173
|
+
return "0";
|
|
174
|
+
case "string":
|
|
175
|
+
return '""';
|
|
176
|
+
case "array":
|
|
177
|
+
return "[]";
|
|
178
|
+
case "object":
|
|
179
|
+
return "{}";
|
|
180
|
+
case "null":
|
|
181
|
+
return "null";
|
|
182
|
+
}
|
|
183
|
+
return "null";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Follow a single layer of `$ref` indirection so callers can ask for an object
|
|
188
|
+
* schema by type name (the request-body `typeName`) and receive the resolved
|
|
189
|
+
* component back. Returns `null` when the ref does not point at a known
|
|
190
|
+
* component.
|
|
191
|
+
*/
|
|
192
|
+
function resolveSchema(
|
|
193
|
+
schema: OpenApi.IJsonSchema,
|
|
194
|
+
doc: OpenApi.IDocument,
|
|
195
|
+
): OpenApi.IJsonSchema | null {
|
|
196
|
+
if ("$ref" in schema && typeof schema.$ref === "string") {
|
|
197
|
+
const name = schema.$ref.replace(/^#\/components\/schemas\//, "");
|
|
198
|
+
const target = (doc.components?.schemas ?? {})[name];
|
|
199
|
+
return (target ?? null) as OpenApi.IJsonSchema | null;
|
|
200
|
+
}
|
|
201
|
+
return schema;
|
|
202
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { describeEndpointRequestBodyShape } from "./describeEndpointRequestBodyShape";
|
|
5
|
+
|
|
6
|
+
const op = (
|
|
7
|
+
overrides: Partial<IAutoViewEndpoint>,
|
|
8
|
+
): IAutoViewEndpoint => ({
|
|
9
|
+
method: "patch",
|
|
10
|
+
path: "/things",
|
|
11
|
+
specification: "",
|
|
12
|
+
description: "",
|
|
13
|
+
authorizationType: null,
|
|
14
|
+
parameters: [],
|
|
15
|
+
requestBody: null,
|
|
16
|
+
responseBody: null,
|
|
17
|
+
authorizationActor: null,
|
|
18
|
+
name: "index",
|
|
19
|
+
prerequisites: [],
|
|
20
|
+
accessor: ["things", "index"],
|
|
21
|
+
...overrides,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const doc = (
|
|
25
|
+
schemas: Record<string, OpenApi.IJsonSchema>,
|
|
26
|
+
): OpenApi.IDocument =>
|
|
27
|
+
({
|
|
28
|
+
operations: [],
|
|
29
|
+
components: {
|
|
30
|
+
schemas,
|
|
31
|
+
securitySchemes: {},
|
|
32
|
+
},
|
|
33
|
+
}) as unknown as OpenApi.IDocument;
|
|
34
|
+
|
|
35
|
+
describe("describeEndpointRequestBodyShape", () => {
|
|
36
|
+
it("returns null when the operation has no request body", () => {
|
|
37
|
+
expect(describeEndpointRequestBodyShape(op({}), doc({}))).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("falls back to the bare type name when the schema is missing", () => {
|
|
41
|
+
expect(
|
|
42
|
+
describeEndpointRequestBodyShape(
|
|
43
|
+
op({
|
|
44
|
+
requestBody: { description: "", typeName: "IMissing" },
|
|
45
|
+
}),
|
|
46
|
+
doc({}),
|
|
47
|
+
),
|
|
48
|
+
).toBe("IMissing");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("expands sort grammars as arrays of literal-string unions", () => {
|
|
52
|
+
expect(
|
|
53
|
+
describeEndpointRequestBodyShape(
|
|
54
|
+
op({
|
|
55
|
+
requestBody: { description: "", typeName: "ITrashRequest" },
|
|
56
|
+
}),
|
|
57
|
+
doc({
|
|
58
|
+
ITrashRequest: {
|
|
59
|
+
type: "object",
|
|
60
|
+
description: "",
|
|
61
|
+
properties: {
|
|
62
|
+
page: { type: "integer", description: "" },
|
|
63
|
+
sort: {
|
|
64
|
+
type: "array",
|
|
65
|
+
description: "",
|
|
66
|
+
items: {
|
|
67
|
+
oneOf: [
|
|
68
|
+
{ const: "created_at.asc", description: "" },
|
|
69
|
+
{ const: "created_at.desc", description: "" },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
required: ["page"],
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
).toBe(
|
|
79
|
+
[
|
|
80
|
+
"{",
|
|
81
|
+
" page: number;",
|
|
82
|
+
' sort?: Array<"created_at.asc" | "created_at.desc">;',
|
|
83
|
+
"}",
|
|
84
|
+
].join("\n"),
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { IAutoViewEndpoint } from "../../utils";
|
|
3
|
+
|
|
4
|
+
import { renderNamedSchema } from "./renderJsonSchema";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Render the request body type of a single AutoBE operation as a readable,
|
|
8
|
+
* multi-line TypeScript-shaped string — mirror of
|
|
9
|
+
* {@link describeEndpointResponseShape} for the input side.
|
|
10
|
+
*
|
|
11
|
+
* The existing one-line {@link describeRequestBodyHint} surfaces the typeName,
|
|
12
|
+
* required keys, and a sample literal, but stops short of expanding nested
|
|
13
|
+
* arrays-of-union-literals (sort grammars) or other deeply-typed request DTOs —
|
|
14
|
+
* which is enough for the LLM to fall back on its priors and emit `sort: {
|
|
15
|
+
* field: ..., direction: ... }[]` against an `ITrashRequest.sort` whose real
|
|
16
|
+
* shape is `("created_at.asc" | "created_at.desc" | ...)[]`. Pre-rendering the
|
|
17
|
+
* full shape on the way in kills that whole class of defect at zero LLM cost,
|
|
18
|
+
* just like the response path does.
|
|
19
|
+
*
|
|
20
|
+
* Returns `null` when the operation has no request body so callers can skip the
|
|
21
|
+
* line entirely rather than emitting `body: void`.
|
|
22
|
+
*
|
|
23
|
+
* Pure. Does not mutate the document.
|
|
24
|
+
*/
|
|
25
|
+
export function describeEndpointRequestBodyShape(
|
|
26
|
+
op: IAutoViewEndpoint,
|
|
27
|
+
doc: OpenApi.IDocument,
|
|
28
|
+
): string | null {
|
|
29
|
+
if (op.requestBody === null) return null;
|
|
30
|
+
return renderNamedSchema(op.requestBody.typeName, doc);
|
|
31
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { describeEndpointResponseShape } from "./describeEndpointResponseShape";
|
|
5
|
+
|
|
6
|
+
const op = (
|
|
7
|
+
overrides: Partial<IAutoViewEndpoint>,
|
|
8
|
+
): IAutoViewEndpoint => ({
|
|
9
|
+
method: "get",
|
|
10
|
+
path: "/things",
|
|
11
|
+
specification: "",
|
|
12
|
+
description: "",
|
|
13
|
+
authorizationType: null,
|
|
14
|
+
parameters: [],
|
|
15
|
+
requestBody: null,
|
|
16
|
+
responseBody: null,
|
|
17
|
+
authorizationActor: null,
|
|
18
|
+
name: "at",
|
|
19
|
+
prerequisites: [],
|
|
20
|
+
accessor: ["things", "at"],
|
|
21
|
+
...overrides,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const doc = (
|
|
25
|
+
schemas: Record<string, OpenApi.IJsonSchema>,
|
|
26
|
+
): OpenApi.IDocument =>
|
|
27
|
+
({
|
|
28
|
+
operations: [],
|
|
29
|
+
components: {
|
|
30
|
+
schemas,
|
|
31
|
+
securitySchemes: {},
|
|
32
|
+
},
|
|
33
|
+
}) as unknown as OpenApi.IDocument;
|
|
34
|
+
|
|
35
|
+
describe("describeEndpointResponseShape", () => {
|
|
36
|
+
it("returns `void` when the operation has no response body", () => {
|
|
37
|
+
expect(describeEndpointResponseShape(op({}), doc({}))).toBe("void");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("falls back to the bare type name when the schema is missing", () => {
|
|
41
|
+
expect(
|
|
42
|
+
describeEndpointResponseShape(
|
|
43
|
+
op({
|
|
44
|
+
responseBody: { description: "", typeName: "IMissing" },
|
|
45
|
+
}),
|
|
46
|
+
doc({}),
|
|
47
|
+
),
|
|
48
|
+
).toBe("IMissing");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("delegates resolved schemas to the shared renderer", () => {
|
|
52
|
+
expect(
|
|
53
|
+
describeEndpointResponseShape(
|
|
54
|
+
op({
|
|
55
|
+
responseBody: { description: "", typeName: "IFlag" },
|
|
56
|
+
}),
|
|
57
|
+
doc({
|
|
58
|
+
IFlag: {
|
|
59
|
+
type: "object",
|
|
60
|
+
description: "",
|
|
61
|
+
properties: {
|
|
62
|
+
value: { type: "boolean", description: "" },
|
|
63
|
+
},
|
|
64
|
+
required: ["value"],
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
),
|
|
68
|
+
).toBe(["{", " value: boolean;", "}"].join("\n"));
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { IAutoViewEndpoint } from "../../utils";
|
|
3
|
+
|
|
4
|
+
import { renderNamedSchema } from "./renderJsonSchema";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Render the response body type of a single AutoBE operation as a readable,
|
|
8
|
+
* multi-line TypeScript-shaped string. Used by the Render phase to spoon-feed
|
|
9
|
+
* the LLM the exact field names + nesting of every endpoint's return value —
|
|
10
|
+
* otherwise the model invents plausible-sounding properties (e.g. `auth.member`
|
|
11
|
+
* on `IAuthorized` when the real shape is `{ id, created_at, token }`), which
|
|
12
|
+
* then fails TypeScript when the user runs `npm run typecheck` against the
|
|
13
|
+
* generated frontend.
|
|
14
|
+
*
|
|
15
|
+
* Returns `void` when the operation has no response body, so callers can
|
|
16
|
+
* pass-through to `Promise<void>` in the rendered signature. Delegates the
|
|
17
|
+
* actual schema walk to {@link renderJsonSchema} so request and response
|
|
18
|
+
* descriptions stay shape-compatible.
|
|
19
|
+
*
|
|
20
|
+
* Pure. Does not mutate the document.
|
|
21
|
+
*/
|
|
22
|
+
export function describeEndpointResponseShape(
|
|
23
|
+
op: IAutoViewEndpoint,
|
|
24
|
+
doc: OpenApi.IDocument,
|
|
25
|
+
): string {
|
|
26
|
+
if (op.responseBody === null) return "void";
|
|
27
|
+
const shape = renderNamedSchema(op.responseBody.typeName, doc);
|
|
28
|
+
// A list endpoint responds with an array of the element type. Make the
|
|
29
|
+
// array explicit so the Render phase builds a table/list off the element
|
|
30
|
+
// fields, not a single-record view.
|
|
31
|
+
return op.responseBody.isArray ? `${shape}[]` : shape;
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Pair } from "tstl";
|
|
2
|
+
import { v7 } from "uuid";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Executes a task list with semaphore-controlled parallelization.
|
|
6
|
+
*
|
|
7
|
+
* All tasks are dispatched immediately into a worker pool, with concurrency
|
|
8
|
+
* limited by `semaphore` to prevent overwhelming LLM APIs. Results are returned
|
|
9
|
+
* in original order. On the first task failure the remaining queue is aborted
|
|
10
|
+
* and the original error is rethrown.
|
|
11
|
+
*
|
|
12
|
+
* Standalone copy of `@autobe/agent`'s `executeCachedBatch` that takes the
|
|
13
|
+
* concurrency cap directly as a number — the autoview package does not need the
|
|
14
|
+
* full `AutoBeContext` shape just to read `ctx.vendor.semaphore`.
|
|
15
|
+
*
|
|
16
|
+
* @param semaphore Concurrency cap (1–N parallel tasks at any one time).
|
|
17
|
+
* @param taskList List of async tasks to execute, each receiving the cache key
|
|
18
|
+
* as its argument.
|
|
19
|
+
* @param promptCacheKey Optional cache key (generates a UUID if omitted) — used
|
|
20
|
+
* as the user-message body so the LLM provider can reuse a cached system
|
|
21
|
+
* prompt across calls.
|
|
22
|
+
*/
|
|
23
|
+
export const executeCachedBatch = async <T>(
|
|
24
|
+
semaphore: number,
|
|
25
|
+
taskList: Task<T>[],
|
|
26
|
+
promptCacheKey?: string,
|
|
27
|
+
): Promise<T[]> => {
|
|
28
|
+
if (taskList.length === 0) return [];
|
|
29
|
+
|
|
30
|
+
promptCacheKey ??= v7();
|
|
31
|
+
|
|
32
|
+
const queue: Array<Pair<Task<T>, number>> = taskList.map(
|
|
33
|
+
(task, index) => new Pair(task, index),
|
|
34
|
+
);
|
|
35
|
+
const results: Pair<T, number>[] = [];
|
|
36
|
+
let aborted: boolean = false;
|
|
37
|
+
let firstError: unknown = null;
|
|
38
|
+
await Promise.allSettled(
|
|
39
|
+
new Array(Math.min(semaphore, queue.length)).fill(0).map(async () => {
|
|
40
|
+
while (queue.length !== 0 && !aborted) {
|
|
41
|
+
const item: Pair<Task<T>, number> = queue.splice(0, 1)[0]!;
|
|
42
|
+
try {
|
|
43
|
+
const result: T = await item.first(promptCacheKey!);
|
|
44
|
+
if (!aborted) results.push(new Pair(result, item.second));
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (!aborted) {
|
|
47
|
+
aborted = true;
|
|
48
|
+
queue.length = 0;
|
|
49
|
+
firstError = error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
if (firstError !== null) throw firstError;
|
|
56
|
+
return results.sort((x, y) => x.second - y.second).map((p) => p.first);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type Task<T> = (user: string) => Promise<T>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import { OpenApiConverter } from "@typia/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Lazy-load `@samchon/shopping-api/swagger.json` and convert it to an
|
|
6
|
+
* {@link OpenApi.IDocument} so AutoView can run against a stable reference
|
|
7
|
+
* SDK without depending on the live `interface` phase.
|
|
8
|
+
*
|
|
9
|
+
* Also surfaces the swagger's first declared server URL — the bundled
|
|
10
|
+
* `@samchon/shopping-api` swagger lists `https://shopping-be.wrtn.ai` so the
|
|
11
|
+
* generated frontend can hit a real backend (and render real product names like
|
|
12
|
+
* "Apple Watch") instead of typia-random mock gibberish. The Scaffold phase
|
|
13
|
+
* uses this URL to seed the default `IConnection.host`.
|
|
14
|
+
*
|
|
15
|
+
* The swagger payload is ~700 KB, so the result is memoized on the first call.
|
|
16
|
+
* The conversion reuses the same `invertOpenApiDocument` helper the live
|
|
17
|
+
* interface compiler relies on, which means the rest of the AutoView pipeline
|
|
18
|
+
* cannot tell the document came from a fixture instead of a freshly generated
|
|
19
|
+
* session.
|
|
20
|
+
*
|
|
21
|
+
* The shopping-api package ships an OpenAPI 3.x document — its shape is
|
|
22
|
+
* structurally identical to typia's `OpenApi.IDocument`, so we cast through
|
|
23
|
+
* `unknown` rather than dragging in another normalization library. The
|
|
24
|
+
* downstream invert helper validates the relevant fields itself; an
|
|
25
|
+
* incompatible document would surface there.
|
|
26
|
+
*/
|
|
27
|
+
export interface IShoppingFixture {
|
|
28
|
+
document: OpenApi.IDocument;
|
|
29
|
+
/**
|
|
30
|
+
* First entry from `swagger.servers[]`. `null` when the swagger omits
|
|
31
|
+
* `servers` (the SDK would then have to rely on simulate-only mocks).
|
|
32
|
+
*/
|
|
33
|
+
serverUrl: string | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let cached: IShoppingFixture | null = null;
|
|
37
|
+
|
|
38
|
+
export function loadShoppingFixture(): IShoppingFixture {
|
|
39
|
+
if (cached !== null) return cached;
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
|
+
const swagger = require("@samchon/shopping-api/swagger.json") as {
|
|
42
|
+
servers?: ReadonlyArray<{ url?: string | null } | null> | null;
|
|
43
|
+
};
|
|
44
|
+
const document = OpenApiConverter.upgradeDocument(
|
|
45
|
+
swagger as unknown as Parameters<typeof OpenApiConverter.upgradeDocument>[0],
|
|
46
|
+
);
|
|
47
|
+
const serverUrl =
|
|
48
|
+
swagger.servers?.find((s) => typeof s?.url === "string" && s.url.length > 0)
|
|
49
|
+
?.url ?? null;
|
|
50
|
+
cached = { document, serverUrl: serverUrl ?? null };
|
|
51
|
+
return cached;
|
|
52
|
+
}
|