Skip to content

Commit 75e37dd

Browse files
Merge pull request #2 from speakeasy-api/req-pojos
refactor: support the new decorators and pojo handling
2 parents 6d25159 + 3f1fe29 commit 75e37dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1279
-1541
lines changed

.genignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

gen.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
typescript:
2+
packagename: "@speakeasy-api/speakeasy-client-sdk-typescript"
3+
version: 0.0.1
4+
author: Speakeasy

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "",
3-
"version": "",
4-
"author": "",
2+
"name": "@speakeasy-api/speakeasy-client-sdk-typescript",
3+
"version": "0.0.1",
4+
"author": "Speakeasy",
55
"scripts": {
66
"lint:fix": "tsc --noemit && eslint \"./src\" --ext .ts,.tsx --fix"
77
},
@@ -19,6 +19,7 @@
1919
"eslint-config-prettier": "^8.5.0",
2020
"eslint-plugin-prettier": "^4.2.1",
2121
"prettier": "^2.7.1",
22-
"typescript": "^4.8.4"
22+
"typescript": "^4.8.4",
23+
"@types/reflect-metadata": "^0.1.0"
2324
}
2425
}

src/internal/utils/pathparams.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,26 @@ export function ParsePathParamDecorator(
2727
}
2828

2929
export function GetSimplePathParams(
30-
paramName: string,
31-
paramValue: any
30+
paramName: string,
31+
paramValue: any,
32+
explode: boolean
3233
): Map<string, string> {
33-
let pathParams: Map<string, string> = new Map<string, string>();
34-
if (typeof paramValue === "string") pathParams.set(paramName, paramValue);
35-
else pathParams.set(paramName, JSON.stringify(paramValue));
34+
const pathParams: Map<string, string> = new Map<string, string>();
35+
const ppVals: string[] = [];
36+
if (Array.isArray(paramValue)) {
37+
paramValue.forEach((param) => {
38+
ppVals.push(String(param));
39+
});
40+
pathParams.set(paramName, ppVals.join(","));
41+
} else if (paramValue instanceof Object) {
42+
Object.getOwnPropertyNames(paramValue).forEach((paramName: string) => {
43+
if (explode) ppVals.push(`${paramName}=${paramValue[paramName]}`);
44+
else ppVals.push(`${paramName},${paramValue[paramName]}`);
45+
});
46+
pathParams.set(paramName, ppVals.join(","));
47+
} else {
48+
pathParams.set(paramName, String(paramValue));
49+
}
3650
return pathParams;
3751
}
3852

src/internal/utils/utils.ts

Lines changed: 134 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,139 @@
11
import "reflect-metadata";
2-
import axios, { AxiosInstance } from "axios";
2+
33
import {
4-
ppMetadataKey,
4+
GetSimplePathParams,
55
ParamDecorator,
66
ParsePathParamDecorator,
7-
GetSimplePathParams,
7+
ppMetadataKey,
88
} from "./pathparams";
99

