@grafana/openapi-to-k6 0.2.5 → 0.3.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 (128) hide show
  1. package/.github/workflows/tests.yaml +1 -0
  2. package/README.md +10 -4
  3. package/dist/cli.js +27 -12
  4. package/dist/constants.js +7 -3
  5. package/dist/errors.js +10 -0
  6. package/dist/generator/index.js +50 -3
  7. package/dist/generator/k6Client.js +5 -55
  8. package/dist/generator/k6ScriptBuilder.js +256 -0
  9. package/dist/helper.js +32 -0
  10. package/examples/basic_schema/single/k6-script.sample.ts +3 -2
  11. package/examples/basic_schema/single/simpleAPI.ts +1 -1
  12. package/examples/basic_schema/split/k6-script.sample.ts +3 -2
  13. package/examples/basic_schema/split/simpleAPI.schemas.ts +1 -1
  14. package/examples/basic_schema/split/simpleAPI.ts +1 -1
  15. package/examples/basic_schema/tags/default.ts +1 -1
  16. package/examples/basic_schema/tags/k6-script.sample.ts +4 -3
  17. package/examples/basic_schema/tags/simpleAPI.schemas.ts +1 -1
  18. package/examples/form_data_schema/schema.json +6 -3
  19. package/examples/form_data_schema/single/formDataAPI.ts +1 -1
  20. package/examples/form_data_schema/single/k6-script.sample.ts +10 -2
  21. package/examples/form_data_schema/split/formDataAPI.schemas.ts +1 -1
  22. package/examples/form_data_schema/split/formDataAPI.ts +1 -1
  23. package/examples/form_data_schema/split/k6-script.sample.ts +10 -2
  24. package/examples/form_data_schema/tags/default.ts +1 -1
  25. package/examples/form_data_schema/tags/formDataAPI.schemas.ts +1 -1
  26. package/examples/form_data_schema/tags/k6-script.sample.ts +11 -3
  27. package/examples/form_url_encoded_data_schema/schema.json +6 -3
  28. package/examples/form_url_encoded_data_schema/single/formURLEncodedAPI.ts +1 -1
  29. package/examples/form_url_encoded_data_schema/single/k6-script.sample.ts +11 -2
  30. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.schemas.ts +1 -1
  31. package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.ts +1 -1
  32. package/examples/form_url_encoded_data_schema/split/k6-script.sample.ts +11 -2
  33. package/examples/form_url_encoded_data_schema/tags/default.ts +1 -1
  34. package/examples/form_url_encoded_data_schema/tags/formURLEncodedAPI.schemas.ts +1 -1
  35. package/examples/form_url_encoded_data_schema/tags/k6-script.sample.ts +12 -3
  36. package/examples/form_url_encoded_data_with_query_params_schema/schema.json +8 -4
  37. package/examples/form_url_encoded_data_with_query_params_schema/single/formURLEncodedAPIWithQueryParameters.ts +1 -1
  38. package/examples/form_url_encoded_data_with_query_params_schema/single/k6-script.sample.ts +19 -6
  39. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
  40. package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.ts +1 -1
  41. package/examples/form_url_encoded_data_with_query_params_schema/split/k6-script.sample.ts +19 -6
  42. package/examples/form_url_encoded_data_with_query_params_schema/tags/default.ts +1 -1
  43. package/examples/form_url_encoded_data_with_query_params_schema/tags/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
  44. package/examples/form_url_encoded_data_with_query_params_schema/tags/k6-script.sample.ts +14 -3
  45. package/examples/get_request_with_path_parameters_schema/schema.json +2 -1
  46. package/examples/get_request_with_path_parameters_schema/single/k6-script.sample.ts +6 -2
  47. package/examples/get_request_with_path_parameters_schema/single/simpleAPI.ts +1 -1
  48. package/examples/get_request_with_path_parameters_schema/split/k6-script.sample.ts +6 -2
  49. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.schemas.ts +1 -1
  50. package/examples/get_request_with_path_parameters_schema/split/simpleAPI.ts +1 -1
  51. package/examples/get_request_with_path_parameters_schema/tags/default.ts +1 -1
  52. package/examples/get_request_with_path_parameters_schema/tags/k6-script.sample.ts +7 -3
  53. package/examples/get_request_with_path_parameters_schema/tags/simpleAPI.schemas.ts +1 -1
  54. package/examples/headers_schema/schema.json +2 -1
  55. package/examples/headers_schema/single/headerDemoAPI.ts +1 -1
  56. package/examples/headers_schema/single/k6-script.sample.ts +15 -4
  57. package/examples/headers_schema/split/headerDemoAPI.schemas.ts +1 -1
  58. package/examples/headers_schema/split/headerDemoAPI.ts +1 -1
  59. package/examples/headers_schema/split/k6-script.sample.ts +15 -4
  60. package/examples/headers_schema/tags/default.ts +1 -1
  61. package/examples/headers_schema/tags/headerDemoAPI.schemas.ts +1 -1
  62. package/examples/headers_schema/tags/k6-script.sample.ts +16 -5
  63. package/examples/no_title_schema/single/k6-script.sample.ts +3 -2
  64. package/examples/no_title_schema/single/k6Client.ts +1 -1
  65. package/examples/no_title_schema/split/k6-script.sample.ts +3 -2
  66. package/examples/no_title_schema/split/k6Client.schemas.ts +1 -1
  67. package/examples/no_title_schema/split/k6Client.ts +1 -1
  68. package/examples/no_title_schema/tags/default.ts +1 -1
  69. package/examples/no_title_schema/tags/k6-script.sample.ts +4 -3
  70. package/examples/no_title_schema/tags/k6Client.schemas.ts +1 -1
  71. package/examples/post_request_with_query_params/schema.json +14 -7
  72. package/examples/post_request_with_query_params/single/exampleAPI.ts +1 -1
  73. package/examples/post_request_with_query_params/single/k6-script.sample.ts +11 -2
  74. package/examples/post_request_with_query_params/split/exampleAPI.schemas.ts +1 -1
  75. package/examples/post_request_with_query_params/split/exampleAPI.ts +1 -1
  76. package/examples/post_request_with_query_params/split/k6-script.sample.ts +11 -2
  77. package/examples/post_request_with_query_params/tags/default.ts +1 -1
  78. package/examples/post_request_with_query_params/tags/exampleAPI.schemas.ts +1 -1
  79. package/examples/post_request_with_query_params/tags/k6-script.sample.ts +12 -3
  80. package/examples/query_params_schema/schema.json +20 -10
  81. package/examples/query_params_schema/single/exampleAPI.ts +1 -1
  82. package/examples/query_params_schema/single/k6-script.sample.ts +8 -2
  83. package/examples/query_params_schema/split/exampleAPI.schemas.ts +1 -1
  84. package/examples/query_params_schema/split/exampleAPI.ts +1 -1
  85. package/examples/query_params_schema/split/k6-script.sample.ts +8 -2
  86. package/examples/query_params_schema/tags/default.ts +1 -1
  87. package/examples/query_params_schema/tags/exampleAPI.schemas.ts +1 -1
  88. package/examples/query_params_schema/tags/k6-script.sample.ts +9 -3
  89. package/examples/simple_post_request_schema/schema.json +30 -15
  90. package/examples/simple_post_request_schema/single/exampleAPI.ts +1 -1
  91. package/examples/simple_post_request_schema/single/k6-script.sample.ts +16 -2
  92. package/examples/simple_post_request_schema/split/exampleAPI.schemas.ts +1 -1
  93. package/examples/simple_post_request_schema/split/exampleAPI.ts +1 -1
  94. package/examples/simple_post_request_schema/split/k6-script.sample.ts +16 -2
  95. package/examples/simple_post_request_schema/tags/default.ts +1 -1
  96. package/examples/simple_post_request_schema/tags/exampleAPI.schemas.ts +1 -1
  97. package/examples/simple_post_request_schema/tags/k6-script.sample.ts +17 -3
  98. package/package.json +3 -1
  99. package/src/cli.ts +32 -14
  100. package/src/constants.ts +7 -3
  101. package/src/errors.ts +6 -0
  102. package/src/generator/index.ts +67 -2
  103. package/src/generator/k6Client.ts +3 -72
  104. package/src/generator/k6ScriptBuilder.ts +328 -0
  105. package/src/helper.ts +40 -0
  106. package/src/type.d.ts +1 -0
  107. package/tests/e2e/schema.json +136 -18
  108. package/tests/e2e/single-tag-filter/k6Script.ts +50 -0
  109. package/tests/e2e/tags/k6Script.ts +3 -3
  110. package/tests/functional-tests/helper.ts +16 -0
  111. package/tests/functional-tests/{generator.test.ts → test-generator/generator.test.ts} +12 -21
  112. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_using_ref_models.json +394 -0
  113. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_examples.json +416 -0
  114. package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_no_variables.json +32 -0
  115. package/tests/functional-tests/test-sample-k6-scripts/sampleK6Scripts.test.ts +248 -0
  116. package/tests/functional-tests/test-tags-filtering/fixtures/tags_filtering.json +141 -0
  117. package/tests/functional-tests/test-tags-filtering/tagsFiltering.test.ts +166 -0
  118. package/tests/helper.test.ts +59 -0
  119. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/basic_schema.json +0 -0
  120. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_data_schema.json +0 -0
  121. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_schema.json +0 -0
  122. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_with_query_params_schema.json +0 -0
  123. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/get_request_with_path_parameters_schema.json +0 -0
  124. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/headers_schema.json +0 -0
  125. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/no_title_schema.json +0 -0
  126. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/post_request_with_query_params.json +0 -0
  127. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/query_params_schema.json +0 -0
  128. /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/simple_post_request_schema.json +0 -0
