@azure-tools/typespec-ts 0.43.0 → 0.44.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +6 -2
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/modular/buildClientContext.js +1 -1
  6. package/dist/src/modular/buildClientContext.js.map +1 -1
  7. package/dist/src/modular/buildRestorePoller.d.ts.map +1 -1
  8. package/dist/src/modular/buildRestorePoller.js +1 -0
  9. package/dist/src/modular/buildRestorePoller.js.map +1 -1
  10. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  11. package/dist/src/modular/buildRootIndex.js +2 -2
  12. package/dist/src/modular/buildRootIndex.js.map +1 -1
  13. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  14. package/dist/src/modular/buildSubpathIndex.js +2 -2
  15. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  16. package/dist/src/modular/emitModels.d.ts.map +1 -1
  17. package/dist/src/modular/emitModels.js +3 -3
  18. package/dist/src/modular/emitModels.js.map +1 -1
  19. package/dist/src/modular/serialization/buildDeserializerFunction.js +2 -3
  20. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  21. package/dist/src/modular/serialization/buildSerializerFunction.js +2 -3
  22. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +22 -22
  25. package/src/index.ts +8 -2
  26. package/src/modular/buildClientContext.ts +1 -1
  27. package/src/modular/buildRestorePoller.ts +1 -0
  28. package/src/modular/buildRootIndex.ts +2 -3
  29. package/src/modular/buildSubpathIndex.ts +3 -2
  30. package/src/modular/emitModels.ts +6 -3
  31. package/src/modular/serialization/buildDeserializerFunction.ts +2 -2
  32. package/src/modular/serialization/buildSerializerFunction.ts +2 -2
  33. package/static/static-helpers/cloudSettingHelpers.ts +10 -1
  34. package/static/static-helpers/urlTemplate.ts +26 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -18,15 +18,15 @@
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
20
  "@azure-rest/core-client": "^2.3.1",
21
- "@typespec/http-specs": "0.1.0-alpha.26-dev.0",
22
- "@typespec/spector": "0.1.0-alpha.18-dev.0",
23
- "@typespec/spec-api": "0.1.0-alpha.9-dev.0",
21
+ "@typespec/http-specs": "0.1.0-alpha.27-dev.0",
22
+ "@typespec/spector": "0.1.0-alpha.19-dev.0",
23
+ "@typespec/spec-api": "0.1.0-alpha.10-dev.0",
24
24
  "@typespec/tspd": "0.72.1",
25
- "@azure-tools/azure-http-specs": "0.1.0-alpha.26-dev.1",
26
- "@azure-tools/typespec-autorest": "^0.59.0",
27
- "@azure-tools/typespec-azure-core": "^0.59.0",
28
- "@azure-tools/typespec-azure-resource-manager": "^0.59.0",
29
- "@azure-tools/typespec-client-generator-core": "^0.59.0",
25
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.29-dev.0",
26
+ "@azure-tools/typespec-autorest": "^0.60.0",
27
+ "@azure-tools/typespec-azure-core": "^0.60.0",
28
+ "@azure-tools/typespec-azure-resource-manager": "^0.60.0",
29
+ "@azure-tools/typespec-client-generator-core": "^0.60.0",
30
30
  "@azure/abort-controller": "^2.1.2",
31
31
  "@azure/core-auth": "^1.6.0",
32
32
  "@azure/core-lro": "^3.1.0",
@@ -41,12 +41,12 @@
41
41
  "@types/node": "^18.0.0",
42
42
  "@typescript-eslint/eslint-plugin": "^8.28.0",
43
43
  "@typescript-eslint/parser": "^8.28.0",
44
- "@typespec/compiler": "^1.3.0",
45
- "@typespec/http": "^1.3.0",
46
- "@typespec/openapi": "^1.3.0",
47
- "@typespec/rest": "^0.73.0",
44
+ "@typespec/compiler": "^1.4.0",
45
+ "@typespec/http": "^1.4.0",
46
+ "@typespec/openapi": "^1.4.0",
47
+ "@typespec/rest": "^0.74.0",
48
48
  "@typespec/ts-http-runtime": "^0.1.0",
