@azure-tools/typespec-ts 0.38.4 → 0.38.5

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 (139) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/src/framework/hooks/binder.d.ts.map +1 -1
  3. package/dist/src/framework/hooks/binder.js +9 -4
  4. package/dist/src/framework/hooks/binder.js.map +1 -1
  5. package/dist/src/index.d.ts +0 -2
  6. package/dist/src/index.d.ts.map +1 -1
  7. package/dist/src/index.js +57 -42
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/lib.d.ts +11 -1
  10. package/dist/src/lib.d.ts.map +1 -1
  11. package/dist/src/lib.js +7 -0
  12. package/dist/src/lib.js.map +1 -1
  13. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  14. package/dist/src/modular/buildClassicalClient.js +17 -14
  15. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  16. package/dist/src/modular/buildClassicalOperationGroups.d.ts.map +1 -1
  17. package/dist/src/modular/buildClassicalOperationGroups.js +4 -32
  18. package/dist/src/modular/buildClassicalOperationGroups.js.map +1 -1
  19. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  20. package/dist/src/modular/buildClientContext.js +5 -2
  21. package/dist/src/modular/buildClientContext.js.map +1 -1
  22. package/dist/src/modular/buildModularOptions.d.ts +1 -2
  23. package/dist/src/modular/buildModularOptions.d.ts.map +1 -1
  24. package/dist/src/modular/buildModularOptions.js +2 -3
  25. package/dist/src/modular/buildModularOptions.js.map +1 -1
  26. package/dist/src/modular/buildOperations.d.ts +1 -2
  27. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  28. package/dist/src/modular/buildOperations.js +16 -33
  29. package/dist/src/modular/buildOperations.js.map +1 -1
  30. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  31. package/dist/src/modular/buildProjectFiles.js +1 -3
  32. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  33. package/dist/src/modular/buildRestorePoller.d.ts.map +1 -1
  34. package/dist/src/modular/buildRestorePoller.js +3 -1
  35. package/dist/src/modular/buildRestorePoller.js.map +1 -1
  36. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  37. package/dist/src/modular/buildRootIndex.js +30 -11
  38. package/dist/src/modular/buildRootIndex.js.map +1 -1
  39. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  40. package/dist/src/modular/buildSubpathIndex.js +21 -12
  41. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  42. package/dist/src/modular/emitLoggerFile.d.ts.map +1 -1
  43. package/dist/src/modular/emitLoggerFile.js +3 -1
  44. package/dist/src/modular/emitLoggerFile.js.map +1 -1
  45. package/dist/src/modular/emitModels.d.ts +2 -2
  46. package/dist/src/modular/emitModels.d.ts.map +1 -1
  47. package/dist/src/modular/emitModels.js +37 -12
  48. package/dist/src/modular/emitModels.js.map +1 -1
  49. package/dist/src/modular/emitModelsOptions.d.ts +1 -1
  50. package/dist/src/modular/emitModelsOptions.d.ts.map +1 -1
  51. package/dist/src/modular/emitModelsOptions.js +19 -14
  52. package/dist/src/modular/emitModelsOptions.js.map +1 -1
  53. package/dist/src/modular/emitSamples.js +1 -1
  54. package/dist/src/modular/emitSamples.js.map +1 -1
  55. package/dist/src/modular/helpers/classicalOperationHelpers.d.ts.map +1 -1
  56. package/dist/src/modular/helpers/classicalOperationHelpers.js +28 -15
  57. package/dist/src/modular/helpers/classicalOperationHelpers.js.map +1 -1
  58. package/dist/src/modular/helpers/clientHelpers.js +2 -2
  59. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  60. package/dist/src/modular/helpers/namingHelpers.d.ts +1 -3
  61. package/dist/src/modular/helpers/namingHelpers.d.ts.map +1 -1
  62. package/dist/src/modular/helpers/namingHelpers.js +2 -4
  63. package/dist/src/modular/helpers/namingHelpers.js.map +1 -1
  64. package/dist/src/modular/helpers/operationHelpers.d.ts +1 -1
  65. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  66. package/dist/src/modular/helpers/operationHelpers.js +9 -6
  67. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  68. package/dist/src/modular/interfaces.d.ts +0 -2
  69. package/dist/src/modular/interfaces.d.ts.map +1 -1
  70. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  71. package/dist/src/modular/serialization/buildDeserializerFunction.js +18 -18
  72. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  73. package/dist/src/modular/serialization/buildSerializerFunction.d.ts.map +1 -1
  74. package/dist/src/modular/serialization/buildSerializerFunction.js +17 -18
  75. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  76. package/dist/src/transform/transformHelperFunctionDetails.d.ts.map +1 -1
  77. package/dist/src/transform/transformHelperFunctionDetails.js +5 -2
  78. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  79. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  80. package/dist/src/transform/transformParameters.js +11 -10
  81. package/dist/src/transform/transformParameters.js.map +1 -1
  82. package/dist/src/transform/transformResponses.js +2 -1
  83. package/dist/src/transform/transformResponses.js.map +1 -1
  84. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  85. package/dist/src/transform/transfromRLCOptions.js +7 -17
  86. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  87. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  88. package/dist/src/utils/clientUtils.js +7 -6
  89. package/dist/src/utils/clientUtils.js.map +1 -1
  90. package/dist/src/utils/credentialUtils.d.ts +3 -3
  91. package/dist/src/utils/credentialUtils.d.ts.map +1 -1
  92. package/dist/src/utils/credentialUtils.js +1 -1
  93. package/dist/src/utils/credentialUtils.js.map +1 -1
  94. package/dist/src/utils/modelUtils.d.ts +5 -3
  95. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  96. package/dist/src/utils/modelUtils.js +72 -16
  97. package/dist/src/utils/modelUtils.js.map +1 -1
  98. package/dist/src/utils/parameterUtils.d.ts.map +1 -1
  99. package/dist/src/utils/parameterUtils.js +11 -22
  100. package/dist/src/utils/parameterUtils.js.map +1 -1
  101. package/dist/tsconfig.tsbuildinfo +1 -1
  102. package/package.json +23 -23
  103. package/src/framework/hooks/binder.ts +8 -8
  104. package/src/index.ts +61 -46
  105. package/src/lib.ts +8 -0
  106. package/src/modular/buildClassicalClient.ts +18 -20
  107. package/src/modular/buildClassicalOperationGroups.ts +4 -59
  108. package/src/modular/buildClientContext.ts +5 -2
  109. package/src/modular/buildModularOptions.ts +1 -5
  110. package/src/modular/buildOperations.ts +31 -66
  111. package/src/modular/buildProjectFiles.ts +1 -3
  112. package/src/modular/buildRestorePoller.ts +5 -7
  113. package/src/modular/buildRootIndex.ts +35 -27
  114. package/src/modular/buildSubpathIndex.ts +25 -14
  115. package/src/modular/emitLoggerFile.ts +5 -7
  116. package/src/modular/emitModels.ts +47 -19
  117. package/src/modular/emitModelsOptions.ts +31 -24
  118. package/src/modular/emitSamples.ts +4 -4
  119. package/src/modular/helpers/classicalOperationHelpers.ts +67 -51
  120. package/src/modular/helpers/clientHelpers.ts +3 -3
  121. package/src/modular/helpers/namingHelpers.ts +2 -7
  122. package/src/modular/helpers/operationHelpers.ts +18 -15
  123. package/src/modular/interfaces.ts +0 -2
  124. package/src/modular/serialization/buildDeserializerFunction.ts +28 -23
  125. package/src/modular/serialization/buildSerializerFunction.ts +25 -23
  126. package/src/transform/transformHelperFunctionDetails.ts +5 -2
  127. package/src/transform/transformParameters.ts +13 -13
  128. package/src/transform/transformResponses.ts +2 -1
  129. package/src/transform/transfromRLCOptions.ts +6 -22
  130. package/src/utils/clientUtils.ts +8 -7
  131. package/src/utils/credentialUtils.ts +9 -5
  132. package/src/utils/modelUtils.ts +89 -26
  133. package/src/utils/parameterUtils.ts +19 -38
  134. package/static/static-helpers/multipartHelpers.ts +15 -7
  135. package/dist/src/utils/casingUtils.d.ts +0 -4
  136. package/dist/src/utils/casingUtils.d.ts.map +0 -1
  137. package/dist/src/utils/casingUtils.js +0 -39
  138. package/dist/src/utils/casingUtils.js.map +0 -1
  139. package/src/utils/casingUtils.ts +0 -48
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.38.4",
3
+ "version": "0.38.5",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -18,14 +18,14 @@
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
20
  "@azure-rest/core-client": "^2.3.1",
