@grafana/openapi-to-k6 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/.github/workflows/publish.yaml +2 -0
  2. package/.github/workflows/tests.yaml +14 -6
  3. package/README.md +49 -14
  4. package/dist/cli.js +18 -2
  5. package/dist/constants.js +8 -2
  6. package/dist/{generator.js → generator/index.js} +7 -13
  7. package/dist/{k6SdkClient.js → generator/k6Client.js} +148 -161
  8. package/examples/basic_schema/single/k6-script.sample.ts +11 -0
  9. package/examples/basic_schema/single/simpleAPI.ts +87 -0
  10. package/examples/basic_schema/split/k6-script.sample.ts +11 -0
  11. package/examples/basic_schema/split/simpleAPI.schemas.ts +9 -0
  12. package/examples/basic_schema/split/simpleAPI.ts +85 -0
  13. package/examples/basic_schema/tags/default.ts +85 -0
  14. package/examples/basic_schema/tags/k6-script.sample.ts +11 -0
  15. package/examples/basic_schema/tags/simpleAPI.schemas.ts +9 -0
  16. package/examples/form_data_schema/single/formDataAPI.ts +115 -0
  17. package/examples/form_data_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  18. package/examples/form_data_schema/split/formDataAPI.schemas.ts +24 -0
  19. package/examples/form_data_schema/split/formDataAPI.ts +98 -0
  20. package/examples/form_data_schema/split/k6-script.sample.ts +11 -0
  21. package/examples/form_data_schema/tags/default.ts +98 -0
  22. package/examples/form_data_schema/tags/formDataAPI.schemas.ts +24 -0
  23. package/examples/form_data_schema/tags/k6-script.sample.ts +11 -0
  24. package/examples/form_url_encoded_data_schema/single/formURLEncodedAPI.ts +112 -0
  25. package/examples/form_url_encoded_data_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  26. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.schemas.ts +24 -0
  27. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.ts +98 -0
  28. package/examples/form_url_encoded_data_schema/split/k6-script.sample.ts +11 -0
  29. package/examples/form_url_encoded_data_schema/tags/default.ts +98 -0
  30. package/examples/form_url_encoded_data_schema/tags/formURLEncodedAPI.schemas.ts +24 -0
  31. package/examples/form_url_encoded_data_schema/tags/k6-script.sample.ts +11 -0
  32. package/examples/form_url_encoded_data_with_query_params_schema/single/formURLEncodedAPIWithQueryParameters.ts +128 -0
  33. package/examples/form_url_encoded_data_with_query_params_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  34. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.schemas.ts +35 -0
  35. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.ts +104 -0
  36. package/examples/form_url_encoded_data_with_query_params_schema/split/k6-script.sample.ts +14 -0
  37. package/examples/form_url_encoded_data_with_query_params_schema/tags/default.ts +104 -0
  38. package/examples/form_url_encoded_data_with_query_params_schema/tags/formURLEncodedAPIWithQueryParameters.schemas.ts +35 -0
  39. package/examples/form_url_encoded_data_with_query_params_schema/tags/k6-script.sample.ts +14 -0
  40. package/examples/get_request_with_path_parameters_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  41. package/examples/get_request_with_path_parameters_schema/single/simpleAPI.ts +94 -0
  42. package/examples/get_request_with_path_parameters_schema/split/k6-script.sample.ts +11 -0
  43. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.schemas.ts +12 -0
  44. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.ts +90 -0
  45. package/examples/get_request_with_path_parameters_schema/tags/default.ts +90 -0
  46. package/examples/get_request_with_path_parameters_schema/tags/k6-script.sample.ts +11 -0
  47. package/examples/get_request_with_path_parameters_schema/tags/simpleAPI.schemas.ts +12 -0
  48. package/examples/headers_schema/single/headerDemoAPI.ts +202 -0
  49. package/examples/headers_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  50. package/examples/headers_schema/split/headerDemoAPI.schemas.ts +32 -0
  51. package/examples/headers_schema/split/headerDemoAPI.ts +184 -0
  52. package/examples/headers_schema/split/k6-script.sample.ts +25 -0
  53. package/examples/headers_schema/tags/default.ts +182 -0
  54. package/examples/headers_schema/tags/headerDemoAPI.schemas.ts +32 -0
  55. package/examples/headers_schema/tags/k6-script.sample.ts +25 -0
  56. package/examples/no_title_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  57. package/examples/no_title_schema/single/k6Client.ts +87 -0
  58. package/examples/{basic_schema → no_title_schema/split}/k6-script.sample.ts +2 -2
  59. package/examples/no_title_schema/split/k6Client.schemas.ts +9 -0
  60. package/examples/no_title_schema/split/k6Client.ts +85 -0
  61. package/examples/no_title_schema/tags/default.ts +85 -0
  62. package/examples/no_title_schema/tags/k6-script.sample.ts +11 -0
  63. package/examples/no_title_schema/tags/k6Client.schemas.ts +9 -0
  64. package/examples/post_request_with_query_params/single/exampleAPI.ts +126 -0
  65. package/examples/post_request_with_query_params/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  66. package/examples/post_request_with_query_params/split/exampleAPI.schemas.ts +33 -0
  67. package/examples/post_request_with_query_params/split/exampleAPI.ts +105 -0
  68. package/examples/post_request_with_query_params/split/k6-script.sample.ts +14 -0
  69. package/examples/post_request_with_query_params/tags/default.ts +105 -0
  70. package/examples/post_request_with_query_params/tags/exampleAPI.schemas.ts +33 -0
  71. package/examples/post_request_with_query_params/tags/k6-script.sample.ts +14 -0
  72. package/examples/query_params_schema/single/exampleAPI.ts +120 -0
  73. package/examples/query_params_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  74. package/examples/query_params_schema/split/exampleAPI.schemas.ts +37 -0
  75. package/examples/query_params_schema/split/exampleAPI.ts +94 -0
  76. package/examples/query_params_schema/split/k6-script.sample.ts +11 -0
  77. package/examples/query_params_schema/tags/default.ts +94 -0
  78. package/examples/query_params_schema/tags/exampleAPI.schemas.ts +37 -0
  79. package/examples/query_params_schema/tags/k6-script.sample.ts +11 -0
  80. package/examples/simple_post_request_schema/{exampleAPI.ts → single/exampleAPI.ts} +49 -49
  81. package/examples/simple_post_request_schema/{k6-script.sample.ts → single/k6-script.sample.ts} +2 -2
  82. package/examples/simple_post_request_schema/split/exampleAPI.schemas.ts +47 -0
  83. package/examples/simple_post_request_schema/split/exampleAPI.ts +99 -0
  84. package/examples/simple_post_request_schema/split/k6-script.sample.ts +13 -0
  85. package/examples/simple_post_request_schema/tags/default.ts +99 -0
  86. package/examples/simple_post_request_schema/tags/exampleAPI.schemas.ts +47 -0
  87. package/examples/simple_post_request_schema/tags/k6-script.sample.ts +13 -0
  88. package/images/openapi-to-k6.png +0 -0
  89. package/package.json +2 -2
  90. package/src/cli.ts +28 -2
  91. package/src/constants.ts +7 -1
  92. package/src/{generator.ts → generator/index.ts} +8 -21
  93. package/src/{k6SdkClient.ts → generator/k6Client.ts} +174 -222
  94. package/src/type.d.ts +3 -4
  95. package/tests/e2e/schema.json +8 -0
  96. package/tests/e2e/{k6Script.ts → single/k6Script.ts} +7 -2
  97. package/tests/e2e/split/k6Script.ts +82 -0
  98. package/tests/e2e/tags/k6Script.ts +106 -0
  99. package/tests/functional-tests/fixtures/schemas/basic_schema.json +1 -4
  100. package/tests/functional-tests/fixtures/schemas/form_data_schema.json +4 -4
  101. package/tests/functional-tests/fixtures/schemas/form_url_encoded_data_schema.json +3 -3
  102. package/tests/functional-tests/fixtures/schemas/form_url_encoded_data_with_query_params_schema.json +2 -2
  103. package/tests/functional-tests/fixtures/schemas/get_request_with_path_parameters_schema.json +2 -2
  104. package/tests/functional-tests/fixtures/schemas/headers_schema.json +7 -8
  105. package/tests/functional-tests/fixtures/schemas/no_title_schema.json +2 -5
  106. package/tests/functional-tests/fixtures/schemas/post_request_with_query_params.json +3 -4
  107. package/tests/functional-tests/fixtures/schemas/query_params_schema.json +3 -3
  108. package/tests/functional-tests/fixtures/schemas/simple_post_request_schema.json +3 -5
  109. package/tests/functional-tests/generator.test.ts +46 -5
  110. package/examples/basic_schema/simpleAPI.ts +0 -87
  111. package/examples/form_data_schema/formDataAPI.ts +0 -115
  112. package/examples/form_url_encoded_data_schema/formURLEncodedAPI.ts +0 -114
  113. package/examples/form_url_encoded_data_with_query_params_schema/formURLEncodedAPIWithQueryParameters.ts +0 -130
  114. package/examples/get_request_with_path_parameters_schema/simpleAPI.ts +0 -94
  115. package/examples/headers_schema/headerDemoAPI.ts +0 -196
  116. package/examples/no_title_schema/K6Client.ts +0 -86
  117. package/examples/post_request_with_query_params/exampleAPI.ts +0 -124
  118. package/examples/query_params_schema/exampleAPI.ts +0 -118
  119. package/examples/update_examples.sh +0 -21
