@azure-tools/typespec-ts 0.15.0 → 0.16.0-alpha.20230918.1
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 +163 -69
- 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 +167 -88
- 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 +212 -75
- 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 +256 -127
- package/src/modular/helpers/typeHelpers.ts +19 -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)) {
|
|
@@ -172,34 +180,44 @@ function isLro(_program: Program, operation: Operation): boolean {
|
|
|
172
180
|
return false;
|
|
173
181
|
}
|
|
174
182
|
|
|
175
|
-
function
|
|
183
|
+
function isDiscriminator(
|
|
184
|
+
context: SdkContext,
|
|
185
|
+
type: Model,
|
|
186
|
+
propertyName: string
|
|
187
|
+
): boolean {
|
|
188
|
+
const discriminator = getDiscriminator(context.program, type);
|
|
189
|
+
if (discriminator && discriminator.propertyName === propertyName) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function handleDiscriminator(context: SdkContext, type: Model) {
|
|
176
196
|
const discriminator = getDiscriminator(context.program, type);
|
|
177
197
|
if (discriminator) {
|
|
178
|
-
|
|
198
|
+
const discriminatorValues: string[] = [];
|
|
179
199
|
for (const childModel of type.derivedModels) {
|
|
180
200
|
const modelType = getType(context, childModel);
|
|
181
201
|
for (const property of modelType.properties) {
|
|
182
202
|
if (property.restApiName === discriminator.propertyName) {
|
|
183
203
|
modelType.discriminatorValue = property.type.value;
|
|
184
|
-
|
|
185
|
-
model.discriminatedSubtypes[property.type.value] = modelType;
|
|
186
|
-
discriminatorProperty = property;
|
|
204
|
+
discriminatorValues.push(modelType.discriminatorValue);
|
|
187
205
|
}
|
|
188
206
|
}
|
|
189
207
|
}
|
|
190
|
-
// it is not included in properties of
|
|
191
|
-
if (
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
208
|
+
// it is not included in properties of typespec but needed by python codegen
|
|
209
|
+
if (discriminatorValues.length > 0) {
|
|
210
|
+
const discriminatorInfo = {
|
|
211
|
+
description: `the discriminator possible values ${discriminatorValues.join(
|
|
212
|
+
", "
|
|
213
|
+
)}`,
|
|
196
214
|
isPolymorphic: true,
|
|
197
|
-
|
|
215
|
+
isDiscriminator: true
|
|
198
216
|
};
|
|
199
|
-
|
|
200
|
-
model.properties.push(propertyCopy);
|
|
217
|
+
return discriminatorInfo;
|
|
201
218
|
}
|
|
202
219
|
}
|
|
220
|
+
return undefined;
|
|
203
221
|
}
|
|
204
222
|
|
|
205
223
|
function getEffectiveSchemaType(program: Program, type: Model | Union): Model {
|
|
@@ -258,10 +276,14 @@ function processModelProperties(
|
|
|
258
276
|
if (newValue.properties === undefined || newValue.properties === null) {
|
|
259
277
|
newValue.properties = [];
|
|
260
278
|
}
|
|
261
|
-
|
|
279
|
+
let newProperty = emitProperty(context, property);
|
|
280
|
+
if (isDiscriminator(context, model, property.name)) {
|
|
281
|
+
newProperty = { ...newProperty, ...handleDiscriminator(context, model) };
|
|
282
|
+
}
|
|
283
|
+
newValue.properties.push(newProperty);
|
|
262
284
|
}
|
|
263
285
|
// need to do discriminator outside `emitModel` to avoid infinite recursion
|
|
264
|
-
handleDiscriminator(context, model, newValue);
|
|
286
|
+
// handleDiscriminator(context, model, newValue);
|
|
265
287
|
}
|
|
266
288
|
|
|
267
289
|
function getType(
|
|
@@ -270,8 +292,7 @@ function getType(
|
|
|
270
292
|
options: { disableEffectiveModel?: boolean } = {}
|
|
271
293
|
): any {
|
|
272
294
|
// don't cache simple type(string, int, etc) since decorators may change the result
|
|
273
|
-
const enableCache =
|
|
274
|
-
!isSimpleType(context.program, type) && !isEmptyModel(type);
|
|
295
|
+
const enableCache = !isSimpleType(context.program, type);
|
|
275
296
|
const effectiveModel =
|
|
276
297
|
!options.disableEffectiveModel &&
|
|
277
298
|
(type.kind === "Model" || type.kind === "Union")
|
|
@@ -291,6 +312,10 @@ function getType(
|
|
|
291
312
|
newValue = emitType(context, type);
|
|
292
313
|
}
|
|
293
314
|
|
|
315
|
+
if (type.kind === "ModelProperty" || type.kind === "Scalar") {
|
|
316
|
+
newValue = applyEncoding(context.program, type, newValue);
|
|
317
|
+
}
|
|
318
|
+
|
|
294
319
|
if (enableCache) {
|
|
295
320
|
typesMap.set(effectiveModel, newValue);
|
|
296
321
|
if (type.kind === "Union") {
|
|
@@ -328,6 +353,7 @@ type ParamBase = {
|
|
|
328
353
|
addedOn: string | undefined;
|
|
329
354
|
clientName: string;
|
|
330
355
|
inOverload: boolean;
|
|
356
|
+
format?: string;
|
|
331
357
|
};
|
|
332
358
|
function emitParamBase(
|
|
333
359
|
program: Program,
|
|
@@ -337,12 +363,15 @@ function emitParamBase(
|
|
|
337
363
|
let name: string;
|
|
338
364
|
let description: string = "";
|
|
339
365
|
let addedOn: string | undefined;
|
|
366
|
+
let format: string | undefined;
|
|
340
367
|
|
|
341
368
|
if (parameter.kind === "ModelProperty") {
|
|
369
|
+
const newParameter = applyEncoding(program, parameter, parameter);
|
|
342
370
|
optional = parameter.optional;
|
|
343
371
|
name = parameter.name;
|
|
344
372
|
description = getDocStr(program, parameter);
|
|
345
373
|
addedOn = getAddedOnVersion(program, parameter);
|
|
374
|
+
format = newParameter.format;
|
|
346
375
|
} else {
|
|
347
376
|
optional = false;
|
|
348
377
|
name = "body";
|
|
@@ -353,7 +382,8 @@ function emitParamBase(
|
|
|
353
382
|
description,
|
|
354
383
|
addedOn,
|
|
355
384
|
clientName: applyCasing(name, { casing: CASING }),
|
|
356
|
-
inOverload: false
|
|
385
|
+
inOverload: false,
|
|
386
|
+
format
|
|
357
387
|
};
|
|
358
388
|
}
|
|
359
389
|
|
|
@@ -421,7 +451,6 @@ function emitBodyParameter(
|
|
|
421
451
|
const type = getType(context, getBodyType(context.program, httpOperation), {
|
|
422
452
|
disableEffectiveModel: true
|
|
423
453
|
});
|
|
424
|
-
|
|
425
454
|
if (type.type === "model" && type.name === "") {
|
|
426
455
|
type.name = capitalize(httpOperation.operation.name) + "Request";
|
|
427
456
|
}
|
|
@@ -459,9 +488,10 @@ function emitParameter(
|
|
|
459
488
|
const paramMap: any = {
|
|
460
489
|
restApiName: parameter.name,
|
|
461
490
|
location: parameter.type,
|
|
462
|
-
type: type,
|
|
491
|
+
type: base.format ? { ...type, format: base.format } : type,
|
|
463
492
|
implementation: implementation,
|
|
464
|
-
skipUrlEncoding: parameter.type === "endpointPath"
|
|
493
|
+
skipUrlEncoding: parameter.type === "endpointPath",
|
|
494
|
+
format: (parameter as any).format ?? base.format
|
|
465
495
|
};
|
|
466
496
|
|
|
467
497
|
if (paramMap.type.type === "constant") {
|
|
@@ -550,23 +580,6 @@ function emitResponseHeaders(
|
|
|
550
580
|
return retval;
|
|
551
581
|
}
|
|
552
582
|
|
|
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
583
|
function emitResponse(
|
|
571
584
|
context: SdkContext,
|
|
572
585
|
response: HttpOperationResponse,
|
|
@@ -749,6 +762,9 @@ function emitBasicOperation(
|
|
|
749
762
|
});
|
|
750
763
|
|
|
751
764
|
for (const param of httpOperation.parameters.parameters) {
|
|
765
|
+
if (isIgnoredHeaderParam(param)) {
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
752
768
|
const emittedParam = emitParameter(context, param, "Method");
|
|
753
769
|
if (isApiVersion(context, param) && apiVersionParam === undefined) {
|
|
754
770
|
apiVersionParam = emittedParam;
|
|
@@ -768,7 +784,7 @@ function emitBasicOperation(
|
|
|
768
784
|
innerResponse
|
|
769
785
|
);
|
|
770
786
|
if (isErrorModel(context.program, response.type)) {
|
|
771
|
-
// * is valid status code in
|
|
787
|
+
// * is valid status code in typespec but invalid for autorest.python
|
|
772
788
|
if (response.statusCode === "*") {
|
|
773
789
|
exceptions.push(emittedResponse);
|
|
774
790
|
}
|
|
@@ -820,7 +836,7 @@ function emitBasicOperation(
|
|
|
820
836
|
}
|
|
821
837
|
|
|
822
838
|
function isReadOnly(program: Program, type: ModelProperty): boolean {
|
|
823
|
-
// https://microsoft.github.io/
|
|
839
|
+
// https://microsoft.github.io/typespec/standard-library/http/operations#automatic-visibility
|
|
824
840
|
// Only "read" should be readOnly
|
|
825
841
|
const visibility = getVisibility(program, type);
|
|
826
842
|
if (visibility) {
|
|
@@ -834,6 +850,7 @@ function emitProperty(
|
|
|
834
850
|
context: SdkContext,
|
|
835
851
|
property: ModelProperty
|
|
836
852
|
): Record<string, any> {
|
|
853
|
+
const newProperty = applyEncoding(context.program, property, property);
|
|
837
854
|
let clientDefaultValue = undefined;
|
|
838
855
|
const propertyDefaultKind = property.default?.kind;
|
|
839
856
|
if (
|
|
@@ -845,6 +862,10 @@ function emitProperty(
|
|
|
845
862
|
clientDefaultValue = property.default.value;
|
|
846
863
|
}
|
|
847
864
|
|
|
865
|
+
if (propertyDefaultKind === "EnumMember") {
|
|
866
|
+
clientDefaultValue = property.default.value ?? property.default.name;
|
|
867
|
+
}
|
|
868
|
+
|
|
848
869
|
// const [clientName, jsonName] = getPropertyNames(context, property);
|
|
849
870
|
const clientName = property.name;
|
|
850
871
|
const jsonName =
|
|
@@ -853,16 +874,18 @@ function emitProperty(
|
|
|
853
874
|
if (property.model) {
|
|
854
875
|
getType(context, property.model);
|
|
855
876
|
}
|
|
877
|
+
const type = getType(context, property.type);
|
|
856
878
|
return {
|
|
857
879
|
clientName: applyCasing(clientName, { casing: CASING }),
|
|
858
880
|
restApiName: jsonName,
|
|
859
|
-
type:
|
|
881
|
+
type: newProperty.format ? { ...type, format: newProperty.format } : type,
|
|
860
882
|
optional: property.optional,
|
|
861
883
|
description: getDocStr(context.program, property),
|
|
862
884
|
addedOn: getAddedOnVersion(context.program, property),
|
|
863
885
|
readonly:
|
|
864
886
|
isReadOnly(context.program, property) || isKey(context.program, property),
|
|
865
|
-
clientDefaultValue: clientDefaultValue
|
|
887
|
+
clientDefaultValue: clientDefaultValue,
|
|
888
|
+
format: newProperty.format
|
|
866
889
|
};
|
|
867
890
|
}
|
|
868
891
|
|
|
@@ -896,9 +919,35 @@ function emitModel(context: SdkContext, type: Model): Record<string, any> {
|
|
|
896
919
|
baseModel = getType(context, type.baseModel);
|
|
897
920
|
}
|
|
898
921
|
const effectiveName = getEffectiveSchemaType(context.program, type).name;
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
|
|
922
|
+
const overridedModelName =
|
|
923
|
+
getProjectedName(context.program, type, "javascript") ??
|
|
924
|
+
getProjectedName(context.program, type, "client") ??
|
|
925
|
+
getFriendlyName(context.program, type);
|
|
926
|
+
let modelName =
|
|
927
|
+
overridedModelName ??
|
|
928
|
+
(effectiveName ? effectiveName : getName(context.program, type));
|
|
929
|
+
if (
|
|
930
|
+
!overridedModelName &&
|
|
931
|
+
type.templateMapper &&
|
|
932
|
+
type.templateMapper.args &&
|
|
933
|
+
type.templateMapper.args.length > 0 &&
|
|
934
|
+
getPagedResult(context.program, type)
|
|
935
|
+
) {
|
|
936
|
+
modelName =
|
|
937
|
+
type.templateMapper.args
|
|
938
|
+
.map((it) => {
|
|
939
|
+
switch (it.kind) {
|
|
940
|
+
case "Model":
|
|
941
|
+
return it.name;
|
|
942
|
+
case "String":
|
|
943
|
+
return it.value;
|
|
944
|
+
default:
|
|
945
|
+
return "";
|
|
946
|
+
}
|
|
947
|
+
})
|
|
948
|
+
.join("") + "List";
|
|
949
|
+
}
|
|
950
|
+
|
|
902
951
|
return {
|
|
903
952
|
type: "model",
|
|
904
953
|
name: modelName,
|
|
@@ -1000,9 +1049,10 @@ function emitStdScalar(
|
|
|
1000
1049
|
program: Program,
|
|
1001
1050
|
scalar: Scalar & { name: IntrinsicScalarName }
|
|
1002
1051
|
): Record<string, any> {
|
|
1052
|
+
const newScalar = applyEncoding(program, scalar, scalar);
|
|
1003
1053
|
switch (scalar.name) {
|
|
1004
1054
|
case "bytes":
|
|
1005
|
-
return { type: "byte-array", format:
|
|
1055
|
+
return { type: "byte-array", format: newScalar.format };
|
|
1006
1056
|
case "int8":
|
|
1007
1057
|
case "int16":
|
|
1008
1058
|
case "int32":
|
|
@@ -1024,13 +1074,15 @@ function emitStdScalar(
|
|
|
1024
1074
|
case "boolean":
|
|
1025
1075
|
return { type: "boolean" };
|
|
1026
1076
|
case "plainDate":
|
|
1027
|
-
return { type: "date" };
|
|
1077
|
+
return { type: "datetime", format: newScalar.format ?? "date" };
|
|
1028
1078
|
case "utcDateTime":
|
|
1029
|
-
return { type: "datetime", format:
|
|
1079
|
+
return { type: "datetime", format: newScalar.format };
|
|
1030
1080
|
case "plainTime":
|
|
1031
|
-
return { type: "time" };
|
|
1081
|
+
return { type: "datetime", format: newScalar.format ?? "time" };
|
|
1082
|
+
case "offsetDateTime":
|
|
1083
|
+
return { type: "string" };
|
|
1032
1084
|
case "duration":
|
|
1033
|
-
return { type: "duration" };
|
|
1085
|
+
return { type: "duration", format: newScalar.format };
|
|
1034
1086
|
case "numeric":
|
|
1035
1087
|
return {}; // Waiting on design for more precise type https://github.com/microsoft/cadl/issues/1260
|
|
1036
1088
|
default:
|
|
@@ -1038,12 +1090,51 @@ function emitStdScalar(
|
|
|
1038
1090
|
}
|
|
1039
1091
|
}
|
|
1040
1092
|
|
|
1093
|
+
function applyEncoding(
|
|
1094
|
+
program: Program,
|
|
1095
|
+
typespecType: Scalar | ModelProperty,
|
|
1096
|
+
target: any = {}
|
|
1097
|
+
) {
|
|
1098
|
+
const encodeData = getEncode(program, typespecType);
|
|
1099
|
+
const formatData = getFormat(program, typespecType);
|
|
1100
|
+
formatData;
|
|
1101
|
+
if (encodeData) {
|
|
1102
|
+
const newTarget = { ...target };
|
|
1103
|
+
const newType = emitScalar(program, encodeData.type);
|
|
1104
|
+
// newTarget["type"] = newType["type"];
|
|
1105
|
+
// If the target already has a format it takes priority. (e.g. int32)
|
|
1106
|
+
newTarget["format"] = mergeFormatAndEncoding(
|
|
1107
|
+
newTarget.format,
|
|
1108
|
+
encodeData.encoding,
|
|
1109
|
+
newType["format"]
|
|
1110
|
+
);
|
|
1111
|
+
return newTarget;
|
|
1112
|
+
}
|
|
1113
|
+
return target;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function mergeFormatAndEncoding(
|
|
1117
|
+
format: string | undefined,
|
|
1118
|
+
encoding: string,
|
|
1119
|
+
encodeAsFormat: string | undefined
|
|
1120
|
+
): string {
|
|
1121
|
+
switch (format) {
|
|
1122
|
+
case undefined:
|
|
1123
|
+
return encodeAsFormat ?? encoding;
|
|
1124
|
+
case "date-time":
|
|
1125
|
+
return encoding;
|
|
1126
|
+
case "duration":
|
|
1127
|
+
default:
|
|
1128
|
+
return encodeAsFormat ?? encoding;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1041
1132
|
function applyIntrinsicDecorators(
|
|
1042
1133
|
program: Program,
|
|
1043
1134
|
type: Scalar | ModelProperty,
|
|
1044
1135
|
result: any
|
|
1045
1136
|
): Record<string, any> {
|
|
1046
|
-
|
|
1137
|
+
let newResult = { ...result };
|
|
1047
1138
|
const docStr = getDoc(program, type);
|
|
1048
1139
|
const isString = isStringType(program, getPropertyType(type));
|
|
1049
1140
|
const isNumeric = isNumericType(program, getPropertyType(type));
|
|
@@ -1052,10 +1143,7 @@ function applyIntrinsicDecorators(
|
|
|
1052
1143
|
newResult.description = docStr;
|
|
1053
1144
|
}
|
|
1054
1145
|
|
|
1055
|
-
|
|
1056
|
-
if (isString && !result.format && formatStr) {
|
|
1057
|
-
newResult.format = formatStr;
|
|
1058
|
-
}
|
|
1146
|
+
newResult = applyEncoding(program, type, newResult);
|
|
1059
1147
|
|
|
1060
1148
|
const pattern = getPattern(program, type);
|
|
1061
1149
|
if (isString && !result.pattern && pattern) {
|
|
@@ -1096,7 +1184,8 @@ function applyIntrinsicDecorators(
|
|
|
1096
1184
|
|
|
1097
1185
|
function emitScalar(program: Program, scalar: Scalar): Record<string, any> {
|
|
1098
1186
|
let result: Record<string, any> = {};
|
|
1099
|
-
|
|
1187
|
+
const isStd = program.checker.isStdType(scalar);
|
|
1188
|
+
if (isStd) {
|
|
1100
1189
|
result = emitStdScalar(program, scalar);
|
|
1101
1190
|
} else if (scalar.baseScalar) {
|
|
1102
1191
|
result = emitScalar(program, scalar.baseScalar);
|
|
@@ -1127,7 +1216,7 @@ function emitListOrDict(
|
|
|
1127
1216
|
return undefined;
|
|
1128
1217
|
}
|
|
1129
1218
|
|
|
1130
|
-
function
|
|
1219
|
+
function mapTypeSpecType(context: SdkContext, type: Type): any {
|
|
1131
1220
|
switch (type.kind) {
|
|
1132
1221
|
case "Number":
|
|
1133
1222
|
return constantType(type.value, intOrFloat(type.value));
|
|
@@ -1228,7 +1317,7 @@ function emitType(context: SdkContext, type: EmitterType): Record<string, any> {
|
|
|
1228
1317
|
if (type.kind === "CredentialTypeUnion") {
|
|
1229
1318
|
return emitCredentialUnion(type);
|
|
1230
1319
|
}
|
|
1231
|
-
const builtinType =
|
|
1320
|
+
const builtinType = mapTypeSpecType(context, type);
|
|
1232
1321
|
if (builtinType !== undefined) {
|
|
1233
1322
|
// add in description elements for types derived from primitive types (SecureString, etc.)
|
|
1234
1323
|
const doc = getDoc(context.program, type);
|
|
@@ -1288,9 +1377,38 @@ function emitOperationGroups(
|
|
|
1288
1377
|
operations: clientOperations
|
|
1289
1378
|
});
|
|
1290
1379
|
}
|
|
1380
|
+
resolveConflictIfExist(operationGroups);
|
|
1291
1381
|
return operationGroups;
|
|
1292
1382
|
}
|
|
1293
1383
|
|
|
1384
|
+
function resolveConflictIfExist(operationGroups: OperationGroup[]) {
|
|
1385
|
+
if (operationGroups.length < 2) {
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
const nameSet = new Set<string>();
|
|
1390
|
+
const hasConflict = operationGroups.some((g) =>
|
|
1391
|
+
g.operations.some((op) => {
|
|
1392
|
+
if (nameSet.has(op.name)) {
|
|
1393
|
+
return true;
|
|
1394
|
+
} else {
|
|
1395
|
+
nameSet.add(op.name);
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
})
|
|
1399
|
+
);
|
|
1400
|
+
if (!hasConflict) {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
// Append operation group prefix
|
|
1404
|
+
operationGroups.forEach((g) =>
|
|
1405
|
+
g.operations.forEach((op) => {
|
|
1406
|
+
op.oriName = op.name;
|
|
1407
|
+
op.name = `${g.propertyName}_${op.name}`;
|
|
1408
|
+
})
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1294
1412
|
function getServerHelper(
|
|
1295
1413
|
program: Program,
|
|
1296
1414
|
namespace: Namespace
|
|
@@ -1468,7 +1586,8 @@ function emitClients(
|
|
|
1468
1586
|
operationGroups: emitOperationGroups(context, client, rlcModels),
|
|
1469
1587
|
url: server ? server.url : "",
|
|
1470
1588
|
apiVersions: [],
|
|
1471
|
-
rlcClientName: rlcModels ? getClientName(rlcModels) : client.name
|
|
1589
|
+
rlcClientName: rlcModels ? getClientName(rlcModels) : client.name,
|
|
1590
|
+
subfolder: ""
|
|
1472
1591
|
};
|
|
1473
1592
|
const emittedApiVersionParam = getApiVersionParameter(context);
|
|
1474
1593
|
if (emittedApiVersionParam) {
|
|
@@ -1501,23 +1620,28 @@ function getNamespaces(context: SdkContext): Set<string> {
|
|
|
1501
1620
|
}
|
|
1502
1621
|
|
|
1503
1622
|
export function emitCodeModel(
|
|
1504
|
-
|
|
1623
|
+
dpgContext: SdkContext,
|
|
1505
1624
|
rlcModelsMap: Map<string, RLCModel>,
|
|
1625
|
+
modularSourcesRoot: string,
|
|
1626
|
+
project: Project,
|
|
1506
1627
|
options: { casing: "snake" | "camel" } = { casing: "snake" }
|
|
1507
1628
|
): ModularCodeModel {
|
|
1508
1629
|
CASING = options.casing ?? CASING;
|
|
1509
|
-
const dpgContext = createSdkContext(context);
|
|
1510
1630
|
const clientNamespaceString =
|
|
1511
1631
|
getClientNamespaceString(dpgContext)?.toLowerCase();
|
|
1512
1632
|
// Get types
|
|
1513
1633
|
const codeModel: ModularCodeModel = {
|
|
1514
|
-
options:
|
|
1634
|
+
options: dpgContext.rlcOptions ?? {},
|
|
1635
|
+
modularOptions: { sourceRoot: modularSourcesRoot },
|
|
1515
1636
|
namespace: clientNamespaceString,
|
|
1516
1637
|
subnamespaceToClients: {},
|
|
1517
1638
|
clients: [],
|
|
1518
|
-
types: []
|
|
1639
|
+
types: [],
|
|
1640
|
+
project
|
|
1519
1641
|
};
|
|
1520
1642
|
|
|
1643
|
+
typesMap.clear();
|
|
1644
|
+
simpleTypesMap.clear();
|
|
1521
1645
|
const allModels = getAllModels(dpgContext);
|
|
1522
1646
|
for (const model of allModels) {
|
|
1523
1647
|
getType(dpgContext, model);
|
|
@@ -1526,12 +1650,25 @@ export function emitCodeModel(
|
|
|
1526
1650
|
for (const namespace of getNamespaces(dpgContext)) {
|
|
1527
1651
|
if (namespace === clientNamespaceString) {
|
|
1528
1652
|
codeModel.clients = emitClients(dpgContext, namespace, rlcModelsMap);
|
|
1653
|
+
codeModel.clients.length > 1 &&
|
|
1654
|
+
codeModel.clients.map((client) => {
|
|
1655
|
+
client["subfolder"] = normalizeName(
|
|
1656
|
+
client.name.replace("Client", ""),
|
|
1657
|
+
NameType.File
|
|
1658
|
+
);
|
|
1659
|
+
});
|
|
1529
1660
|
} else {
|
|
1530
1661
|
codeModel["subnamespaceToClients"][namespace] = emitClients(
|
|
1531
1662
|
dpgContext,
|
|
1532
1663
|
namespace,
|
|
1533
1664
|
rlcModelsMap
|
|
1534
1665
|
);
|
|
1666
|
+
codeModel["subnamespaceToClients"][namespace].length > 1 &&
|
|
1667
|
+
(codeModel["subnamespaceToClients"][namespace] as HrlcClient[]).map(
|
|
1668
|
+
(client) => {
|
|
1669
|
+
client["subfolder"] = normalizeName(client.name, NameType.File);
|
|
1670
|
+
}
|
|
1671
|
+
);
|
|
1535
1672
|
}
|
|
1536
1673
|
}
|
|
1537
1674
|
|
|
@@ -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
|
}
|