@azure-tools/rlc-common 1.0.0-beta.1 → 1.0.0-beta.10
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/.eslintrc.json +23 -0
- package/.prettierignore +1 -0
- package/.prettierrc +7 -0
- package/.rush/temp/package-deps_build.json +33 -25
- package/.rush/temp/shrinkwrap-deps.json +84 -9
- package/CHANGELOG.md +52 -1
- package/CONTRIBUTING.md +29 -0
- package/README.md +3 -0
- package/dist/buildClient.js +89 -19
- package/dist/buildClient.js.map +1 -1
- package/dist/buildClientDefinitions.js.map +1 -1
- package/dist/buildIndexFile.js +18 -0
- package/dist/buildIndexFile.js.map +1 -1
- package/dist/buildIsUnexpectedHelper.js +52 -51
- package/dist/buildIsUnexpectedHelper.js.map +1 -1
- package/dist/buildMethodShortcuts.js +1 -1
- package/dist/buildMethodShortcuts.js.map +1 -1
- package/dist/buildObjectTypes.js +47 -11
- package/dist/buildObjectTypes.js.map +1 -1
- package/dist/buildParameterTypes.js +31 -3
- package/dist/buildParameterTypes.js.map +1 -1
- package/dist/buildResponseTypes.js +19 -6
- package/dist/buildResponseTypes.js.map +1 -1
- package/dist/buildSchemaType.js +22 -1
- package/dist/buildSchemaType.js.map +1 -1
- package/dist/buildSerializeHelper.js +35 -0
- package/dist/buildSerializeHelper.js.map +1 -0
- package/dist/buildTopLevelIndexFile.js +6 -3
- package/dist/buildTopLevelIndexFile.js.map +1 -1
- package/dist/helpers/nameConstructors.js +2 -2
- package/dist/helpers/nameConstructors.js.map +1 -1
- package/dist/helpers/nameUtils.js +1 -1
- package/dist/helpers/nameUtils.js.map +1 -1
- package/dist/helpers/operationHelpers.js +23 -3
- package/dist/helpers/operationHelpers.js.map +1 -1
- package/dist/helpers/pathUtils.js +13 -0
- package/dist/helpers/pathUtils.js.map +1 -0
- package/dist/helpers/shortcutMethods.js +1 -1
- package/dist/helpers/shortcutMethods.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/metadata/buildPackageFile.js +70 -28
- package/dist/metadata/buildPackageFile.js.map +1 -1
- package/dist/metadata/buildReadmeFile.js +3 -3
- package/dist/package.json +1 -1
- package/dist/static/paginateContent.js +1 -1
- package/dist/static/pollingContent.js +26 -6
- package/dist/static/pollingContent.js.map +1 -1
- package/dist/static/serializeHelper.js +30 -0
- package/dist/static/serializeHelper.js.map +1 -0
- package/dist/test/template.js +1 -2
- package/dist/test/template.js.map +1 -1
- package/dist-esm/buildClient.js +88 -18
- package/dist-esm/buildClient.js.map +1 -1
- package/dist-esm/buildClientDefinitions.js +1 -1
- package/dist-esm/buildClientDefinitions.js.map +1 -1
- package/dist-esm/buildIndexFile.js +19 -1
- package/dist-esm/buildIndexFile.js.map +1 -1
- package/dist-esm/buildIsUnexpectedHelper.js +52 -51
- package/dist-esm/buildIsUnexpectedHelper.js.map +1 -1
- package/dist-esm/buildMethodShortcuts.js +1 -1
- package/dist-esm/buildMethodShortcuts.js.map +1 -1
- package/dist-esm/buildObjectTypes.js +47 -8
- package/dist-esm/buildObjectTypes.js.map +1 -1
- package/dist-esm/buildParameterTypes.js +35 -2
- package/dist-esm/buildParameterTypes.js.map +1 -1
- package/dist-esm/buildResponseTypes.js +19 -6
- package/dist-esm/buildResponseTypes.js.map +1 -1
- package/dist-esm/buildSchemaType.js +23 -2
- package/dist-esm/buildSchemaType.js.map +1 -1
- package/dist-esm/buildSerializeHelper.js +31 -0
- package/dist-esm/buildSerializeHelper.js.map +1 -0
- package/dist-esm/buildTopLevelIndexFile.js +6 -3
- package/dist-esm/buildTopLevelIndexFile.js.map +1 -1
- package/dist-esm/helpers/nameConstructors.js +2 -2
- package/dist-esm/helpers/nameConstructors.js.map +1 -1
- package/dist-esm/helpers/nameUtils.js +1 -1
- package/dist-esm/helpers/nameUtils.js.map +1 -1
- package/dist-esm/helpers/operationHelpers.js +15 -3
- package/dist-esm/helpers/operationHelpers.js.map +1 -1
- package/dist-esm/helpers/pathUtils.js +9 -0
- package/dist-esm/helpers/pathUtils.js.map +1 -0
- package/dist-esm/helpers/shortcutMethods.js +1 -1
- package/dist-esm/helpers/shortcutMethods.js.map +1 -1
- package/dist-esm/index.js +1 -0
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/interfaces.js.map +1 -1
- package/dist-esm/metadata/buildPackageFile.js +70 -28
- package/dist-esm/metadata/buildPackageFile.js.map +1 -1
- package/dist-esm/metadata/buildReadmeFile.js +3 -3
- package/dist-esm/package.json +1 -1
- package/dist-esm/static/paginateContent.js +1 -1
- package/dist-esm/static/pollingContent.js +26 -6
- package/dist-esm/static/pollingContent.js.map +1 -1
- package/dist-esm/static/serializeHelper.js +27 -0
- package/dist-esm/static/serializeHelper.js.map +1 -0
- package/dist-esm/test/template.js +1 -2
- package/dist-esm/test/template.js.map +1 -1
- package/package.json +10 -4
- package/src/buildClient.ts +121 -19
- package/src/buildClientDefinitions.ts +6 -2
- package/src/buildIndexFile.ts +28 -0
- package/src/buildIsUnexpectedHelper.ts +52 -52
- package/src/buildMethodShortcuts.ts +1 -1
- package/src/buildObjectTypes.ts +66 -10
- package/src/buildParameterTypes.ts +45 -3
- package/src/buildResponseTypes.ts +23 -6
- package/src/buildSchemaType.ts +24 -1
- package/src/buildSerializeHelper.ts +42 -0
- package/src/buildTopLevelIndexFile.ts +9 -3
- package/src/helpers/nameConstructors.ts +2 -2
- package/src/helpers/nameUtils.ts +1 -1
- package/src/helpers/operationHelpers.ts +19 -3
- package/src/helpers/pathUtils.ts +9 -0
- package/src/helpers/schemaHelpers.ts +1 -1
- package/src/helpers/shortcutMethods.ts +1 -1
- package/src/index.ts +1 -0
- package/src/interfaces.ts +16 -1
- package/src/metadata/buildPackageFile.ts +94 -31
- package/src/metadata/buildReadmeFile.ts +3 -3
- package/src/static/paginateContent.ts +1 -1
- package/src/static/pollingContent.ts +26 -6
- package/src/static/serializeHelper.ts +29 -0
- package/src/test/template.ts +1 -2
- package/types/buildObjectTypes.d.ts +2 -1
- package/types/buildParameterTypes.d.ts +9 -1
- package/types/buildSerializeHelper.d.ts +5 -0
- package/types/helpers/operationHelpers.d.ts +4 -0
- package/types/helpers/pathUtils.d.ts +1 -0
- package/types/index.d.ts +1 -0
- package/types/interfaces.d.ts +15 -1
- package/types/static/pollingContent.d.ts +1 -1
- package/types/static/serializeHelper.d.ts +4 -0
- package/types/test/template.d.ts +1 -1
package/src/buildClient.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
InterfaceDeclarationStructure,
|
|
6
|
+
OptionalKind,
|
|
5
7
|
Project,
|
|
6
8
|
StatementStructures,
|
|
7
9
|
StructureKind,
|
|
@@ -13,7 +15,31 @@ import * as path from "path";
|
|
|
13
15
|
import { NameType, normalizeName } from "./helpers/nameUtils.js";
|
|
14
16
|
import { isConstantSchema } from "./helpers/schemaHelpers.js";
|
|
15
17
|
import { buildMethodShortcutImplementation } from "./buildMethodShortcuts.js";
|
|
16
|
-
import { RLCModel, Schema, File } from "./interfaces.js";
|
|
18
|
+
import { RLCModel, Schema, File, PathParameter } from "./interfaces.js";
|
|
19
|
+
|
|
20
|
+
function getClientOptionsInterface(
|
|
21
|
+
clientName: string,
|
|
22
|
+
optionalUrlParameters?: PathParameter[]
|
|
23
|
+
): OptionalKind<InterfaceDeclarationStructure> | undefined {
|
|
24
|
+
if (!optionalUrlParameters || optionalUrlParameters.length === 0) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const properties = optionalUrlParameters.map((param) => {
|
|
29
|
+
return {
|
|
30
|
+
name: param.name,
|
|
31
|
+
type: param.type,
|
|
32
|
+
hasQuestionToken: true
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
name: `${clientName}Options`,
|
|
38
|
+
extends: ["ClientOptions"],
|
|
39
|
+
isExported: true,
|
|
40
|
+
properties
|
|
41
|
+
};
|
|
42
|
+
}
|
|
17
43
|
|
|
18
44
|
export function buildClient(model: RLCModel): File | undefined {
|
|
19
45
|
const name = normalizeName(model.libraryName, NameType.File);
|
|
@@ -26,7 +52,29 @@ export function buildClient(model: RLCModel): File | undefined {
|
|
|
26
52
|
|
|
27
53
|
// Get all paths
|
|
28
54
|
const clientName = model.libraryName;
|
|
29
|
-
const
|
|
55
|
+
const clientInterfaceName = clientName.endsWith("Client")
|
|
56
|
+
? `${clientName}`
|
|
57
|
+
: `${clientName}Client`;
|
|
58
|
+
|
|
59
|
+
normalizeUrlInfo(model);
|
|
60
|
+
const urlParameters = model?.urlInfo?.urlParameters?.filter(
|
|
61
|
+
// Do not include parameters with constant values in the signature, these should go in the options bag
|
|
62
|
+
(p) => p.value === undefined
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const optionalUrlParameters = model?.urlInfo?.urlParameters?.filter(
|
|
66
|
+
// Do not include parameters with constant values in the signature, these should go in the options bag
|
|
67
|
+
(p) => Boolean(p.value)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const clientOptionsInterface = getClientOptionsInterface(
|
|
71
|
+
clientInterfaceName,
|
|
72
|
+
optionalUrlParameters
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (clientOptionsInterface) {
|
|
76
|
+
clientFile.addInterface(clientOptionsInterface);
|
|
77
|
+
}
|
|
30
78
|
|
|
31
79
|
if (!model.options) {
|
|
32
80
|
return undefined;
|
|
@@ -46,26 +94,39 @@ export function buildClient(model: RLCModel): File | undefined {
|
|
|
46
94
|
...(addCredentials === false ||
|
|
47
95
|
!isSecurityInfoDefined(credentialScopes, credentialKeyHeaderName)
|
|
48
96
|
? []
|
|
49
|
-
: [
|
|
97
|
+
: [
|
|
98
|
+
{
|
|
99
|
+
name: "credentials",
|
|
100
|
+
type: credentialTypes.join(" | "),
|
|
101
|
+
description: `uniquely identify client credential`
|
|
102
|
+
}
|
|
103
|
+
])
|
|
50
104
|
];
|
|
51
|
-
const clientInterfaceName = clientName.endsWith("Client")
|
|
52
|
-
? `${clientName}`
|
|
53
|
-
: `${clientName}Client`;
|
|
54
105
|
|
|
106
|
+
const allClientParams = [
|
|
107
|
+
...commonClientParams,
|
|
108
|
+
{
|
|
109
|
+
name: "options",
|
|
110
|
+
type: `${clientOptionsInterface?.name ?? "ClientOptions"} = {}`,
|
|
111
|
+
description: "the parameter for all optional parameters"
|
|
112
|
+
}
|
|
113
|
+
];
|
|
55
114
|
const functionStatement = {
|
|
56
115
|
isExported: true,
|
|
57
116
|
name: `createClient`,
|
|
58
|
-
parameters:
|
|
59
|
-
...commonClientParams,
|
|
60
|
-
{ name: "options", type: "ClientOptions = {}" }
|
|
61
|
-
],
|
|
117
|
+
parameters: allClientParams,
|
|
62
118
|
docs: [
|
|
63
119
|
{
|
|
64
120
|
description:
|
|
65
|
-
`Initialize a new instance of
|
|
66
|
-
|
|
121
|
+
`Initialize a new instance of \`${clientInterfaceName}\` \n` +
|
|
122
|
+
allClientParams
|
|
67
123
|
.map((param) => {
|
|
68
|
-
return `@param ${param.name} type: ${param.type
|
|
124
|
+
return `@param ${param.name} type: ${param.type
|
|
125
|
+
.split("=")[0]
|
|
126
|
+
.split(" ")
|
|
127
|
+
.join("")}, ${
|
|
128
|
+
param.description ?? "The parameter " + param.name
|
|
129
|
+
}`;
|
|
69
130
|
})
|
|
70
131
|
.join("\n")
|
|
71
132
|
}
|
|
@@ -127,6 +188,19 @@ function getClientFactoryBody(
|
|
|
127
188
|
let clientPackageName = packageDetails.nameWithoutScope ?? "";
|
|
128
189
|
const packageVersion = packageDetails.version;
|
|
129
190
|
const { endpoint, urlParameters } = model.urlInfo;
|
|
191
|
+
|
|
192
|
+
const optionalUrlParameters: string[] = [];
|
|
193
|
+
|
|
194
|
+
for (const param of urlParameters ?? []) {
|
|
195
|
+
if (param.value) {
|
|
196
|
+
const value =
|
|
197
|
+
typeof param.value === "string" ? `"${param.value}"` : param.value;
|
|
198
|
+
optionalUrlParameters.push(
|
|
199
|
+
`const ${param.name} = options.${param.name} ?? ${value}`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
130
204
|
let baseUrl: string;
|
|
131
205
|
if (urlParameters && endpoint) {
|
|
132
206
|
let parsedEndpoint = endpoint;
|
|
@@ -142,7 +216,7 @@ function getClientFactoryBody(
|
|
|
142
216
|
baseUrl = `options.baseUrl ?? "${endpoint}"`;
|
|
143
217
|
}
|
|
144
218
|
|
|
145
|
-
const apiVersion =
|
|
219
|
+
const apiVersion = getApiVersionInQueryParam(model);
|
|
146
220
|
let apiVersionStatement: string = "";
|
|
147
221
|
if (apiVersion) {
|
|
148
222
|
apiVersionStatement = `options.apiVersion = options.apiVersion ?? "${apiVersion}"`;
|
|
@@ -224,6 +298,7 @@ function getClientFactoryBody(
|
|
|
224
298
|
}
|
|
225
299
|
|
|
226
300
|
return [
|
|
301
|
+
...optionalUrlParameters,
|
|
227
302
|
baseUrlStatement,
|
|
228
303
|
apiVersionStatement,
|
|
229
304
|
credentials,
|
|
@@ -235,17 +310,44 @@ function getClientFactoryBody(
|
|
|
235
310
|
];
|
|
236
311
|
}
|
|
237
312
|
|
|
238
|
-
function
|
|
239
|
-
if (!model.
|
|
313
|
+
function getApiVersionInQueryParam(model: RLCModel): string | undefined {
|
|
314
|
+
if (!model.apiVersionInQueryParam) {
|
|
240
315
|
return undefined;
|
|
241
316
|
}
|
|
242
317
|
|
|
243
318
|
if (
|
|
244
|
-
model.
|
|
245
|
-
isConstantSchema(model.
|
|
319
|
+
model.apiVersionInQueryParam &&
|
|
320
|
+
isConstantSchema(model.apiVersionInQueryParam as Schema)
|
|
246
321
|
) {
|
|
247
|
-
return model.
|
|
322
|
+
return model.apiVersionInQueryParam.default;
|
|
248
323
|
}
|
|
249
324
|
|
|
250
325
|
return undefined;
|
|
251
326
|
}
|
|
327
|
+
|
|
328
|
+
function normalizeUrlInfo(model: RLCModel) {
|
|
329
|
+
if (
|
|
330
|
+
!model ||
|
|
331
|
+
!model.urlInfo ||
|
|
332
|
+
!model.urlInfo.endpoint ||
|
|
333
|
+
!model.urlInfo.urlParameters ||
|
|
334
|
+
model.urlInfo.urlParameters.length === 0
|
|
335
|
+
) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
let parsedEndpoint = model.urlInfo.endpoint;
|
|
340
|
+
const urlParameters = model.urlInfo.urlParameters;
|
|
341
|
+
urlParameters.forEach((urlParameter) => {
|
|
342
|
+
const name = urlParameter.name;
|
|
343
|
+
const normalizedName = normalizeName(name, NameType.Parameter);
|
|
344
|
+
if (name !== normalizedName) {
|
|
345
|
+
urlParameter.name = normalizedName;
|
|
346
|
+
parsedEndpoint = parsedEndpoint.replace(
|
|
347
|
+
`{${name}}`,
|
|
348
|
+
`{${normalizedName}}`
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
model.urlInfo.endpoint = parsedEndpoint;
|
|
353
|
+
}
|
|
@@ -18,8 +18,12 @@ import {
|
|
|
18
18
|
} from "./helpers/operationHelpers.js";
|
|
19
19
|
import { PathMetadata, Paths, RLCModel } from "./interfaces.js";
|
|
20
20
|
import { generateMethodShortcuts } from "./helpers/shortcutMethods.js";
|
|
21
|
-
import { REST_CLIENT_RESERVED } from
|
|
22
|
-
import {
|
|
21
|
+
import { REST_CLIENT_RESERVED } from "./buildMethodShortcuts.js";
|
|
22
|
+
import {
|
|
23
|
+
CasingConvention,
|
|
24
|
+
NameType,
|
|
25
|
+
normalizeName
|
|
26
|
+
} from "./helpers/nameUtils.js";
|
|
23
27
|
import { pascalCase } from "./helpers/nameUtils.js";
|
|
24
28
|
|
|
25
29
|
export function buildClientDefinitions(model: RLCModel) {
|
package/src/buildIndexFile.ts
CHANGED
|
@@ -5,9 +5,13 @@ import { Project, SourceFile } from "ts-morph";
|
|
|
5
5
|
import { NameType, normalizeName } from "./helpers/nameUtils.js";
|
|
6
6
|
import {
|
|
7
7
|
hasInputModels,
|
|
8
|
+
hasMultiCollection,
|
|
8
9
|
hasOutputModels,
|
|
9
10
|
hasPagingOperations,
|
|
11
|
+
hasPipeCollection,
|
|
10
12
|
hasPollingOperations,
|
|
13
|
+
hasSsvCollection,
|
|
14
|
+
hasTsvCollection,
|
|
11
15
|
hasUnexpectedHelper
|
|
12
16
|
} from "./helpers/operationHelpers.js";
|
|
13
17
|
import { RLCModel } from "./interfaces.js";
|
|
@@ -89,6 +93,19 @@ function generateRLCIndexForMultiClient(file: SourceFile, model: RLCModel) {
|
|
|
89
93
|
exports.push("PollingHelper");
|
|
90
94
|
}
|
|
91
95
|
|
|
96
|
+
if (
|
|
97
|
+
hasMultiCollection(model) ||
|
|
98
|
+
hasSsvCollection(model) ||
|
|
99
|
+
hasPipeCollection(model) ||
|
|
100
|
+
hasTsvCollection(model)
|
|
101
|
+
) {
|
|
102
|
+
file.addImportDeclaration({
|
|
103
|
+
namespaceImport: "SerializeHelper",
|
|
104
|
+
moduleSpecifier: "./serializeHelper"
|
|
105
|
+
});
|
|
106
|
+
exports.push("SerializeHelper");
|
|
107
|
+
}
|
|
108
|
+
|
|
92
109
|
file.addExportDeclarations([
|
|
93
110
|
{
|
|
94
111
|
moduleSpecifier: `./${moduleName}`,
|
|
@@ -165,6 +182,17 @@ function generateRLCIndex(file: SourceFile, model: RLCModel) {
|
|
|
165
182
|
]);
|
|
166
183
|
}
|
|
167
184
|
|
|
185
|
+
if (
|
|
186
|
+
hasMultiCollection(model) ||
|
|
187
|
+
hasSsvCollection(model) ||
|
|
188
|
+
hasPipeCollection(model) ||
|
|
189
|
+
hasTsvCollection(model)
|
|
190
|
+
) {
|
|
191
|
+
file.addExportDeclarations([{
|
|
192
|
+
moduleSpecifier: "./serializeHelper"
|
|
193
|
+
}]);
|
|
194
|
+
}
|
|
195
|
+
|
|
168
196
|
file.addExportAssignment({
|
|
169
197
|
expression: createClientFuncName,
|
|
170
198
|
isExportEquals: false
|
|
@@ -22,9 +22,9 @@ export function buildIsUnexpectedHelper(model: RLCModel) {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
let map: Record<string, string[]> = {};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const allResponseTypes: Set<string> = new Set();
|
|
26
|
+
const allErrorTypes: Set<string> = new Set();
|
|
27
|
+
const overloads: OptionalKind<FunctionDeclarationOverloadStructure>[] = [];
|
|
28
28
|
const pathDictionary = model.paths;
|
|
29
29
|
|
|
30
30
|
for (const [path, details] of Object.entries(pathDictionary)) {
|
|
@@ -112,7 +112,7 @@ export function buildIsUnexpectedHelper(model: RLCModel) {
|
|
|
112
112
|
} pathDetails = responseMap[\`\${method} \${url.pathname}\`];
|
|
113
113
|
if (!pathDetails) {`,
|
|
114
114
|
hasTemplate
|
|
115
|
-
? "pathDetails =
|
|
115
|
+
? "pathDetails = getParametrizedPathSuccess(method, url.pathname);"
|
|
116
116
|
: `return true;`,
|
|
117
117
|
` }
|
|
118
118
|
return !pathDetails.includes(response.status);
|
|
@@ -122,7 +122,7 @@ export function buildIsUnexpectedHelper(model: RLCModel) {
|
|
|
122
122
|
if (hasTemplate) {
|
|
123
123
|
isErrorHelper.addFunction({
|
|
124
124
|
isExported: false,
|
|
125
|
-
name: "
|
|
125
|
+
name: "getParametrizedPathSuccess",
|
|
126
126
|
parameters: [
|
|
127
127
|
{
|
|
128
128
|
name: "method",
|
|
@@ -136,75 +136,75 @@ export function buildIsUnexpectedHelper(model: RLCModel) {
|
|
|
136
136
|
returnType: `string[]`,
|
|
137
137
|
statements: [
|
|
138
138
|
`
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
139
|
+
const pathParts = path.split("/");
|
|
140
|
+
|
|
141
|
+
// Traverse list to match the longest candidate
|
|
142
|
+
// matchedLen: the length of candidate path
|
|
143
|
+
// matchedValue: the matched status code array
|
|
144
|
+
let matchedLen = -1,
|
|
145
|
+
matchedValue: string[] = [];
|
|
146
|
+
|
|
147
|
+
// Iterate the responseMap to find a match
|
|
148
|
+
for (const [key, value] of Object.entries(responseMap)) {
|
|
149
|
+
// Extracting the path from the map key which is in format
|
|
150
|
+
// GET /path/foo
|
|
151
|
+
if (!key.startsWith(method)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const candidatePath = getPathFromMapKey(key);
|
|
155
|
+
// Get each part of the url path
|
|
156
|
+
const candidateParts = candidatePath.split("/");
|
|
157
|
+
|
|
158
158
|
// track if we have found a match to return the values found.
|
|
159
159
|
let found = true;
|
|
160
|
-
for (
|
|
160
|
+
for (
|
|
161
|
+
let i = candidateParts.length - 1, j = pathParts.length - 1;
|
|
162
|
+
i >= 1 && j >= 1;
|
|
163
|
+
i--, j--
|
|
164
|
+
) {
|
|
161
165
|
if (
|
|
162
166
|
candidateParts[i]?.startsWith("{") &&
|
|
163
|
-
candidateParts[i]?.
|
|
167
|
+
candidateParts[i]?.indexOf("}") !== -1
|
|
164
168
|
) {
|
|
169
|
+
const start = candidateParts[i]!.indexOf("}") + 1,
|
|
170
|
+
end = candidateParts[i]?.length;
|
|
165
171
|
// If the current part of the candidate is a "template" part
|
|
166
|
-
//
|
|
167
|
-
//
|
|
172
|
+
// Try to use the suffix of pattern to match the path
|
|
173
|
+
// {guid} ==> $
|
|
174
|
+
// {guid}:export ==> :export$
|
|
175
|
+
const isMatched = new RegExp(
|
|
176
|
+
\`\${candidateParts[i]?.slice(start, end)}\`
|
|
177
|
+
).test(pathParts[j] || '');
|
|
178
|
+
|
|
179
|
+
if (!isMatched) {
|
|
180
|
+
found = false;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
168
183
|
continue;
|
|
169
184
|
}
|
|
170
|
-
|
|
185
|
+
|
|
171
186
|
// If the candidate part is not a template and
|
|
172
187
|
// the parts don't match mark the candidate as not found
|
|
173
188
|
// to move on with the next candidate path.
|
|
174
|
-
if (candidateParts[i] !== pathParts[
|
|
189
|
+
if (candidateParts[i] !== pathParts[j]) {
|
|
175
190
|
found = false;
|
|
176
191
|
break;
|
|
177
192
|
}
|
|
178
193
|
}
|
|
179
|
-
|
|
194
|
+
|
|
180
195
|
// We finished evaluating the current candidate parts
|
|
181
|
-
// if
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
196
|
+
// Update the matched value if and only if we found the longer pattern
|
|
197
|
+
if (found && candidatePath.length > matchedLen) {
|
|
198
|
+
matchedLen = candidatePath.length;
|
|
199
|
+
matchedValue = value;
|
|
185
200
|
}
|
|
186
201
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// No match was found, return an empty array.
|
|
190
|
-
return [];
|
|
202
|
+
|
|
203
|
+
return matchedValue;
|
|
191
204
|
`
|
|
192
205
|
]
|
|
193
206
|
});
|
|
194
207
|
|
|
195
|
-
isErrorHelper.addFunction({
|
|
196
|
-
isExported: false,
|
|
197
|
-
name: "hasParametrizedPath",
|
|
198
|
-
parameters: [
|
|
199
|
-
{
|
|
200
|
-
name: "path",
|
|
201
|
-
type: "string"
|
|
202
|
-
}
|
|
203
|
-
],
|
|
204
|
-
returnType: `boolean`,
|
|
205
|
-
statements: [`return path.includes("/{");`]
|
|
206
|
-
});
|
|
207
|
-
|
|
208
208
|
isErrorHelper.addFunction({
|
|
209
209
|
isExported: false,
|
|
210
210
|
name: "getPathFromMapKey",
|
|
@@ -22,7 +22,7 @@ export const REST_CLIENT_RESERVED: ReservedName[] = [
|
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
export function buildMethodShortcutImplementation(paths: Paths) {
|
|
25
|
-
|
|
25
|
+
const keys: Record<string, string[]> = {};
|
|
26
26
|
for (const path of Object.keys(paths)) {
|
|
27
27
|
const groupName = normalizeName(
|
|
28
28
|
paths[path].operationGroupName,
|
package/src/buildObjectTypes.ts
CHANGED
|
@@ -33,6 +33,9 @@ export function buildObjectInterfaces(
|
|
|
33
33
|
const objectInterfaces: InterfaceDeclarationStructure[] = [];
|
|
34
34
|
|
|
35
35
|
for (const objectSchema of objectSchemas) {
|
|
36
|
+
if (objectSchema.alias || objectSchema.outputAlias) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
36
39
|
const baseName = getObjectBaseName(objectSchema, schemaUsage);
|
|
37
40
|
const interfaceDeclaration = getObjectInterfaceDeclaration(
|
|
38
41
|
baseName,
|
|
@@ -46,6 +49,40 @@ export function buildObjectInterfaces(
|
|
|
46
49
|
return objectInterfaces;
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
export function buildObjectAliases(
|
|
53
|
+
model: RLCModel,
|
|
54
|
+
importedModels: Set<string>,
|
|
55
|
+
schemaUsage: SchemaContext[]
|
|
56
|
+
) {
|
|
57
|
+
const objectSchemas: ObjectSchema[] = (model.schemas ?? []).filter(
|
|
58
|
+
(o) =>
|
|
59
|
+
isObjectSchema(o) &&
|
|
60
|
+
(o as ObjectSchema).usage?.some((u) => schemaUsage.includes(u))
|
|
61
|
+
);
|
|
62
|
+
const objectAliases: TypeAliasDeclarationStructure[] = [];
|
|
63
|
+
|
|
64
|
+
for (const objectSchema of objectSchemas) {
|
|
65
|
+
if (objectSchema.alias || objectSchema.outputAlias) {
|
|
66
|
+
const description = objectSchema.description;
|
|
67
|
+
objectAliases.push({
|
|
68
|
+
kind: StructureKind.TypeAlias,
|
|
69
|
+
...(description && { docs: [{ description }] }),
|
|
70
|
+
name: schemaUsage.includes(SchemaContext.Input)
|
|
71
|
+
? `${objectSchema.typeName}`
|
|
72
|
+
: `${objectSchema.outputTypeName}`,
|
|
73
|
+
type: schemaUsage.includes(SchemaContext.Input)
|
|
74
|
+
? `${objectSchema.alias}`
|
|
75
|
+
: `${objectSchema.outputAlias}`,
|
|
76
|
+
isExported: true
|
|
77
|
+
});
|
|
78
|
+
if (objectSchema.alias?.startsWith("Paged<")) {
|
|
79
|
+
importedModels.add("Paged");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return objectAliases;
|
|
84
|
+
}
|
|
85
|
+
|
|
49
86
|
export function buildPolymorphicAliases(
|
|
50
87
|
model: RLCModel,
|
|
51
88
|
schemaUsage: SchemaContext[]
|
|
@@ -123,7 +160,7 @@ function getPolymorphicTypeAlias(
|
|
|
123
160
|
}
|
|
124
161
|
|
|
125
162
|
const description = objectSchema.description;
|
|
126
|
-
|
|
163
|
+
|
|
127
164
|
return {
|
|
128
165
|
kind: StructureKind.TypeAlias,
|
|
129
166
|
...(description && { docs: [{ description }] }),
|
|
@@ -316,7 +353,7 @@ function getImmediateParentsNames(
|
|
|
316
353
|
return [];
|
|
317
354
|
}
|
|
318
355
|
|
|
319
|
-
|
|
356
|
+
const extendFrom: string[] = [];
|
|
320
357
|
|
|
321
358
|
// If an immediate parent is a DictionarySchema, that means that the object has been marked
|
|
322
359
|
// with additional properties. We need to add Record<string, unknown> to the extend list and
|
|
@@ -350,7 +387,12 @@ function getPropertySignatures(
|
|
|
350
387
|
schemaUsage: SchemaContext[],
|
|
351
388
|
importedModels: Set<string>
|
|
352
389
|
) {
|
|
353
|
-
|
|
390
|
+
let validProperties = Object.keys(properties);
|
|
391
|
+
const readOnlyFilter = (name: string) =>
|
|
392
|
+
!(schemaUsage.includes(SchemaContext.Input) && properties[name].readOnly);
|
|
393
|
+
const neverFilter = (name: string) => properties[name].type !== "never";
|
|
394
|
+
validProperties = validProperties.filter(readOnlyFilter).filter(neverFilter);
|
|
395
|
+
return validProperties.map((p) =>
|
|
354
396
|
getPropertySignature(
|
|
355
397
|
{ ...properties[p], name: p },
|
|
356
398
|
schemaUsage,
|
|
@@ -368,26 +410,40 @@ function getPropertySignatures(
|
|
|
368
410
|
export function getPropertySignature(
|
|
369
411
|
property: Property | Parameter,
|
|
370
412
|
schemaUsage: SchemaContext[],
|
|
371
|
-
importedModels
|
|
413
|
+
importedModels: Set<string>
|
|
372
414
|
): PropertySignatureStructure {
|
|
373
415
|
const propertyName = property.name;
|
|
374
416
|
|
|
375
417
|
const description = property.description;
|
|
376
|
-
|
|
377
|
-
(
|
|
378
|
-
property.usage?.includes(SchemaContext.Output)) ||
|
|
379
|
-
(schemaUsage.includes(SchemaContext.Exception) &&
|
|
380
|
-
property.usage?.includes(SchemaContext.Exception))) &&
|
|
381
|
-
property.outputTypeName
|
|
418
|
+
let type =
|
|
419
|
+
generateForOutput(schemaUsage, property.usage) && property.outputTypeName
|
|
382
420
|
? property.outputTypeName
|
|
383
421
|
: property.typeName
|
|
384
422
|
? property.typeName
|
|
385
423
|
: property.type;
|
|
424
|
+
if (property.typeName && property.fromCore) {
|
|
425
|
+
importedModels.add(property.typeName);
|
|
426
|
+
type = property.typeName;
|
|
427
|
+
}
|
|
386
428
|
return {
|
|
387
429
|
name: propertyName,
|
|
388
430
|
...(description && { docs: [{ description }] }),
|
|
389
431
|
hasQuestionToken: !property.required,
|
|
432
|
+
isReadonly:
|
|
433
|
+
generateForOutput(schemaUsage, property.usage) && property.readOnly,
|
|
390
434
|
type,
|
|
391
435
|
kind: StructureKind.PropertySignature
|
|
392
436
|
};
|
|
393
437
|
}
|
|
438
|
+
|
|
439
|
+
function generateForOutput(
|
|
440
|
+
schemaUsage: SchemaContext[],
|
|
441
|
+
propertyUsage?: SchemaContext[]
|
|
442
|
+
) {
|
|
443
|
+
return (
|
|
444
|
+
(schemaUsage.includes(SchemaContext.Output) &&
|
|
445
|
+
propertyUsage?.includes(SchemaContext.Output)) ||
|
|
446
|
+
(schemaUsage.includes(SchemaContext.Exception) &&
|
|
447
|
+
propertyUsage?.includes(SchemaContext.Exception))
|
|
448
|
+
);
|
|
449
|
+
}
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
import * as path from "path";
|
|
12
12
|
import {
|
|
13
13
|
ImportKind,
|
|
14
|
+
ObjectSchema,
|
|
14
15
|
ParameterMetadata,
|
|
15
16
|
ParameterMetadatas,
|
|
16
17
|
RLCModel,
|
|
17
18
|
Schema
|
|
18
19
|
} from "./interfaces.js";
|
|
19
|
-
import { NameType, normalizeName } from "./helpers/nameUtils.js";
|
|
20
20
|
import {
|
|
21
21
|
getParameterBaseName,
|
|
22
22
|
getParameterTypeName
|
|
@@ -92,6 +92,11 @@ export function buildParameterTypes(model: RLCModel) {
|
|
|
92
92
|
i
|
|
93
93
|
);
|
|
94
94
|
|
|
95
|
+
const bodyTypeAlias = buildBodyTypeAlias(parameter);
|
|
96
|
+
if (bodyTypeAlias) {
|
|
97
|
+
parametersFile.addTypeAlias(bodyTypeAlias);
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
// Add interfaces for body and query parameters
|
|
96
101
|
parametersFile.addInterfaces([
|
|
97
102
|
...(bodyParameterDefinition ?? []),
|
|
@@ -215,7 +220,7 @@ function getPropertyFromSchema(schema: Schema): PropertySignatureStructure {
|
|
|
215
220
|
name: schema.name,
|
|
216
221
|
...(description && { docs: [{ description }] }),
|
|
217
222
|
type: schema.type,
|
|
218
|
-
hasQuestionToken: !
|
|
223
|
+
hasQuestionToken: !schema.required,
|
|
219
224
|
kind: StructureKind.PropertySignature
|
|
220
225
|
};
|
|
221
226
|
}
|
|
@@ -296,8 +301,12 @@ function buildHeaderParameterDefinitions(
|
|
|
296
301
|
baseName
|
|
297
302
|
);
|
|
298
303
|
|
|
304
|
+
let isOptional = true;
|
|
299
305
|
if (headersInterface) {
|
|
300
306
|
parametersFile.addInterface(headersInterface);
|
|
307
|
+
isOptional = !(headersInterface.properties || []).some(
|
|
308
|
+
(prop) => prop.hasQuestionToken === false
|
|
309
|
+
);
|
|
301
310
|
}
|
|
302
311
|
|
|
303
312
|
internalReferences.add(headerParameterInterfaceName);
|
|
@@ -310,7 +319,8 @@ function buildHeaderParameterDefinitions(
|
|
|
310
319
|
{
|
|
311
320
|
name: "headers",
|
|
312
321
|
type: `RawHttpHeadersInput & ${baseName}Headers`,
|
|
313
|
-
kind: StructureKind.PropertySignature
|
|
322
|
+
kind: StructureKind.PropertySignature,
|
|
323
|
+
hasQuestionToken: isOptional
|
|
314
324
|
}
|
|
315
325
|
]
|
|
316
326
|
};
|
|
@@ -433,3 +443,35 @@ function buildBodyParametersDefinition(
|
|
|
433
443
|
];
|
|
434
444
|
}
|
|
435
445
|
}
|
|
446
|
+
|
|
447
|
+
export function buildBodyTypeAlias(parameters: ParameterMetadatas) {
|
|
448
|
+
const bodyParameters = parameters.body;
|
|
449
|
+
if (
|
|
450
|
+
!bodyParameters ||
|
|
451
|
+
!bodyParameters?.body ||
|
|
452
|
+
!bodyParameters?.body.length
|
|
453
|
+
) {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
const schema = bodyParameters.body[0] as ObjectSchema;
|
|
457
|
+
const headerParameters = (parameters.parameters || []).filter(
|
|
458
|
+
(p) => p.type === "header" && p.name === "contentType"
|
|
459
|
+
);
|
|
460
|
+
if (!headerParameters.length || headerParameters.length > 1) {
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const contentType = headerParameters[0].param.type;
|
|
465
|
+
const description = `${schema.description}`;
|
|
466
|
+
const typeName = `${schema.typeName}ResourceMergeAndPatch`;
|
|
467
|
+
if (contentType.includes("application/merge-patch+json")) {
|
|
468
|
+
const type = `Partial<${schema.typeName}>`;
|
|
469
|
+
return {
|
|
470
|
+
// kind: StructureKind.TypeAlias,
|
|
471
|
+
...(description && { docs: [{ description }] }),
|
|
472
|
+
name: `${typeName}`,
|
|
473
|
+
type,
|
|
474
|
+
isExported: true
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|