@@ -19,6 +19,8 @@ jobs:
19
19
  node-version: '21'
20
20
  registry-url: 'https://registry.npmjs.org'
21
21
  scope: '@grafana'
22
+ cache: 'npm'
23
+ cache-dependency-path: 'package-lock.json'
22
24
  - run: npm ci
23
25
  - name: Update version in package.json
24
26
  run: |
@@ -12,7 +12,9 @@ jobs:
12
12
  - uses: actions/checkout@v4
13
13
  - uses: actions/setup-node@v4
14
14
  with:
15
- node-version: '21.5.0'
15
+ node-version: '21'
16
+ cache: 'npm'
17
+ cache-dependency-path: 'package-lock.json'
16
18
  - run: npm ci
17
19
  - run: npm run lint
18
20
  - run: npm test
@@ -22,10 +24,15 @@ jobs:
22
24
  - uses: actions/checkout@v4
23
25
  - uses: actions/setup-node@v4
24
26
  with:
25
- node-version: '21.5.0'
27
+ node-version: '21'
28
+ cache: 'npm'
29
+ cache-dependency-path: 'package-lock.json'
26
30
  - run: npm ci
27
31
  - name: Generate SDK for E2E tests
28
- run: npm run dev -- ./tests/e2e/schema.json ./tests/e2e/sdk.ts --disable-analytics
32
+ run: |
33
+ npm run dev -- ./tests/e2e/schema.json ./tests/e2e/single/sdk.ts --disable-analytics --mode single
34
+ npm run dev -- ./tests/e2e/schema.json ./tests/e2e/split/sdk.ts --disable-analytics --mode split
35
+ npm run dev -- ./tests/e2e/schema.json ./tests/e2e/tags/sdk.ts --disable-analytics --mode tags
29
36
  - name: Start Mockoon CLI
