@azure-tools/typespec-ts 0.50.0 → 0.50.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 (36) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +40 -16
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/lib.d.ts +6 -0
  6. package/dist/src/lib.d.ts.map +1 -1
  7. package/dist/src/lib.js +5 -0
  8. package/dist/src/lib.js.map +1 -1
  9. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  10. package/dist/src/modular/buildRootIndex.js +19 -33
  11. package/dist/src/modular/buildRootIndex.js.map +1 -1
  12. package/dist/src/modular/buildSubpathIndex.d.ts +7 -0
  13. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  14. package/dist/src/modular/buildSubpathIndex.js +44 -14
  15. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  16. package/dist/src/modular/helpers/operationHelpers.d.ts +2 -1
  17. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  18. package/dist/src/modular/helpers/operationHelpers.js +108 -14
  19. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  20. package/dist/src/modular/static-helpers-metadata.d.ts +17 -0
  21. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  22. package/dist/src/modular/static-helpers-metadata.js +17 -0
  23. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  24. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  25. package/dist/src/transform/transfromRLCOptions.js +3 -1
  26. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +2 -2
  29. package/src/index.ts +68 -19
  30. package/src/lib.ts +12 -0
  31. package/src/modular/buildRootIndex.ts +67 -63
  32. package/src/modular/buildSubpathIndex.ts +75 -34
  33. package/src/modular/helpers/operationHelpers.ts +143 -8
  34. package/src/modular/static-helpers-metadata.ts +18 -0
  35. package/src/transform/transfromRLCOptions.ts +3 -1
  36. package/static/static-helpers/storageCompatResponse.ts +90 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-ts",
3
- "version": "0.50.0",
3
+ "version": "0.50.1",
4
4
  "description": "An experimental TypeSpec emitter for TypeScript RLC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -73,7 +73,7 @@
73
73
  "@typespec/xml": "^0.79.0"
74
74
  },
75
75
  "dependencies": {
76
- "@azure-tools/rlc-common": "^0.50.0",
76
+ "@azure-tools/rlc-common": "^0.50.1",
77
77
  "fast-xml-parser": "^4.5.0",
78
78
  "fs-extra": "^11.1.0",
79
79
  "lodash": "^4.17.21",
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  PollingHelpers,
19
19
  SerializationHelpers,
20
20
  SimplePollerHelpers,
21
+ StorageCompatHelpers,
21
22
  UrlTemplateHelpers,
22
23
  XmlHelpers
23
24
  } from "./modular/static-helpers-metadata.js";
