@azure-tools/typespec-ts 0.15.0 → 0.16.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/CHANGELOG.md +10 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -17
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +3 -3
- package/dist/src/lib.js.map +1 -1
- package/dist/src/modular/buildClassicalClient.d.ts +2 -3
- package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
- package/dist/src/modular/buildClassicalClient.js +26 -12
- package/dist/src/modular/buildClassicalClient.js.map +1 -1
- package/dist/src/modular/buildClientContext.d.ts +3 -3
- package/dist/src/modular/buildClientContext.d.ts.map +1 -1
- package/dist/src/modular/buildClientContext.js +5 -4
- package/dist/src/modular/buildClientContext.js.map +1 -1
- package/dist/src/modular/buildCodeModel.d.ts +3 -2
- package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
- package/dist/src/modular/buildCodeModel.js +141 -54
- package/dist/src/modular/buildCodeModel.js.map +1 -1
- package/dist/src/modular/buildOperations.d.ts +2 -2
- package/dist/src/modular/buildOperations.d.ts.map +1 -1
- package/dist/src/modular/buildOperations.js +15 -8
- package/dist/src/modular/buildOperations.js.map +1 -1
- package/dist/src/modular/buildProjectFiles.js +2 -2
- package/dist/src/modular/buildProjectFiles.js.map +1 -1
- package/dist/src/modular/buildRootIndex.d.ts +4 -4
- package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
- package/dist/src/modular/buildRootIndex.js +12 -5
- package/dist/src/modular/buildRootIndex.js.map +1 -1
- package/dist/src/modular/buildSubpathIndex.d.ts +2 -2
- package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
- package/dist/src/modular/buildSubpathIndex.js +7 -4
- package/dist/src/modular/buildSubpathIndex.js.map +1 -1
- package/dist/src/modular/emitModels.d.ts +3 -3
- package/dist/src/modular/emitModels.d.ts.map +1 -1
- package/dist/src/modular/emitModels.js +28 -18
- package/dist/src/modular/emitModels.js.map +1 -1
- package/dist/src/modular/helpers/clientHelpers.js +1 -1
- package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.d.ts +1 -1
- package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.js +140 -77
- package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
- package/dist/src/modular/helpers/typeHelpers.d.ts +2 -2
- package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/typeHelpers.js +13 -7
- package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
- package/dist/src/modular/modularCodeModel.d.ts +11 -0
- package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
- package/dist/src/transform/transformHelperFunctionDetails.js +3 -4
- package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
- package/dist/src/transform/transformParameters.d.ts +0 -10
- package/dist/src/transform/transformParameters.d.ts.map +1 -1
- package/dist/src/transform/transformParameters.js +7 -51
- package/dist/src/transform/transformParameters.js.map +1 -1
- package/dist/src/transform/transformResponses.js +3 -4
- package/dist/src/transform/transformResponses.js.map +1 -1
- package/dist/src/transform/transformSchemas.d.ts.map +1 -1
- package/dist/src/transform/transformSchemas.js +4 -8
- package/dist/src/transform/transformSchemas.js.map +1 -1
- package/dist/src/transform/transformTelemetryInfo.d.ts.map +1 -1
- package/dist/src/transform/transformTelemetryInfo.js +3 -10
- package/dist/src/transform/transformTelemetryInfo.js.map +1 -1
- package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
- package/dist/src/transform/transfromRLCOptions.js +48 -9
- package/dist/src/transform/transfromRLCOptions.js.map +1 -1
- package/dist/src/utils/modelUtils.d.ts +2 -1
- package/dist/src/utils/modelUtils.d.ts.map +1 -1
- package/dist/src/utils/modelUtils.js +83 -73
- package/dist/src/utils/modelUtils.js.map +1 -1
- package/dist/src/utils/operationUtil.d.ts +15 -1
- package/dist/src/utils/operationUtil.d.ts.map +1 -1
- package/dist/src/utils/operationUtil.js +82 -3
- package/dist/src/utils/operationUtil.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -11
- package/src/index.ts +24 -51
- package/src/lib.ts +3 -3
- package/src/modular/buildClassicalClient.ts +29 -16
- package/src/modular/buildClientContext.ts +8 -9
- package/src/modular/buildCodeModel.ts +183 -60
- package/src/modular/buildOperations.ts +16 -11
- package/src/modular/buildProjectFiles.ts +2 -2
- package/src/modular/buildRootIndex.ts +19 -12
- package/src/modular/buildSubpathIndex.ts +10 -8
- package/src/modular/emitModels.ts +35 -24
- package/src/modular/helpers/clientHelpers.ts +1 -1
- package/src/modular/helpers/operationHelpers.ts +231 -118
- package/src/modular/helpers/typeHelpers.ts +14 -7
- package/src/modular/modularCodeModel.ts +11 -0
- package/src/transform/transformHelperFunctionDetails.ts +10 -4
- package/src/transform/transformParameters.ts +15 -57
- package/src/transform/transformResponses.ts +2 -4
- package/src/transform/transformSchemas.ts +5 -9
- package/src/transform/transformTelemetryInfo.ts +4 -18
- package/src/transform/transfromRLCOptions.ts +67 -9
- package/src/utils/modelUtils.ts +81 -72
- package/src/utils/operationUtil.ts +121 -4
|
@@ -27,10 +27,8 @@ import {
|
|
|
27
27
|
isStringType,
|
|
28
28
|
getPropertyType,
|
|
29
29
|
isNumericType,
|
|
30
|
-
getFormat,
|
|
31
30
|
getMinItems,
|
|
32
31
|
getMaxItems,
|
|
33
|
-
EmitContext,
|
|
34
32
|
listServices,
|
|
35
33
|
Union,
|
|
36
34
|
Type,
|
|
@@ -38,12 +36,12 @@ import {
|
|
|
38
36
|
getProjectedName,
|
|
39
37
|
isNullType,
|
|
40
38
|
getEncode,
|
|
41
|
-
isTemplateDeclarationOrInstance
|
|
39
|
+
isTemplateDeclarationOrInstance,
|
|
40
|
+
getFormat
|
|
42
41
|
} from "@typespec/compiler";
|
|
43
42
|
import {
|
|
44
43
|
getAuthentication,
|
|
45
44
|
getHeaderFieldName,
|
|
46
|
-
getHttpOperation,
|
|
47
45
|
getPathParamName,
|
|
48
46
|
getQueryParamName,
|
|
49
47
|
getServers,
|
|
@@ -54,7 +52,8 @@ import {
|
|
|
54
52
|
HttpServer,
|
|
55
53
|
isStatusCode,
|
|
56
54
|
HttpOperation,
|
|
57
|
-
isHeader
|
|
55
|
+
isHeader,
|
|
56
|
+
getHttpOperation
|
|
58
57
|
} from "@typespec/http";
|
|
59
58
|
import { getAddedOnVersions } from "@typespec/versioning";
|
|
60
59
|
import {
|
|
@@ -65,7 +64,6 @@ import {
|
|
|
65
64
|
isApiVersion,
|
|
66
65
|
getDefaultApiVersion,
|
|
67
66
|
getClientNamespaceString,
|
|
68
|
-
createSdkContext,
|
|
69
67
|
getSdkUnion,
|
|
70
68
|
getAllModels,
|
|
71
69
|
SdkSimpleType,
|
|
@@ -82,15 +80,24 @@ import {
|
|
|
82
80
|
Type as HrlcType,
|
|
83
81
|
Header
|
|
84
82
|
} from "./modularCodeModel.js";
|
|
85
|
-
import {
|
|
86
|
-
|
|
83
|
+
import {
|
|
84
|
+
getEnrichedDefaultApiVersion,
|
|
85
|
+
isAzureCoreErrorType
|
|
86
|
+
} from "../utils/modelUtils.js";
|
|
87
87
|
import { camelToSnakeCase, toCamelCase } from "../utils/casingUtils.js";
|
|
88
|
-
import {
|
|
88
|
+
import {
|
|
89
|
+
RLCModel,
|
|
90
|
+
getClientName,
|
|
91
|
+
NameType,
|
|
92
|
+
normalizeName
|
|
93
|
+
} from "@azure-tools/rlc-common";
|
|
89
94
|
import {
|
|
90
95
|
getOperationGroupName,
|
|
91
|
-
getOperationName
|
|
96
|
+
getOperationName,
|
|
97
|
+
isIgnoredHeaderParam
|
|
92
98
|
} from "../utils/operationUtil.js";
|
|
93
99
|
import { SdkContext } from "../utils/interfaces.js";
|
|
100
|
+
import { Project } from "ts-morph";
|
|
94
101
|
|
|
95
102
|
interface HttpServerParameter {
|
|
96
103
|
type: "endpointPath";
|
|
@@ -148,7 +155,8 @@ function isSimpleType(
|
|
|
148
155
|
getMaxValue,
|
|
149
156
|
getMinLength,
|
|
150
157
|
getMaxLength,
|
|
151
|
-
getPattern
|
|
158
|
+
getPattern,
|
|
159
|
+
getEncode
|
|
152
160
|
];
|
|
153
161
|
for (const func of funcs) {
|
|
154
162
|
if (func(program, type)) {
|
|
@@ -187,7 +195,7 @@ function handleDiscriminator(context: SdkContext, type: Model, model: any) {
|
|
|
187
195
|
}
|
|
188
196
|
}
|
|
189
197
|
}
|
|
190
|
-
// it is not included in properties of
|
|
198
|
+
// it is not included in properties of typespec but needed by python codegen
|
|
191
199
|
if (discriminatorProperty) {
|
|
192
200
|
const discriminatorType = { ...discriminatorProperty.type };
|
|
193
201
|
discriminatorType.value = null;
|
|
@@ -270,8 +278,7 @@ function getType(
|
|
|
270
278
|
options: { disableEffectiveModel?: boolean } = {}
|
|
271
279
|
): any {
|
|
272
280
|
// don't cache simple type(string, int, etc) since decorators may change the result
|
|
273
|
-
const enableCache =
|
|
274
|
-
!isSimpleType(context.program, type) && !isEmptyModel(type);
|
|
281
|
+
const enableCache = !isSimpleType(context.program, type);
|
|
275
282
|
const effectiveModel =
|
|
276
283
|
!options.disableEffectiveModel &&
|
|
277
284
|
(type.kind === "Model" || type.kind === "Union")
|
|
@@ -291,6 +298,10 @@ function getType(
|
|
|
291
298
|
newValue = emitType(context, type);
|
|
292
299
|
}
|
|
293
300
|
|
|
301
|
+
if (type.kind === "ModelProperty" || type.kind === "Scalar") {
|
|
302
|
+
newValue = applyEncoding(context.program, type, newValue);
|
|
303
|
+
}
|
|
304
|
+
|
|
294
305
|
if (enableCache) {
|
|
295
306
|
typesMap.set(effectiveModel, newValue);
|
|
296
307
|
if (type.kind === "Union") {
|
|
@@ -328,6 +339,7 @@ type ParamBase = {
|
|
|
328
339
|
addedOn: string | undefined;
|
|
329
340
|
clientName: string;
|
|
330
341
|
inOverload: boolean;
|
|
342
|
+
format?: string;
|
|
331
343
|
};
|
|
332
344
|
function emitParamBase(
|
|
333
345
|
program: Program,
|
|
@@ -337,12 +349,15 @@ function emitParamBase(
|
|
|
337
349
|
let name: string;
|
|
338
350
|
let description: string = "";
|
|
339
351
|
let addedOn: string | undefined;
|
|
352
|
+
let format: string | undefined;
|
|
340
353
|
|
|
341
354
|
if (parameter.kind === "ModelProperty") {
|
|
355
|
+
const newParameter = applyEncoding(program, parameter, parameter);
|
|
342
356
|
optional = parameter.optional;
|
|
343
357
|
name = parameter.name;
|
|
344
358
|
description = getDocStr(program, parameter);
|
|
345
359
|
addedOn = getAddedOnVersion(program, parameter);
|
|
360
|
+
format = newParameter.format;
|
|
346
361
|
} else {
|
|
347
362
|
optional = false;
|
|
348
363
|
name = "body";
|
|
@@ -353,7 +368,8 @@ function emitParamBase(
|
|
|
353
368
|
description,
|
|
354
369
|
addedOn,
|
|
355
370
|
clientName: applyCasing(name, { casing: CASING }),
|
|
356
|
-
inOverload: false
|
|
371
|
+
inOverload: false,
|
|
372
|
+
format
|
|
357
373
|
};
|
|
358
374
|
}
|
|
359
375
|
|
|
@@ -421,7 +437,6 @@ function emitBodyParameter(
|
|
|
421
437
|
const type = getType(context, getBodyType(context.program, httpOperation), {
|
|
422
438
|
disableEffectiveModel: true
|
|
423
439
|
});
|
|
424
|
-
|
|
425
440
|
if (type.type === "model" && type.name === "") {
|
|
426
441
|
type.name = capitalize(httpOperation.operation.name) + "Request";
|
|
427
442
|
}
|
|
@@ -459,9 +474,10 @@ function emitParameter(
|
|
|
459
474
|
const paramMap: any = {
|
|
460
475
|
restApiName: parameter.name,
|
|
461
476
|
location: parameter.type,
|
|
462
|
-
type: type,
|
|
477
|
+
type: base.format ? { ...type, format: base.format } : type,
|
|
463
478
|
implementation: implementation,
|
|
464
|
-
skipUrlEncoding: parameter.type === "endpointPath"
|
|
479
|
+
skipUrlEncoding: parameter.type === "endpointPath",
|
|
480
|
+
format: (parameter as any).format ?? base.format
|
|
465
481
|
};
|
|
466
482
|
|
|
467
483
|
if (paramMap.type.type === "constant") {
|
|
@@ -550,23 +566,6 @@ function emitResponseHeaders(
|
|
|
550
566
|
return retval;
|
|
551
567
|
}
|
|
552
568
|
|
|
553
|
-
function isAzureCoreErrorType(t?: Type): boolean {
|
|
554
|
-
if (
|
|
555
|
-
t?.kind !== "Model" ||
|
|
556
|
-
!["Error", "ErrorResponse", "InnerError"].includes(t.name)
|
|
557
|
-
)
|
|
558
|
-
return false;
|
|
559
|
-
const namespaces = ".Azure.Core.Foundations".split(".");
|
|
560
|
-
while (
|
|
561
|
-
namespaces.length > 0 &&
|
|
562
|
-
(t?.kind === "Model" || t?.kind === "Namespace") &&
|
|
563
|
-
t.namespace?.name === namespaces.pop()
|
|
564
|
-
) {
|
|
565
|
-
t = t.namespace;
|
|
566
|
-
}
|
|
567
|
-
return namespaces.length == 0;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
569
|
function emitResponse(
|
|
571
570
|
context: SdkContext,
|
|
572
571
|
response: HttpOperationResponse,
|
|
@@ -749,6 +748,9 @@ function emitBasicOperation(
|
|
|
749
748
|
});
|
|
750
749
|
|
|
751
750
|
for (const param of httpOperation.parameters.parameters) {
|
|
751
|
+
if (isIgnoredHeaderParam(param)) {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
752
754
|
const emittedParam = emitParameter(context, param, "Method");
|
|
753
755
|
if (isApiVersion(context, param) && apiVersionParam === undefined) {
|
|
754
756
|
apiVersionParam = emittedParam;
|
|
@@ -768,7 +770,7 @@ function emitBasicOperation(
|
|
|
768
770
|
innerResponse
|
|
769
771
|
);
|
|
770
772
|
if (isErrorModel(context.program, response.type)) {
|
|
771
|
-
// * is valid status code in
|
|
773
|
+
// * is valid status code in typespec but invalid for autorest.python
|
|
772
774
|
if (response.statusCode === "*") {
|
|
773
775
|
exceptions.push(emittedResponse);
|
|
774
776
|
}
|
|
@@ -820,7 +822,7 @@ function emitBasicOperation(
|
|
|
820
822
|
}
|
|
821
823
|
|
|
822
824
|
function isReadOnly(program: Program, type: ModelProperty): boolean {
|
|
823
|
-
// https://microsoft.github.io/
|
|
825
|
+
// https://microsoft.github.io/typespec/standard-library/http/operations#automatic-visibility
|
|
824
826
|
// Only "read" should be readOnly
|
|
825
827
|
const visibility = getVisibility(program, type);
|
|
826
828
|
if (visibility) {
|
|
@@ -834,6 +836,7 @@ function emitProperty(
|
|
|
834
836
|
context: SdkContext,
|
|
835
837
|
property: ModelProperty
|
|
836
838
|
): Record<string, any> {
|
|
839
|
+
const newProperty = applyEncoding(context.program, property, property);
|
|
837
840
|
let clientDefaultValue = undefined;
|
|
838
841
|
const propertyDefaultKind = property.default?.kind;
|
|
839
842
|
if (
|
|
@@ -845,6 +848,10 @@ function emitProperty(
|
|
|
845
848
|
clientDefaultValue = property.default.value;
|
|
846
849
|
}
|
|
847
850
|
|
|
851
|
+
if (propertyDefaultKind === "EnumMember") {
|
|
852
|
+
clientDefaultValue = property.default.value ?? property.default.name;
|
|
853
|
+
}
|
|
854
|
+
|
|
848
855
|
// const [clientName, jsonName] = getPropertyNames(context, property);
|
|
849
856
|
const clientName = property.name;
|
|
850
857
|
const jsonName =
|
|
@@ -853,16 +860,18 @@ function emitProperty(
|
|
|
853
860
|
if (property.model) {
|
|
854
861
|
getType(context, property.model);
|
|
855
862
|
}
|
|
863
|
+
const type = getType(context, property.type);
|
|
856
864
|
return {
|
|
857
865
|
clientName: applyCasing(clientName, { casing: CASING }),
|
|
858
866
|
restApiName: jsonName,
|
|
859
|
-
type:
|
|
867
|
+
type: newProperty.format ? { ...type, format: newProperty.format } : type,
|
|
860
868
|
optional: property.optional,
|
|
861
869
|
description: getDocStr(context.program, property),
|
|
862
870
|
addedOn: getAddedOnVersion(context.program, property),
|
|
863
871
|
readonly:
|
|
864
872
|
isReadOnly(context.program, property) || isKey(context.program, property),
|
|
865
|
-
clientDefaultValue: clientDefaultValue
|
|
873
|
+
clientDefaultValue: clientDefaultValue,
|
|
874
|
+
format: newProperty.format
|
|
866
875
|
};
|
|
867
876
|
}
|
|
868
877
|
|
|
@@ -896,9 +905,35 @@ function emitModel(context: SdkContext, type: Model): Record<string, any> {
|
|
|
896
905
|
baseModel = getType(context, type.baseModel);
|
|
897
906
|
}
|
|
898
907
|
const effectiveName = getEffectiveSchemaType(context.program, type).name;
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
|
|
908
|
+
const overridedModelName =
|
|
909
|
+
getProjectedName(context.program, type, "javascript") ??
|
|
910
|
+
getProjectedName(context.program, type, "client") ??
|
|
911
|
+
getFriendlyName(context.program, type);
|
|
912
|
+
let modelName =
|
|
913
|
+
overridedModelName ??
|
|
914
|
+
(effectiveName ? effectiveName : getName(context.program, type));
|
|
915
|
+
if (
|
|
916
|
+
!overridedModelName &&
|
|
917
|
+
type.templateMapper &&
|
|
918
|
+
type.templateMapper.args &&
|
|
919
|
+
type.templateMapper.args.length > 0 &&
|
|
920
|
+
getPagedResult(context.program, type)
|
|
921
|
+
) {
|
|
922
|
+
modelName =
|
|
923
|
+
type.templateMapper.args
|
|
924
|
+
.map((it) => {
|
|
925
|
+
switch (it.kind) {
|
|
926
|
+
case "Model":
|
|
927
|
+
return it.name;
|
|
928
|
+
case "String":
|
|
929
|
+
return it.value;
|
|
930
|
+
default:
|
|
931
|
+
return "";
|
|
932
|
+
}
|
|
933
|
+
})
|
|
934
|
+
.join("") + "List";
|
|
935
|
+
}
|
|
936
|
+
|
|
902
937
|
return {
|
|
903
938
|
type: "model",
|
|
904
939
|
name: modelName,
|
|
@@ -1000,9 +1035,10 @@ function emitStdScalar(
|
|
|
1000
1035
|
program: Program,
|
|
1001
1036
|
scalar: Scalar & { name: IntrinsicScalarName }
|
|
1002
1037
|
): Record<string, any> {
|
|
1038
|
+
const newScalar = applyEncoding(program, scalar, scalar);
|
|
1003
1039
|
switch (scalar.name) {
|
|
1004
1040
|
case "bytes":
|
|
1005
|
-
return { type: "byte-array", format:
|
|
1041
|
+
return { type: "byte-array", format: newScalar.format };
|
|
1006
1042
|
case "int8":
|
|
1007
1043
|
case "int16":
|
|
1008
1044
|
case "int32":
|
|
@@ -1024,13 +1060,15 @@ function emitStdScalar(
|
|
|
1024
1060
|
case "boolean":
|
|
1025
1061
|
return { type: "boolean" };
|
|
1026
1062
|
case "plainDate":
|
|
1027
|
-
return { type: "date" };
|
|
1063
|
+
return { type: "datetime", format: newScalar.format ?? "date" };
|
|
1028
1064
|
case "utcDateTime":
|
|
1029
|
-
return { type: "datetime", format:
|
|
1065
|
+
return { type: "datetime", format: newScalar.format };
|
|
1030
1066
|
case "plainTime":
|
|
1031
|
-
return { type: "time" };
|
|
1067
|
+
return { type: "datetime", format: newScalar.format ?? "time" };
|
|
1068
|
+
case "offsetDateTime":
|
|
1069
|
+
return { type: "datetime", format: newScalar.format ?? "rfc7231" };
|
|
1032
1070
|
case "duration":
|
|
1033
|
-
return { type: "duration" };
|
|
1071
|
+
return { type: "duration", format: newScalar.format };
|
|
1034
1072
|
case "numeric":
|
|
1035
1073
|
return {}; // Waiting on design for more precise type https://github.com/microsoft/cadl/issues/1260
|
|
1036
1074
|
default:
|
|
@@ -1038,12 +1076,51 @@ function emitStdScalar(
|
|
|
1038
1076
|
}
|
|
1039
1077
|
}
|
|
1040
1078
|
|
|
1079
|
+
function applyEncoding(
|
|
1080
|
+
program: Program,
|
|
1081
|
+
typespecType: Scalar | ModelProperty,
|
|
1082
|
+
target: any = {}
|
|
1083
|
+
) {
|
|
1084
|
+
const encodeData = getEncode(program, typespecType);
|
|
1085
|
+
const formatData = getFormat(program, typespecType);
|
|
1086
|
+
formatData;
|
|
1087
|
+
if (encodeData) {
|
|
1088
|
+
const newTarget = { ...target };
|
|
1089
|
+
const newType = emitScalar(program, encodeData.type);
|
|
1090
|
+
// newTarget["type"] = newType["type"];
|
|
1091
|
+
// If the target already has a format it takes priority. (e.g. int32)
|
|
1092
|
+
newTarget["format"] = mergeFormatAndEncoding(
|
|
1093
|
+
newTarget.format,
|
|
1094
|
+
encodeData.encoding,
|
|
1095
|
+
newType["format"]
|
|
1096
|
+
);
|
|
1097
|
+
return newTarget;
|
|
1098
|
+
}
|
|
1099
|
+
return target;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function mergeFormatAndEncoding(
|
|
1103
|
+
format: string | undefined,
|
|
1104
|
+
encoding: string,
|
|
1105
|
+
encodeAsFormat: string | undefined
|
|
1106
|
+
): string {
|
|
1107
|
+
switch (format) {
|
|
1108
|
+
case undefined:
|
|
1109
|
+
return encodeAsFormat ?? encoding;
|
|
1110
|
+
case "date-time":
|
|
1111
|
+
return encoding;
|
|
1112
|
+
case "duration":
|
|
1113
|
+
default:
|
|
1114
|
+
return encodeAsFormat ?? encoding;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1041
1118
|
function applyIntrinsicDecorators(
|
|
1042
1119
|
program: Program,
|
|
1043
1120
|
type: Scalar | ModelProperty,
|
|
1044
1121
|
result: any
|
|
1045
1122
|
): Record<string, any> {
|
|
1046
|
-
|
|
1123
|
+
let newResult = { ...result };
|
|
1047
1124
|
const docStr = getDoc(program, type);
|
|
1048
1125
|
const isString = isStringType(program, getPropertyType(type));
|
|
1049
1126
|
const isNumeric = isNumericType(program, getPropertyType(type));
|
|
@@ -1052,10 +1129,7 @@ function applyIntrinsicDecorators(
|
|
|
1052
1129
|
newResult.description = docStr;
|
|
1053
1130
|
}
|
|
1054
1131
|
|
|
1055
|
-
|
|
1056
|
-
if (isString && !result.format && formatStr) {
|
|
1057
|
-
newResult.format = formatStr;
|
|
1058
|
-
}
|
|
1132
|
+
newResult = applyEncoding(program, type, newResult);
|
|
1059
1133
|
|
|
1060
1134
|
const pattern = getPattern(program, type);
|
|
1061
1135
|
if (isString && !result.pattern && pattern) {
|
|
@@ -1096,7 +1170,8 @@ function applyIntrinsicDecorators(
|
|
|
1096
1170
|
|
|
1097
1171
|
function emitScalar(program: Program, scalar: Scalar): Record<string, any> {
|
|
1098
1172
|
let result: Record<string, any> = {};
|
|
1099
|
-
|
|
1173
|
+
const isStd = program.checker.isStdType(scalar);
|
|
1174
|
+
if (isStd) {
|
|
1100
1175
|
result = emitStdScalar(program, scalar);
|
|
1101
1176
|
} else if (scalar.baseScalar) {
|
|
1102
1177
|
result = emitScalar(program, scalar.baseScalar);
|
|
@@ -1127,7 +1202,7 @@ function emitListOrDict(
|
|
|
1127
1202
|
return undefined;
|
|
1128
1203
|
}
|
|
1129
1204
|
|
|
1130
|
-
function
|
|
1205
|
+
function mapTypeSpecType(context: SdkContext, type: Type): any {
|
|
1131
1206
|
switch (type.kind) {
|
|
1132
1207
|
case "Number":
|
|
1133
1208
|
return constantType(type.value, intOrFloat(type.value));
|
|
@@ -1228,7 +1303,7 @@ function emitType(context: SdkContext, type: EmitterType): Record<string, any> {
|
|
|
1228
1303
|
if (type.kind === "CredentialTypeUnion") {
|
|
1229
1304
|
return emitCredentialUnion(type);
|
|
1230
1305
|
}
|
|
1231
|
-
const builtinType =
|
|
1306
|
+
const builtinType = mapTypeSpecType(context, type);
|
|
1232
1307
|
if (builtinType !== undefined) {
|
|
1233
1308
|
// add in description elements for types derived from primitive types (SecureString, etc.)
|
|
1234
1309
|
const doc = getDoc(context.program, type);
|
|
@@ -1288,9 +1363,38 @@ function emitOperationGroups(
|
|
|
1288
1363
|
operations: clientOperations
|
|
1289
1364
|
});
|
|
1290
1365
|
}
|
|
1366
|
+
resolveConflictIfExist(operationGroups);
|
|
1291
1367
|
return operationGroups;
|
|
1292
1368
|
}
|
|
1293
1369
|
|
|
1370
|
+
function resolveConflictIfExist(operationGroups: OperationGroup[]) {
|
|
1371
|
+
if (operationGroups.length < 2) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
const nameSet = new Set<string>();
|
|
1376
|
+
const hasConflict = operationGroups.some((g) =>
|
|
1377
|
+
g.operations.some((op) => {
|
|
1378
|
+
if (nameSet.has(op.name)) {
|
|
1379
|
+
return true;
|
|
1380
|
+
} else {
|
|
1381
|
+
nameSet.add(op.name);
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
})
|
|
1385
|
+
);
|
|
1386
|
+
if (!hasConflict) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
// Append operation group prefix
|
|
1390
|
+
operationGroups.forEach((g) =>
|
|
1391
|
+
g.operations.forEach((op) => {
|
|
1392
|
+
op.oriName = op.name;
|
|
1393
|
+
op.name = `${g.propertyName}_${op.name}`;
|
|
1394
|
+
})
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1294
1398
|
function getServerHelper(
|
|
1295
1399
|
program: Program,
|
|
1296
1400
|
namespace: Namespace
|
|
@@ -1468,7 +1572,8 @@ function emitClients(
|
|
|
1468
1572
|
operationGroups: emitOperationGroups(context, client, rlcModels),
|
|
1469
1573
|
url: server ? server.url : "",
|
|
1470
1574
|
apiVersions: [],
|
|
1471
|
-
rlcClientName: rlcModels ? getClientName(rlcModels) : client.name
|
|
1575
|
+
rlcClientName: rlcModels ? getClientName(rlcModels) : client.name,
|
|
1576
|
+
subfolder: ""
|
|
1472
1577
|
};
|
|
1473
1578
|
const emittedApiVersionParam = getApiVersionParameter(context);
|
|
1474
1579
|
if (emittedApiVersionParam) {
|
|
@@ -1501,23 +1606,28 @@ function getNamespaces(context: SdkContext): Set<string> {
|
|
|
1501
1606
|
}
|
|
1502
1607
|
|
|
1503
1608
|
export function emitCodeModel(
|
|
1504
|
-
|
|
1609
|
+
dpgContext: SdkContext,
|
|
1505
1610
|
rlcModelsMap: Map<string, RLCModel>,
|
|
1611
|
+
modularSourcesRoot: string,
|
|
1612
|
+
project: Project,
|
|
1506
1613
|
options: { casing: "snake" | "camel" } = { casing: "snake" }
|
|
1507
1614
|
): ModularCodeModel {
|
|
1508
1615
|
CASING = options.casing ?? CASING;
|
|
1509
|
-
const dpgContext = createSdkContext(context);
|
|
1510
1616
|
const clientNamespaceString =
|
|
1511
1617
|
getClientNamespaceString(dpgContext)?.toLowerCase();
|
|
1512
1618
|
// Get types
|
|
1513
1619
|
const codeModel: ModularCodeModel = {
|
|
1514
|
-
options:
|
|
1620
|
+
options: dpgContext.rlcOptions ?? {},
|
|
1621
|
+
modularOptions: { sourceRoot: modularSourcesRoot },
|
|
1515
1622
|
namespace: clientNamespaceString,
|
|
1516
1623
|
subnamespaceToClients: {},
|
|
1517
1624
|
clients: [],
|
|
1518
|
-
types: []
|
|
1625
|
+
types: [],
|
|
1626
|
+
project
|
|
1519
1627
|
};
|
|
1520
1628
|
|
|
1629
|
+
typesMap.clear();
|
|
1630
|
+
simpleTypesMap.clear();
|
|
1521
1631
|
const allModels = getAllModels(dpgContext);
|
|
1522
1632
|
for (const model of allModels) {
|
|
1523
1633
|
getType(dpgContext, model);
|
|
@@ -1526,12 +1636,25 @@ export function emitCodeModel(
|
|
|
1526
1636
|
for (const namespace of getNamespaces(dpgContext)) {
|
|
1527
1637
|
if (namespace === clientNamespaceString) {
|
|
1528
1638
|
codeModel.clients = emitClients(dpgContext, namespace, rlcModelsMap);
|
|
1639
|
+
codeModel.clients.length > 1 &&
|
|
1640
|
+
codeModel.clients.map((client) => {
|
|
1641
|
+
client["subfolder"] = normalizeName(
|
|
1642
|
+
client.name.replace("Client", ""),
|
|
1643
|
+
NameType.File
|
|
1644
|
+
);
|
|
1645
|
+
});
|
|
1529
1646
|
} else {
|
|
1530
1647
|
codeModel["subnamespaceToClients"][namespace] = emitClients(
|
|
1531
1648
|
dpgContext,
|
|
1532
1649
|
namespace,
|
|
1533
1650
|
rlcModelsMap
|
|
1534
1651
|
);
|
|
1652
|
+
codeModel["subnamespaceToClients"][namespace].length > 1 &&
|
|
1653
|
+
(codeModel["subnamespaceToClients"][namespace] as HrlcClient[]).map(
|
|
1654
|
+
(client) => {
|
|
1655
|
+
client["subfolder"] = normalizeName(client.name, NameType.File);
|
|
1656
|
+
}
|
|
1657
|
+
);
|
|
1535
1658
|
}
|
|
1536
1659
|
}
|
|
1537
1660
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getDeserializePrivateFunction,
|
|
8
8
|
getOperationOptionsName
|
|
9
9
|
} from "./helpers/operationHelpers.js";
|
|
10
|
-
import { Client, Operation } from "./modularCodeModel.js";
|
|
10
|
+
import { Client, ModularCodeModel, Operation } from "./modularCodeModel.js";
|
|
11
11
|
import { isRLCMultiEndpoint } from "../utils/clientUtils.js";
|
|
12
12
|
import { getDocsFromDescription } from "./helpers/docsHelpers.js";
|
|
13
13
|
import { SdkContext } from "../utils/interfaces.js";
|
|
@@ -19,12 +19,11 @@ import { SdkContext } from "../utils/interfaces.js";
|
|
|
19
19
|
*/
|
|
20
20
|
export function buildOperationFiles(
|
|
21
21
|
dpgContext: SdkContext,
|
|
22
|
+
codeModel: ModularCodeModel,
|
|
22
23
|
client: Client,
|
|
23
|
-
project: Project,
|
|
24
|
-
srcPath: string = "src",
|
|
25
|
-
subfolder: string = "",
|
|
26
24
|
needUnexpectedHelper: boolean = true
|
|
27
25
|
) {
|
|
26
|
+
const operationFiles = [];
|
|
28
27
|
for (const operationGroup of client.operationGroups) {
|
|
29
28
|
const importSet: Map<string, Set<string>> = new Map<string, Set<string>>();
|
|
30
29
|
const fileName = operationGroup.className
|
|
@@ -33,7 +32,9 @@ export function buildOperationFiles(
|
|
|
33
32
|
// into a nameless operation group. We'll call this operations.
|
|
34
33
|
"operations";
|
|
35
34
|
|
|
36
|
-
const
|
|
35
|
+
const subfolder = client.subfolder;
|
|
36
|
+
const srcPath = codeModel.modularOptions.sourceRoot;
|
|
37
|
+
const operationGroupFile = codeModel.project.createSourceFile(
|
|
37
38
|
`${srcPath}/${
|
|
38
39
|
subfolder && subfolder !== "" ? subfolder + "/" : ""
|
|
39
40
|
}api/${fileName}.ts`
|
|
@@ -41,7 +42,7 @@ export function buildOperationFiles(
|
|
|
41
42
|
|
|
42
43
|
// Import models used from ./models.ts
|
|
43
44
|
// We SHOULD keep this because otherwise ts-morph will "helpfully" try to import models from the rest layer when we call fixMissingImports().
|
|
44
|
-
importModels(srcPath, operationGroupFile, project, subfolder);
|
|
45
|
+
importModels(srcPath, operationGroupFile, codeModel.project, subfolder);
|
|
45
46
|
|
|
46
47
|
const namedImports: string[] = [];
|
|
47
48
|
let clientType = "Client";
|
|
@@ -114,7 +115,9 @@ export function buildOperationFiles(
|
|
|
114
115
|
operationGroupFile.fixMissingImports();
|
|
115
116
|
// have to fixUnusedIdentifiers after everything get generated.
|
|
116
117
|
operationGroupFile.fixUnusedIdentifiers();
|
|
118
|
+
operationFiles.push(operationGroupFile);
|
|
117
119
|
}
|
|
120
|
+
return operationFiles;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
export function importModels(
|
|
@@ -134,10 +137,12 @@ export function importModels(
|
|
|
134
137
|
models.push(entry[0]);
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
if (models.length > 0) {
|
|
141
|
+
sourceFile.addImportDeclaration({
|
|
142
|
+
moduleSpecifier: "../models/models.js",
|
|
143
|
+
namedImports: models
|
|
144
|
+
});
|
|
145
|
+
}
|
|
141
146
|
|
|
142
147
|
// Import all models and then let ts-morph clean up the unused ones
|
|
143
148
|
// we can't fixUnusedIdentifiers here because the operaiton files are still being generated.
|
|
@@ -169,7 +174,7 @@ export function buildOperationOptions(
|
|
|
169
174
|
return {
|
|
170
175
|
docs: getDocsFromDescription(p.description),
|
|
171
176
|
hasQuestionToken: true,
|
|
172
|
-
...buildType(p.clientName, p.type)
|
|
177
|
+
...buildType(p.clientName, p.type, p.format)
|
|
173
178
|
};
|
|
174
179
|
})
|
|
175
180
|
});
|
|
@@ -100,7 +100,7 @@ export function emitPackage(
|
|
|
100
100
|
generateSample
|
|
101
101
|
)}`,
|
|
102
102
|
clean:
|
|
103
|
-
"rimraf dist dist-browser dist-esm test-dist temp types *.tgz *.log",
|
|
103
|
+
"rimraf --glob dist dist-browser dist-esm test-dist temp types *.tgz *.log",
|
|
104
104
|
"execute:samples": "echo skipped",
|
|
105
105
|
"extract-api":
|
|
106
106
|
"rimraf review && mkdirp ./review && api-extractor run --local",
|
|
@@ -156,7 +156,7 @@ export function emitPackage(
|
|
|
156
156
|
eslint: "^8.0.0",
|
|
157
157
|
mkdirp: "^2.1.2",
|
|
158
158
|
prettier: "^2.5.1",
|
|
159
|
-
rimraf: "^
|
|
159
|
+
rimraf: "^5.0.0",
|
|
160
160
|
"source-map-support": "^0.5.9",
|
|
161
161
|
typescript: "~5.0.0"
|
|
162
162
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Project, SourceFile } from "ts-morph";
|
|
2
2
|
import { getClientName } from "./helpers/namingHelpers.js";
|
|
3
|
-
import { Client } from "./modularCodeModel.js";
|
|
3
|
+
import { Client, ModularCodeModel } from "./modularCodeModel.js";
|
|
4
4
|
|
|
5
5
|
export function buildRootIndex(
|
|
6
|
+
codeModel: ModularCodeModel,
|
|
6
7
|
client: Client,
|
|
7
|
-
|
|
8
|
-
rootIndexFile: SourceFile,
|
|
9
|
-
srcPath: string,
|
|
10
|
-
subfolder: string
|
|
8
|
+
rootIndexFile: SourceFile
|
|
11
9
|
) {
|
|
10
|
+
const { project } = codeModel;
|
|
11
|
+
const srcPath = codeModel.modularOptions.sourceRoot;
|
|
12
|
+
const subfolder = client.subfolder ?? "";
|
|
12
13
|
const clientName = `${getClientName(client)}Client`;
|
|
13
14
|
const clientFile = project.getSourceFile(
|
|
14
15
|
`${srcPath}/${subfolder !== "" ? subfolder + "/" : ""}${clientName}.ts`
|
|
@@ -71,12 +72,12 @@ function exportModels(
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
export function buildSubClientIndexFile(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
srcPath: string,
|
|
77
|
-
subfolder: string
|
|
75
|
+
codeModel: ModularCodeModel,
|
|
76
|
+
client: Client
|
|
78
77
|
) {
|
|
79
|
-
const
|
|
78
|
+
const subfolder = client.subfolder ?? "";
|
|
79
|
+
const srcPath = codeModel.modularOptions.sourceRoot;
|
|
80
|
+
const subClientIndexFile = codeModel.project.createSourceFile(
|
|
80
81
|
`${srcPath}/${subfolder !== "" ? subfolder + "/" : ""}index.ts`,
|
|
81
82
|
undefined,
|
|
82
83
|
{ overwrite: true }
|
|
@@ -85,12 +86,18 @@ export function buildSubClientIndexFile(
|
|
|
85
86
|
const clientFilePath = `${srcPath}/${
|
|
86
87
|
subfolder !== "" ? subfolder + "/" : ""
|
|
87
88
|
}${clientName}.ts`;
|
|
88
|
-
const clientFile = project.getSourceFile(clientFilePath);
|
|
89
|
+
const clientFile = codeModel.project.getSourceFile(clientFilePath);
|
|
89
90
|
|
|
90
91
|
if (!clientFile) {
|
|
91
92
|
throw new Error(`Couldn't find client file: ${clientFilePath}`);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
exportClassicalClient(client, subClientIndexFile, subfolder, true);
|
|
95
|
-
exportModels(
|
|
96
|
+
exportModels(
|
|
97
|
+
subClientIndexFile,
|
|
98
|
+
codeModel.project,
|
|
99
|
+
srcPath,
|
|
100
|
+
clientName,
|
|
101
|
+
subfolder
|
|
102
|
+
);
|
|
96
103
|
}
|