@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.
- package/.github/workflows/tests.yaml +1 -0
- package/README.md +10 -4
- package/dist/cli.js +27 -12
- package/dist/constants.js +7 -3
- package/dist/errors.js +10 -0
- package/dist/generator/index.js +50 -3
- package/dist/generator/k6Client.js +5 -55
- package/dist/generator/k6ScriptBuilder.js +256 -0
- package/dist/helper.js +32 -0
- package/examples/basic_schema/single/k6-script.sample.ts +3 -2
- package/examples/basic_schema/single/simpleAPI.ts +1 -1
- package/examples/basic_schema/split/k6-script.sample.ts +3 -2
- package/examples/basic_schema/split/simpleAPI.schemas.ts +1 -1
- package/examples/basic_schema/split/simpleAPI.ts +1 -1
- package/examples/basic_schema/tags/default.ts +1 -1
- package/examples/basic_schema/tags/k6-script.sample.ts +4 -3
- package/examples/basic_schema/tags/simpleAPI.schemas.ts +1 -1
- package/examples/form_data_schema/schema.json +6 -3
- package/examples/form_data_schema/single/formDataAPI.ts +1 -1
- package/examples/form_data_schema/single/k6-script.sample.ts +10 -2
- package/examples/form_data_schema/split/formDataAPI.schemas.ts +1 -1
- package/examples/form_data_schema/split/formDataAPI.ts +1 -1
- package/examples/form_data_schema/split/k6-script.sample.ts +10 -2
- package/examples/form_data_schema/tags/default.ts +1 -1
- package/examples/form_data_schema/tags/formDataAPI.schemas.ts +1 -1
- package/examples/form_data_schema/tags/k6-script.sample.ts +11 -3
- package/examples/form_url_encoded_data_schema/schema.json +6 -3
- package/examples/form_url_encoded_data_schema/single/formURLEncodedAPI.ts +1 -1
- package/examples/form_url_encoded_data_schema/single/k6-script.sample.ts +11 -2
- package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.schemas.ts +1 -1
- package/examples/form_url_encoded_data_schema/split/formURLEncodedAPI.ts +1 -1
- package/examples/form_url_encoded_data_schema/split/k6-script.sample.ts +11 -2
- package/examples/form_url_encoded_data_schema/tags/default.ts +1 -1
- package/examples/form_url_encoded_data_schema/tags/formURLEncodedAPI.schemas.ts +1 -1
- package/examples/form_url_encoded_data_schema/tags/k6-script.sample.ts +12 -3
- package/examples/form_url_encoded_data_with_query_params_schema/schema.json +8 -4
- package/examples/form_url_encoded_data_with_query_params_schema/single/formURLEncodedAPIWithQueryParameters.ts +1 -1
- package/examples/form_url_encoded_data_with_query_params_schema/single/k6-script.sample.ts +19 -6
- package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
- package/examples/form_url_encoded_data_with_query_params_schema/split/formURLEncodedAPIWithQueryParameters.ts +1 -1
- package/examples/form_url_encoded_data_with_query_params_schema/split/k6-script.sample.ts +19 -6
- package/examples/form_url_encoded_data_with_query_params_schema/tags/default.ts +1 -1
- package/examples/form_url_encoded_data_with_query_params_schema/tags/formURLEncodedAPIWithQueryParameters.schemas.ts +1 -1
- package/examples/form_url_encoded_data_with_query_params_schema/tags/k6-script.sample.ts +14 -3
- package/examples/get_request_with_path_parameters_schema/schema.json +2 -1
- package/examples/get_request_with_path_parameters_schema/single/k6-script.sample.ts +6 -2
- package/examples/get_request_with_path_parameters_schema/single/simpleAPI.ts +1 -1
- package/examples/get_request_with_path_parameters_schema/split/k6-script.sample.ts +6 -2
- package/examples/get_request_with_path_parameters_schema/split/simpleAPI.schemas.ts +1 -1
- package/examples/get_request_with_path_parameters_schema/split/simpleAPI.ts +1 -1
- package/examples/get_request_with_path_parameters_schema/tags/default.ts +1 -1
- package/examples/get_request_with_path_parameters_schema/tags/k6-script.sample.ts +7 -3
- package/examples/get_request_with_path_parameters_schema/tags/simpleAPI.schemas.ts +1 -1
- package/examples/headers_schema/schema.json +2 -1
- package/examples/headers_schema/single/headerDemoAPI.ts +1 -1
- package/examples/headers_schema/single/k6-script.sample.ts +15 -4
- package/examples/headers_schema/split/headerDemoAPI.schemas.ts +1 -1
- package/examples/headers_schema/split/headerDemoAPI.ts +1 -1
- package/examples/headers_schema/split/k6-script.sample.ts +15 -4
- package/examples/headers_schema/tags/default.ts +1 -1
- package/examples/headers_schema/tags/headerDemoAPI.schemas.ts +1 -1
- package/examples/headers_schema/tags/k6-script.sample.ts +16 -5
- package/examples/no_title_schema/single/k6-script.sample.ts +3 -2
- package/examples/no_title_schema/single/k6Client.ts +1 -1
- package/examples/no_title_schema/split/k6-script.sample.ts +3 -2
- package/examples/no_title_schema/split/k6Client.schemas.ts +1 -1
- package/examples/no_title_schema/split/k6Client.ts +1 -1
- package/examples/no_title_schema/tags/default.ts +1 -1
- package/examples/no_title_schema/tags/k6-script.sample.ts +4 -3
- package/examples/no_title_schema/tags/k6Client.schemas.ts +1 -1
- package/examples/post_request_with_query_params/schema.json +14 -7
- package/examples/post_request_with_query_params/single/exampleAPI.ts +1 -1
- package/examples/post_request_with_query_params/single/k6-script.sample.ts +11 -2
- package/examples/post_request_with_query_params/split/exampleAPI.schemas.ts +1 -1
- package/examples/post_request_with_query_params/split/exampleAPI.ts +1 -1
- package/examples/post_request_with_query_params/split/k6-script.sample.ts +11 -2
- package/examples/post_request_with_query_params/tags/default.ts +1 -1
- package/examples/post_request_with_query_params/tags/exampleAPI.schemas.ts +1 -1
- package/examples/post_request_with_query_params/tags/k6-script.sample.ts +12 -3
- package/examples/query_params_schema/schema.json +20 -10
- package/examples/query_params_schema/single/exampleAPI.ts +1 -1
- package/examples/query_params_schema/single/k6-script.sample.ts +8 -2
- package/examples/query_params_schema/split/exampleAPI.schemas.ts +1 -1
- package/examples/query_params_schema/split/exampleAPI.ts +1 -1
- package/examples/query_params_schema/split/k6-script.sample.ts +8 -2
- package/examples/query_params_schema/tags/default.ts +1 -1
- package/examples/query_params_schema/tags/exampleAPI.schemas.ts +1 -1
- package/examples/query_params_schema/tags/k6-script.sample.ts +9 -3
- package/examples/simple_post_request_schema/schema.json +30 -15
- package/examples/simple_post_request_schema/single/exampleAPI.ts +1 -1
- package/examples/simple_post_request_schema/single/k6-script.sample.ts +16 -2
- package/examples/simple_post_request_schema/split/exampleAPI.schemas.ts +1 -1
- package/examples/simple_post_request_schema/split/exampleAPI.ts +1 -1
- package/examples/simple_post_request_schema/split/k6-script.sample.ts +16 -2
- package/examples/simple_post_request_schema/tags/default.ts +1 -1
- package/examples/simple_post_request_schema/tags/exampleAPI.schemas.ts +1 -1
- package/examples/simple_post_request_schema/tags/k6-script.sample.ts +17 -3
- package/package.json +3 -1
- package/src/cli.ts +32 -14
- package/src/constants.ts +7 -3
- package/src/errors.ts +6 -0
- package/src/generator/index.ts +67 -2
- package/src/generator/k6Client.ts +3 -72
- package/src/generator/k6ScriptBuilder.ts +328 -0
- package/src/helper.ts +40 -0
- package/src/type.d.ts +1 -0
- package/tests/e2e/schema.json +136 -18
- package/tests/e2e/single-tag-filter/k6Script.ts +50 -0
- package/tests/e2e/tags/k6Script.ts +3 -3
- package/tests/functional-tests/helper.ts +16 -0
- package/tests/functional-tests/{generator.test.ts → test-generator/generator.test.ts} +12 -21
- package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_using_ref_models.json +394 -0
- package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_examples.json +416 -0
- package/tests/functional-tests/test-sample-k6-scripts/fixtures/schema_with_no_variables.json +32 -0
- package/tests/functional-tests/test-sample-k6-scripts/sampleK6Scripts.test.ts +248 -0
- package/tests/functional-tests/test-tags-filtering/fixtures/tags_filtering.json +141 -0
- package/tests/functional-tests/test-tags-filtering/tagsFiltering.test.ts +166 -0
- package/tests/helper.test.ts +59 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/basic_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_data_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/form_url_encoded_data_with_query_params_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/get_request_with_path_parameters_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/headers_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/no_title_schema.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/post_request_with_query_params.json +0 -0
- /package/tests/functional-tests/{fixtures/schemas → test-generator/fixtures}/query_params_schema.json +0 -0
- /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,13 +1,27 @@
|
|
|
1
1
|
import { ExampleAPIClient } from './exampleAPI.ts'
|
|
2
2
|
|
|
3
3
|
const baseUrl = '<BASE_URL>'
|
|
4
|
-
const
|
|
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
|
-
|
|
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,13 +1,27 @@
|
|
|
1
1
|
import { ExampleAPIClient } from './exampleAPI.ts'
|
|
2
2
|
|
|
3
3
|
const baseUrl = '<BASE_URL>'
|
|
4
|
-
const
|
|
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
|
-
|
|
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,13 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DefaultClient } from './default.ts'
|
|
2
2
|
|
|
3
3
|
const baseUrl = '<BASE_URL>'
|
|
4
|
-
const
|
|
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
|
-
|
|
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.
|
|
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(
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
5
|
+
{{{importStatements}}}
|
|
6
6
|
|
|
7
7
|
const baseUrl = '<BASE_URL>';
|
|
8
|
-
|
|
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
|
-
|
|
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
package/src/generator/index.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
|
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,
|