10-
export function Metadata(anns: string) {
11-
const annsArr = anns.split(", ");
12-
return Reflect.metadata(annsArr[0], annsArr[1]);
10+
interface propInfo {
11+
key: string | symbol;
12+
type: any;
13+
elemType: any;
14+
elemDepth: number;
15+
}
16+
17+
function isSpeakeasyBase(type: any): boolean {
18+
return type && Object.getPrototypeOf(type)?.name == "SpeakeasyBase";
19+
}
20+
21+
function handleArray(value: any, elemType: any, elemDepth: number): any {
22+
if (!Array.isArray(value)) {
23+
return value;
24+
}
25+
26+
if (elemDepth == 1) {
27+
return value.map((v: any) => new elemType(v));
28+
} else {
29+
return value.map((v: any) => {
30+
if (Array.isArray(v)) {
31+
return handleArray(v, elemType, elemDepth - 1);
32+
} else if (typeof v == "object") {
33+
return handleObject(v, elemType, elemDepth - 1);
34+
} else {
35+
return v;
36+
}
37+
});
38+
}
39+
}
40+
41+
function handleObject(value: any, elemType: any, elemDepth: number): any {
42+
if (typeof value != "object") {
43+
return value;
44+
}
45+
46+
if (elemDepth == 1) {
47+
return Object.keys(value).reduce((acc: any, key: string) => {
48+
acc[key] = new elemType(value[key]);
49+
return acc;
50+
}, {});
51+
} else {
52+
return Object.keys(value).reduce((acc: any, key: string) => {
53+
const v = value[key];
54+
if (Array.isArray(v)) {
55+
acc[key] = handleArray(v, elemType, elemDepth - 1);
56+
} else if (typeof v == "object") {
57+
acc[key] = handleObject(v, elemType, elemDepth - 1);
58+
} else {
59+
acc[key] = v;
60+
}
61+
return acc;
62+
}, {});
63+
}
64+
}
65+
66+
export class SpeakeasyBase {
67+
constructor(payload?: Record<string | symbol, unknown>) {
68+
const props: propInfo[] = (this as any)["__props__"];
69+
if (props) {
70+
for (const prop of props) {
71+
if (payload && payload.hasOwnProperty(prop.key)) {
72+
const value = payload[prop.key];
73+
if (isSpeakeasyBase(prop.type)) {
74+
(this as any)[prop.key] = new prop.type(value);
75+
} else if (
76+
prop.type.name == "Array" &&
77+
isSpeakeasyBase(prop.elemType)
78+
) {
79+
(this as any)[prop.key] = handleArray(
80+
value,
81+
prop.elemType,
82+
prop.elemDepth
83+
);
84+
} else if (
85+
prop.type.name == "Object" &&
86+
isSpeakeasyBase(prop.elemType)
87+
) {
88+
(this as any)[prop.key] = handleObject(
89+
value,
90+
prop.elemType,
91+
prop.elemDepth
92+
);
93+
} else {
94+
(this as any)[prop.key] = value;
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
102+
export function Metadata<
103+
T extends SpeakeasyBase = Record<string | symbol, unknown>
104+
>(params?: {
105+
data?: string;
106+
elemType?: { new (): T };
107+
elemDepth?: number;
108+
}): PropertyDecorator {
109+
return (target, propertyKey) => {
110+
if (params?.data) {
111+
const annsArr = params.data.split(", ");
112+
113+
for (let i = 0; i < annsArr.length; i += 2) {
114+
Reflect.defineMetadata(annsArr[i], annsArr[i + 1], target, propertyKey);
115+
}
116+
}
117+
118+
let props: propInfo[];
119+
if (target.hasOwnProperty("__props__")) {
120+
props = (target as any)["__props__"];
121+
} else {
122+
props = (target as any)["__props__"] = [];
123+
}
124+
125+
const prop = {
126+
key: propertyKey,
127+
type: Reflect.getMetadata("design:type", target, propertyKey),
128+
} as propInfo;
129+
130+
if (params?.elemType) {
131+
prop.elemType = params.elemType;
132+
prop.elemDepth = params.elemDepth || 1;
133+
}
134+
135+
props.push(prop);
136+
};
13137
}
14138

15139
export function ReplaceParameters(
@@ -29,7 +153,7 @@ export function GenerateURL(
29153
path: string,
30154
pathParams: any
31155
): string {
32-
let url: string = serverURL.replace(/\/$/, "") + path;
156+
const url: string = serverURL.replace(/\/$/, "") + path;
33157
const parsedParameters: Map<string, string> = new Map<string, string>();
34158
const fieldNames: string[] = Object.getOwnPropertyNames(pathParams);
35159
fieldNames.forEach((fname) => {
@@ -41,12 +165,13 @@ export function GenerateURL(
41165
case "simple":
42166
const simpleParams: Map<string, string> = GetSimplePathParams(
43167
ppDecorator.ParamName,
44-
pathParams[fname]
168+
pathParams[fname],
169+
ppDecorator.Explode
45170
);
46171
simpleParams.forEach((value, key) => {
47172
parsedParameters.set(key, value);
48173
});
49174
}
50175
});
51176
return ReplaceParameters(url, parsedParameters);
52-
}
177+
}

src/sdk/models/operations/deleteapi.ts

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,28 @@
1-
import {Metadata} from "../../../internal/utils/utils";
1+
import { Metadata, SpeakeasyBase } from "../../../internal/utils/utils";
22
import * as shared from "../shared";
33

4-
export class DeleteApiPathParams {
5-
@Metadata("pathParam, style=simple;explode=false;name=apiID")
6-
ApiId: string;
7-
@Metadata("pathParam, style=simple;explode=false;name=versionID")
8-
VersionId: string;
9-
10-
constructor(ApiId: string, VersionId: string) {
11-
this.ApiId = ApiId;
12-
this.VersionId = VersionId;
13-
}
4+
export class DeleteApiPathParams extends SpeakeasyBase {
5+
@Metadata({ data: "pathParam, style=simple;explode=false;name=apiID" })
6+
ApiId: string;
7+
@Metadata({ data: "pathParam, style=simple;explode=false;name=versionID" })
8+
VersionId: string;
9+
1410
}
1511

16-
export class DeleteApiRequest {
17-
18-
PathParams: DeleteApiPathParams;
19-
20-
constructor(PathParams: DeleteApiPathParams) {
21-
this.PathParams = PathParams;
22-
}
12+
export class DeleteApiRequest extends SpeakeasyBase {
13+
@Metadata()
14+
PathParams: DeleteApiPathParams;
15+
2316
}
2417

25-
export class DeleteApiResponse {
26-
27-
ContentType: string;
28-
29-
Error?: shared.Error;
30-
31-
StatusCode: number;
32-
33-
constructor(ContentType: string, StatusCode: number, Error?: shared.Error) {
34-
this.ContentType = ContentType;
35-
this.Error = Error;
36-
this.StatusCode = StatusCode;
37-
}
18+
export class DeleteApiResponse extends SpeakeasyBase {
19+
@Metadata()
20+
ContentType: string;
21+
@Metadata()
22+
Error?: shared.Error;
23+
@Metadata()
24+
StatusCode: number;
25+
3826
}
3927

4028

src/sdk/models/operations/deleteapiendpoint.ts

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,30 @@
1-
import {Metadata} from "../../../internal/utils/utils";
1+
import { Metadata, SpeakeasyBase } from "../../../internal/utils/utils";
22
import * as shared from "../shared";
33

4-
export class DeleteApiEndpointPathParams {
5-
@Metadata("pathParam, style=simple;explode=false;name=apiEndpointID")
6-
ApiEndpointId: string;
7-
@Metadata("pathParam, style=simple;explode=false;name=apiID")
8-
ApiId: string;
9-
@Metadata("pathParam, style=simple;explode=false;name=versionID")
10-
VersionId: string;
11-
12-
constructor(ApiEndpointId: string, ApiId: string, VersionId: string) {
13-
this.ApiEndpointId = ApiEndpointId;
14-
this.ApiId = ApiId;
15-
this.VersionId = VersionId;
16-
}
4+
export class DeleteApiEndpointPathParams extends SpeakeasyBase {
5+
@Metadata({ data: "pathParam, style=simple;explode=false;name=apiEndpointID" })
6+
ApiEndpointId: string;
7+
@Metadata({ data: "pathParam, style=simple;explode=false;name=apiID" })
8+
ApiId: string;
9+
@Metadata({ data: "pathParam, style=simple;explode=false;name=versionID" })
10+
VersionId: string;
11+
1712
}
1813

19-
export class DeleteApiEndpointRequest {
20-
21-
PathParams: DeleteApiEndpointPathParams;
22-
23-
constructor(PathParams: DeleteApiEndpointPathParams) {
24-
this.PathParams = PathParams;
25-
}
14+
export class DeleteApiEndpointRequest extends SpeakeasyBase {
15+
@Metadata()
16+
PathParams: DeleteApiEndpointPathParams;
17+
2618
}
2719

28-
export class DeleteApiEndpointResponse {
29-
30-
ContentType: string;
31-
32-
Error?: shared.Error;
33-
34-
StatusCode: number;
35-
36-
constructor(ContentType: string, StatusCode: number, Error?: shared.Error) {
37-
this.ContentType = ContentType;
38-
this.Error = Error;
39-
this.StatusCode = StatusCode;
40-
}
20+
export class DeleteApiEndpointResponse extends SpeakeasyBase {
21+
@Metadata()
22+
ContentType: string;
23+
@Metadata()
24+
Error?: shared.Error;
25+
@Metadata()
26+
StatusCode: number;
27+
4128
}
4229

4330

0 commit comments

Comments
 (0)