49
- "@typespec/versioning": "^0.73.0",
49
+ "@typespec/versioning": "^0.74.0",
50
50
  "chai": "^4.3.6",
51
51
  "chalk": "^4.0.0",
52
52
  "cross-env": "^7.0.3",
@@ -68,16 +68,16 @@
68
68
  "js-yaml": "^4.1.0"
69
69
  },
70
70
  "peerDependencies": {
71
- "@azure-tools/typespec-azure-core": "^0.59.0",
72
- "@azure-tools/typespec-client-generator-core": "^0.59.0",
73
- "@typespec/compiler": "^1.3.0",
74
- "@typespec/http": "^1.3.0",
75
- "@typespec/rest": "^0.73.0",
76
- "@typespec/versioning": "^0.73.0",
77
- "@typespec/xml": "^0.73.0"
71
+ "@azure-tools/typespec-azure-core": "^0.60.0",
72
+ "@azure-tools/typespec-client-generator-core": "^0.60.0",
73
+ "@typespec/compiler": "^1.4.0",
74
+ "@typespec/http": "^1.4.0",
75
+ "@typespec/rest": "^0.74.0",
76
+ "@typespec/versioning": "^0.74.0",
77
+ "@typespec/xml": "^0.74.0"
78
78
  },
79
79
  "dependencies": {
80
- "@azure-tools/rlc-common": "^0.43.0",
80
+ "@azure-tools/rlc-common": "^0.44.0",
81
81
  "fs-extra": "^11.1.0",
82
82
  "lodash": "^4.17.21",
83
83
  "prettier": "^3.3.3",
package/src/index.ts CHANGED
@@ -210,9 +210,15 @@ export async function $onEmit(context: EmitContext) {
210
210
  async function calculateGenerationDir(): Promise<GenerationDirDetail> {
211
211
  const projectRoot = context.emitterOutputDir ?? "";
212
212
  const customizationFolder = join(projectRoot, "generated");
213
+ const srcGeneratedFolder = join(projectRoot, "src", "generated");
213
214
  // if customization folder exists, use it as sources root
214
- const sourcesRoot = (await fsextra.pathExists(customizationFolder))
215
- ? customizationFolder
215
+ const finalCustomizationFolder = (await fsextra.pathExists(
216
+ srcGeneratedFolder
217
+ ))
218
+ ? srcGeneratedFolder
219
+ : customizationFolder;
220
+ const sourcesRoot = (await fsextra.pathExists(finalCustomizationFolder))
221
+ ? finalCustomizationFolder
216
222
  : join(projectRoot, "src");
217
223
  return {
218
224
  rootDir: projectRoot,
@@ -108,7 +108,7 @@ export function buildClientContext(
108
108
  const propertiesInOptions = getClientParameters(client, dpgContext, {
109
109
  optionalOnly: true
110
110
  })
111
- .filter((p) => p.name !== "endpoint")
111
+ .filter((p) => getClientParameterName(p) !== "endpoint")
112
112
  .map((p) => {
113
113
  return {
114
114
  name: getClientParameterName(p),
@@ -126,6 +126,7 @@ export function buildRestorePoller(
126
126
  }
127
127
 
128
128
  interface DeserializationHelper {
129
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
129
130
  deserializer: Function;
130
131
  expectedStatuses: string[];
131
132
  }
@@ -294,7 +294,7 @@ function exportModules(
294
294
  }
295
295
 
296
296
  const exported = [...indexFile.getExportedDeclarations().keys()];
297
-
297
+ const serializerOrDeserializerRegex = /.*(Serializer|Deserializer)(_\d+)?$/;
298
298
  const namedExports = [...modelsFile.getExportedDeclarations().entries()]
299
299
  .filter((exDeclaration) => {
300
300
  if (exDeclaration[0].startsWith("_")) {
@@ -310,8 +310,7 @@ function exportModules(
310
310
  if (
311
311
  moduleName === "models" &&
312
312
  ex.getKindName() === "FunctionDeclaration" &&
313
- (exDeclaration[0].endsWith("Serializer") ||
314
- exDeclaration[0].endsWith("Deserializer"))
313
+ serializerOrDeserializerRegex.test(exDeclaration[0])
315
314
  ) {
316
315
  return false;
317
316
  }
@@ -72,6 +72,8 @@ export function buildSubpathIndexFile(
72
72
  const indexFile = project.createSourceFile(`${folder}/index.ts`);
73
73
  for (const file of apiFiles) {
74
74
  const filePath = file.getFilePath();
75
+ const serializerOrDeserializerRegex =
76
+ /.*(Serializer|Deserializer)(_\d+)?$/;
75
77
  if (!options.exportIndex && filePath.endsWith("index.ts")) {
76
78
  continue;
77
79
  }
@@ -100,8 +102,7 @@ export function buildSubpathIndexFile(
100
102
  if (
101
103
  subpath === "models" &&
102
104
  ex.getKindName() === "FunctionDeclaration" &&
103
- (exDeclaration[0].endsWith("Serializer") ||
104
- exDeclaration[0].endsWith("Deserializer"))
105
+ serializerOrDeserializerRegex.test(exDeclaration[0])
105
106
  ) {
106
107
  return false;
107
108
  }
@@ -396,7 +396,7 @@ export function buildEnumTypes(
396
396
  const docs = type.doc ? type.doc : "Type of " + enumAsUnion.name;
397
397
  enumAsUnion.docs =
398
398
  isExtensibleEnum(context, type) && type.doc
399
- ? [getExtensibleEnumDescription(type) ?? docs]
399
+ ? [getExtensibleEnumDescription(context, type) ?? docs]
400
400
  : [docs];
401
401
  enumDeclaration.docs = type.doc
402
402
  ? [type.doc]
@@ -405,7 +405,10 @@ export function buildEnumTypes(
405
405
  return [enumAsUnion, enumDeclaration];
406
406
  }
407
407
 
408
- function getExtensibleEnumDescription(model: SdkEnumType): string | undefined {
408
+ function getExtensibleEnumDescription(
409
+ context: SdkContext,
410
+ model: SdkEnumType
411
+ ): string | undefined {
409
412
  if (model.isFixed && model.name && model.values) {
410
413
  return;
411
414
  }
@@ -415,7 +418,7 @@ function getExtensibleEnumDescription(model: SdkEnumType): string | undefined {
415
418
  // Escape the character / to make sure we don't incorrectly announce a comment blocks /** */
416
419
  .replace(/^\//g, "\\/")
417
420
  .replace(/([^\\])(\/)/g, "$1\\/");
418
- const enumLink = `{@link Known${model.name}} can be used interchangeably with ${model.name},\n this enum contains the known values that the service supports.`;
421
+ const enumLink = `{@link Known${normalizeModelName(context, model)}} can be used interchangeably with ${normalizeModelName(context, model)},\n this enum contains the known values that the service supports.`;
419
422
 
420
423
  return [
421
424
  `${model.doc} \\`,
@@ -165,7 +165,7 @@ function buildPolymorphicDeserializer(
165
165
  });
166
166
 
167
167
  statements.push(`
168
- switch (item.${type.discriminatorProperty.name}) {
168
+ switch (item.${normalizeName(type.discriminatorProperty.name, NameType.Property)}) {
169
169
  ${cases.join("\n")}
170
170
  default:
171
171
  return item;
@@ -232,7 +232,7 @@ function buildDiscriminatedUnionDeserializer(
232
232
  `);
233
233
  }
234
234
  output.push(`
235
- switch (item.${type.discriminatorProperty?.name}) {
235
+ switch (item.${type.discriminatorProperty ? normalizeName(type.discriminatorProperty.name, NameType.Property) : "unknown"}) {
236
236
  ${cases.join("\n")}
237
237
  default:
238
238
  return ${baseDeserializerName}(item);
@@ -172,7 +172,7 @@ function buildPolymorphicSerializer(
172
172
  });
173
173
 
174
174
  statements.push(`
175
- switch (item.${type.discriminatorProperty.name}) {
175
+ switch (item.${normalizeName(type.discriminatorProperty.name, NameType.Property)}) {
176
176
  ${cases.join("\n")}
177
177
  default:
178
178
  return item;
@@ -239,7 +239,7 @@ function buildDiscriminatedUnionSerializer(
239
239
  `);
240
240
  }
241
241
  output.push(`
242
- switch (item.${type.discriminatorProperty?.name}) {
242
+ switch (item.${type.discriminatorProperty ? normalizeName(type.discriminatorProperty.name, NameType.Property) : "unknown"}) {
243
243
  ${cases.join("\n")}
244
244
  default:
245
245
  return ${baseSerializerName}(item);
@@ -1,4 +1,7 @@
1
- /** An enum to describe Azure Cloud. */
1
+ /**
2
+ * An enum to describe Azure Cloud environments.
3
+ * @enum {string}
4
+ */
2
5
  export enum AzureClouds {
3
6
  /** Azure public cloud, which is the default cloud for Azure SDKs. */
4
7
  AZURE_PUBLIC_CLOUD = "AZURE_PUBLIC_CLOUD",
@@ -11,6 +14,12 @@ export enum AzureClouds {
11
14
  /** The supported values for cloud setting as a string literal type */
12
15
  export type AzureSupportedClouds = `${AzureClouds}`;
13
16
 
17
+ /**
18
+ * Gets the Azure Resource Manager endpoint URL for the specified cloud setting.
19
+ * @param cloudSetting - The Azure cloud environment setting. Use one of the AzureClouds enum values.
20
+ * @returns The ARM endpoint URL for the specified cloud, or undefined if cloudSetting is undefined.
21
+ * @throws {Error} Throws an error if an unknown cloud setting is provided.
22
+ */
14
23
  export function getArmEndpoint(
15
24
  cloudSetting?: AzureSupportedClouds
16
25
  ): string | undefined {
@@ -1,6 +1,6 @@
1
- //---------------------
1
+ // ---------------------
2
2
  // interfaces
3
- //---------------------
3
+ // ---------------------
4
4
  interface ValueOptions {
5
5
  isFirst: boolean; // is first value in the expression
6
6
  op?: string; // operator
@@ -18,27 +18,27 @@ export interface UrlTemplateOptions {
18
18
  // ---------------------
19
19
  // helpers
20
20
  // ---------------------
21
- function encodeComponent(val: string, reserved?: boolean, op?: string) {
21
+ function encodeComponent(val: string, reserved?: boolean, op?: string): string {
22
22
  return (reserved ?? op === "+") || op === "#"
23
23
  ? encodeReservedComponent(val)
24
24
  : encodeRFC3986URIComponent(val);
25
25
  }
26
26
 
27
- function encodeReservedComponent(str: string) {
27
+ function encodeReservedComponent(str: string): string {
28
28
  return str
29
29
  .split(/(%[0-9A-Fa-f]{2})/g)
30
30
  .map((part) => (!/%[0-9A-Fa-f]/.test(part) ? encodeURI(part) : part))
31
31
  .join("");
32
32
  }
33
33
 
34
- function encodeRFC3986URIComponent(str: string) {
34
+ function encodeRFC3986URIComponent(str: string): string {
35
35
  return encodeURIComponent(str).replace(
36
36
  /[!'()*]/g,
37
37
  (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
38
38
  );
39
39
  }
40
40
 
41
- function isDefined(val: any) {
41
+ function isDefined(val: any): boolean {
42
42
  return val !== undefined && val !== null;
43
43
  }
44
44
 
@@ -49,7 +49,7 @@ function getNamedAndIfEmpty(op?: string): [boolean, string] {
49
49
  ];
50
50
  }
51
51
 
52
- function getFirstOrSep(op?: string, isFirst = false) {
52
+ function getFirstOrSep(op?: string, isFirst = false): string {
53
53
  if (isFirst) {
54
54
  return !op || op === "+" ? "" : op;
55
55
  } else if (!op || op === "+" || op === "#") {
@@ -61,7 +61,7 @@ function getFirstOrSep(op?: string, isFirst = false) {
61
61
  }
62
62
  }
63
63
 
64
- function getExpandedValue(option: ValueOptions) {
64
+ function getExpandedValue(option: ValueOptions): string {
65
65
  let isFirst = option.isFirst;
66
66
  const { op, varName, varValue: value, reserved } = option;
67
67
  const vals: string[] = [];
@@ -73,7 +73,11 @@ function getExpandedValue(option: ValueOptions) {
73
73
  vals.push(`${getFirstOrSep(op, isFirst)}`);
74
74
  if (named && varName) {
75
75
  vals.push(`${encodeURIComponent(varName)}`);
76
- val === "" ? vals.push(ifEmpty) : vals.push("=");
76
+ if (val === "") {
77
+ vals.push(ifEmpty);
78
+ } else {
79
+ vals.push("=");
80
+ }
77
81
  }
78
82
  vals.push(encodeComponent(val, reserved, op));
79
83
  isFirst = false;
@@ -88,7 +92,11 @@ function getExpandedValue(option: ValueOptions) {
88
92
  vals.push(`${getFirstOrSep(op, isFirst)}`);
89
93
  if (key) {
90
94
  vals.push(`${encodeURIComponent(key)}`);
91
- named && val === "" ? vals.push(ifEmpty) : vals.push("=");
95
+ if (named && val === "") {
96
+ vals.push(ifEmpty);
97
+ } else {
98
+ vals.push("=");
99
+ }
92
100
  }
93
101
  vals.push(encodeComponent(val, reserved, op));
94
102
  isFirst = false;
@@ -97,7 +105,7 @@ function getExpandedValue(option: ValueOptions) {
97
105
  return vals.join("");
98
106
  }
99
107
 
100
- function getNonExpandedValue(option: ValueOptions) {
108
+ function getNonExpandedValue(option: ValueOptions): string | undefined {
101
109
  const { op, varName, varValue: value, isFirst, reserved } = option;
102
110
  const vals: string[] = [];
103
111
  const first = getFirstOrSep(op, isFirst);
@@ -143,7 +151,11 @@ function getVarValue(option: ValueOptions): string | undefined {
143
151
  if (named && varName) {
144
152
  // No need to encode varName considering it is already encoded
145
153
  vals.push(varName);
146
- val === "" ? vals.push(ifEmpty) : vals.push("=");
154
+ if (val === "") {
155
+ vals.push(ifEmpty);
156
+ } else {
157
+ vals.push("=");
158
+ }
147
159
  }
148
160
  if (modifier && modifier !== "*") {
149
161
  val = val.substring(0, parseInt(modifier, 10));
@@ -165,7 +177,7 @@ export function expandUrlTemplate(
165
177
  context: Record<string, any>,
166
178
  option?: UrlTemplateOptions
167
179
  ): string {
168
- return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, (_, expr, text) => {
180
+ return template.replace(/\{([^{}]+)\}|([^{}]+)/g, (_, expr, text) => {
169
181
  if (!expr) {
170
182
  return encodeReservedComponent(text);
171
183
  }
@@ -177,7 +189,7 @@ export function expandUrlTemplate(
177
189
  const varList = expr.split(/,/g);
178
190
  const result = [];
179
191
  for (const varSpec of varList) {
180
- const varMatch = /([^:\*]*)(?::(\d+)|(\*))?/.exec(varSpec);
192
+ const varMatch = /([^:*]*)(?::(\d+)|(\*))?/.exec(varSpec);
181
193
  if (!varMatch || !varMatch[1]) {
182
194
  continue;
183
195
  }