@aws/nx-plugin 1.0.0-rc.30 → 1.0.0-rc.32

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 (59) hide show
  1. package/LICENSE-THIRD-PARTY +235 -1336
  2. package/README.md +1 -1
  3. package/package.json +1 -2
  4. package/src/mcp-server/tools/create-workspace-command.js +2 -2
  5. package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
  6. package/src/open-api/ts-client/__snapshots__/generator.additional-properties.spec.ts.snap +147 -33
  7. package/src/open-api/ts-client/__snapshots__/generator.arrays.spec.ts.snap +308 -75
  8. package/src/open-api/ts-client/__snapshots__/generator.complex-types.spec.ts.snap +286 -62
  9. package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +674 -93
  10. package/src/open-api/ts-client/__snapshots__/generator.content-type.spec.ts.snap +211 -36
  11. package/src/open-api/ts-client/__snapshots__/generator.duplicate-types.spec.ts.snap +196 -44
  12. package/src/open-api/ts-client/__snapshots__/generator.edge-cases.spec.ts.snap +5507 -0
  13. package/src/open-api/ts-client/__snapshots__/generator.fast-api.spec.ts.snap +219 -60
  14. package/src/open-api/ts-client/__snapshots__/generator.multipart.spec.ts.snap +280 -0
  15. package/src/open-api/ts-client/__snapshots__/generator.primitive-types.spec.ts.snap +351 -80
  16. package/src/open-api/ts-client/__snapshots__/generator.request.spec.ts.snap +170 -49
  17. package/src/open-api/ts-client/__snapshots__/generator.reserved-keywords.spec.ts.snap +98 -22
  18. package/src/open-api/ts-client/__snapshots__/generator.response.spec.ts.snap +147 -33
  19. package/src/open-api/ts-client/__snapshots__/generator.streaming.spec.ts.snap +392 -88
  20. package/src/open-api/ts-client/__snapshots__/generator.tags.spec.ts.snap +196 -44
  21. package/src/open-api/ts-client/files/client.gen.ts.template +166 -19
  22. package/src/open-api/ts-client/files/types.gen.ts.template +4 -4
  23. package/src/open-api/ts-client/generator.js +1 -1
  24. package/src/open-api/ts-client/generator.js.map +1 -1
  25. package/src/open-api/ts-hooks/files/options-proxy.gen.ts.template +5 -0
  26. package/src/open-api/ts-hooks/generator.spec.tsx +70 -0
  27. package/src/open-api/utils/codegen-data/languages.d.ts +0 -6
  28. package/src/open-api/utils/codegen-data/languages.js +23 -18
  29. package/src/open-api/utils/codegen-data/languages.js.map +1 -1
  30. package/src/open-api/utils/codegen-data/types.d.ts +240 -10
  31. package/src/open-api/utils/codegen-data/types.js +24 -1
  32. package/src/open-api/utils/codegen-data/types.js.map +1 -1
  33. package/src/open-api/utils/codegen-data.d.ts +2 -2
  34. package/src/open-api/utils/codegen-data.js +357 -617
  35. package/src/open-api/utils/codegen-data.js.map +1 -1
  36. package/src/open-api/utils/normalise.js +167 -22
  37. package/src/open-api/utils/normalise.js.map +1 -1
  38. package/src/open-api/utils/parser.d.ts +55 -0
  39. package/src/open-api/utils/parser.js +754 -0
  40. package/src/open-api/utils/parser.js.map +1 -0
  41. package/src/open-api/utils/types.d.ts +18 -0
  42. package/src/open-api/utils/types.js.map +1 -1
  43. package/src/preset/__snapshots__/generator.spec.ts.snap +6 -6
  44. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +414 -6
  45. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +276 -4
  46. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +414 -6
  47. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +0 -23
  48. package/src/ts/mcp-server/generator.js +10 -22
  49. package/src/ts/mcp-server/generator.js.map +1 -1
  50. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +69 -1
  51. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +69 -1
  52. package/src/utils/mcp.js +1 -1
  53. package/src/utils/mcp.js.map +1 -1
  54. package/src/utils/names.d.ts +6 -0
  55. package/src/utils/names.js +6 -1
  56. package/src/utils/names.js.map +1 -1
  57. package/src/utils/versions.d.ts +5 -5
  58. package/src/utils/versions.js +4 -4
  59. package/src/utils/versions.js.map +1 -1