21
- "@typespec/http-specs": "0.1.0-alpha.11",
22
- "@typespec/spector": "0.1.0-alpha.8",
21
+ "@typespec/http-specs": "0.1.0-alpha.15",
22
+ "@typespec/spector": "0.1.0-alpha.9",
23
23
  "@typespec/spec-api": "0.1.0-alpha.1",
24
- "@azure-tools/azure-http-specs": "0.1.0-alpha.7",
25
- "@azure-tools/typespec-autorest": ">=0.52.0 <1.0.0",
26
- "@azure-tools/typespec-azure-core": ">=0.52.0 <1.0.0",
27
- "@azure-tools/typespec-azure-resource-manager": ">=0.52.0 <1.0.0",
28
- "@azure-tools/typespec-client-generator-core": ">=0.52.0 <1.0.0",
24
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.10",
25
+ "@azure-tools/typespec-autorest": ">=0.53.0 <1.0.0",
26
+ "@azure-tools/typespec-azure-core": ">=0.53.0 <1.0.0",
27
+ "@azure-tools/typespec-azure-resource-manager": ">=0.53.0 <1.0.0",
28
+ "@azure-tools/typespec-client-generator-core": ">=0.53.1 <1.0.0",
29
29
  "@azure/abort-controller": "^2.1.2",
30
30
  "@azure/core-auth": "^1.6.0",
31
31
  "@azure/core-lro": "^3.1.0",
@@ -40,12 +40,12 @@
40
40
  "@types/node": "^18.0.0",
41
41
  "@typescript-eslint/eslint-plugin": "^6.8.0",
42
42
  "@typescript-eslint/parser": "^6.8.0",