30
37
  uses: mockoon/cli-action@v2
31
38
  with:
@@ -35,17 +42,18 @@ jobs:
35
42
  - uses: grafana/setup-k6-action@v1
36
43
  - uses: grafana/run-k6-action@v1
37
44
  with:
38
- path: './tests/e2e/k6Script.ts'
45
+ path: './tests/e2e/*/k6Script.ts'
39
46
  flags: '--compatibility-mode=experimental_enhanced'
40
47
  inspect-flags: '--compatibility-mode=experimental_enhanced'
41
48
  run-examples:
42
49
  runs-on: ubuntu-latest
43
- needs: [test, e2e-test]
44
50
  steps:
45
51
  - uses: actions/checkout@v4
46
52
  - uses: actions/setup-node@v4
47
53
  with:
48
- node-version: '21.5.0'
54
+ node-version: '21'
55
+ cache: 'npm'
56
+ cache-dependency-path: 'package-lock.json'
49
57
  - run: npm ci
50
58
  - name: Update examples
51
59
  run: npm run update-examples
package/README.md CHANGED
@@ -1,10 +1,15 @@
1
- # openapi-to-k6
2
-
3
- <p align="center">⚠️</p>
4
-
5
- ***This tool is currently in the experimental stage. Expect bugs, incomplete features, and breaking changes as development progresses. Use at your own risk, and please report any issues or feedback to help us improve.***
6
-
7
- ---
1
+ <div align="center">
2
+
3
+ <img
4
+ src="./images/openapi-to-k6.png"
5
+ width="600"
6
+ style="pointer-events: none;" />
7
+ <br />
8
+ <hr/>
9
+ <p align="center">⚠️</p>
10
+ <b>This tool is currently in the experimental stage. Expect bugs, incomplete features, and breaking changes as development progresses. Use at your own risk, and please report any issues or feedback to help us improve.</b>
11
+ <hr/>
12
+ </div>
8
13
 
9
14
  ## Overview
10
15
 
@@ -17,16 +22,46 @@ OpenAPI documentation.
17
22
 
18
23
  Along with the client, it also generates a sample k6 script as an example of how to use the client.
19
24
 
20
- To get started, install the tool with npm via `npm install openapi-to-k6` and run it to convert your
21
- OpenAPI specification to a TypeScript client for k6.
25
+ The generated client exports a class with methods for each endpoint in the OpenAPI specification. You can create
26
+ a instance of the class and use the methods to call the endpoints.
22
27
 
23
- To take a look at a few examples of how the generated client and sample script looks, check out the [examples](./examples) directory.
28
+ To take a look at a few examples of how the generated client looks and sample script looks, check out the [examples](./examples) directory.
24
29
 
25
- Note: Optional usage analytics are gathered to make the tool better. To disable this, use the option
26
- `--disable-analytics` or set an environment variable `DISABLE_ANALYTICS=true`.
27
30
 
28
31
  ## Getting started
29
32
 
33
+ 1. Install the tool globally via
34
+
35
+ ```shell
36
+ npm install -g @grafana/openapi-to-k6
37
+ ```
38
+
39
+ 2. To start using the tool either give path to your OpenAPI schema file or provide a URL to your Open
40
+ API schema and the output path where you want to generate the client files.
41
+
42
+ ```shell
43
+ openapi-to-k6 <path-to-openapi-schema | url-to-openapi-schema> <output path>
44
+ ```
45
+
46
+ This will the generate a TypeScript client and a sample k6 script in the corresponding directory.
47
+
48
+ ### Options
49
+
50
+ Following are some of the configuration options supported by the tool.
51
+
52
+ 1. `--mode` or ` -m`: Specify the mode to use for generating the client. Following are available options:
53
+ 1. `single`: This is the default mode used is nothing is specified. It generated the TypeScript client as a single file with all the types and implementation in a single file.
54
+ 2. `split`: This mode splits the types and implementation into separate files.
55
+ 3. `tags`: This modes splits your OpenAPI schema based on the tags and generates a separate client for each tag. If a route has no tag set, it will be available in `default.ts` file.
56
+
57
+ To check how the output looks for each mode, check out the [examples](./examples) directory.
58
+ 2. `--disable-analytics`: Disable anonymous usage analytics reporting which helping making the tool better. You can also set an environment variable `DISABLE_ANALYTICS=true` to disable the analytics.
59
+ 3. `--disable-sample-script`: Disable the generation of sample k6 script.
60
+ 4. `--verbose` or ` -v` : Enable verbose logging to see more detailed logging output.
61
+ 5. `--help` or ` -h` : Show help message.
62
+
63
+ ## Developing locally
64
+
30
65
  1. Clone the repository