package/README.md CHANGED
@@ -133,7 +133,7 @@ Create a workspace and start adding components — zero configuration required:
133
133
 
134
134
  ```bash
135
135
  # Create a new workspace
136
- pnpm create @aws/nx-workspace@next my-project
136
+ pnpm create @aws/nx-workspace my-project
137
137
  cd my-project
138
138
 
139
139
  # Add a tRPC API
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin",
3
- "version": "1.0.0-rc.30",
3
+ "version": "1.0.0-rc.32",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -43,7 +43,6 @@
43
43
  "@biomejs/js-api": "4.0.0",
44
44
  "@biomejs/wasm-nodejs": "2.5.1",
45
45
  "@getgrit/gritql": "0.0.3",
46
- "@hey-api/openapi-ts": "0.64.13",
47
46
  "@iarna/toml": "2.2.5",
48
47
  "@modelcontextprotocol/sdk": "1.29.0",
49
48
  "@nx/devkit": "23.0.1",
@@ -19,7 +19,7 @@ import { PackageManagerSchema } from "../schema.js";
19
19
  text: `Run the following command to create a workspace:
20
20
 
21
21
  \`\`\`bash
22
- ${buildCreateNxWorkspaceCommand(packageManager, '<workspace-name>', undefined, 'next')} --no-interactive
22
+ ${buildCreateNxWorkspaceCommand(packageManager, '<workspace-name>')} --no-interactive
23
23
  \`\`\`
24
24
 
25
25
  This will create a new workspace within the \`<workspace-name>\` directory.
@@ -27,7 +27,7 @@ This will create a new workspace within the \`<workspace-name>\` directory.
27
27
  If you are already inside an empty directory intended for this project, you can pass \`.\` as the workspace name to create the workspace in the current directory:
28
28
 
29
29
  \`\`\`bash
30
- ${buildCreateNxWorkspaceCommand(packageManager, '.', undefined, 'next')} --no-interactive
30
+ ${buildCreateNxWorkspaceCommand(packageManager, '.')} --no-interactive
31
31
  \`\`\`
32
32
 
33
33
  Note that this will prompt for an Infrastructure as Code provider (${IAC_PROVIDERS.join(', ')}).
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/mcp-server/tools/create-workspace-command.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { buildCreateNxWorkspaceCommand } from '../../utils/commands';\nimport { IAC_PROVIDERS } from '../../utils/iac-providers';\nimport { PackageManagerSchema } from '../schema';\n\n/**\n * Add a tool which tells a model how to create an Nx workspace\n */\nexport const addCreateWorkspaceCommandTool = (server: McpServer) => {\n server.registerTool(\n 'create-workspace-command',\n {\n description:\n 'Tool to discover how to create a workspace to start a new project.',\n inputSchema: {\n packageManager: PackageManagerSchema,\n },\n },\n ({ packageManager }) => ({\n content: [\n {\n type: 'text' as const,\n text: `Run the following command to create a workspace:\n\n\\`\\`\\`bash\n${buildCreateNxWorkspaceCommand(packageManager, '<workspace-name>', undefined, 'next')} --no-interactive\n\\`\\`\\`\n\nThis will create a new workspace within the \\`<workspace-name>\\` directory.\n\nIf you are already inside an empty directory intended for this project, you can pass \\`.\\` as the workspace name to create the workspace in the current directory:\n\n\\`\\`\\`bash\n${buildCreateNxWorkspaceCommand(packageManager, '.', undefined, 'next')} --no-interactive\n\\`\\`\\`\n\nNote that this will prompt for an Infrastructure as Code provider (${IAC_PROVIDERS.join(', ')}).\nIf you know the preferred option, pass ${IAC_PROVIDERS.map((iac) => `\\`--iac=${iac}\\``).join(' or ')} to the above command to skip the prompt.\n\nAdditional options:\n- \\`--no-gitSecrets\\`: Opt out of the default git-secrets pre-commit hook (prevents committing AWS credentials)\n\nRefer to the \\`general-guidance\\` tool for full workspace documentation including structure, common commands, and configuration.\n `,\n },\n ],\n }),\n );\n};\n"],"names":["buildCreateNxWorkspaceCommand","IAC_PROVIDERS","PackageManagerSchema","addCreateWorkspaceCommandTool","server","registerTool","description","inputSchema","packageManager","content","type","text","undefined","join","map","iac"],"mappings":"AAAA;;;CAGC,GAED,SAASA,6BAA6B,QAAQ,0BAAuB;AACrE,SAASC,aAAa,QAAQ,+BAA4B;AAC1D,SAASC,oBAAoB,QAAQ,eAAY;AAEjD;;CAEC,GACD,OAAO,MAAMC,gCAAgC,CAACC;IAC5CA,OAAOC,YAAY,CACjB,4BACA;QACEC,aACE;QACFC,aAAa;YACXC,gBAAgBN;QAClB;IACF,GACA,CAAC,EAAEM,cAAc,EAAE,GAAM,CAAA;YACvBC,SAAS;gBACP;oBACEC,MAAM;oBACNC,MAAM,CAAC;;;AAGjB,EAAEX,8BAA8BQ,gBAAgB,oBAAoBI,WAAW,QAAQ;;;;;;;;AAQvF,EAAEZ,8BAA8BQ,gBAAgB,KAAKI,WAAW,QAAQ;;;mEAGL,EAAEX,cAAcY,IAAI,CAAC,MAAM;uCACvD,EAAEZ,cAAca,GAAG,CAAC,CAACC,MAAQ,CAAC,QAAQ,EAAEA,IAAI,EAAE,CAAC,EAAEF,IAAI,CAAC,QAAQ;;;;;;EAMnG,CAAC;gBACK;aACD;QACH,CAAA;AAEJ,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/mcp-server/tools/create-workspace-command.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { buildCreateNxWorkspaceCommand } from '../../utils/commands';\nimport { IAC_PROVIDERS } from '../../utils/iac-providers';\nimport { PackageManagerSchema } from '../schema';\n\n/**\n * Add a tool which tells a model how to create an Nx workspace\n */\nexport const addCreateWorkspaceCommandTool = (server: McpServer) => {\n server.registerTool(\n 'create-workspace-command',\n {\n description:\n 'Tool to discover how to create a workspace to start a new project.',\n inputSchema: {\n packageManager: PackageManagerSchema,\n },\n },\n ({ packageManager }) => ({\n content: [\n {\n type: 'text' as const,\n text: `Run the following command to create a workspace:\n\n\\`\\`\\`bash\n${buildCreateNxWorkspaceCommand(packageManager, '<workspace-name>')} --no-interactive\n\\`\\`\\`\n\nThis will create a new workspace within the \\`<workspace-name>\\` directory.\n\nIf you are already inside an empty directory intended for this project, you can pass \\`.\\` as the workspace name to create the workspace in the current directory:\n\n\\`\\`\\`bash\n${buildCreateNxWorkspaceCommand(packageManager, '.')} --no-interactive\n\\`\\`\\`\n\nNote that this will prompt for an Infrastructure as Code provider (${IAC_PROVIDERS.join(', ')}).\nIf you know the preferred option, pass ${IAC_PROVIDERS.map((iac) => `\\`--iac=${iac}\\``).join(' or ')} to the above command to skip the prompt.\n\nAdditional options:\n- \\`--no-gitSecrets\\`: Opt out of the default git-secrets pre-commit hook (prevents committing AWS credentials)\n\nRefer to the \\`general-guidance\\` tool for full workspace documentation including structure, common commands, and configuration.\n `,\n },\n ],\n }),\n );\n};\n"],"names":["buildCreateNxWorkspaceCommand","IAC_PROVIDERS","PackageManagerSchema","addCreateWorkspaceCommandTool","server","registerTool","description","inputSchema","packageManager","content","type","text","join","map","iac"],"mappings":"AAAA;;;CAGC,GAED,SAASA,6BAA6B,QAAQ,0BAAuB;AACrE,SAASC,aAAa,QAAQ,+BAA4B;AAC1D,SAASC,oBAAoB,QAAQ,eAAY;AAEjD;;CAEC,GACD,OAAO,MAAMC,gCAAgC,CAACC;IAC5CA,OAAOC,YAAY,CACjB,4BACA;QACEC,aACE;QACFC,aAAa;YACXC,gBAAgBN;QAClB;IACF,GACA,CAAC,EAAEM,cAAc,EAAE,GAAM,CAAA;YACvBC,SAAS;gBACP;oBACEC,MAAM;oBACNC,MAAM,CAAC;;;AAGjB,EAAEX,8BAA8BQ,gBAAgB,oBAAoB;;;;;;;;AAQpE,EAAER,8BAA8BQ,gBAAgB,KAAK;;;mEAGc,EAAEP,cAAcW,IAAI,CAAC,MAAM;uCACvD,EAAEX,cAAcY,GAAG,CAAC,CAACC,MAAQ,CAAC,QAAQ,EAAEA,IAAI,EAAE,CAAC,EAAEF,IAAI,CAAC,QAAQ;;;;;;EAMnG,CAAC;gBACK;aACD;QACH,CAAA;AAEJ,EAAE"}
@@ -66,7 +66,7 @@ exports[`openApiTsClientGenerator - complex types > should handle response objec
66
66
  * Utility for serialisation and deserialisation of API types.