43
- "@typespec/compiler": ">=0.66.0 <1.0.0",
44
- "@typespec/http": ">=0.66.0 <1.0.0",
45
- "@typespec/openapi": ">=0.66.0, <1.0.0",
46
- "@typespec/rest": ">=0.66.0 <1.0.0",
43
+ "@typespec/compiler": ">=0.67.1 <1.0.0",
44
+ "@typespec/http": ">=0.67.1 <1.0.0",
45
+ "@typespec/openapi": ">=0.67.1 <1.0.0",
46
+ "@typespec/rest": ">=0.67.1 <1.0.0",
47
47
  "@typespec/ts-http-runtime": "0.1.0",
48
- "@typespec/versioning": ">=0.66.0 <1.0.0",
48
+ "@typespec/versioning": ">=0.67.1 <1.0.0",
49
49
  "chai": "^4.3.6",
50
50
  "chalk": "^4.0.0",
51
51
  "cross-env": "^7.0.3",
@@ -57,7 +57,7 @@
57
57
  "prettier": "^3.3.3",
58
58
  "rimraf": "^5.0.0",
59
59
  "ts-node": "~10.9.1",
60
- "typescript": "~5.6.2",
60
+ "typescript": "~5.7.2",
61
61
  "vitest": "~1.6.0",
62
62
  "@vitest/coverage-v8": "~1.6.0",
63
63
  "@vitest/coverage-istanbul": "~1.6.0",
@@ -67,15 +67,15 @@
67
67
  "js-yaml": "^4.1.0"
68
68
  },
69
69
  "peerDependencies": {
70
- "@azure-tools/typespec-azure-core": ">=0.52.0 <1.0.0",
71
- "@azure-tools/typespec-client-generator-core": ">=0.52.0 <1.0.0",
72
- "@typespec/compiler": ">=0.66.0 <1.0.0",
73
- "@typespec/http": ">=0.66.0 <1.0.0",
74
- "@typespec/rest": ">=0.66.0 <1.0.0",
75
- "@typespec/versioning": ">=0.66.0 <1.0.0"
70
+ "@azure-tools/typespec-azure-core": ">=0.53.0 <1.0.0",
71
+ "@azure-tools/typespec-client-generator-core": ">=0.53.1 <1.0.0",
72
+ "@typespec/compiler": ">=0.67.1 <1.0.0",
73
+ "@typespec/http": ">=0.67.1 <1.0.0",
74
+ "@typespec/rest": ">=0.67.1 <1.0.0",
75
+ "@typespec/versioning": ">=0.67.1 <1.0.0"
76
76
  },
