@azure-tools/typespec-ts 0.30.1 → 0.31.0-alpha.20240723.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.
Files changed (184) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/src/contextManager.d.ts +4 -0
  3. package/dist/src/contextManager.d.ts.map +1 -1
  4. package/dist/src/contextManager.js.map +1 -1
  5. package/dist/src/framework/declaration.d.ts +9 -0
  6. package/dist/src/framework/declaration.d.ts.map +1 -0
  7. package/dist/src/framework/declaration.js +28 -0
  8. package/dist/src/framework/declaration.js.map +1 -0
  9. package/dist/src/framework/hooks/binder.d.ts +25 -0
  10. package/dist/src/framework/hooks/binder.d.ts.map +1 -0
  11. package/dist/src/framework/hooks/binder.js +168 -0
  12. package/dist/src/framework/hooks/binder.js.map +1 -0
  13. package/dist/src/framework/hooks/sdkTypes.d.ts +12 -0
  14. package/dist/src/framework/hooks/sdkTypes.d.ts.map +1 -0
  15. package/dist/src/framework/hooks/sdkTypes.js +67 -0
  16. package/dist/src/framework/hooks/sdkTypes.js.map +1 -0
  17. package/dist/src/framework/reference.d.ts +2 -0
  18. package/dist/src/framework/reference.d.ts.map +1 -0
  19. package/dist/src/framework/reference.js +8 -0
  20. package/dist/src/framework/reference.js.map +1 -0
  21. package/dist/src/framework/refkey.d.ts +7 -0
  22. package/dist/src/framework/refkey.d.ts.map +1 -0
  23. package/dist/src/framework/refkey.js +22 -0
  24. package/dist/src/framework/refkey.js.map +1 -0
  25. package/dist/src/framework/sample.d.ts +2 -0
  26. package/dist/src/framework/sample.d.ts.map +1 -0
  27. package/dist/src/framework/sample.js +71 -0
  28. package/dist/src/framework/sample.js.map +1 -0
  29. package/dist/src/framework/utils/tsmorph-helpers.d.ts +2 -0
  30. package/dist/src/framework/utils/tsmorph-helpers.d.ts.map +1 -0
  31. package/dist/src/framework/utils/tsmorph-helpers.js +2 -0
  32. package/dist/src/framework/utils/tsmorph-helpers.js.map +1 -0
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +7 -8
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/lib.d.ts +10 -1
  37. package/dist/src/lib.d.ts.map +1 -1
  38. package/dist/src/lib.js +6 -0
  39. package/dist/src/lib.js.map +1 -1
  40. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  41. package/dist/src/modular/buildClassicalClient.js +6 -5
  42. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  43. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  44. package/dist/src/modular/buildClientContext.js +8 -4
  45. package/dist/src/modular/buildClientContext.js.map +1 -1
  46. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  47. package/dist/src/modular/buildCodeModel.js +22 -11
  48. package/dist/src/modular/buildCodeModel.js.map +1 -1
  49. package/dist/src/modular/buildOperations.d.ts +1 -2
  50. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  51. package/dist/src/modular/buildOperations.js +3 -9
  52. package/dist/src/modular/buildOperations.js.map +1 -1
  53. package/dist/src/modular/buildRootIndex.js +1 -1
  54. package/dist/src/modular/buildRootIndex.js.map +1 -1
  55. package/dist/src/modular/buildSerializeUtils.d.ts.map +1 -1
  56. package/dist/src/modular/buildSerializeUtils.js +2 -1
  57. package/dist/src/modular/buildSerializeUtils.js.map +1 -1
  58. package/dist/src/modular/helpers/clientHelpers.d.ts +4 -0
  59. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  60. package/dist/src/modular/helpers/clientHelpers.js +15 -1
  61. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  62. package/dist/src/modular/helpers/namingHelpers.d.ts +1 -0
  63. package/dist/src/modular/helpers/namingHelpers.d.ts.map +1 -1
  64. package/dist/src/modular/helpers/namingHelpers.js +3 -1
  65. package/dist/src/modular/helpers/namingHelpers.js.map +1 -1
  66. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  67. package/dist/src/modular/helpers/operationHelpers.js +60 -40
  68. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  69. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  70. package/dist/src/modular/helpers/typeHelpers.js +6 -1
  71. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  72. package/dist/src/modular/modularCodeModel.d.ts +2 -0
  73. package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
  74. package/dist/src/transform/transformApiVersionInfo.d.ts.map +1 -1
  75. package/dist/src/transform/transformApiVersionInfo.js +3 -5
  76. package/dist/src/transform/transformApiVersionInfo.js.map +1 -1
  77. package/dist/src/transform/transformHelperFunctionDetails.d.ts.map +1 -1
  78. package/dist/src/transform/transformHelperFunctionDetails.js +7 -10
  79. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  80. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  81. package/dist/src/transform/transformParameters.js +5 -7
  82. package/dist/src/transform/transformParameters.js.map +1 -1
  83. package/dist/src/transform/transformPaths.d.ts.map +1 -1
  84. package/dist/src/transform/transformPaths.js +4 -6
  85. package/dist/src/transform/transformPaths.js.map +1 -1
  86. package/dist/src/transform/transformResponses.d.ts.map +1 -1
  87. package/dist/src/transform/transformResponses.js +70 -16
  88. package/dist/src/transform/transformResponses.js.map +1 -1
  89. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  90. package/dist/src/transform/transformSchemas.js +5 -6
  91. package/dist/src/transform/transformSchemas.js.map +1 -1
  92. package/dist/src/transform/transformTelemetryInfo.d.ts.map +1 -1
  93. package/dist/src/transform/transformTelemetryInfo.js +3 -6
  94. package/dist/src/transform/transformTelemetryInfo.js.map +1 -1
  95. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  96. package/dist/src/transform/transfromRLCOptions.js +5 -6
  97. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  98. package/dist/src/utils/modelUtils.d.ts +3 -3
  99. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  100. package/dist/src/utils/modelUtils.js +42 -24
  101. package/dist/src/utils/modelUtils.js.map +1 -1
  102. package/dist/src/utils/operationUtil.d.ts +2 -2
  103. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  104. package/dist/src/utils/operationUtil.js +5 -7
  105. package/dist/src/utils/operationUtil.js.map +1 -1
  106. package/dist/tsconfig.tsbuildinfo +1 -1
  107. package/package.json +23 -23
  108. package/src/contextManager.ts +4 -0
  109. package/src/framework/declaration.ts +100 -0
  110. package/src/framework/hooks/binder.ts +259 -0
  111. package/src/framework/hooks/sdkTypes.ts +101 -0
  112. package/src/framework/reference.ts +9 -0
  113. package/src/framework/refkey.ts +28 -0
  114. package/src/framework/sample.ts +92 -0
  115. package/src/framework/utils/tsmorph-helpers.ts +0 -0
  116. package/src/index.ts +8 -10
  117. package/src/lib.ts +6 -0
  118. package/src/modular/buildClassicalClient.ts +11 -4
  119. package/src/modular/buildClientContext.ts +11 -5
  120. package/src/modular/buildCodeModel.ts +25 -21
  121. package/src/modular/buildOperations.ts +13 -41
  122. package/src/modular/buildRootIndex.ts +1 -1
  123. package/src/modular/buildSerializeUtils.ts +2 -1
  124. package/src/modular/helpers/clientHelpers.ts +25 -1
  125. package/src/modular/helpers/namingHelpers.ts +4 -1
  126. package/src/modular/helpers/operationHelpers.ts +86 -45
  127. package/src/modular/helpers/typeHelpers.ts +6 -1
  128. package/src/modular/modularCodeModel.ts +2 -0
  129. package/src/transform/transformApiVersionInfo.ts +3 -6
  130. package/src/transform/transformHelperFunctionDetails.ts +9 -9
  131. package/src/transform/transformParameters.ts +5 -6
  132. package/src/transform/transformPaths.ts +5 -9
  133. package/src/transform/transformResponses.ts +92 -19
  134. package/src/transform/transformSchemas.ts +6 -5
  135. package/src/transform/transformTelemetryInfo.ts +3 -5
  136. package/src/transform/transfromRLCOptions.ts +5 -10
  137. package/src/utils/modelUtils.ts +49 -39
  138. package/src/utils/operationUtil.ts +6 -12
  139. package/dist/src/modular/serialization/collectionUtils.d.ts +0 -3
  140. package/dist/src/modular/serialization/collectionUtils.d.ts.map +0 -1
  141. package/dist/src/modular/serialization/collectionUtils.js +0 -17
  142. package/dist/src/modular/serialization/collectionUtils.js.map +0 -1
  143. package/dist/src/modular/serialization/index.d.ts +0 -5
  144. package/dist/src/modular/serialization/index.d.ts.map +0 -1
  145. package/dist/src/modular/serialization/index.js +0 -155
  146. package/dist/src/modular/serialization/index.js.map +0 -1
  147. package/dist/src/modular/serialization/operationHelpers.d.ts +0 -37
  148. package/dist/src/modular/serialization/operationHelpers.d.ts.map +0 -1
  149. package/dist/src/modular/serialization/operationHelpers.js +0 -457
  150. package/dist/src/modular/serialization/operationHelpers.js.map +0 -1
  151. package/dist/src/modular/serialization/serializeArray.d.ts +0 -5
  152. package/dist/src/modular/serialization/serializeArray.d.ts.map +0 -1
  153. package/dist/src/modular/serialization/serializeArray.js +0 -33
  154. package/dist/src/modular/serialization/serializeArray.js.map +0 -1
  155. package/dist/src/modular/serialization/serializeDateTime.d.ts +0 -4
  156. package/dist/src/modular/serialization/serializeDateTime.d.ts.map +0 -1
  157. package/dist/src/modular/serialization/serializeDateTime.js +0 -19
  158. package/dist/src/modular/serialization/serializeDateTime.js.map +0 -1
  159. package/dist/src/modular/serialization/serializeHeaders.d.ts +0 -7
  160. package/dist/src/modular/serialization/serializeHeaders.d.ts.map +0 -1
  161. package/dist/src/modular/serialization/serializeHeaders.js +0 -44
  162. package/dist/src/modular/serialization/serializeHeaders.js.map +0 -1
  163. package/dist/src/modular/serialization/serializers.d.ts +0 -17
  164. package/dist/src/modular/serialization/serializers.d.ts.map +0 -1
  165. package/dist/src/modular/serialization/serializers.js +0 -175
  166. package/dist/src/modular/serialization/serializers.js.map +0 -1
  167. package/dist/src/modular/serialization/util.d.ts +0 -27
  168. package/dist/src/modular/serialization/util.d.ts.map +0 -1
  169. package/dist/src/modular/serialization/util.js +0 -115
  170. package/dist/src/modular/serialization/util.js.map +0 -1
  171. package/dist/src/reify/index.d.ts +0 -12
  172. package/dist/src/reify/index.d.ts.map +0 -1
  173. package/dist/src/reify/index.js +0 -22
  174. package/dist/src/reify/index.js.map +0 -1
  175. package/src/modular/serialization/collectionUtils.ts +0 -20
  176. package/src/modular/serialization/index.ts +0 -267
  177. package/src/modular/serialization/operationHelpers.ts +0 -659
  178. package/src/modular/serialization/serializeArray.ts +0 -51
  179. package/src/modular/serialization/serializeDateTime.ts +0 -22
  180. package/src/modular/serialization/serializeHeaders.ts +0 -64
  181. package/src/modular/serialization/serializers.ts +0 -304
  182. package/src/modular/serialization/util.ts +0 -171
  183. package/src/modular/static/karma.conf.cjs +0 -120
  184. package/src/reify/index.ts +0 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.30.1",