67
67
  */
68
68
  export class $IO {
69
- protected static $mapValues = (data: any, fn: (item: any) => any) =>
69
+ public static $mapValues = (data: any, fn: (item: any) => any) =>
70
70
  Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
71
71
 
72
72
  public static GetDynamicPropertiesAny200Response = {
@@ -457,11 +457,31 @@ export class TestApi {
457
457
  this.getDynamicPropertyValues = this.getDynamicPropertyValues.bind(this);
458
458
  }
459
459
 
460
+ private $collectionDelimiters: { [format: string]: string } = {
461
+ csv: ',',
462
+ ssv: ' ',
463
+ pipes: '|',
464
+ };
465
+
466
+ private $deepObject = (key: string, value: any): string[] => {
467
+ if (value === undefined || value === null) {
468
+ return [];
469
+ }
470
+ if (typeof value !== 'object') {
471
+ return [\`\${key}=\${encodeURIComponent(String(value))}\`];
472
+ }
473
+ return Object.entries(value).flatMap(([prop, v]) =>
474
+ this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
475
+ );
476
+ };
477
+
460
478
  private $url = (
461
479
  path: string,
462
480
  pathParameters: { [key: string]: any },
463
481
  queryParameters: { [key: string]: any },
464
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
482
+ collectionFormats?: {
483
+ [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
484
+ },
465
485
  ): string => {
466
486
  const baseUrl = this.$config.url.endsWith('/')
467
487
  ? this.$config.url.slice(0, -1)
@@ -472,15 +492,24 @@ export class TestApi {
472
492
  path,
473
493
  );
474
494
  const queryString = Object.entries(queryParameters)
475
- .map(([key, value]) => {
495
+ .flatMap(([key, value]) => {
476
496
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
477
- return value
478
- .map(
479
- (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
480
- )
481
- .join('&');
497
+ return value.map(
498
+ (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
499
+ );
500
+ }
501
+ if (
502
+ collectionFormats?.[key] === 'deepObject' &&
503
+ value !== null &&
504
+ typeof value === 'object'
505
+ ) {
506
+ return this.$deepObject(encodeURIComponent(key), value);
482
507
  }
483
- return \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(',') : String(value))}\`;
508
+ const delimiter =
509
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
510
+ return [
511
+ \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
512
+ ];
484
513
  })
485
514
  .join('&');
486
515
  return (
@@ -490,13 +519,22 @@ export class TestApi {
490
519
 
491
520
  private $headers = (
492
521
  headerParameters: { [key: string]: any },
493
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
522
+ collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
494
523
  ): [string, string][] => {
495
524
  return Object.entries(headerParameters).flatMap(([key, value]) => {
496
525
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
497
526
  return value.map((v) => [key, String(v)]) as [string, string][];
498
527
  }
499
- return [[key, String(value)]];
528
+ const delimiter =
529
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
530
+ return [
531
+ [
532
+ key,
533
+ Array.isArray(value)
534
+ ? value.map(String).join(delimiter)
535
+ : String(value),
536
+ ],
537
+ ];
500
538
  });
501
539
  };
502
540
 
@@ -765,7 +803,7 @@ exports[`openApiTsClientGenerator - complex types > should handle response objec
765
803
  * Utility for serialisation and deserialisation of API types.
766
804
  */
767
805
  export class $IO {
768
- protected static $mapValues = (data: any, fn: (item: any) => any) =>
806
+ public static $mapValues = (data: any, fn: (item: any) => any) =>
769
807
  Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
770
808
 
771
809
  public static GetPatternPropertiesArrayArrays200Response = {
@@ -1872,11 +1910,31 @@ export class TestApi {
1872
1910
  this.getPatternPropertiesSingle.bind(this);
1873
1911
  }
1874
1912
 
1913
+ private $collectionDelimiters: { [format: string]: string } = {
1914
+ csv: ',',
1915
+ ssv: ' ',
1916
+ pipes: '|',
1917
+ };
1918
+
1919
+ private $deepObject = (key: string, value: any): string[] => {
1920
+ if (value === undefined || value === null) {
1921
+ return [];
1922
+ }
1923
+ if (typeof value !== 'object') {
1924
+ return [\`\${key}=\${encodeURIComponent(String(value))}\`];
1925
+ }
1926
+ return Object.entries(value).flatMap(([prop, v]) =>
1927
+ this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
1928
+ );
1929
+ };
1930
+
1875
1931
  private $url = (
1876
1932
  path: string,
1877
1933
  pathParameters: { [key: string]: any },
1878
1934
  queryParameters: { [key: string]: any },
1879
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
1935
+ collectionFormats?: {
1936
+ [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
1937
+ },
1880
1938
  ): string => {
1881
1939
  const baseUrl = this.$config.url.endsWith('/')
1882
1940
  ? this.$config.url.slice(0, -1)
@@ -1887,15 +1945,24 @@ export class TestApi {
1887
1945
  path,
1888
1946
  );
1889
1947
  const queryString = Object.entries(queryParameters)
1890
- .map(([key, value]) => {
1948
+ .flatMap(([key, value]) => {
1891
1949
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
1892
- return value
1893
- .map(
1894
- (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
1895
- )
1896
- .join('&');
1950
+ return value.map(
1951
+ (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
1952
+ );
1953
+ }
1954
+ if (
1955
+ collectionFormats?.[key] === 'deepObject' &&
1956
+ value !== null &&
1957
+ typeof value === 'object'
1958
+ ) {
1959
+ return this.$deepObject(encodeURIComponent(key), value);
1897
1960
  }
1898
- return \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(',') : String(value))}\`;
1961
+ const delimiter =
1962
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
1963
+ return [
1964
+ \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
1965
+ ];
1899
1966
  })
1900
1967
  .join('&');
1901
1968
  return (
@@ -1905,13 +1972,22 @@ export class TestApi {
1905
1972
 
1906
1973
  private $headers = (
1907
1974
  headerParameters: { [key: string]: any },
1908
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
1975
+ collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
1909
1976
  ): [string, string][] => {
1910
1977
  return Object.entries(headerParameters).flatMap(([key, value]) => {
1911
1978
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
1912
1979
  return value.map((v) => [key, String(v)]) as [string, string][];
1913
1980
  }
1914
- return [[key, String(value)]];
1981
+ const delimiter =
1982
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
1983
+ return [
1984
+ [
1985
+ key,
1986
+ Array.isArray(value)
1987
+ ? value.map(String).join(delimiter)
1988
+ : String(value),
1989
+ ],
1990
+ ];
1915
1991
  });
1916
1992
  };
1917
1993
 
@@ -2245,7 +2321,7 @@ exports[`openApiTsClientGenerator - complex types > should render \`unknown\` va
2245
2321
  * Utility for serialisation and deserialisation of API types.
2246
2322
  */
2247
2323
  export class $IO {
2248
- protected static $mapValues = (data: any, fn: (item: any) => any) =>
2324
+ public static $mapValues = (data: any, fn: (item: any) => any) =>
2249
2325
  Object.fromEntries(Object.entries(data).map(([k, v]) => [k, fn(v)]));
2250
2326
 
2251
2327
  public static GetAdditionalPropsTrue200Response = {
@@ -2326,11 +2402,31 @@ export class TestApi {
2326
2402
  this.getBareObject = this.getBareObject.bind(this);
2327
2403
  }
2328
2404
 
2405
+ private $collectionDelimiters: { [format: string]: string } = {
2406
+ csv: ',',
2407
+ ssv: ' ',
2408
+ pipes: '|',
2409
+ };
2410
+
2411
+ private $deepObject = (key: string, value: any): string[] => {
2412
+ if (value === undefined || value === null) {
2413
+ return [];
2414
+ }
2415
+ if (typeof value !== 'object') {
2416
+ return [\`\${key}=\${encodeURIComponent(String(value))}\`];
2417
+ }
2418
+ return Object.entries(value).flatMap(([prop, v]) =>
2419
+ this.$deepObject(\`\${key}[\${encodeURIComponent(prop)}]\`, v),
2420
+ );
2421
+ };
2422
+
2329
2423
  private $url = (
2330
2424
  path: string,
2331
2425
  pathParameters: { [key: string]: any },
2332
2426
  queryParameters: { [key: string]: any },
2333
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
2427
+ collectionFormats?: {
2428
+ [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' | 'deepObject';
2429
+ },
2334
2430
  ): string => {
2335
2431
  const baseUrl = this.$config.url.endsWith('/')
2336
2432
  ? this.$config.url.slice(0, -1)
@@ -2341,15 +2437,24 @@ export class TestApi {
2341
2437
  path,
2342
2438
  );
2343
2439
  const queryString = Object.entries(queryParameters)
2344
- .map(([key, value]) => {
2440
+ .flatMap(([key, value]) => {
2345
2441
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
2346
- return value
2347
- .map(
2348
- (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
2349
- )
2350
- .join('&');
2442
+ return value.map(
2443
+ (v) => \`\${encodeURIComponent(key)}=\${encodeURIComponent(\`\${v}\`)}\`,
2444
+ );
2445
+ }
2446
+ if (
2447
+ collectionFormats?.[key] === 'deepObject' &&
2448
+ value !== null &&
2449
+ typeof value === 'object'
2450
+ ) {
2451
+ return this.$deepObject(encodeURIComponent(key), value);
2351
2452
  }
2352
- return \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(',') : String(value))}\`;
2453
+ const delimiter =
2454
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
2455
+ return [
2456
+ \`\${encodeURIComponent(key)}=\${encodeURIComponent(Array.isArray(value) ? value.map(String).join(delimiter) : String(value))}\`,
2457
+ ];
2353
2458
  })
2354
2459
  .join('&');
2355
2460
  return (
@@ -2359,13 +2464,22 @@ export class TestApi {
2359
2464
 
2360
2465
  private $headers = (
2361
2466
  headerParameters: { [key: string]: any },
2362
- collectionFormats?: { [key: string]: 'multi' | 'csv' },
2467
+ collectionFormats?: { [key: string]: 'multi' | 'csv' | 'ssv' | 'pipes' },
2363
2468
  ): [string, string][] => {
2364
2469
  return Object.entries(headerParameters).flatMap(([key, value]) => {
2365
2470
  if (Array.isArray(value) && collectionFormats?.[key] === 'multi') {
2366
2471
  return value.map((v) => [key, String(v)]) as [string, string][];
2367
2472
  }
2368
- return [[key, String(value)]];
2473
+ const delimiter =
2474
+ this.$collectionDelimiters[collectionFormats?.[key] ?? 'csv'] ?? ',';
2475
+ return [
2476
+ [
2477
+ key,
2478
+ Array.isArray(value)
2479
+ ? value.map(String).join(delimiter)
2480
+ : String(value),
2481
+ ],
2482
+ ];
2369
2483
  });
2370
2484
  };
2371
2485