77
77
  "dependencies": {
78
- "@azure-tools/rlc-common": "^0.38.4",
78
+ "@azure-tools/rlc-common": "^0.38.5",
79
79
  "fs-extra": "^11.1.0",
80
80
  "lodash": "^4.17.21",
81
81
  "prettier": "^3.3.3",
@@ -112,7 +112,7 @@
112
112
  "lint:fix": "eslint src --fix --ext .ts",
113
113
  "format": "npm run -s prettier -- --write",
114
114
  "check-format": "npm run prettier -- --check",
115
- "prettier": "prettier --config ./.prettierrc \"src/**/*.ts\"",
115
+ "prettier": "prettier --config ./.prettierrc \"{src,test,static}/**/*.ts\" \"!test/**/generated/**/*.ts\"",
116
116
  "check:tree": "node --loader ts-node/esm ./test/commands/check-clean-tree.ts",
117
117
  "integration-test-ci": "npm-run-all copy:typespec integration-test-ci:rlc integration-test-ci:azure-rlc integration-test-ci:modular integration-test-ci:azure-modular",
118
118
  "integration-test-ci:sequential": "npm-run-all --serial copy:typespec integration-test-ci:modular && npm run integration-test-ci:modular",
@@ -125,7 +125,7 @@
125
125
  "start-test-server:azure-rlc": "mkdirp -p coverage && npx tsp-spector serve ./node_modules/@azure-tools/azure-http-specs/specs ./node_modules/@typespec/http-specs/specs --coverageFile ./coverage/spector-coverage-typescript-rlc-azure.json",
126
126
  "start-test-server:modular": "mkdirp -p coverage && npx tsp-spector serve ./node_modules/@typespec/http-specs/specs --port 3002 --coverageFile ./coverage/spector-coverage-typescript-modular-standard.json",
127
127
  "start-test-server:azure-modular": "mkdirp -p coverage && npx tsp-spector serve ./node_modules/@azure-tools/azure-http-specs/specs ./node_modules/@typespec/http-specs/specs --port 3002 --coverageFile ./coverage/spector-coverage-typescript-modular-azure.json",
128
- "copy:typespec": "rm -rf temp && mkdirp -p temp && cp -r ./node_modules/@typespec/http-specs/* ./temp && cp -r ./node_modules/@azure-tools/azure-http-specs/specs/* ./temp/specs && cp -r ./test/integration/typespec/* ./temp/specs",
128
+ "copy:typespec": "rm -rf temp && mkdirp -p temp/specs && mkdirp -p temp/assets && cp -r ./node_modules/@typespec/http-specs/specs/* ./temp/specs && cp -r ./node_modules/@azure-tools/azure-http-specs/specs/* ./temp/specs && cp -r ./test/integration/typespec/* ./temp/specs && cp -r ./node_modules/@typespec/http-specs/assets/* ./temp/assets",
129
129
  "generate-and-run:rlc": "npm run generate-tsp-only:rlc && npm run integration-test:alone:rlc && npm run stop-test-server -- -p 3000",
130
130
  "generate-and-run:azure-rlc": "npm run generate-tsp-only:azure-rlc && npm run integration-test:alone:azure-rlc && npm run stop-test-server -- -p 3000",
131
131
  "generate-and-run:modular": "npm run generate-tsp-only:modular && npm run integration-test:alone:modular && npm run stop-test-server -- -p 3002",
@@ -10,7 +10,6 @@ import { ReferenceableSymbol } from "../dependency.js";
10
10
  import { provideDependencies, useDependencies } from "./useDependencies.js";
11
11
  import { refkey } from "../refkey.js";
12
12
  import {
13
- isStaticHelperMetadata,
14
13
  SourceFileSymbol,
15
14
  StaticHelperMetadata
16
15
  } from "../load-static-helpers.js";
@@ -182,10 +181,13 @@ class BinderImp implements Binder {
182
181
  if (typeof fileWhereImportPointsTo === "string") {
183
182
  moduleSpecifier = fileWhereImportPointsTo;
184
183
  } else {
184
+ const relative = fileWhereImportIsAdded
185
+ .getRelativePathTo(fileWhereImportPointsTo)
186
+ .replace(".ts", ".js");
185
187
  moduleSpecifier =
186
- fileWhereImportIsAdded.getRelativePathAsModuleSpecifierTo(
187
- fileWhereImportPointsTo
188
- ) + ".js";
188
+ relative.startsWith(".") || relative.startsWith("/")
189
+ ? relative
190
+ : `./${relative}`;
189
191
  }
190
192
 
191
193
  const importStructures = this.imports.get(fileWhereImportIsAdded) || [];
@@ -265,10 +267,8 @@ class BinderImp implements Binder {
265
267
  ...this.staticHelpers
266
268
  ]) {
267
269
  const placeholderKey = this.serializePlaceholder(declarationKey);
268
- if (
269
- isStaticHelperMetadata(declaration) &&
270
- !countPlaceholderOccurrences(file, placeholderKey)
271
- ) {
270
+ const occurences = countPlaceholderOccurrences(file, placeholderKey);
271
+ if (!occurences) {
272
272
  continue;
273
273
  }
274
274
 
package/src/index.ts CHANGED
@@ -48,7 +48,10 @@ import {
48
48
  isAzurePackage,
49
49
  updatePackageFile,
50
50
  buildSampleEnvFile,
51
- buildSnippets
51
+ buildSnippets,
52
+ buildTsSrcConfig,
53
+ buildTsSampleConfig,
54
+ buildTsTestConfig
52
55
  } from "@azure-tools/rlc-common";
53
56
  import {
54
57
  buildRootIndex,
@@ -59,7 +62,7 @@ import { provideContext, useContext } from "./contextManager.js";
59
62
 
60
63
  import { EmitterOptions } from "./lib.js";
61
64
  import { ModularEmitterOptions } from "./modular/interfaces.js";
62
- import { Project, SourceFile } from "ts-morph";
65
+ import { Project } from "ts-morph";
63
66
  import { buildClassicOperationFiles } from "./modular/buildClassicalOperationGroups.js";
64
67
  import { buildClassicalClient } from "./modular/buildClassicalClient.js";
65
68
  import {
@@ -92,6 +95,7 @@ import { emitSamples } from "./modular/emitSamples.js";
92
95
  export * from "./lib.js";
93
96
 
94
97
  export async function $onEmit(context: EmitContext) {
98
+ console.time("onEmit");
95
99
  if (context.program.compilerOptions.noEmit || context.program.hasError()) {
96
100
  return;
97
101
  }
@@ -99,7 +103,9 @@ export async function $onEmit(context: EmitContext) {
99
103
  const outputProject = new Project();
100
104
  const program: Program = context.program;
101
105
  const emitterOptions: EmitterOptions = context.options;
106
+ console.time("onEmit: create context");
102
107
  const dpgContext = await createContextWithDefaultOptions(context);
108
+ console.timeEnd("onEmit: create context");
103
109
  // Enrich the dpg context with path detail and common options
104
110
  await enrichDpgContext();
105
111
  const rlcOptions = dpgContext.rlcOptions ?? {};
@@ -116,6 +122,7 @@ export async function $onEmit(context: EmitContext) {
116
122
  compilerContext: context,
117
123
  tcgcContext: dpgContext
118
124
  });
125
+ console.time("onEmit: load static helpers");
119
126
  const staticHelpers = await loadStaticHelpers(
120
127
  outputProject,
121
128
  {
@@ -130,6 +137,7 @@ export async function $onEmit(context: EmitContext) {
130
137
  options: rlcOptions
131
138
  }
132
139
  );
140
+ console.timeEnd("onEmit: load static helpers");
133
141
  const extraDependencies = isAzurePackage({ options: rlcOptions })
134
142
  ? {
135
143
  ...AzurePollingDependencies,
@@ -137,6 +145,7 @@ export async function $onEmit(context: EmitContext) {
137
145
  ...AzureIdentityDependencies
138
146
  }
139
147
  : { ...DefaultCoreDependencies };
148
+ console.time("onEmit: provide binder");
140
149
  const binder = provideBinder(outputProject, {
141
150
  staticHelpers,
142
151
  dependencies: {
@@ -144,6 +153,7 @@ export async function $onEmit(context: EmitContext) {
144
153
  }
145
154
  });
146
155
  provideSdkTypes(dpgContext);
156
+ console.timeEnd("onEmit: provide binder");
147
157
 
148
158
  const rlcCodeModels: RLCModel[] = [];
149
159
  let modularEmitterOptions: ModularEmitterOptions;
@@ -151,7 +161,9 @@ export async function $onEmit(context: EmitContext) {
151
161
  await clearSrcFolder();
152
162
  // 2. Generate RLC code model
153
163
  // TODO: skip this step in modular once modular generator is sufficiently decoupled
164
+ console.time("onEmit: build RLC code models");
154
165
  await buildRLCCodeModels();
166
+ console.timeEnd("onEmit: build RLC code models");
155
167
 
156
168
  // 4. Generate sources
157
169
  if (emitterOptions.isModularLibrary) {
@@ -245,13 +257,13 @@ export async function $onEmit(context: EmitContext) {
245
257
  }
246
258
 
247
259
  async function generateModularSources() {
260
+ console.time("onEmit: generate modular sources");
248
261
  const modularSourcesRoot =
249
262
  dpgContext.generationPathDetail?.modularSourcesDir ?? "src";
250
263
  const project = useContext("outputProject");
251
264
  modularEmitterOptions = transformModularEmitterOptions(
252
265
  dpgContext,
253
266
  modularSourcesRoot,
254
- project,
255
267
  {
256
268
  casing: "camel"
257
269
  }
@@ -268,8 +280,9 @@ export async function $onEmit(context: EmitContext) {
268
280
  );
269
281
 
270
282
  const isMultiClients = dpgContext.sdkPackage.clients.length > 1;
271
-
283
+ console.time("onEmit: emit models");
272
284
  emitTypes(dpgContext, { sourceRoot: modularSourcesRoot });
285
+ console.timeEnd("onEmit: emit models");
273
286
  buildSubpathIndexFile(
274
287
  dpgContext,
275
288
  modularEmitterOptions,
@@ -277,6 +290,7 @@ export async function $onEmit(context: EmitContext) {
277
290
  undefined,
278
291
  { recursive: true }
279
292
  );
293
+ console.time("onEmit: emit source files");
280
294
  for (const subClient of dpgContext.sdkPackage.clients) {
281
295
  await renameClientName(subClient, modularEmitterOptions);
282
296
  buildApiOptions(dpgContext, subClient, modularEmitterOptions);
@@ -288,7 +302,11 @@ export async function $onEmit(context: EmitContext) {
288
302
  dpgContext,
289
303
  modularEmitterOptions,
290
304
  "api",
291
- subClient
305
+ subClient,
306
+ {
307
+ exportIndex: false,
308
+ recursive: true
309
+ }
292
310
  );
293
311
  } else {
294
312
  buildSubpathIndexFile(
@@ -297,6 +315,7 @@ export async function $onEmit(context: EmitContext) {
297
315
  "api",
298
316
  subClient,
299
317
  {
318
+ recursive: true,
300
319
  exportIndex: true
301
320
  }
302
321
  );
@@ -324,9 +343,12 @@ export async function $onEmit(context: EmitContext) {
324
343
  rootIndexFile
325
344
  );
326
345
  }
346
+ console.timeEnd("onEmit: emit source files");
327
347
  // Enable modular sample generation when explicitly set to true or MPG
328
348
  if (emitterOptions.generateSample === true) {
349
+ console.time("onEmit: emit samples");
329
350
  const samples = emitSamples(dpgContext);
351
+ console.timeEnd("onEmit: emit samples");
330
352
  // Refine the rlc sample generation logic
331
353
  // TODO: remember to remove this out when RLC is splitted from Modular
332
354
  if (samples.length > 0) {
@@ -334,26 +356,21 @@ export async function $onEmit(context: EmitContext) {
334
356
  }
335
357
  }
336
358
 
359
+ console.time("onEmit: resolve references");
337
360
  binder.resolveAllReferences(modularSourcesRoot);
361
+ console.timeEnd("onEmit: resolve references");
362
+
363
+ console.time("onEmit: generate files");
338
364
 
339
365
  for (const file of project.getSourceFiles()) {
340
- file.fixMissingImports(
341
- {},
342
- {
343
- importModuleSpecifierEnding: "js",
344
- importModuleSpecifierPreference: "relative",
345
- includePackageJsonAutoImports: "off",
346
- excludeLibrarySymbolsInNavTo: true
347
- }
348
- );
349
- await removeUnusedImports(file);
350
- file.fixUnusedIdentifiers();
351
366
  await emitContentByBuilder(
352
367
  program,
353
368
  () => ({ content: file.getFullText(), path: file.getFilePath() }),
354
369
  modularEmitterOptions as any
355
370
  );
356
371
  }
372
+ console.timeEnd("onEmit: generate files");
373
+ console.timeEnd("onEmit: generate modular sources");
357
374
  }
358
375
 
359
376
  async function generateMetadataAndTest(context: SdkContext) {
@@ -373,6 +390,18 @@ export async function $onEmit(context: EmitContext) {
373
390
  const shouldGenerateMetadata =
374
391
  option.generateMetadata === true ||
375
392
  (option.generateMetadata === undefined && !hasPackageFile);
393
+ const existingTestFolderPath = join(
394
+ dpgContext.generationPathDetail?.metadataDir ?? "",
395
+ "test"
396
+ );
397
+ const hasTestFolder = await existsSync(existingTestFolderPath);
398
+ if (option.azureSdkForJs && option.generateTest === undefined) {
399
+ if (hasTestFolder) {
400
+ option.generateTest = false;
401
+ } else {
402
+ option.generateTest = true;
403
+ }
404
+ }
376
405
  if (shouldGenerateMetadata) {
377
406
  const commonBuilders = [
378
407
  buildRollupConfig,
@@ -381,8 +410,9 @@ export async function $onEmit(context: EmitContext) {
381
410
  buildLicenseFile,
382
411
  buildSampleEnvFile
383
412
  ];
384
- if (option.moduleKind === "esm") {
413
+ if (option.generateTest) {
385
414
  commonBuilders.push((model) => buildVitestConfig(model, "node"));
415
+ commonBuilders.push((model) => buildVitestConfig(model, "esm"));
386
416
  commonBuilders.push((model) => buildVitestConfig(model, "browser"));
387
417
  commonBuilders.push((model) => buildTsTestBrowserConfig(model));
388
418
  }
@@ -411,6 +441,15 @@ export async function $onEmit(context: EmitContext) {
411
441
  buildPackageFile(model, modularPackageInfo)
412
442
  );
413
443
  commonBuilders.push(buildTsConfig);
444
+ if (option.azureSdkForJs) {
445
+ commonBuilders.push(buildTsSrcConfig);
446
+ if (option.generateSample) {
447
+ commonBuilders.push(buildTsSampleConfig);
448
+ }
449
+ if (option.generateTest) {
450
+ commonBuilders.push(buildTsTestConfig);
451
+ }
452
+ }
414
453
 
415
454
  // TODO: need support snippets generation for multi-client cases. https://github.com/Azure/autorest.typescript/issues/3048
416
455
  if (option.generateTest && isAzureFlavor) {
@@ -467,33 +506,7 @@ export async function $onEmit(context: EmitContext) {
467
506
  .map((subClient) => getClientContextPath(context, subClient, options))
468
507
  .map((path) => path.substring(path.indexOf("src")));
469
508
  }
470
- }
471
-
472
- export async function removeUnusedImports(file: SourceFile) {
473
- file.getImportDeclarations().map((importDeclaration) => {
474
- importDeclaration.getFullText();
475
- importDeclaration.getNamedImports().map((namedImport) => {
476
- namedImport.getFullText();
477
- if (
478
- namedImport
479
- .getNameNode()
480
- .findReferencesAsNodes()
481
- .filter((n) => {
482
- return n.getSourceFile().getFilePath() === file.getFilePath();
483
- }).length === 1
484
- ) {
485
- namedImport.remove();
486
- }
487
- });
488
- if (importDeclaration.getNamedImports().length === 0) {
489
- importDeclaration.remove();
490
- }
491
- });
492
- file.getExportDeclarations().map((exportDeclaration) => {
493
- if (exportDeclaration.getNamedExports().length === 0) {
494
- exportDeclaration.remove();
495
- }
496
- });
509
+ console.timeEnd("onEmit");
497
510
  }
498
511
 
499
512
  export async function createContextWithDefaultOptions(
@@ -508,7 +521,6 @@ export async function createContextWithDefaultOptions(
508
521
  const tcgcSettings = {
509
522
  "generate-protocol-methods": true,
510
523
  "generate-convenience-methods": true,
511
- "flatten-union-as-enum": flattenUnionAsEnum,
512
524
  emitters: [
513
525
  {
514
526
  main: "@azure-tools/typespec-ts",
@@ -523,7 +535,10 @@ export async function createContextWithDefaultOptions(
523
535
 
524
536
  return (await createSdkContext(
525
537
  context,
526
- context.program.emitters[0]?.metadata.name ?? "@azure-tools/typespec-ts"
538
+ context.program.emitters[0]?.metadata.name ?? "@azure-tools/typespec-ts",
539
+ {
540
+ flattenUnionAsEnum
541
+ }
527
542
  )) as SdkContext;
528
543
  }
529
544
 
package/src/lib.ts CHANGED
@@ -68,6 +68,7 @@ export interface EmitterOptions extends RLCOptions {
68
68
  branded?: boolean;
69
69
  "typespec-title-map"?: Record<string, string>;
70
70
  "ignore-enum-member-name-normalize"?: boolean;
71
+ "default-value-object"?: boolean;
71
72
  }
72
73
 
73
74
  const _RLCOptionsSchema: JSONSchemaType<RLCOptions> = {
@@ -247,6 +248,7 @@ export const RLCOptionsSchema: JSONSchemaType<EmitterOptions> = {
247
248
  "ignore-property-name-normalize": { type: "boolean", nullable: true },
248
249
  "ignore-enum-member-name-normalize": { type: "boolean", nullable: true },
249
250
  "compatibility-query-multi-format": { type: "boolean", nullable: true },
251
+ "default-value-object": { type: "boolean", nullable: true },
250
252
  "typespec-title-map": {
251
253
  type: "object",
252
254
  additionalProperties: {
@@ -453,6 +455,12 @@ const libDef = {
453
455
  messages: {
454
456
  default: paramMessage`Enum member name ${"memberName"} is normalized to ${"normalizedName"} with "_" prefix.`
455
457
  }
458
+ },
459
+ "default-value-object": {
460
+ severity: "warning",
461
+ messages: {
462
+ default: paramMessage`Please note the default value is an object type.`
463
+ }
456
464
  }
457
465
  },
458
466
  emitter: {
@@ -31,12 +31,15 @@ import {
31
31
  SdkServiceOperation
32
32
  } from "@azure-tools/typespec-client-generator-core";
33
33
  import { getMethodHierarchiesMap } from "../utils/operationUtil.js";
34
+ import { useContext } from "../contextManager.js";
35
+ import { refkey } from "../framework/refkey.js";
34
36
 
35
37
  export function buildClassicalClient(
36
38
  dpgContext: SdkContext,
37
39
  client: SdkClientType<SdkServiceOperation>,
38
40
  emitterOptions: ModularEmitterOptions
39
41
  ) {
42
+ const project = useContext("outputProject");
40
43
  const dependencies = useDependencies();
41
44
  const modularClientName = getClientName(client);
42
45
  const classicalClientName = `${getClassicalClientName(client)}`;
@@ -53,7 +56,7 @@ export function buildClassicalClient(
53
56
  client
54
57
  );
55
58
 
56
- const clientFile = emitterOptions.project.createSourceFile(
59
+ const clientFile = project.createSourceFile(
57
60
  `${srcPath}/${subfolder && subfolder !== "" ? subfolder + "/" : ""}${normalizeName(
58
61
  classicalClientName,
59
62
  NameType.File
@@ -121,7 +124,7 @@ export function buildClassicalClient(
121
124
  ]);
122
125
  constructor.addStatements(`this.pipeline = this._client.pipeline;`);
123
126
 
124
- buildClientOperationGroups(clientFile, client, dpgContext, clientClass);
127
+ buildClientOperationGroups(client, dpgContext, clientClass);
125
128
  importAllApis(clientFile, srcPath, subfolder ?? "");
126
129
  clientFile.fixUnusedIdentifiers();
127
130
  return clientFile;
@@ -161,7 +164,7 @@ function generateMethod(
161
164
  kind: StructureKind.Method,
162
165
  returnType: declarations.returnType,
163
166
  parameters: declarations.parameters?.filter((p) => p.name !== "context"),
164
- statements: `return ${declarations.name}(${[
167
+ statements: `return ${resolveReference(refkey(method[1], "api"))}(${[
165
168
  "this._client",
166
169
  ...[
167
170
  declarations.parameters
@@ -173,7 +176,6 @@ function generateMethod(
173
176
  return result;
174
177
  }
175
178
  function buildClientOperationGroups(
176
- clientFile: SourceFile,
177
179
  client: SdkClientType<SdkServiceOperation>,
178
180
  dpgContext: SdkContext,
179
181
  clientClass: ClassDeclaration
@@ -186,35 +188,34 @@ function buildClientOperationGroups(
186
188
  const methodMap = getMethodHierarchiesMap(dpgContext, client);
187
189
  for (const [prefixKey, operations] of methodMap) {
188
190
  const prefixes = prefixKey.split("/");
191
+ const layer = 0;
189
192
  if (prefixKey === "") {
190
193
  operations.forEach((op) => {
191
194
  const method = generateMethod(dpgContext, clientType, [prefixes, op]);
192
195
  clientClass.addMethod(method);
193
196
  });
194
197
  } else {
195
- const groupName = normalizeName(prefixes[0] ?? "", NameType.Property);
198
+ // The `rawGroupName` is used to any places where we need normalized name twice so we need to keep the raw as PascalCase.
199
+ const rawGroupName = normalizeName(prefixes[0] ?? "", NameType.Interface);
196
200
  const operationName = `_get${normalizeName(
197
- groupName,
201
+ rawGroupName,
198
202
  NameType.OperationGroup
199
203
  )}Operations`;
200
204
  const propertyType = `${normalizeName(
201
- groupName,
205
+ rawGroupName,
202
206
  NameType.OperationGroup
203
207
  )}Operations`;
208
+ // The `groupName` is used to any places where we don't need normalized name again
209
+ const groupName = normalizeName(rawGroupName, NameType.Property);
204
210
  const existProperty = clientClass.getProperties().filter((p) => {
205
- return p.getName() === groupName;
211
+ return p.getName() === normalizeName(groupName, NameType.Property);
206
212
  });
207
213
  if (!existProperty || existProperty.length === 0) {
208
- clientFile.addImportDeclaration({
209
- namedImports: [operationName, propertyType],
210
- moduleSpecifier: `./classic/${normalizeName(
211
- groupName,
212
- NameType.File
213
- )}/index.js`
214
- });
215
214
  clientClass.addProperty({
216
215
  name: groupName,
217
- type: propertyType,
216
+ type: resolveReference(
217
+ refkey(propertyType, layer, "classicOperations")
218
+ ),
218
219
  scope: Scope.Public,
219
220
  isReadonly: true,
220
221
  docs: ["The operation groups for " + groupName]
@@ -222,10 +223,7 @@ function buildClientOperationGroups(
222
223
  clientClass
223
224
  .getConstructors()[0]
224
225
  ?.addStatements(
225
- `this.${groupName} = _get${normalizeName(
226
- groupName,
227
- NameType.OperationGroup
228
- )}Operations(this._client)`
226
+ `this.${groupName} = ${resolveReference(refkey(operationName, layer, "getClassicOperations"))}(this._client)`
229
227
  );
230
228
  }
231
229
  }
@@ -10,6 +10,7 @@ import {
10
10
  SdkServiceOperation
11
11
  } from "@azure-tools/typespec-client-generator-core";
12
12
  import { getModularClientOptions } from "../utils/clientUtils.js";
13
+ import { useContext } from "../contextManager.js";
13
14
 
14
15
  export function buildClassicOperationFiles(
15
16
  dpgContext: SdkContext,
@@ -17,6 +18,7 @@ export function buildClassicOperationFiles(
17
18
  emitterOptions: ModularEmitterOptions
18
19
  ) {
19
20
  // const sdkPackage = dpgContext.sdkPackage;
21
+ const project = useContext("outputProject");
20
22
  const { subfolder } = getModularClientOptions(dpgContext, client);
21
23
  const classicOperationFiles: Map<string, SourceFile> = new Map<
22
24
  string,
@@ -41,7 +43,7 @@ export function buildClassicOperationFiles(
41
43
  const srcPath = emitterOptions.modularOptions.sourceRoot;
42
44
  const classicFile =
43
45
  classicOperationFiles.get(classicOperationFileName) ??
44
- emitterOptions.project.createSourceFile(
46
+ project.createSourceFile(
45
47
  `${srcPath}/${
46
48
  subfolder && subfolder !== "" ? subfolder + "/" : ""
47
49
  }classic/${classicOperationFileName}.ts`
@@ -50,9 +52,6 @@ export function buildClassicOperationFiles(
50
52
  prefixes,
51
53
  operations
52
54
  ]);
53
-
54
- importApis(dpgContext, classicFile, client, emitterOptions, prefixes);
55
- // We need to import the paging helpers and types explicitly because ts-morph may not be able to find them.
56
55
  classicOperationFiles.set(classicOperationFileName, classicFile);
57
56
  }
58
57
  }
@@ -74,7 +73,7 @@ export function buildClassicOperationFiles(
74
73
  const srcPath = emitterOptions.modularOptions.sourceRoot;
75
74
  const classicFile =
76
75
  classicOperationFiles.get(classicOperationFileName) ??
77
- emitterOptions.project.createSourceFile(
76
+ project.createSourceFile(
78
77
  `${srcPath}/${
79
78
  subfolder && subfolder !== "" ? subfolder + "/" : ""
80
79
  }classic/${classicOperationFileName}.ts`
@@ -86,63 +85,9 @@ export function buildClassicOperationFiles(
86
85
  [prefixes, operations],
87
86
  layer
88
87
  );
89
- importApis(
90
- dpgContext,
91
- classicFile,
92
- client,
93
- emitterOptions,
94
- prefixes,
95
- layer
96
- );
97
88
  classicOperationFiles.set(classicOperationFileName, classicFile);
98
89
  }
99
90
  }
100
91
  }
101
92
  return classicOperationFiles;
102
93
  }
103
-
104
- function importApis(
105
- context: SdkContext,
106
- classicFile: SourceFile,
107
- client: SdkClientType<SdkServiceOperation>,
108
- emitterOptions: ModularEmitterOptions,
109
- prefixes: string[],
110
- layer: number = prefixes.length - 1
111
- ) {
112
- const { subfolder } = getModularClientOptions(context, client);
113
- const classicOperationFileName =
114
- prefixes.length > 0 && prefixes[0] !== ""
115
- ? `${getClassicalLayerPrefix(prefixes, NameType.File, "/", layer)}/index`
116
- : // When the program has no operation groups defined all operations are put
117
- // into a nameless operation group. We'll call this operations.
118
- "index";
119
-
120
- const srcPath = emitterOptions.modularOptions.sourceRoot;
121
- const apiFile = emitterOptions.project.getSourceFile(
122
- `${srcPath}/${
123
- subfolder && subfolder !== "" ? subfolder + "/" : ""
124
- }api/${classicOperationFileName}.ts`
125
- );
126
-
127
- if (!apiFile) {
128
- return;
129
- }
130
-
131
- const exported = [...apiFile.getExportedDeclarations().keys()].filter((e) => {
132
- return !e.startsWith("_");
133
- });
134
-
135
- const existApiImport = classicFile.getImportDeclarations().filter((i) => {
136
- return i
137
- .getModuleSpecifierValue()
138
- .includes(`../api/${classicOperationFileName}`);
139
- })[0];
140
- if (exported.length > 0 && !existApiImport) {
141
- classicFile.addImportDeclaration({
142
- moduleSpecifier: `${"../".repeat(
143
- prefixes.length + 1
144
- )}api/${classicOperationFileName}.js`,
145
- namedImports: exported
146
- });
147
- }
148
- }