3
+ "version": "0.31.0-alpha.20240723.1",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -18,16 +18,16 @@
18
18
  "license": "MIT",
19
19
  "devDependencies": {
20
20
  "@azure-rest/core-client": "^2.1.0",
21
- "@azure-tools/cadl-ranch-expect": "^0.13.4",
22
- "@azure-tools/cadl-ranch-specs": "^0.33.4",
23
- "@azure-tools/cadl-ranch": "^0.12.8",
24
- "@azure-tools/typespec-autorest": ">=0.43.0 <1.0.0",
25
- "@azure-tools/typespec-azure-core": ">=0.43.0 <1.0.0",
26
- "@azure-tools/typespec-azure-resource-manager": ">=0.43.0 <1.0.0",
27
- "@azure-tools/typespec-client-generator-core": ">=0.43.0 <1.0.0",
21
+ "@azure-tools/cadl-ranch-expect": "^0.14.1",
22
+ "@azure-tools/cadl-ranch-specs": "^0.34.7",
23
+ "@azure-tools/cadl-ranch": "^0.13.4",
24
+ "@azure-tools/typespec-autorest": ">=0.44.0 <1.0.0",
25
+ "@azure-tools/typespec-azure-core": ">=0.44.0 <1.0.0",
26
+ "@azure-tools/typespec-azure-resource-manager": ">=0.44.0 <1.0.0",
27
+ "@azure-tools/typespec-client-generator-core": ">=0.44.1 <1.0.0",
28
28
  "@azure/abort-controller": "^2.1.2",
29
29
  "@azure/core-auth": "^1.6.0",
30
- "@azure/core-lro": "3.0.0",
30
+ "@azure/core-lro": "^3.0.0",
31
31
  "@azure/core-paging": "^1.5.0",
32
32
  "@azure/core-rest-pipeline": "^1.14.0",
33
33
  "@azure/core-util": "^1.4.0",
@@ -39,12 +39,12 @@
39
39
  "@types/node": "^18.0.0",
40
40
  "@typescript-eslint/eslint-plugin": "^6.8.0",
41
41
  "@typescript-eslint/parser": "^6.8.0",
42
- "@typespec/compiler": ">=0.57.0 <1.0.0",
43
- "@typespec/http": ">=0.57.0 <1.0.0",
44
- "@typespec/openapi": ">=0.57.0, <1.0.0",
45
- "@typespec/rest": ">=0.57.0 <1.0.0",
42
+ "@typespec/compiler": ">=0.58.1 <1.0.0",
43
+ "@typespec/http": ">=0.58.0 <1.0.0",
44
+ "@typespec/openapi": ">=0.58.0, <1.0.0",
45
+ "@typespec/rest": ">=0.58.0 <1.0.0",
46
46
  "@typespec/ts-http-runtime": "1.0.0-alpha.20240314.2",
47
- "@typespec/versioning": ">=0.57.0 <1.0.0",
47
+ "@typespec/versioning": ">=0.58.0 <1.0.0",
48
48
  "chai": "^4.3.6",
49
49
  "chalk": "^4.0.0",
50
50
  "cross-env": "^7.0.3",
@@ -56,21 +56,21 @@
56
56
  "prettier": "^3.1.0",
57
57
  "rimraf": "^5.0.0",
58
58
  "ts-node": "~10.9.1",
59
- "typescript": "~5.4.5",
59
+ "typescript": "~5.5.3",
60
60
  "vitest": "~1.6.0",
61
61
  "@vitest/coverage-v8": "~1.6.0",
62
62
  "@vitest/coverage-istanbul": "~1.6.0"
63
63
  },