@@ -20,39 +20,46 @@
20
20
  "properties": {
21
21
  "name": {
22
22
  "type": "string",
23
- "description": "A string parameter"
23
+ "description": "A string parameter",
24
+ "example": "John Doe"
24
25
  },
25
26
  "age": {
26
27
  "type": "integer",
27
28
  "format": "int32",
28
- "description": "An integer parameter"
29
+ "description": "An integer parameter",
30
+ "example": 25
29
31
  },
30
32
  "isActive": {
31
33
  "type": "boolean",
32
- "description": "A boolean parameter"
34
+ "description": "A boolean parameter",
35
+ "example": true
33
36
  },
34
37
  "tags": {
35
38
  "type": "array",
36
39
  "items": {
37
40
  "type": "string"
38
41
  },
39
- "description": "An array of strings"
42
+ "description": "An array of strings",
43
+ "example": ["tag1", "tag2"]
40
44
  },
41
45
  "date": {
42
46
  "type": "string",
43
47
  "format": "date",
44
- "description": "A date parameter in YYYY-MM-DD format"
48
+ "description": "A date parameter in YYYY-MM-DD format",
49
+ "example": "2024-01-01"
45
50
  },
46
51
  "meta": {
47
52
  "type": "object",
48
53
  "properties": {
49
54
  "createdBy": {
50
55
  "type": "string",
51
- "description": "A string parameter for the creator's name"
56
+ "description": "A string parameter for the creator's name",
57
+ "example": "John Doe"
52
58
  },
53
59
  "updatedBy": {
54
60
  "type": "string",
55
- "description": "A string parameter for the updater's name"
61
+ "description": "A string parameter for the updater's name",
62
+ "example": "Jane Doe"
56
63
  }
57
64
  },
58
65
  "description": "An object parameter containing metadata"
@@ -77,36 +84,44 @@
77
84
  "properties": {
78
85
  "id": {
79
86
  "type": "string",
80
- "description": "The unique ID of the created resource"
87
+ "description": "The unique ID of the created resource",
88
+ "example": "12345"
81
89
  },
82
90
  "name": {
83
- "type": "string"
91
+ "type": "string",
92
+ "example": "John Doe"
84
93
  },
85
94
  "age": {
86
95
  "type": "integer",
87
- "format": "int32"
96
+ "format": "int32",
97
+ "example": 25
88
98
  },
89
99
  "isActive": {
90
- "type": "boolean"
100
+ "type": "boolean",
101
+ "example": true
91
102
  },
92
103
  "tags": {
93
104
  "type": "array",
94
105
  "items": {
95
- "type": "string"
106
+ "type": "string",
107
+ "example": ["tag1", "tag2"]
96
108
  }
97
109
  },
98
110
  "date": {
99
111
  "type": "string",
100
- "format": "date"
112
+ "format": "date",
113
+ "example": "2024-01-01"
101
114
  },
102
115
  "meta": {
103
116
  "type": "object",
104
117
  "properties": {
105
118
  "createdBy": {
106
- "type": "string"
119
+ "type": "string",
120
+ "example": "John Doe"
107
121
  },
108
122
  "updatedBy": {
109
- "type": "string"
123
+ "type": "string",
124
+ "example": "Jane Doe"
110
125
  }
111
126
  }
112
127
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Automatically generated by @grafana/openapi-to-k6: 0.2.5
2
+ * Automatically generated by @grafana/openapi-to-k6: 0.3.0
3
3
  * Do not edit manually.
4
4
  * Example API
5
5
  * API with all formats of data in the POST request body
@@ -1,13 +1,27 @@
1
1
  import { ExampleAPIClient } from './exampleAPI.ts'
2
2
 
3
3
  const baseUrl = '<BASE_URL>'
4
- const client = new ExampleAPIClient({ baseUrl })
4
+ const exampleAPIClient = new ExampleAPIClient({ baseUrl })
5
5
 
6
6
  export default function () {
7
+ let createExampleDataBody
8
+
7
9
  /**
8
10
  * Create example data
9
11
  */
10
- const createExampleDataResponseData = client.createExampleData(
12
+ createExampleDataBody = {
13
+ name: 'John Doe',
14
+ age: '25',
15
+ isActive: 'true',
16
+ tags: 'tag1,tag2',
17
+ date: '2024-01-01',
18
+ meta: {
19
+ createdBy: 'John Doe',
20
+ updatedBy: 'Jane Doe',
21
+ },
22
+ }
23
+
24
+ const createExampleDataResponseData = exampleAPIClient.createExampleData(
11
25
  createExampleDataBody
12
26
  )
13
27
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Automatically generated by @grafana/openapi-to-k6: 0.2.5
2
+ * Automatically generated by @grafana/openapi-to-k6: 0.3.0
3
3
  * Do not edit manually.
4
4
  * Example API
5
5
  * API with all formats of data in the POST request body
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Automatically generated by @grafana/openapi-to-k6: 0.2.5
2
+ * Automatically generated by @grafana/openapi-to-k6: 0.3.0
3
3
  * Do not edit manually.
4
4
  * Example API
5
5
  * API with all formats of data in the POST request body
@@ -1,13 +1,27 @@
1
1
  import { ExampleAPIClient } from './exampleAPI.ts'
2
2
 
3
3
  const baseUrl = '<BASE_URL>'
4
- const client = new ExampleAPIClient({ baseUrl })
4
+ const exampleAPIClient = new ExampleAPIClient({ baseUrl })
5
5
 
6
6
  export default function () {
7
+ let createExampleDataBody
8
+
7
9
  /**
8
10
  * Create example data
9
11
  */
10
- const createExampleDataResponseData = client.createExampleData(
12
+ createExampleDataBody = {
13
+ name: 'John Doe',
14
+ age: '25',
15
+ isActive: 'true',
16
+ tags: 'tag1,tag2',
17
+ date: '2024-01-01',
18
+ meta: {
19
+ createdBy: 'John Doe',
20
+ updatedBy: 'Jane Doe',
21
+ },
22
+ }
23
+
24
+ const createExampleDataResponseData = exampleAPIClient.createExampleData(
11
25
  createExampleDataBody
12
26
  )
13
27
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Automatically generated by @grafana/openapi-to-k6: 0.2.5
2
+ * Automatically generated by @grafana/openapi-to-k6: 0.3.0
3
3
  * Do not edit manually.
4
4
  * Example API
5
5
  * API with all formats of data in the POST request body
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Automatically generated by @grafana/openapi-to-k6: 0.2.5
2
+ * Automatically generated by @grafana/openapi-to-k6: 0.3.0
3
3
  * Do not edit manually.
4
4
  * Example API
5
5
  * API with all formats of data in the POST request body
@@ -1,13 +1,27 @@
1
- import { ExampleAPIClient } from './exampleAPI.ts'
1
+ import { DefaultClient } from './default.ts'
2
2
 
3
3
  const baseUrl = '<BASE_URL>'
4
- const client = new ExampleAPIClient({ baseUrl })
4
+ const defaultClient = new DefaultClient({ baseUrl })
5
5
 
6
6
  export default function () {
7
+ let createExampleDataBody
8
+
7
9
  /**
8
10
  * Create example data
9
11
  */
10
- const createExampleDataResponseData = client.createExampleData(
12
+ createExampleDataBody = {
13
+ name: 'John Doe',
14
+ age: '25',
15
+ isActive: 'true',
16
+ tags: 'tag1,tag2',
17
+ date: '2024-01-01',
18
+ meta: {
19
+ createdBy: 'John Doe',
20
+ updatedBy: 'Jane Doe',
21
+ },
22
+ }
23
+
24
+ const createExampleDataResponseData = defaultClient.createExampleData(
11
25
  createExampleDataBody
12
26
  )
13
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/openapi-to-k6",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "A CLI tool to generate helper modules for K6 from OpenAPI schema",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "scripts": {
10
10
  "build": "tsc",
11
11
  "dev": "DISABLE_ANALYTICS=true ts-node src/cli.ts",
12
+ "dev:inspect": "DISABLE_ANALYTICS=true node --inspect-brk --require ts-node/register src/cli.ts",
12
13
  "test": "vitest run --coverage",
13
14
  "lint": "eslint --ext .ts,.tsx .",
14
15
  "lint:fix": "eslint --ext .ts,.tsx . --fix",
@@ -20,6 +21,7 @@
20
21
  "repository": "http://github.com/grafana/openapi-to-k6",
21
22
  "license": "AGPL-3.0",
22
23
  "dependencies": {
24
+ "@faker-js/faker": "^9.2.0",
23
25
  "@types/k6": "^0.54.0",
24
26
  "axios": "^1.7.7",
25
27
  "chalk": "^4.1.2",
package/src/cli.ts CHANGED
@@ -4,6 +4,7 @@ import chalk from 'chalk'
4
4
  import { Command, InvalidArgumentError } from 'commander'
5
5
  import { generateDefaultAnalyticsData, reportUsageAnalytics } from './analytics'
6
6
  import { Mode } from './constants'
7
+ import { NoFilesGeneratedError } from './errors'
7
8
  import generateK6SDK from './generator'
8
9
  import { getPackageDetails } from './helper'
9
10
  import { logger } from './logger'
@@ -33,10 +34,21 @@ async function generateSDK({
33
34
  shouldGenerateSampleK6Script,
34
35
  analyticsData,
35
36
  mode,
37
+ tags,
36
38
  }: GenerateK6SDKOptions) {
37
- logger.logMessage('Generating TypeScript client for k6...\n')
38
- logger.logMessage(`OpenAPI schema: ${openApiPath}`)
39
- logger.logMessage(`Output: ${outputDir}\n`)
39
+ logger.logMessage(
40
+ 'Generating TypeScript client for k6...\n' +
41
+ 'OpenAPI schema: ' +
42
+ chalk.cyan(openApiPath) +
43
+ '\n' +
44
+ 'Output: ' +
45
+ chalk.cyan(outputDir) +
46
+ '\n' +
47
+ (tags?.length
48
+ ? 'Filtering by tag(s): ' + chalk.cyan(tags.join(', '))
49
+ : '') +
50
+ '\n'
51
+ )
40
52
 
41
53
  await generateK6SDK({
42
54
  openApiPath,
@@ -44,16 +56,13 @@ async function generateSDK({
44
56
  shouldGenerateSampleK6Script,
45
57
  analyticsData,
46
58
  mode,
59
+ tags,
47
60
  })
48
61
 
49
- if (shouldGenerateSampleK6Script) {
50
- logger.logMessage(
51
- `TypeScript client and sample k6 script generated successfully.`,
52
- chalk.green
53
- )
54
- } else {
55
- logger.logMessage(`TypeScript client generated successfully.`, chalk.green)
56
- }
62
+ const message = shouldGenerateSampleK6Script
63
+ ? 'TypeScript client and sample k6 script generated successfully.'
64
+ : 'TypeScript client generated successfully.'
65
+ logger.logMessage(message, chalk.green)
57
66
  }
58
67
 
59
68
  program
@@ -68,6 +77,10 @@ program
68
77
  validateMode,
69
78
  Mode.SINGLE
70
79
  )
80
+ .option(
81
+ '--only-tags <filters...>',
82
+ 'list of tags to filter on. Generated client will only include operations with these tags'
83
+ )
71
84
  .option('-v, --verbose', 'enable verbose mode to show debug logs')
72
85
  .option('--include-sample-script', 'generate a sample k6 script')
73
86
  .option('--disable-analytics', 'disable anonymous usage data collection')
@@ -78,6 +91,7 @@ program
78
91
  options: {
79
92
  verbose?: boolean
80
93
  mode: Mode
94
+ onlyTags?: (string | RegExp)[]
81
95
  disableAnalytics?: boolean
82
96
  includeSampleScript?: boolean
83
97
  }
@@ -112,16 +126,20 @@ program
112
126
  shouldGenerateSampleK6Script: !!options.includeSampleScript,
113
127
  analyticsData,
114
128
  mode: options.mode,
129
+ tags: options.onlyTags,
115
130
  })
116
131
  } catch (error) {
117
- logger.error('Failed to generate SDK:')
118
- console.error(error)
132
+ if (error instanceof NoFilesGeneratedError) {
133
+ logger.logMessage(error.message, chalk.yellow)
134
+ } else {
135
+ logger.error('Failed to generate SDK:')
136
+ console.error(error)
137
+ }
119
138
  }
120
139
 
121
140
  if (!shouldDisableAnalytics && analyticsData) {
122
141
  logger.debug('Reporting following usage analytics data:')
123
142
  logger.debug(JSON.stringify(analyticsData, null, 2))
124
-
125
143
  await reportUsageAnalytics(analyticsData)
126
144
  }
127
145
  }
package/src/constants.ts CHANGED
@@ -2,17 +2,21 @@ export const DEFAULT_SCHEMA_TITLE = 'K6Client'
2
2
 
3
3
  export const SAMPLE_K6_SCRIPT_FILE_NAME = 'k6-script.sample.ts'
4
4
  export const K6_SCRIPT_TEMPLATE = `
5
- import { {{clientFunctionName}} } from '{{clientPath}}'
5
+ {{{importStatements}}}
6
6
 
7
7
  const baseUrl = '<BASE_URL>';
8
- const client = new {{clientFunctionName}}({ baseUrl })
8
+ {{{clientInitializationStatement}}}
9
+
9
10
 
10
11
  export default function () {
12
+ {{{this.variableDefinition}}}
13
+
11
14
  {{#each clientFunctionsList}}
12
15
  /**
13
16
  * {{this.summary}}
14
17
  */
15
- const {{this.operationName}}ResponseData = client.{{this.operationName}}({{this.requiredParametersString}});
18
+ {{{this.exampleValues}}}
19
+ const {{this.operationName}}ResponseData = {{clientObjectName}}.{{this.operationName}}({{this.requiredParametersString}});
16
20
 
17
21
  {{/each}}
18
22
  }
package/src/errors.ts ADDED
@@ -0,0 +1,6 @@
1
+ export class NoFilesGeneratedError extends Error {
2
+ constructor(message: string = 'No files were generated') {
3
+ super(message)
4
+ this.name = 'NoFilesGeneratedError'
5
+ }
6
+ }
@@ -3,9 +3,11 @@ import { InfoObject } from 'openapi3-ts/oas30'
3
3
  import orval from 'orval'
4
4
  import path from 'path'
5
5
  import { DEFAULT_SCHEMA_TITLE } from '../constants'
6
+ import { NoFilesGeneratedError } from '../errors'
6
7
  import {
7
8
  formatFileWithPrettier,
8
9
  getPackageDetails,
10
+ hasOnlyComments,
9
11
  OutputOverrider,
10
12
  } from '../helper'
11
13
  import { logger } from '../logger'
@@ -26,7 +28,32 @@ const generatedFileHeaderGenerator = (info: InfoObject) => {
26
28
  }
27
29
 
28
30
  const afterAllFilesWriteHandler = async (filePaths: string[]) => {
31
+ const removeSingleFile = (filePath: string) => {
32
+ try {
33
+ fs.unlinkSync(filePath)
34
+ } catch (error) {
35
+ // This is non-critical, so we just log it
36
+ logger.debug(
37
+ `afterAllFilesWriteHandler ~ Error deleting file ${filePath}: ${error}`
38
+ )
39
+ }
40
+ }
41
+ const emptyFileList: string[] = []
42
+
29
43
  for (const filePath of filePaths) {
44
+ // There is a bug in the orval library which generates empty files when tags filter is applied
45
+ // and no matching endpoints are found and used mode is split or single.
46
+ // It generates the file with only the header comment.
47
+ // Hence, we manually remove those empty files.
48
+ // Issue link - https://github.com/orval-labs/orval/issues/1691
49
+
50
+ if (hasOnlyComments(fs.readFileSync(filePath, 'utf-8'))) {
51
+ emptyFileList.push(filePath)
52
+ // Delete the file
53
+ removeSingleFile(filePath)
54
+ continue
55
+ }
56
+
30
57
  await formatFileWithPrettier(filePath)
31
58
 
32
59
  const fileName = path.basename(filePath)
@@ -42,6 +69,28 @@ const afterAllFilesWriteHandler = async (filePaths: string[]) => {
42
69
  fs.renameSync(filePath, newPath)
43
70
  }
44
71
  }
72
+
73
+ if (emptyFileList.length > 0) {
74
+ logger.debug(
75
+ `afterAllFilesWriteHandler ~ The following files were empty and removed: ${emptyFileList.join(
76
+ ', '
77
+ )}`
78
+ )
79
+ }
80
+
81
+ // Return the list of generated file paths excluding the empty files
82
+ const filteredFilePaths = filePaths.filter(
83
+ (filePath) => !emptyFileList.includes(filePath)
84
+ )
85
+
86
+ // Check if all the filtered file path end with `.schemas.ts`
87
+ if (filteredFilePaths.every((filePath) => filePath.endsWith('.schemas.ts'))) {
88
+ // If yes we should remove them as only schemas files is not needed
89
+ filteredFilePaths.map(removeSingleFile)
90
+ return []
91
+ }
92
+
93
+ return filteredFilePaths
45
94
  }
46
95
 
47
96
  export default async ({
@@ -50,15 +99,20 @@ export default async ({
50
99
  shouldGenerateSampleK6Script,
51
100
  analyticsData,
52
101
  mode,
102
+ tags,
53
103
  }: GenerateK6SDKOptions) => {
54
104
  /**
55
105
  * Note!
56
106
  * 1. override.requestOptions is not supported for the custom K6 client
57
107
  * 2. override.mutator is not supported for the custom K6 client
58
108
  */
109
+ const generatedFilePaths: string[] = []
59
110
  await outputOverrider.redirectOutputToNullStream(async () => {
60
111
  await orval({
61
- input: openApiPath,
112
+ input: {
113
+ target: openApiPath,
114
+ filters: { tags: tags && tags.length > 0 ? tags : undefined },
115
+ },
62
116
  output: {
63
117
  target: outputDir,
64
118
  mode: mode,
@@ -70,8 +124,19 @@ export default async ({
70
124
  headers: true,
71
125
  },
72
126
  hooks: {
73
- afterAllFilesWrite: afterAllFilesWriteHandler,
127
+ afterAllFilesWrite: async (filePaths: string[]) => {
128
+ const filteredFilePaths = await afterAllFilesWriteHandler(filePaths)
129
+ generatedFilePaths.push(...filteredFilePaths)
130
+ },
74
131
  },
75
132
  })
76
133
  })
134
+
135
+ if (generatedFilePaths.length === 0) {
136
+ const tagsMessage =
137
+ tags?.length && tags.length > 0
138
+ ? ` Applied tag filter(s): ${tags.join(', ')}`
139
+ : ''
140
+ throw new NoFilesGeneratedError(`No files were generated.${tagsMessage}`)
141
+ }
77
142
  }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  ClientDependenciesBuilder,
3
- ClientExtraFilesBuilder,
4
3
  ClientFooterBuilder,
5
4
  ClientGeneratorsBuilder,
6
5
  ClientHeaderBuilder,
@@ -17,17 +16,9 @@ import {
17
16
  sanitize,
18
17
  toObjectString,
19
18
  } from '@orval/core'
20
- import Handlebars from 'handlebars'
21
- import path from 'path'
22
- import {
23
- DEFAULT_SCHEMA_TITLE,
24
- K6_SCRIPT_TEMPLATE,
25
- SAMPLE_K6_SCRIPT_FILE_NAME,
26
- } from '../constants'
27
- import { getDirectoryForPath, getGeneratedClientPath } from '../helper'
28
- import { logger } from '../logger'
19
+ import { DEFAULT_SCHEMA_TITLE } from '../constants'
29
20
  import { AnalyticsData } from '../type'
30
-
21
+ import { k6ScriptBuilder } from './k6ScriptBuilder'
31
22
  /**
32
23
  * In case the supplied schema does not have a title set, it will set the default title to ensure
33
24
  * proper client generation
@@ -260,7 +251,7 @@ const generateK6Implementation = (
260
251
  `
261
252
  }
262
253
 
263
- const generateTitle: ClientTitleBuilder = (title) => {
254
+ export const generateTitle: ClientTitleBuilder = (title) => {
264
255
  const sanTitle = sanitize(title || DEFAULT_SCHEMA_TITLE)
265
256
  return `${pascal(sanTitle)}Client`
266
257
  }
@@ -295,66 +286,6 @@ const generateFooter: ClientFooterBuilder = () => {
295
286
  return footer
296
287
  }
297
288
 
298
- const k6ScriptBuilder: ClientExtraFilesBuilder = async (
299
- verbOptions,
300
- output,
301
- context
302
- ) => {
303
- const schemaTitle =
304
- context.specs[context.specKey]?.info.title || DEFAULT_SCHEMA_TITLE
305
- const {
306
- path: pathOfGeneratedClient,
307
- filename,
308
- extension,
309
- } = await getGeneratedClientPath(output.target!, schemaTitle)
310
- const directoryPath = getDirectoryForPath(pathOfGeneratedClient)
311
- const generateScriptPath = path.join(
312
- directoryPath,
313
- SAMPLE_K6_SCRIPT_FILE_NAME
314
- )
315
-
316
- logger.debug(
317
- `k6ScriptBuilder ~ Generating sample K6 Script\n${JSON.stringify(
318
- {
319
- pathOfGeneratedClient,
320
- filename,
321
- extension,
322
- schemaTitle,
323
- directoryPath,
324
- generateScriptPath,
325
- },
326
- null,
327
- 2
328
- )}`
329
- )
330
-
331
- const clientFunctionsList = []
332
-
333
- for (const verbOption of Object.values(verbOptions)) {
334
- const { operationName, summary, props } = verbOption
335
- const requiredProps = props.filter((prop) => prop.required)
336
- clientFunctionsList.push({
337
- operationName,
338
- summary,
339
- requiredParametersString: toObjectString(requiredProps, 'name'),
340
- })
341
- }
342
-
343
- const scriptContentData = {
344
- clientFunctionName: generateTitle(schemaTitle),
345
- clientPath: `./${filename}${extension}`,
346
- clientFunctionsList,
347
- }
348
- const template = Handlebars.compile(K6_SCRIPT_TEMPLATE)
349
-
350
- return [
351
- {
352
- path: generateScriptPath,
353
- content: template(scriptContentData),
354
- },
355
- ]
356
- }
357
-
358
289
  function getK6Client(analyticsData?: AnalyticsData) {
359
290
  return function (
360
291
  verbOptions: GeneratorVerbOptions,