31
66
 
32
67
  ```shell
@@ -69,7 +104,7 @@ cd tests/e2e/
69
104
  This will run the mock server in a docker container in background.
70
105
 
71
106
  ```shell
72
- docker run -d -v ./schema.json:/tmp/schema.json -p 3000:3000 mockoon/cli:latest -d /tmp/schema.json
107
+ docker run -v ./schema.json:/tmp/schema.json -p 3000:3000 mockoon/cli:latest -d /tmp/schema.json
73
108
  ```
74
109
 
75
110
  3. Assuming you have already followed previous steps and have the environment set up, you can generate the SDK by using
@@ -90,4 +125,4 @@ k6 run --compatibility-mode=experimental_enhanced ./K6Script.ts
90
125
  2. Install the compiled package locally by using `npm install .` or `npm install -g .`.
91
126
  3. Use the CLI `k6-sdkgen <path-to-openapi-schema> <output path>`
92
127
 
93
- Special thanks for the the open-source library [Orval](https://orval.dev/) to facilitate the generation of these SDK.
128
+ Special mention for the the open-source library [Orval](https://orval.dev/) which is used for the generation of the TypeScript client.
package/dist/cli.js CHANGED
@@ -16,13 +16,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  const chalk_1 = __importDefault(require("chalk"));
17
17
  const commander_1 = require("commander");
18
18
  const analytics_1 = require("./analytics");
19
+ const constants_1 = require("./constants");
19
20
  const generator_1 = __importDefault(require("./generator"));
20
21
  const helper_1 = require("./helper");
21
22
  const logger_1 = require("./logger");
22
23
  const program = new commander_1.Command();
23
24
  const packageDetails = (0, helper_1.getPackageDetails)();
25
+ /**
26
+ * Validate that the mode argument is one of the supported modes.
27
+ *
28
+ * @param {string} value - The mode value to validate
29
+ * @return {Mode} - The validated mode value
30
+ */
31
+ function validateMode(value) {
32
+ if (!Object.values(constants_1.Mode).includes(value)) {
33
+ throw new commander_1.InvalidArgumentError(`Supported modes: ${Object.values(constants_1.Mode).join(', ')}`);
34
+ }
35
+ return value;
36
+ }
24
37
  function generateSDK(_a) {
25
- return __awaiter(this, arguments, void 0, function* ({ openApiPath, outputDir, shouldGenerateSampleK6Script, analyticsData, }) {
38
+ return __awaiter(this, arguments, void 0, function* ({ openApiPath, outputDir, shouldGenerateSampleK6Script, analyticsData, mode, }) {
26
39
  logger_1.logger.logMessage('Generating TypeScript client for k6...\n');
27
40
  logger_1.logger.logMessage(`OpenAPI schema: ${openApiPath}`);
28
41
  logger_1.logger.logMessage(`Output: ${outputDir}\n`);
@@ -31,6 +44,7 @@ function generateSDK(_a) {
31
44
  outputDir,
32
45
  shouldGenerateSampleK6Script,
33
46
  analyticsData,
47
+ mode,
34
48
  });
35
49
  if (shouldGenerateSampleK6Script) {
36
50
  logger_1.logger.logMessage(`TypeScript client and sample k6 script generated successfully.`, chalk_1.default.green);
@@ -46,8 +60,9 @@ program
46
60
  .version(packageDetails.version)
47
61
  .argument('<openApiPath>', 'Path or URL for the OpenAPI schema file')
48
62
  .argument('<outputDir>', 'Directory where the SDK should be generated')
63
+ .option('-m, --mode <string>', `mode to use for generating the client. Valid values - ${Object.values(constants_1.Mode).join(', ')}`, validateMode, constants_1.Mode.SINGLE)
49
64
  .option('-v, --verbose', 'enable verbose mode to show debug logs')
50
- .option('--no-sample-script', 'disable generating sample k6 script')
65
+ .option('--disable-sample-script', 'disable generating sample k6 script')
51
66
  .option('--disable-analytics', 'disable anonymous usage data collection')
52
67
  .action((openApiPath, outputDir, options) => __awaiter(void 0, void 0, void 0, function* () {
53
68
  let analyticsData;
@@ -75,6 +90,7 @@ program
75
90
  outputDir,
76
91
  shouldGenerateSampleK6Script: !shouldDisableSampleScript,
77
92
  analyticsData,
93
+ mode: options.mode,
78
94
  });
79
95
  }
80
96
  catch (error) {
package/dist/constants.js CHANGED
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.K6_SCRIPT_TEMPLATE = exports.SAMPLE_K6_SCRIPT_FILE_NAME = exports.DEFAULT_SCHEMA_TITLE = void 0;
3
+ exports.Mode = exports.K6_SCRIPT_TEMPLATE = exports.SAMPLE_K6_SCRIPT_FILE_NAME = exports.DEFAULT_SCHEMA_TITLE = void 0;
4
4
  exports.DEFAULT_SCHEMA_TITLE = 'K6Client';
5
5
  exports.SAMPLE_K6_SCRIPT_FILE_NAME = 'k6-script.sample.ts';
6
6
  exports.K6_SCRIPT_TEMPLATE = `
7
7
  import { {{clientFunctionName}} } from '{{clientPath}}'
8
8
 
9
9
  const baseUrl = '<BASE_URL>';