@@ -37,6 +38,7 @@ import {
37
38
  buildPollingHelper,
38
39
  buildPaginateHelper as buildRLCPaginateHelper,
39
40
  buildReadmeFile,
41
+ hasClientNameChanged,
40
42
  updateReadmeFile,
41
43
  buildRecordedClientFile,
42
44
  buildResponseTypes,
@@ -51,6 +53,7 @@ import {
51
53
  buildTestNodeTsConfig,
52
54
  buildTestMainTsConfig,
53
55
  buildVitestConfig,
56
+ buildWarpConfig,
54
57
  getClientName,
55
58
  hasUnexpectedHelper,
56
59
  isAzurePackage,
@@ -105,6 +108,7 @@ import { transformRLCModel } from "./transform/transform.js";
105
108
  import { transformRLCOptions } from "./transform/transfromRLCOptions.js";
106
109
  import { emitSamples } from "./modular/emitSamples.js";
107
110
  import { generateCrossLanguageDefinitionFile } from "./utils/crossLanguageDef.js";
111
+ import { getClassicalClientName } from "./modular/helpers/namingHelpers.js";
108
112
 
109
113
  export * from "./lib.js";
110
114
 
@@ -143,7 +147,8 @@ export async function $onEmit(context: EmitContext) {
143
147
  ...UrlTemplateHelpers,
144
148
  ...MultipartHelpers,
145
149
  ...CloudSettingHelpers,
146
- ...XmlHelpers
150
+ ...XmlHelpers,
151
+ ...(rlcOptions.enableStorageCompat ? StorageCompatHelpers : {})
147
152
  },
148
153
  {
149
154
  sourcesDir: dpgContext.generationPathDetail?.modularSourcesDir,
@@ -391,7 +396,7 @@ export async function $onEmit(context: EmitContext) {
391
396
  }
392
397
 
393
398
  interface Metadata {
394
- apiVersion?: string;
399
+ apiVersions?: Record<string, string>;
395
400
  emitterVersion?: string;
396
401
  crossLanguageDefinitions?: {
397
402
  CrossLanguagePackageId: string;
@@ -407,9 +412,7 @@ export async function $onEmit(context: EmitContext) {
407
412
  }
408
413
  const content: Metadata = {};
409
414
  if (apiVersions !== undefined && apiVersions.size > 0) {
410
- // Use the first/latest API version if multiple are available
411
- const firstVersion = Array.from(apiVersions.values())[0];
412
- content.apiVersion = firstVersion;
415
+ content.apiVersions = Object.fromEntries(apiVersions);
413
416
  }
414
417
  if (emitterVersion !== undefined) {
415
418
  content.emitterVersion = emitterVersion;
@@ -443,6 +446,11 @@ export async function $onEmit(context: EmitContext) {
443
446
  "README.md"
444
447
  );
445
448
  const hasReadmeFile = await existsSync(existingReadmeFilePath);
449
+ const existingWarpConfigFilePath = join(
450
+ dpgContext.generationPathDetail?.metadataDir ?? "",
451
+ "warp.config.yml"
452
+ );
453
+ const hasWarpConfigFile = await existsSync(existingWarpConfigFilePath);
446
454
  const shouldGenerateMetadata =
447
455
  option.generateMetadata === true || !hasPackageFile;
448
456
  const existingTestFolderPath = join(
@@ -517,6 +525,12 @@ export async function $onEmit(context: EmitContext) {
517
525
  commonBuilders.push((model) =>
518
526
  buildPackageFile(model, modularPackageInfo)
519
527
  );
528
+ // Generate warp.config.yml for Azure monorepo ESM packages (only if it doesn't exist)
529
+ if (option.azureSdkForJs && !hasWarpConfigFile) {
530
+ commonBuilders.push((model) =>
531
+ buildWarpConfig(model, modularPackageInfo)
532
+ );
533
+ }
520
534
  commonBuilders.push(buildTsConfig);
521
535
  if (option.azureSdkForJs) {
522
536
  commonBuilders.push(buildTsSrcConfig);
@@ -553,30 +567,65 @@ export async function $onEmit(context: EmitContext) {
553
567
  }
554
568
  }
555
569
  } else if (hasPackageFile) {
556
- // update existing package.json file with correct dependencies
570
+ const updateBuilders = [];
557
571
  let modularPackageInfo = {};
572
+
573
+ // update existing package.json file with correct dependencies
558
574
  if (option.isModularLibrary) {
559
575
  modularPackageInfo = {
560
- exports: getModuleExports(context, modularEmitterOptions)
576
+ exports: getModuleExports(context, modularEmitterOptions),
577
+ clientContextPaths: getRelativeContextPaths(
578
+ context,
579
+ modularEmitterOptions
580
+ )
561
581
  };
582
+ updateBuilders.push((model: RLCModel) =>
583
+ updatePackageFile(model, existingPackageFilePath, modularPackageInfo)
584
+ );
585
+ }
586
+
587
+ // Generate warp.config.yml for Azure monorepo packages (only if it doesn't exist)
588
+ if (option.azureSdkForJs && !hasWarpConfigFile) {
589
+ updateBuilders.push((model: RLCModel) =>
590
+ buildWarpConfig(model, modularPackageInfo)
591
+ );
562
592
  }
563
- await emitContentByBuilder(
564
- program,
565
- (model) =>
566
- updatePackageFile(model, existingPackageFilePath, modularPackageInfo),
567
- rlcClient,
568
- dpgContext.generationPathDetail?.metadataDir
569
- );
570
593
 
571
- // update existing README.md file if it exists
594
+ // If the client name changed, regenerate the README and snippets completely;
595
+ // otherwise update only the API reference link in-place.
572
596
  if (hasReadmeFile) {
573
- await emitContentByBuilder(
574
- program,
575
- (model) => updateReadmeFile(model, existingReadmeFilePath),
597
+ const clientNameChanged = hasClientNameChanged(
576
598
  rlcClient,
577
- dpgContext.generationPathDetail?.metadataDir
599
+ existingReadmeFilePath
578
600
  );
601
+ updateBuilders.push(
602
+ clientNameChanged
603
+ ? buildReadmeFile
604
+ : (model: RLCModel) =>
605
+ updateReadmeFile(model, existingReadmeFilePath)
606
+ );
607
+
608
+ // Regenerate snippets.spec.ts only when the client name changed
609
+ if (clientNameChanged && option.azureSdkForJs) {
610
+ for (const subClient of dpgContext.sdkPackage.clients) {
611
+ updateBuilders.push((model: RLCModel) =>
612
+ buildSnippets(
613
+ model,
614
+ getClassicalClientName(subClient),
615
+ option.azureSdkForJs
616
+ )
617
+ );
618
+ }
619
+ }
579
620
  }
621
+
622
+ // update metadata relevant files
623
+ await emitContentByBuilder(
624
+ program,
625
+ updateBuilders,
626
+ rlcClient,
627
+ dpgContext.generationPathDetail?.metadataDir
628
+ );
580
629
  }
581
630
  if (isAzureFlavor) {
582
631
  await emitContentByBuilder(
package/src/lib.ts CHANGED
@@ -79,6 +79,12 @@ export interface EmitterOptions {
79
79
  //TODO should remove this after finish the release tool test
80
80
  "should-use-pnpm-dep"?: boolean;
81
81
  "ignore-nullable-on-optional"?: boolean;
82
+ /**
83
+ * When enabled, every regular (non-LRO, non-paging) operation return type is augmented with a
84
+ * `_response` property containing `rawResponse`, `parsedBody`, and `parsedHeaders`.
85
+ * Defaults to `false`.
86
+ */
87
+ "enable-storage-compat"?: boolean;
82
88
  }
83
89
 
84
90
  export const RLCOptionsSchema: JSONSchemaType<EmitterOptions> = {
@@ -363,6 +369,12 @@ export const RLCOptionsSchema: JSONSchemaType<EmitterOptions> = {
363
369
  nullable: true,
364
370
  description:
365
371
  "If an optional property is also marked as nullable, it will be treated as just optional. Defaults to `true` for Azure services."
372
+ },
373
+ "enable-storage-compat": {
374
+ type: "boolean",
375
+ nullable: true,
376
+ description:
377
+ "When enabled, every regular (non-LRO, non-paging) operation return type is augmented with a `_response` property containing `rawResponse` (PathUncheckedResponse), `parsedBody`, and `parsedHeaders`. Defaults to `false`."
366
378
  }
367
379
  },
368
380
  required: []
@@ -20,6 +20,7 @@ import { reportDiagnostic } from "../lib.js";
20
20
  import { NoTarget } from "@typespec/compiler";
21
21
  import { isLroOnlyOperation } from "./helpers/operationHelpers.js";
22
22
  import { SdkContext } from "../utils/interfaces.js";
23
+ import { partitionAndEmitExports } from "./buildSubpathIndex.js";
23
24
 
24
25
  export function buildRootIndex(
25
26
  context: SdkContext,
@@ -111,10 +112,15 @@ function exportModels(
111
112
 
112
113
  function exportAzureCloudTypes(context: SdkContext, rootIndexFile: SourceFile) {
113
114
  if (context.arm) {
115
+ // AzureClouds is an enum (runtime value), AzureSupportedClouds is a type alias
114
116
  addExportsToRootIndexFile(rootIndexFile, [
115
- resolveReference(CloudSettingHelpers.AzureClouds),
116
- resolveReference(CloudSettingHelpers.AzureSupportedClouds)
117
+ resolveReference(CloudSettingHelpers.AzureClouds)
117
118
  ]);
119
+ addExportsToRootIndexFile(
120
+ rootIndexFile,
121
+ [resolveReference(CloudSettingHelpers.AzureSupportedClouds)],
122
+ true
123
+ );
118
124
  }
119
125
  }
120
126
 
@@ -126,11 +132,15 @@ function exportPagingTypes(context: SdkContext, rootIndexFile: SourceFile) {
126
132
  return;
127
133
  }
128
134
 
129
- addExportsToRootIndexFile(rootIndexFile, [
130
- resolveReference(PagingHelpers.PageSettings),
131
- resolveReference(PagingHelpers.ContinuablePage),
132
- resolveReference(PagingHelpers.PagedAsyncIterableIterator)
133
- ]);
135
+ addExportsToRootIndexFile(
136
+ rootIndexFile,
137
+ [
138
+ resolveReference(PagingHelpers.PageSettings),
139
+ resolveReference(PagingHelpers.ContinuablePage),
140
+ resolveReference(PagingHelpers.PagedAsyncIterableIterator)
141
+ ],
142
+ true
143
+ );
134
144
  }
135
145
 
136
146
  function hasPaging(context: SdkContext): boolean {
@@ -159,9 +169,11 @@ function exportFileContentsType(
159
169
  )
160
170
  )
161
171
  ) {
162
- addExportsToRootIndexFile(rootIndexFile, [
163
- resolveReference(MultipartHelpers.FileContents)
164
- ]);
172
+ addExportsToRootIndexFile(
173
+ rootIndexFile,
174
+ [resolveReference(MultipartHelpers.FileContents)],
175
+ true
176
+ );
165
177
  }
166
178
  }
167
179
 
@@ -186,12 +198,14 @@ function getNewNamedExports(
186
198
 
187
199
  function addExportsToRootIndexFile(
188
200
  rootIndexFile: SourceFile,
189
- namedExports: string[]
201
+ namedExports: string[],
202
+ isTypeOnly: boolean = false
190
203
  ) {
191
204
  const existingExports = getExistingExports(rootIndexFile);
192
205
  const newNamedExports = getNewNamedExports(namedExports, existingExports);
193
206
  if (newNamedExports.length > 0) {
194
207
  rootIndexFile.addExportDeclaration({
208
+ isTypeOnly,
195
209
  namedExports: newNamedExports
196
210
  });
197
211
  }
@@ -227,6 +241,7 @@ function exportSimplePollerLike(
227
241
  isTopLevel && subfolder && subfolder !== "" ? subfolder + "/" : ""
228
242
  }static-helpers/simplePollerHelpers.js`;
229
243
  indexFile.addExportDeclaration({
244
+ isTypeOnly: true,
230
245
  moduleSpecifier,
231
246
  namedExports: ["SimplePollerLike"]
232
247
  });
@@ -248,22 +263,14 @@ function exportRestoreHelpers(
248
263
  if (!helperFile) {
249
264
  return;
250
265
  }
251
- const exported = [...indexFile.getExportedDeclarations().keys()];
252
- const namedExports = [...helperFile.getExportedDeclarations().keys()].map(
253
- (helper) => {
254
- if (exported.indexOf(helper) > -1) {
255
- return `${helper} as ${clientName}${helper}`;
256
- }
257
- return helper;
258
- }
259
- );
266
+ const exported = new Set(indexFile.getExportedDeclarations().keys());
267
+ const allEntries = [...helperFile.getExportedDeclarations().entries()];
260
268
  const moduleSpecifier = `./${
261
269
  isTopLevel && subfolder && subfolder !== "" ? subfolder + "/" : ""
262
270
  }restorePollerHelpers.js`;
263
- indexFile.addExportDeclaration({
264
- moduleSpecifier,
265
- namedExports
266
- });
271
+ const renamer = (name: string) =>
272
+ exported.has(name) ? `${name} as ${clientName}${name}` : name;
273
+ partitionAndEmitExports(indexFile, moduleSpecifier, allEntries, renamer);
267
274
  }
268
275
 
269
276
  function exportClassicalClient(
@@ -341,55 +348,52 @@ function exportModules(
341
348
  continue;
342
349
  }
343
350
 
344
- const exported = [...indexFile.getExportedDeclarations().keys()];
351
+ const exported = new Set(indexFile.getExportedDeclarations().keys());
345
352
  const serializerOrDeserializerRegex = /.*(Serializer|Deserializer)(_\d+)?$/;
346
- const namedExports = [...modelsFile.getExportedDeclarations().entries()]
347
- .filter((exDeclaration) => {
348
- if (exDeclaration[0].startsWith("_")) {
353
+ const filteredEntries = [
354
+ ...modelsFile.getExportedDeclarations().entries()
355
+ ].filter((exDeclaration) => {
356
+ if (exDeclaration[0].startsWith("_")) {
357
+ return false;
358
+ }
359
+ return exDeclaration[1].some((ex) => {
360
+ if (
361
+ options.interfaceOnly &&
362
+ ex.getKindName() !== "InterfaceDeclaration"
363
+ ) {
349
364
  return false;
350
365
  }
351
- return exDeclaration[1].some((ex) => {
352
- if (
353
- options.interfaceOnly &&
354
- ex.getKindName() !== "InterfaceDeclaration"
355
- ) {
356
- return false;
357
- }
358
- if (
359
- moduleName === "models" &&
360
- ex.getKindName() === "FunctionDeclaration" &&
361
- serializerOrDeserializerRegex.test(exDeclaration[0])
362
- ) {
363
- return false;
364
- }
365
- if (
366
- options.interfaceOnly &&
367
- options.isTopLevel &&
368
- exDeclaration[0].endsWith("Context")
369
- ) {
370
- return false;
371
- }
372
-
373
- return true;
374
- });
375
- })
376
- .map((exDeclaration) => {
377
- if (exported.indexOf(exDeclaration[0]) > -1) {
378
- return `${exDeclaration[0]} as ${clientName}${exDeclaration[0]}`;
366
+ if (
367
+ moduleName === "models" &&
368
+ ex.getKindName() === "FunctionDeclaration" &&
369
+ serializerOrDeserializerRegex.test(exDeclaration[0])
370
+ ) {
371
+ return false;
372
+ }
373
+ if (
374
+ options.interfaceOnly &&
375
+ options.isTopLevel &&
376
+ exDeclaration[0].endsWith("Context")
377
+ ) {
378
+ return false;
379
379
  }
380
- return exDeclaration[0];
380
+
381
+ return true;
381
382
  });
383
+ });
382
384
  const moduleSpecifier = `.${modelsFile
383
385
  .getFilePath()
384
386
  .replace(indexFile.getDirectoryPath(), "")
385
387
  .replace(/\\/g, "/")
386
388
  .replace(".ts", "")}.js`;
387
- if (namedExports.length > 0) {
388
- indexFile.addExportDeclaration({
389
- moduleSpecifier,
390
- namedExports
391
- });
392
- }
389
+ const renamer = (name: string) =>
390
+ exported.has(name) ? `${name} as ${clientName}${name}` : name;
391
+ partitionAndEmitExports(
392
+ indexFile,
393
+ moduleSpecifier,
394
+ filteredEntries,
395
+ renamer
396
+ );
393
397
  }
394
398
  }
395
399
 
@@ -7,6 +7,7 @@ import { ModularEmitterOptions } from "./interfaces.js";
7
7
  import { join } from "path";
8
8
  import { getModularClientOptions } from "../utils/clientUtils.js";
9
9
  import { useContext } from "../contextManager.js";
10
+ import { Node, SourceFile } from "ts-morph";
10
11
 
11
12
  export interface buildSubpathIndexFileOptions {
12
13
  exportIndex?: boolean;
@@ -85,50 +86,90 @@ export function buildSubpathIndexFile(
85
86
  continue;
86
87
  }
87
88
 
88
- let namedExports: string[] = [...file.getExportedDeclarations().entries()]
89
- .filter((exDeclaration) => {
90
- if (exDeclaration[0].startsWith("_")) {
89
+ let filteredDeclarations = [
90
+ ...file.getExportedDeclarations().entries()
91
+ ].filter((exDeclaration) => {
92
+ if (exDeclaration[0].startsWith("_")) {
93
+ return false;
94
+ }
95
+ return exDeclaration[1].some((ex) => {
96
+ if (
97
+ options.interfaceOnly &&
98
+ ex.getKindName() !== "InterfaceDeclaration"
99
+ ) {
91
100
  return false;
92
101
  }
93
- return exDeclaration[1].some((ex) => {
94
- if (
95
- options.interfaceOnly &&
96
- ex.getKindName() !== "InterfaceDeclaration"
97
- ) {
98
- return false;
99
- }
100
102
 
101
- // skip exporting serializers for models
102
- if (
103
- subpath === "models" &&
104
- ex.getKindName() === "FunctionDeclaration" &&
105
- serializerOrDeserializerRegex.test(exDeclaration[0])
106
- ) {
107
- return false;
108
- }
103
+ // skip exporting serializers for models
104
+ if (
105
+ subpath === "models" &&
106
+ ex.getKindName() === "FunctionDeclaration" &&
107
+ serializerOrDeserializerRegex.test(exDeclaration[0])
108
+ ) {
109
+ return false;
110
+ }
109
111
 
110
- return true;
111
- });
112
- })
113
- .map((exDeclaration) => {
114
- return exDeclaration[0];
112
+ return true;
115
113
  });
114
+ });
116
115
  // Skip to export PagedResult and BuildPagedAsyncIteratorOptions
117
116
  if (filePath.endsWith("pagingTypes.ts")) {
118
- namedExports = namedExports.filter(
119
- (ex) =>
120
- !["PagedResult", "BuildPagedAsyncIteratorOptions"].includes(ex)
117
+ filteredDeclarations = filteredDeclarations.filter(
118
+ ([name]) =>
119
+ !["PagedResult", "BuildPagedAsyncIteratorOptions"].includes(name)
121
120
  );
122
121
  }
123
- if (namedExports.length > 0) {
124
- indexFile.addExportDeclaration({
125
- moduleSpecifier: `.${filePath
126
- .replace(indexFile.getDirectoryPath(), "")
127
- .replace(/\\/g, "/")
128
- .replace(".ts", "")}.js`,
129
- namedExports
130
- });
122
+ if (filteredDeclarations.length > 0) {
123
+ const moduleSpecifier = `.${filePath
124
+ .replace(indexFile.getDirectoryPath(), "")
125
+ .replace(/\\/g, "/")
126
+ .replace(".ts", "")}.js`;
127
+ partitionAndEmitExports(
128
+ indexFile,
129
+ moduleSpecifier,
130
+ filteredDeclarations
131
+ );
131
132
  }
132
133
  }
133
134
  }
134
135
  }
136
+
137
+ export function isTypeOnlyNode(node: Node): boolean {
138
+ const kind = node.getKindName();
139
+ return kind === "InterfaceDeclaration" || kind === "TypeAliasDeclaration";
140
+ }
141
+
142
+ /**
143
+ * Partition declaration entries into type-only and value exports in a single pass,
144
+ * then emit both export declarations on the index file.
145
+ */
146
+ export function partitionAndEmitExports(
147
+ indexFile: SourceFile,
148
+ moduleSpecifier: string,
149
+ entries: [string, Node[]][],
150
+ mapName: (name: string) => string = (n) => n
151
+ ): void {
152
+ const typeOnlyExports: string[] = [];
153
+ const valueExports: string[] = [];
154
+ for (const [name, decls] of entries) {
155
+ const mapped = mapName(name);
156
+ if (decls.every(isTypeOnlyNode)) {
157
+ typeOnlyExports.push(mapped);
158
+ } else {
159
+ valueExports.push(mapped);
160
+ }
161
+ }
162
+ if (typeOnlyExports.length > 0) {
163
+ indexFile.addExportDeclaration({
164
+ isTypeOnly: true,
165
+ moduleSpecifier,
166
+ namedExports: typeOnlyExports
167
+ });
168
+ }
169
+ if (valueExports.length > 0) {
170
+ indexFile.addExportDeclaration({
171
+ moduleSpecifier,
172
+ namedExports: valueExports
173
+ });
174
+ }
175
+ }