64
64
  "peerDependencies": {
65
- "@azure-tools/typespec-azure-core": ">=0.43.0 <1.0.0",
66
- "@azure-tools/typespec-client-generator-core": ">=0.43.0 <1.0.0",
67
- "@typespec/compiler": ">=0.57.0 <1.0.0",
68
- "@typespec/http": ">=0.57.0 <1.0.0",
69
- "@typespec/rest": ">=0.57.0 <1.0.0",
70
- "@typespec/versioning": ">=0.57.0 <1.0.0"
65
+ "@azure-tools/typespec-azure-core": ">=0.44.0 <1.0.0",
66
+ "@azure-tools/typespec-client-generator-core": ">=0.44.1 <1.0.0",
67
+ "@typespec/compiler": ">=0.58.1 <1.0.0",
68
+ "@typespec/http": ">=0.58.0 <1.0.0",
69
+ "@typespec/rest": ">=0.58.0 <1.0.0",
70
+ "@typespec/versioning": ">=0.58.0 <1.0.0"
71
71
  },
72
72
  "dependencies": {
73
- "@azure-tools/rlc-common": "^0.30.0",
73
+ "@azure-tools/rlc-common": "^0.31.0",
74
74
  "fs-extra": "^11.1.0",
75
75
  "lodash": "^4.17.21",
76
76
  "prettier": "^3.1.0",
@@ -99,7 +99,7 @@
99
99
  "test-next:coverage": "vitest run ./test-next --coverage",
100
100
  "clean": "rimraf ./dist ./typespec-output",
101
101
  "build": "tsc -p .",
102
- "test": "npm run unit-test && npm run integration-test-ci",
102
+ "test": "npm run test-next && npm run unit-test && npm run integration-test-ci",
103
103
  "lint": "eslint src --ext .ts --max-warnings=0",
104
104
  "lint:fix": "eslint src --fix --ext .ts",
105
105
  "format": "npm run -s prettier -- --write",
@@ -2,6 +2,8 @@ import { Project, SourceFile } from "ts-morph";
2
2
  import { ModularMetaTree, RlcMetaTree } from "./metaTree.js";
3
3
  import { EmitContext } from "@typespec/compiler";
4
4
  import { SdkContext } from "@azure-tools/typespec-client-generator-core";
5
+ import { SdkTypeContext } from "./framework/hooks/sdkTypes.js";
6
+ import { Binder } from "./framework/hooks/binder.js";
5
7
 
6
8
  /**
7
9
  * Contexts Object Guidelines
@@ -21,10 +23,12 @@ type Contexts = {
21
23
  modularMetaTree: ModularMetaTree; // Context for modular types metadata.
22
24
  outputProject: Project; // The TS-Morph root project context for code generation.
23
25
  symbolMap: Map<string, SourceFile>; // Mapping of symbols to their corresponding source files.
26
+ sdkTypes: SdkTypeContext;
24
27
  emitContext: {
25
28
  compilerContext: EmitContext;
26
29
  tcgcContext: SdkContext;
27
30
  };
31
+ binder: Binder;
28
32
  };
29
33
 
30
34
  type ContextKey = keyof Contexts;
@@ -0,0 +1,100 @@
1
+ import {
2
+ SourceFile,
3
+ ClassDeclarationStructure,
4
+ EnumDeclarationStructure,
5
+ FunctionDeclarationStructure,
6
+ InterfaceDeclarationStructure,
7
+ TypeAliasDeclarationStructure,
8
+ StructureKind,
9
+ ClassDeclaration,
10
+ EnumDeclaration,
11
+ FunctionDeclaration,
12
+ InterfaceDeclaration,
13
+ TypeAliasDeclaration
14
+ } from "ts-morph";
15
+ import { useBinder } from "./hooks/binder.js";
16
+ import { refkey as getRefKey } from "./refkey.js";
17
+ export type DeclarationStructures =
18
+ | ClassDeclarationStructure
19
+ | EnumDeclarationStructure
20
+ | FunctionDeclarationStructure
21
+ | InterfaceDeclarationStructure
22
+ | TypeAliasDeclarationStructure;
23
+
24
+ export type Declarations =
25
+ | ClassDeclaration
26
+ | EnumDeclaration
27
+ | FunctionDeclaration
28
+ | InterfaceDeclaration
29
+ | TypeAliasDeclaration;
30
+
31
+ export function addDeclaration(
32
+ sourceFile: SourceFile,
33
+ declaration: ClassDeclarationStructure,
34
+ refkey: unknown
35
+ ): ClassDeclaration;
36
+
37
+ export function addDeclaration(
38
+ sourceFile: SourceFile,
39
+ declaration: EnumDeclarationStructure,
40
+ refkey: unknown
41
+ ): EnumDeclaration;
42
+
43
+ export function addDeclaration(
44
+ sourceFile: SourceFile,
45
+ declaration: FunctionDeclarationStructure,
46
+ refkey: unknown
47
+ ): FunctionDeclaration;
48
+
49
+ export function addDeclaration(
50
+ sourceFile: SourceFile,
51
+ declaration: InterfaceDeclarationStructure,
52
+ refkey: unknown
53
+ ): InterfaceDeclaration;
54
+
55
+ export function addDeclaration(
56
+ sourceFile: SourceFile,
57
+ declaration: TypeAliasDeclarationStructure,
58
+ refkey: unknown
59
+ ): TypeAliasDeclaration;
60
+ export function addDeclaration(
61
+ sourceFile: SourceFile,
62
+ declaration: DeclarationStructures,
63
+ refkey: unknown
64
+ ): Declarations {
65
+ const binder = useBinder();
66
+
67
+ if (!declaration.name) {
68
+ throw new Error(
69
+ `Declaration must have a name ${JSON.stringify(declaration)}`
70
+ );
71
+ }
72
+
73
+ const stringRefkey = typeof refkey === "string" ? refkey : getRefKey(refkey);
74
+
75
+ const trackedDeclarationName = binder.trackDeclaration(
76
+ stringRefkey,
77
+ declaration.name,
78
+ sourceFile
79
+ );
80
+
81
+ // Update the declaration name to be unique
82
+ const trackedDeclaration = { ...declaration, name: trackedDeclarationName };
83
+
84
+ switch (trackedDeclaration.kind) {
85
+ case StructureKind.Class:
86
+ return sourceFile.addClass(trackedDeclaration);
87
+ case StructureKind.Enum:
88
+ return sourceFile.addEnum(trackedDeclaration);
89
+ case StructureKind.Function:
90
+ return sourceFile.addFunction(trackedDeclaration);
91
+ case StructureKind.Interface:
92
+ return sourceFile.addInterface(trackedDeclaration);
93
+ case StructureKind.TypeAlias:
94
+ return sourceFile.addTypeAlias(trackedDeclaration);
95
+ default:
96
+ throw new Error(
97
+ `Unsupported declaration kind ${(trackedDeclaration as any).kind}`
98
+ );
99
+ }
100
+ }
@@ -0,0 +1,259 @@
1
+ import {
2
+ SourceFile,
3
+ ImportDeclarationStructure,
4
+ StructureKind,
5
+ ImportSpecifierStructure,
6
+ Project
7
+ } from "ts-morph";
8
+ import { provideContext, useContext } from "../../contextManager.js";
9
+
10
+ export interface DeclarationInfo {
11
+ name: string;
12
+ sourceFile: SourceFile;
13
+ alias?: string;
14
+ }
15
+
16
+ export interface Binder {
17
+ /**
18
+ * Tracks a new declaration.
19
+ * @param refkey - A unique reference key for the declaration.
20
+ * @param name - The name of the declaration.
21
+ * @param sourceFile - The source file where the declaration is made.
22
+ * @returns The tracked declaration name.
23
+ */
24
+ trackDeclaration(
25
+ refkey: unknown,
26
+ name: string,
27
+ sourceFile: SourceFile
28
+ ): string;
29
+ resolveReference(refkey: unknown): string;
30
+ applyImports(): void;
31
+ }
32
+
33
+ class BinderImp implements Binder {
34
+ private declarations = new Map<unknown, DeclarationInfo>();
35
+ private imports = new Map<SourceFile, ImportDeclarationStructure[]>();
36
+ private symbolsBySourceFile = new Map<SourceFile, Set<string>>();
37
+ private project: Project;
38
+
39
+ constructor(project?: Project) {
40
+ this.project = project ?? new Project();
41
+ }
42
+
43
+ trackDeclaration(
44
+ refkey: unknown,
45
+ name: string,
46
+ sourceFile: SourceFile
47
+ ): string {
48
+ const uniqueName = this.generateLocallyUniqueDeclarationName(
49
+ name,
50
+ sourceFile
51
+ );
52
+ const declarationInfo: DeclarationInfo = { name: uniqueName, sourceFile };
53
+ this.declarations.set(refkey, declarationInfo);
54
+
55
+ // Ensure symbolsBySourceFile has an entry for this sourceFile
56
+ if (!this.symbolsBySourceFile.has(sourceFile)) {
57
+ this.symbolsBySourceFile.set(sourceFile, new Set());
58
+ }
59
+ this.symbolsBySourceFile.get(sourceFile)!.add(uniqueName);
60
+
61
+ return uniqueName;
62
+ }
63
+
64
+ /**
65
+ * Generates a locally unique name for a declaration within a source file.
66
+ * @param name - The base name of the declaration.
67
+ * @param sourceFile - The source file where the declaration is made.
68
+ * @returns A unique name for the declaration within the file.
69
+ */
70
+ private generateLocallyUniqueDeclarationName(
71
+ name: string,
72
+ sourceFile: SourceFile
73
+ ): string {
74
+ const existingNamesInFile =
75
+ this.symbolsBySourceFile.get(sourceFile) ?? new Set<string>();
76
+ return this.generateLocallyUniqueName(name, existingNamesInFile);
77
+ }
78
+
79
+ /**
80
+ * Generates a locally unique name for an import within a source file.
81
+ * @param name - The base name of the import.
82
+ * @param sourceFile - The source file where the import is made.
83
+ * @returns A unique name for the import within the file.
84
+ */
85
+ private generateLocallyUniqueImportName(
86
+ name: string,
87
+ sourceFile: SourceFile
88
+ ): string {
89
+ const existingImports = (this.imports.get(sourceFile) ?? [])
90
+ .flatMap((i) => i.namedImports as ImportSpecifierStructure[])
91
+ .map((i) => i.alias ?? i.name);
92
+
93
+ const existingDeclarations =
94
+ this.symbolsBySourceFile.get(sourceFile) ?? new Set<string>();
95
+ return this.generateLocallyUniqueName(
96
+ name,
97
+ new Set([...existingImports, ...existingDeclarations])
98
+ );
99
+ }
100
+
101
+ /**
102
+ * Generates a locally unique name within a set of existing names.
103
+ * @param name - The base name.
104
+ * @param existingNames - A set of names already in use.
105
+ * @returns A unique name not present in the existing names set.
106
+ */
107
+ private generateLocallyUniqueName(
108
+ name: string,
109
+ existingNames: Set<string>
110
+ ): string {
111
+ let uniqueName = name;
112
+ let counter = 1;
113
+ while (existingNames.has(uniqueName)) {
114
+ uniqueName = `${name}_${counter}`;
115
+ counter++;
116
+ }
117
+ return uniqueName;
118
+ }
119
+
120
+ /**
121
+ * Resolves a reference to a declaration.
122
+ * If a declaration is not ready yet, a placeholder is added to the source file.
123
+ * Placeholders will be resolved when the imports are applied.
124
+ * @param refkey - The reference key for the declaration.
125
+ * @param currentSourceFile - The current source file where the reference is being resolved.
126
+ * @returns The declaration information if resolved, or a placeholder if not found.
127
+ */
128
+ resolveReference(refkey: unknown): string {
129
+ return this.serializePlaceholder(refkey);
130
+ }
131
+
132
+ /**
133
+ * Serializes a placeholder reference key to a string.
134
+ * @param refkey - The reference key.
135
+ * @returns The serialized placeholder string.
136
+ */
137
+ private serializePlaceholder(refkey: unknown): string {
138
+ return `PLACEHOLDER:${String(refkey)}`;
139
+ }
140
+
141
+ /**
142
+ * Adds an import declaration to a source file.
143
+ * @param fileWhereImportIsAdded - The source file where the import is added.
144
+ * @param fileWhereImportPointsTo - The source file being imported.
145
+ * @param name - The name of the import.
146
+ * @returns The import specifier structure.
147
+ */
148
+ private addImport(
149
+ fileWhereImportIsAdded: SourceFile,
150
+ fileWhereImportPointsTo: SourceFile,
151
+ name: string
152
+ ): ImportSpecifierStructure {
153
+ const importAlias = this.generateLocallyUniqueImportName(
154
+ name,
155
+ fileWhereImportIsAdded
156
+ );
157
+ const relativePath =
158
+ fileWhereImportIsAdded.getRelativePathAsModuleSpecifierTo(
159
+ fileWhereImportPointsTo
160
+ );
161
+ const importStructures = this.imports.get(fileWhereImportIsAdded) || [];
162
+
163
+ let importStructure = importStructures.find(
164
+ (imp) => imp.moduleSpecifier === relativePath
165
+ );
166
+
167
+ if (!importStructure) {
168
+ importStructure = {
169
+ kind: StructureKind.ImportDeclaration,
170
+ moduleSpecifier: relativePath,
171
+ namedImports: []
172
+ };
173
+ importStructures.push(importStructure);
174
+ }
175
+
176
+ const namedImports =
177
+ importStructure.namedImports as ImportSpecifierStructure[];
178
+ let importSpecifier = namedImports.find((n) => n.name === importAlias);
179
+
180
+ if (!importSpecifier) {
181
+ importSpecifier = {
182
+ name: name,
183
+ alias: name === importAlias ? undefined : importAlias,
184
+ kind: StructureKind.ImportSpecifier
185
+ };
186
+ namedImports.push(importSpecifier);
187
+ }
188
+
189
+ importStructure.namedImports = namedImports;
190
+ this.imports.set(fileWhereImportIsAdded, importStructures);
191
+ return importSpecifier;
192
+ }
193
+
194
+ /**
195
+ * Applies all tracked imports to their respective source files.
196
+ */
197
+ applyImports(): void {
198
+ for (const file of this.project.getSourceFiles()) {
199
+ for (const [declarationKey, declaration] of this.declarations) {
200
+ const placeholderKey = this.serializePlaceholder(declarationKey);
201
+ let name = declaration.name;
202
+ if (file !== declaration.sourceFile) {
203
+ const importDec = this.addImport(
204
+ file,
205
+ declaration.sourceFile,
206
+ declaration.name
207
+ );
208
+ name = importDec.alias ?? declaration.name;
209
+ }
210
+ replacePlaceholder(file, placeholderKey, name);
211
+ }
212
+ }
213
+
214
+ for (const [sourceFile, importStructures] of this.imports) {
215
+ for (const importStructure of importStructures) {
216
+ sourceFile.addImportDeclaration(importStructure);
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ // Provide the binder context to be used globally
223
+ export function provideBinder(project?: Project): void {
224
+ return provideContext("binder", new BinderImp(project));
225
+ }
226
+
227
+ /**
228
+ * Hook to use the binder context.
229
+ * @returns The binder instance.
230
+ */
231
+ export function useBinder(): Binder {
232
+ return useContext("binder");
233
+ }
234
+
235
+ /**
236
+ * Replaces all instances of a placeholder in a source file with a given value.
237
+ * @param sourceFile - The source file where the replacement occurs.
238
+ * @param placeholder - The placeholder string to replace.
239
+ * @param value - The value to replace the placeholder with.
240
+ */
241
+ function replacePlaceholder(
242
+ sourceFile: SourceFile,
243
+ placeholder: string,
244
+ value: string
245
+ ): void {
246
+ const fileText = sourceFile.getFullText();
247
+ const regex = new RegExp(escapeRegExp(placeholder), "g");
248
+ const updatedText = fileText.replace(regex, value);
249
+ sourceFile.replaceWithText(updatedText);
250
+ }
251
+
252
+ /**
253
+ * Escapes special characters in a string to be used in a regular expression.
254
+ * @param string - The input string.
255
+ * @returns The escaped string.
256
+ */
257
+ function escapeRegExp(string: string): string {
258
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
259
+ }
@@ -0,0 +1,101 @@
1
+ import {
2
+ SdkClientType,
3
+ SdkHttpOperation,
4
+ SdkPackage,
5
+ SdkServiceMethod,
6
+ SdkType,
7
+ getClientType
8
+ } from "@azure-tools/typespec-client-generator-core";
9
+ import { Operation, Type, getNamespaceFullName } from "@typespec/compiler";
10
+ import { provideContext, useContext } from "../../contextManager.js";
11
+
12
+ export interface SdkTypeContext {
13
+ operations: Map<Type, SdkServiceMethod<SdkHttpOperation>>;
14
+ types: Map<Type, SdkType>;
15
+ }
16
+
17
+ export function useSdkTypes() {
18
+ const sdkTypesContext = useContext("sdkTypes");
19
+ const { tcgcContext } = useContext("emitContext");
20
+
21
+ function getSdkType(type: Operation): SdkServiceMethod<SdkHttpOperation>;
22
+ function getSdkType(type: Type): SdkType;
23
+ function getSdkType(
24
+ type: Type | Operation
25
+ ): SdkType | SdkServiceMethod<SdkHttpOperation> {
26
+ let sdkType: SdkType | SdkServiceMethod<SdkHttpOperation> | undefined;
27
+
28
+ if (type.kind === "Operation") {
29
+ sdkType = sdkTypesContext.operations.get(type);
30
+ } else {
31
+ sdkType =
32
+ sdkTypesContext.types.get(type) ?? getClientType(tcgcContext, type);
33
+ }
34
+
35
+ if (!sdkType) {
36
+ throw new Error(
37
+ `SdkType not found for type: ${type.kind} ${
38
+ "name" in type && typeof type.name == "string" ? type.name : ""
39
+ } ${
40
+ "namespace" in type && type.namespace
41
+ ? ` in ${getNamespaceFullName(type.namespace)}`
42
+ : ""
43
+ }`
44
+ );
45
+ }
46
+
47
+ return sdkType;
48
+ }
49
+
50
+ return getSdkType;
51
+ }
52
+
53
+ export function provideSdkTypes(sdkPackage: SdkPackage<SdkHttpOperation>) {
54
+ const sdkTypesContext = {
55
+ operations: new Map<Type, SdkServiceMethod<SdkHttpOperation>>(),
56
+ types: new Map<Type, SdkType>()
57
+ };
58
+
59
+ for (const sdkEnum of sdkPackage.enums) {
60
+ if (!sdkEnum.__raw) {
61
+ continue;
62
+ }
63
+
64
+ sdkTypesContext.types.set(sdkEnum.__raw, sdkEnum);
65
+ }
66
+
67
+ for (const sdkModel of sdkPackage.models) {
68
+ if (!sdkModel.__raw) {
69
+ continue;
70
+ }
71
+
72
+ sdkTypesContext.types.set(sdkModel.__raw, sdkModel);
73
+ }
74
+
75
+ for (const client of sdkPackage.clients) {
76
+ for (const method of getAllOperationsFromClient(client)) {
77
+ if (!method.__raw) {
78
+ continue;
79
+ }
80
+
81
+ sdkTypesContext.operations.set(method.__raw, method);
82
+ }
83
+ }
84
+
85
+ provideContext("sdkTypes", sdkTypesContext);
86
+ }
87
+
88
+ function getAllOperationsFromClient(client: SdkClientType<SdkHttpOperation>) {
89
+ const methodQueue = [...client.methods];
90
+ const operations: SdkServiceMethod<SdkHttpOperation>[] = [];
91
+ while (methodQueue.length > 0) {
92
+ const method = methodQueue.pop()!;
93
+ if (method.kind === "clientaccessor") {
94
+ method.response.methods.forEach((m) => methodQueue.push(m));
95
+ } else {
96
+ operations.push(method);
97
+ }
98
+ }
99
+
100
+ return operations;
101
+ }
@@ -0,0 +1,9 @@
1
+ import { useBinder } from "./hooks/binder.js";
2
+ import { refkey as getRefKey } from "./refkey.js";
3
+
4
+ export function resolveReference(refkey: unknown): string | undefined {
5
+ const binder = useBinder();
6
+ const stringRefkey = typeof refkey === "string" ? refkey : getRefKey(refkey);
7
+
8
+ return binder.resolveReference(stringRefkey);
9
+ }
@@ -0,0 +1,28 @@
1
+ const objectIds = new WeakMap<WeakKey, string>();
2
+ let objId = 0;
3
+
4
+ function getObjectKey(value: WeakKey) {
5
+ if (objectIds.has(value)) {
6
+ return `${objectIds.get(value)}`;
7
+ }
8
+
9
+ const key = `o${objId++}`;
10
+ objectIds.set(value, key);
11
+
12
+ return key;
13
+ }
14
+
15
+ declare const RefkeySym: unique symbol;
16
+ export type RefKey = string & { [RefkeySym]: true };
17
+
18
+ function getKey(value: unknown): RefKey {
19
+ if (typeof value === "object" && value !== null) {
20
+ return getObjectKey(value) as RefKey;
21
+ } else {
22
+ return `s${String(value)}` as RefKey;
23
+ }
24
+ }
25
+
26
+ export function refkey(...args: unknown[]) {
27
+ return args.map((v) => getKey(v)).join("\u2063");
28
+ }