10
- const client = {{clientFunctionName}}({ baseUrl })
10
+ const client = new {{clientFunctionName}}({ baseUrl })
11
11
 
12
12
  export default function () {
13
13
  {{#each clientFunctionsList}}
@@ -19,3 +19,9 @@ export default function () {
19
19
  {{/each}}
20
20
  }
21
21
  `;
22
+ var Mode;
23
+ (function (Mode) {
24
+ Mode["SINGLE"] = "single";
25
+ Mode["SPLIT"] = "split";
26
+ Mode["TAGS"] = "tags";
27
+ })(Mode || (exports.Mode = Mode = {}));
@@ -15,10 +15,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const fs_1 = __importDefault(require("fs"));
16
16
  const orval_1 = __importDefault(require("orval"));
17
17
  const path_1 = __importDefault(require("path"));
18
- const constants_1 = require("./constants");
19
- const helper_1 = require("./helper");
20
- const k6SdkClient_1 = require("./k6SdkClient");
21
- const logger_1 = require("./logger");
18
+ const constants_1 = require("../constants");
19
+ const helper_1 = require("../helper");
20
+ const logger_1 = require("../logger");
21
+ const k6Client_1 = require("./k6Client");
22
22
  const outputOverrider = helper_1.OutputOverrider.getInstance();
23
23
  const packageDetails = (0, helper_1.getPackageDetails)();
24
24
  const generatedFileHeaderGenerator = (info) => {
@@ -44,10 +44,7 @@ const afterAllFilesWriteHandler = (filePaths) => __awaiter(void 0, void 0, void
44
44
  }
45
45
  }
46
46
  });
47
- exports.default = (_a) => __awaiter(void 0, [_a], void 0, function* ({ openApiPath, outputDir, shouldGenerateSampleK6Script, analyticsData, }) {
48
- const schemaDetails = {
49
- title: '',
50
- };
47
+ exports.default = (_a) => __awaiter(void 0, [_a], void 0, function* ({ openApiPath, outputDir, shouldGenerateSampleK6Script, analyticsData, mode, }) {
51
48
  /**
52
49
  * Note!
53
50
  * 1. override.requestOptions is not supported for the custom K6 client
@@ -58,8 +55,8 @@ exports.default = (_a) => __awaiter(void 0, [_a], void 0, function* ({ openApiPa
58
55
  input: openApiPath,
59
56
  output: {
60
57
  target: outputDir,
61
- mode: 'single',
62
- client: () => (0, k6SdkClient_1.getK6ClientBuilder)(schemaDetails, shouldGenerateSampleK6Script, analyticsData),
58
+ mode: mode,
59
+ client: () => (0, k6Client_1.getK6ClientBuilder)(shouldGenerateSampleK6Script, analyticsData),
63
60
  override: {
64
61
  header: generatedFileHeaderGenerator,
65
62
  },
@@ -70,7 +67,4 @@ exports.default = (_a) => __awaiter(void 0, [_a], void 0, function* ({ openApiPa
70
67
  },
71
68
  });
72
69
  }));
73
- if (!schemaDetails.title) {
74
- logger_1.logger.warning('Could not find schema title in the OpenAPI spec. Please provide a `title` in the schema in `info` block to generate proper file names');
75
- }
76
70
  });
@@ -12,17 +12,119 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.generateFooter = exports.generateK6Header = exports.generateTitle = exports.getK6Dependencies = void 0;
16
15
  exports.getK6ClientBuilder = getK6ClientBuilder;
17
16
  const core_1 = require("@orval/core");
18
17
  const handlebars_1 = __importDefault(require("handlebars"));
19
18
  const path_1 = __importDefault(require("path"));
20
- const constants_1 = require("./constants");
21
- const helper_1 = require("./helper");
22
- const logger_1 = require("./logger");
23
- // A map to store the operationNames for which a return type is to be written at the end to export
24
- // and the return type definition
25
- const returnTypesToWrite = new Map();
19
+ const constants_1 = require("../constants");
20
+ const helper_1 = require("../helper");
21
+ const logger_1 = require("../logger");
22
+ /**
23
+ * In case the supplied schema does not have a title set, it will set the default title to ensure
24
+ * proper client generation
25
+ *
26
+ * @param context - The context object containing the schema details
27
+ */
28
+ function _setDefaultSchemaTitle(context) {
29
+ const schemaDetails = context.specs[context.specKey];
30
+ if (schemaDetails && !schemaDetails.info.title) {
31
+ schemaDetails.info.title = constants_1.DEFAULT_SCHEMA_TITLE;
32
+ }
33
+ }
34
+ function _generateResponseTypeDefinition(response) {
35
+ let responseDataType = '';
36
+ if (response.definition.success &&
37
+ !['any', 'unknown'].includes(response.definition.success)) {
38
+ responseDataType += response.definition.success;
39
+ }
40
+ else {
41
+ responseDataType += 'ResponseBody';
42
+ }
43
+ return `{
44
+ response: Response
45
+ data: ${responseDataType}
46
+ }`;
47
+ }
48
+ function _getRequestParametersMergerFunctionImplementation() {
49
+ return `/**
50
+ * Merges the provided request parameters with default parameters for the client.
51
+ *
52
+ * @param {Params} requestParameters - The parameters provided specifically for the request
53
+ * @param {Params} commonRequestParameters - Common parameters for all requests
54
+ * @returns {Params} - The merged parameters
55
+ */
56
+ private _mergeRequestParameters (requestParameters?: Params, commonRequestParameters?: Params): Params {
57
+ return {
58
+ ...commonRequestParameters, // Default to common parameters
59
+ ...requestParameters, // Override with request-specific parameters
60
+ headers: {
61
+ ...commonRequestParameters?.headers || {}, // Ensure headers are defined
62
+ ...requestParameters?.headers || {},
63
+ },
64
+ cookies: {
65
+ ...commonRequestParameters?.cookies || {}, // Ensure cookies are defined
66
+ ...requestParameters?.cookies || {},
67
+ },
68
+ tags: {
69
+ ...commonRequestParameters?.tags || {}, // Ensure tags are defined
70
+ ...requestParameters?.tags || {},
71
+ },
72
+ };
73
+ };`;
74
+ }
75
+ const _getRequestParamsValue = ({ response, queryParams, headers, body, }) => {
76
+ if (!queryParams && !headers && !response.isBlob && !body.contentType) {
77
+ // No parameters to merge, return the request parameters directly
78
+ return 'mergedRequestParameters';
79
+ }
80
+ let value = '\n ...mergedRequestParameters,';
81
+ if (response.isBlob) {
82
+ value += `\n responseType: 'binary',`;
83
+ }
84
+ // Expand the headers
85
+ if (body.contentType || headers) {
86
+ let headersValue = `\n headers: {`;
87
+ if (body.contentType) {
88
+ if (body.formData) {
89
+ headersValue += `\n'Content-Type': '${body.contentType}; boundary=' + formData.boundary,`;
90
+ }
91
+ else {
92
+ headersValue += `\n'Content-Type': '${body.contentType}',`;
93
+ }
94
+ }
95
+ if (headers) {
96
+ headersValue += `\n// In the schema, headers can be of any type like number but k6 accepts only strings as headers, hence converting all headers to string`;
97
+ headersValue += `\n...Object.fromEntries(Object.entries(headers || {}).map(([key, value]) => [key, String(value)])),`;
98
+ }
99
+ headersValue += `\n...mergedRequestParameters?.headers},`;
100
+ value += headersValue;
101
+ }
102
+ return `{${value}}`;
103
+ };
104
+ const _getK6RequestOptions = (verbOptions) => {
105
+ const { body, headers, queryParams, response, verb } = verbOptions;
106
+ let fetchBodyOption = 'undefined';
107
+ if (body.formData) {
108
+ // Use the FormData.body() method to get the body of the request
109
+ fetchBodyOption = 'formData.body()';
110
+ }
111
+ else if (body.formUrlEncoded || body.implementation) {
112
+ fetchBodyOption = `JSON.stringify(${body.implementation})`;
113
+ }
114
+ // Generate the params input for the call
115
+ const requestParametersValue = _getRequestParamsValue({
116
+ response,
117
+ body,
118
+ headers: headers === null || headers === void 0 ? void 0 : headers.schema,
119
+ queryParams: queryParams === null || queryParams === void 0 ? void 0 : queryParams.schema,
120
+ });
121
+ // Sample output
122
+ // 'GET', 'http://test.com/route', <body>, <options>
123
+ return `"${verb.toUpperCase()}",
124
+ url.toString(),
125
+ ${fetchBodyOption},
126
+ ${requestParametersValue}`;
127
+ };
26
128
  const getK6Dependencies = () => [
27
129
  {
28
130
  exports: [
@@ -67,32 +169,8 @@ const getK6Dependencies = () => [
67
169
  dependency: 'https://jslib.k6.io/formdata/0.0.2/index.js',
68
170
  },
69
171
  ];
70
- exports.getK6Dependencies = getK6Dependencies;
71
- function getSchemaTitleFromContext(context) {
72
- const specData = Object.values(context.specs);
73
- let schemaTitle;
74
- if (specData[0]) {
75
- schemaTitle = specData[0].info.title;
76
- }
77
- schemaTitle !== null && schemaTitle !== void 0 ? schemaTitle : (schemaTitle = constants_1.DEFAULT_SCHEMA_TITLE);
78
- return schemaTitle;
79
- }
80
- function _generateResponseTypeName(operationName) {
81
- return `${(0, core_1.pascal)(operationName)}Response`;
82
- }
83
- function _generateResponseTypeDefinition(operationName, response) {
84
- const typeName = _generateResponseTypeName(operationName);
85
- let responseDataType = '';
86
- if (response.definition.success) {
87
- responseDataType += response.definition.success + ' | ';
88
- }
89
- responseDataType += 'ResponseBody';
90
- return `export type ${typeName} = {
91
- response: Response
92
- data: ${responseDataType}
93
- };`;
94
- }
95
- const generateK6Implementation = ({ headers, queryParams, operationName, response, body, props, verb, override, formData, formUrlEncoded, paramsSerializer, }, { route }, analyticsData) => {
172
+ const generateK6Implementation = (verbOptions, { route }, analyticsData) => {
173
+ const { queryParams, operationName, response, body, props, verb, formData, formUrlEncoded, } = verbOptions;
96
174
  if (analyticsData) {
97
175
  analyticsData.generatedRequestsCount[verb] += 1;
98
176
  }
@@ -103,33 +181,21 @@ const generateK6Implementation = ({ headers, queryParams, operationName, respons
103
181
  isFormData: true,
104
182
  isFormUrlEncoded: false,
105
183
  });
106
- // Generate response return types
107
- returnTypesToWrite.set(operationName, _generateResponseTypeDefinition(operationName, response));
108
- let url = `cleanBaseUrl + \`${route}\``;
184
+ let url = `this.cleanBaseUrl + \`${route}\``;
109
185
  if (queryParams) {
110
186
  url += '+`?${new URLSearchParams(params).toString()}`';
111
187
  }
112
188
  const urlGeneration = `const url = new URL(${url});`;
113
- const options = getK6RequestOptions({
114
- route,
115
- body,
116
- headers,
117
- queryParams,
118
- response,
119
- verb,
120
- requestOptions: override === null || override === void 0 ? void 0 : override.requestOptions,
121
- paramsSerializer,
122
- paramsSerializerOptions: override === null || override === void 0 ? void 0 : override.paramsSerializerOptions,
123
- });
124
- return `const ${operationName} = (\n ${(0, core_1.toObjectString)(props, 'implementation')} requestParameters?: Params): ${_generateResponseTypeName(operationName)} => {${bodyForm}
189
+ const options = _getK6RequestOptions(verbOptions);
190
+ return `${operationName}(\n ${(0, core_1.toObjectString)(props, 'implementation')} requestParameters?: Params): ${_generateResponseTypeDefinition(response)} {\n${bodyForm}
125
191
  ${urlGeneration}
126
- const mergedRequestParameters = _mergeRequestParameters(requestParameters || {}, clientOptions.commonRequestParameters);
192
+ const mergedRequestParameters = this._mergeRequestParameters(requestParameters || {}, this.commonRequestParameters);
127
193
  const response = http.request(${options});
128
194
  let data;
129
195
 
130
196
  try {
131
197
  data = response.json();
132
- } catch (error) {
198
+ } catch {
133
199
  data = response.body;
134
200
  }
135
201
  return {
@@ -139,120 +205,41 @@ const generateK6Implementation = ({ headers, queryParams, operationName, respons
139
205
  }
140
206
  `;
141
207
  };
142
- const getParamsInputValue = ({ response, queryParams, headers, body, }) => {
143
- if (!queryParams && !headers && !response.isBlob && !body.contentType) {
144
- // No parameters to merge, return the request parameters directly
145
- return 'mergedRequestParameters';
146
- }
147
- let value = '\n ...mergedRequestParameters,';
148
- if (response.isBlob) {
149
- value += `\n responseType: 'binary',`;
150
- }
151
- // Expand the headers
152
- if (body.contentType || headers) {
153
- let headersValue = `\n headers: {`;
154
- if (body.contentType) {
155
- if (body.formData) {
156
- headersValue += `\n'Content-Type': '${body.contentType}; boundary=' + formData.boundary,`;
157
- }
158
- else {
159
- headersValue += `\n'Content-Type': '${body.contentType}',`;
160
- }
161
- }
162
- if (headers) {
163
- headersValue += `\n...headers,`;
164
- }
165
- headersValue += `\n...mergedRequestParameters?.headers},`;
166
- value += headersValue;
167
- }
168
- return `{${value}}`;
169
- };
170
- const getK6RequestOptions = (options) => {
171
- const { body, headers, queryParams, response, verb } = options;
172
- let fetchBodyOption = 'undefined';
173
- if (body.formData) {
174
- // Use the FormData.body() method to get the body of the request
175
- fetchBodyOption = 'formData.body()';
176
- }
177
- else if (body.formUrlEncoded || body.implementation) {
178
- fetchBodyOption = `JSON.stringify(${body.implementation})`;
179
- }
180
- // Generate the params input for the call
181
- const paramsValue = getParamsInputValue({
182
- response,
183
- body,
184
- headers: headers === null || headers === void 0 ? void 0 : headers.schema,
185
- queryParams: queryParams === null || queryParams === void 0 ? void 0 : queryParams.schema,
186
- });
187
- // Sample output
188
- // 'GET', 'http://test.com/route', <body>, <options>
189
- return `"${verb.toUpperCase()}",
190
- url.toString(),
191
- ${fetchBodyOption},
192
- ${paramsValue}`;
193
- };
194
- function _getRequestParametersMergerFunctionImplementation() {
195
- return `/**
196
- * Merges the provided request parameters with default parameters for the client.
197
- *
198
- * @param {Params} requestParameters - The parameters provided specifically for the request
199
- * @param {Params} commonRequestParameters - Common parameters for all requests
200
- * @returns {Params} - The merged parameters
201
- */
202
- const _mergeRequestParameters = (requestParameters?: Params, commonRequestParameters?: Params): Params => {
203
- return {
204
- ...commonRequestParameters, // Default to common parameters
205
- ...requestParameters, // Override with request-specific parameters
206
- headers: {
207
- ...commonRequestParameters?.headers || {}, // Ensure headers are defined
208
- ...requestParameters?.headers || {},
209
- },
210
- cookies: {
211
- ...commonRequestParameters?.cookies || {}, // Ensure cookies are defined
212
- ...requestParameters?.cookies || {},
213
- },
214
- tags: {
215
- ...commonRequestParameters?.tags || {}, // Ensure tags are defined
216
- ...requestParameters?.tags || {},
217
- },
218
- };
219
- };`;
220
- }
221
208
  const generateTitle = (title) => {
222
209
  const sanTitle = (0, core_1.sanitize)(title || constants_1.DEFAULT_SCHEMA_TITLE);
223
- return `create${(0, core_1.pascal)(sanTitle)}`;
210
+ return `${(0, core_1.pascal)(sanTitle)}Client`;
224
211
  };
225
- exports.generateTitle = generateTitle;
226
212
  const generateK6Header = ({ title }) => {
227
- const clientOptionsTypeName = `${(0, core_1.pascal)(title)}Options`;
228
213
  return `
229
- export type ${clientOptionsTypeName} = {
214
+ /**
215
+ * This is the base client to use for interacting with the API.
216
+ */
217
+ export class ${title} {
218
+ private cleanBaseUrl: string;
219
+ private commonRequestParameters: Params;
220
+
221
+ constructor (clientOptions: {
230
222
  baseUrl: string,
231
223
  commonRequestParameters?: Params
232
- }
233
-
234
- /**
235
- * This is the base client to use for interacting with the API.
236
- */
237
- export const ${title} = (clientOptions: ${clientOptionsTypeName}) => {\n
238
- const cleanBaseUrl = clientOptions.baseUrl.replace(/\\/+$/, '');\n`;
224
+ }) {
225
+ this.cleanBaseUrl = clientOptions.baseUrl.replace(/\\/+$/, '');\n
226
+ }\n
227
+ `;
239
228
  };
240
- exports.generateK6Header = generateK6Header;
241
- const generateFooter = ({ operationNames }) => {
242
- let footer = '';
243
- footer += `return {${operationNames.join(',')}}};\n\n`;
244
- operationNames.forEach((operationName) => {
245
- if (returnTypesToWrite.has(operationName)) {
246
- footer += returnTypesToWrite.get(operationName) + '\n';
247
- }
248
- });
229
+ const generateFooter = () => {
249
230
  // Add function definition for merging request parameters
250
- footer += `\n\n${_getRequestParametersMergerFunctionImplementation()}\n`;
231
+ const footer = `
232
+
233
+ ${_getRequestParametersMergerFunctionImplementation()}
234
+
235
+ }
236
+
237
+ `;
251
238
  return footer;
252
239
  };
253
- exports.generateFooter = generateFooter;
254
240
  const k6ScriptBuilder = (verbOptions, output, context) => __awaiter(void 0, void 0, void 0, function* () {
255
- const schemaTitle = getSchemaTitleFromContext(context);
241
+ var _a;
242
+ const schemaTitle = ((_a = context.specs[context.specKey]) === null || _a === void 0 ? void 0 : _a.info.title) || constants_1.DEFAULT_SCHEMA_TITLE;
256
243
  const { path: pathOfGeneratedClient, filename, extension, } = yield (0, helper_1.getGeneratedClientPath)(output.target, schemaTitle);
257
244
  const directoryPath = (0, helper_1.getDirectoryForPath)(pathOfGeneratedClient);
258
245
  const generateScriptPath = path_1.default.join(directoryPath, constants_1.SAMPLE_K6_SCRIPT_FILE_NAME);
@@ -275,7 +262,7 @@ const k6ScriptBuilder = (verbOptions, output, context) => __awaiter(void 0, void
275
262
  });
276
263
  }
277
264
  const scriptContentData = {
278
- clientFunctionName: (0, exports.generateTitle)(schemaTitle),
265
+ clientFunctionName: generateTitle(schemaTitle),
279
266
  clientPath: `./${filename}${extension}`,
280
267
  clientFunctionsList,
281
268
  };
@@ -287,11 +274,11 @@ const k6ScriptBuilder = (verbOptions, output, context) => __awaiter(void 0, void
287
274
  },
288
275
  ];
289
276
  });
290
- function getK6Client(schemaDetails, analyticsData) {
277
+ function getK6Client(analyticsData) {
291
278
  return function (verbOptions, options) {
279
+ _setDefaultSchemaTitle(options.context);
292
280
  const imports = (0, core_1.generateVerbImports)(verbOptions);
293
281
  const implementation = generateK6Implementation(verbOptions, options, analyticsData);
294
- schemaDetails.title = getSchemaTitleFromContext(options.context);
295
282
  const specData = Object.values(options.context.specs);
296
283
  if (specData[0]) {
297
284
  if (analyticsData) {
@@ -301,13 +288,13 @@ function getK6Client(schemaDetails, analyticsData) {
301
288
  return { implementation, imports };
302
289
  };
303
290
  }
304
- function getK6ClientBuilder(schemaDetails, shouldGenerateSampleK6Script, analyticsData) {
291
+ function getK6ClientBuilder(shouldGenerateSampleK6Script, analyticsData) {
305
292
  return {
306
- client: getK6Client(schemaDetails, analyticsData),
307
- header: exports.generateK6Header,
308
- dependencies: exports.getK6Dependencies,
309
- footer: exports.generateFooter,
310
- title: exports.generateTitle,
293
+ client: getK6Client(analyticsData),
294
+ header: generateK6Header,
295
+ dependencies: getK6Dependencies,
296
+ footer: generateFooter,
297
+ title: generateTitle,
311
298
  extraFiles: shouldGenerateSampleK6Script ? k6ScriptBuilder : undefined,
312
299
  };
313
300
  }