@scalar/postman-to-openapi 0.5.2 → 0.5.3
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/CHANGELOG.md +6 -0
- package/dist/convert.js +240 -212
- package/dist/helpers/auth.js +116 -92
- package/dist/helpers/contact.js +24 -20
- package/dist/helpers/external-docs.js +33 -25
- package/dist/helpers/form-data.js +42 -36
- package/dist/helpers/license.js +21 -17
- package/dist/helpers/logo.js +22 -21
- package/dist/helpers/markdown.js +33 -30
- package/dist/helpers/parameters.js +119 -96
- package/dist/helpers/path-items.js +244 -202
- package/dist/helpers/post-response-scripts.js +12 -12
- package/dist/helpers/pre-request-scripts.js +12 -12
- package/dist/helpers/prune-document.js +42 -35
- package/dist/helpers/request-body.js +102 -92
- package/dist/helpers/responses.js +62 -57
- package/dist/helpers/schemas.js +43 -37
- package/dist/helpers/servers.js +83 -57
- package/dist/helpers/status-codes.js +40 -30
- package/dist/helpers/urls.js +74 -51
- package/dist/index.js +1 -5
- package/dist/types.js +1 -1
- package/package.json +6 -11
- package/dist/convert.js.map +0 -7
- package/dist/helpers/auth.js.map +0 -7
- package/dist/helpers/contact.js.map +0 -7
- package/dist/helpers/external-docs.js.map +0 -7
- package/dist/helpers/form-data.js.map +0 -7
- package/dist/helpers/license.js.map +0 -7
- package/dist/helpers/logo.js.map +0 -7
- package/dist/helpers/markdown.js.map +0 -7
- package/dist/helpers/parameters.js.map +0 -7
- package/dist/helpers/path-items.js.map +0 -7
- package/dist/helpers/post-response-scripts.js.map +0 -7
- package/dist/helpers/pre-request-scripts.js.map +0 -7
- package/dist/helpers/prune-document.js.map +0 -7
- package/dist/helpers/request-body.js.map +0 -7
- package/dist/helpers/responses.js.map +0 -7
- package/dist/helpers/schemas.js.map +0 -7
- package/dist/helpers/servers.js.map +0 -7
- package/dist/helpers/status-codes.js.map +0 -7
- package/dist/helpers/urls.js.map +0 -7
- package/dist/index.js.map +0 -7
- package/dist/types.js.map +0 -7
|
@@ -1,102 +1,112 @@
|
|
|
1
|
-
import { processFormDataSchema } from
|
|
2
|
-
import { createParameterObject } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { processFormDataSchema } from './form-data.js';
|
|
2
|
+
import { createParameterObject } from './parameters.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts and converts the request body from a Postman request to an OpenAPI RequestBodyObject.
|
|
5
|
+
* Handles raw JSON, form-data, and URL-encoded body types, creating appropriate schemas and content types.
|
|
6
|
+
*/
|
|
7
|
+
export function extractRequestBody(body) {
|
|
8
|
+
const requestBody = {
|
|
9
|
+
content: {},
|
|
10
|
+
};
|
|
11
|
+
if (body.mode === 'raw') {
|
|
12
|
+
handleRawBody(body, requestBody);
|
|
13
|
+
return requestBody;
|
|
14
|
+
}
|
|
15
|
+
if (body.mode === 'formdata' && body.formdata) {
|
|
16
|
+
handleFormDataBody(body.formdata, requestBody);
|
|
17
|
+
return requestBody;
|
|
18
|
+
}
|
|
19
|
+
if (body.mode === 'urlencoded' && body.urlencoded) {
|
|
20
|
+
handleUrlEncodedBody(body.urlencoded, requestBody);
|
|
21
|
+
return requestBody;
|
|
22
|
+
}
|
|
17
23
|
return requestBody;
|
|
18
|
-
}
|
|
19
|
-
return requestBody;
|
|
20
24
|
}
|
|
21
25
|
function handleRawBody(body, requestBody) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
jsonBody
|
|
29
|
-
isJsonBody =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
const rawBody = body.raw || '';
|
|
27
|
+
const isJsonLanguage = body.options?.raw?.language === 'json';
|
|
28
|
+
// Check if body contains Postman variables (like {{bodyData}})
|
|
29
|
+
const hasVariables = /\{\{[\w-]+\}\}/.test(rawBody);
|
|
30
|
+
// Try parsing the raw body as JSON
|
|
31
|
+
// We use a boolean flag because `null` is a valid JSON value
|
|
32
|
+
let jsonBody;
|
|
33
|
+
let isJsonBody = false;
|
|
34
|
+
try {
|
|
35
|
+
jsonBody = JSON.parse(rawBody);
|
|
36
|
+
isJsonBody = true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Parsing failed - will handle below
|
|
40
|
+
}
|
|
41
|
+
// If we have valid JSON, use it
|
|
42
|
+
if (isJsonBody) {
|
|
43
|
+
requestBody.content = {
|
|
44
|
+
'application/json': {
|
|
45
|
+
schema: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
example: jsonBody,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// If we have variables and JSON language but could not parse JSON,
|
|
54
|
+
// create a JSON schema placeholder
|
|
55
|
+
if (hasVariables && isJsonLanguage) {
|
|
56
|
+
requestBody.content = {
|
|
57
|
+
'application/json': {
|
|
58
|
+
schema: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
description: 'Body data set via pre-request script',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Fallback to text/plain
|
|
44
67
|
requestBody.content = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
'text/plain': {
|
|
69
|
+
schema: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
examples: rawBody ? [rawBody] : undefined,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
51
74
|
};
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
requestBody.content = {
|
|
55
|
-
"text/plain": {
|
|
56
|
-
schema: {
|
|
57
|
-
type: "string",
|
|
58
|
-
examples: rawBody ? [rawBody] : void 0
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
75
|
}
|
|
63
76
|
function handleFormDataBody(formdata, requestBody) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
requestBody.content = {
|
|
78
|
+
'multipart/form-data': {
|
|
79
|
+
schema: processFormDataSchema(formdata),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
69
82
|
}
|
|
70
83
|
function handleUrlEncodedBody(urlencoded, requestBody) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
const schema = {
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {},
|
|
87
|
+
required: [],
|
|
88
|
+
};
|
|
89
|
+
urlencoded.forEach((item) => {
|
|
90
|
+
if (schema.properties) {
|
|
91
|
+
const paramObject = createParameterObject(item, 'query');
|
|
92
|
+
const property = {
|
|
93
|
+
type: 'string',
|
|
94
|
+
examples: [item.value],
|
|
95
|
+
description: paramObject.description,
|
|
96
|
+
};
|
|
97
|
+
// Add x-scalar-disabled extension if parameter is disabled
|
|
98
|
+
if (item.disabled === true) {
|
|
99
|
+
property['x-scalar-disabled'] = true;
|
|
100
|
+
}
|
|
101
|
+
schema.properties[item.key] = property;
|
|
102
|
+
if (paramObject.required) {
|
|
103
|
+
schema.required?.push(item.key);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
requestBody.content = {
|
|
108
|
+
'application/x-www-form-urlencoded': {
|
|
109
|
+
schema,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
98
112
|
}
|
|
99
|
-
export {
|
|
100
|
-
extractRequestBody
|
|
101
|
-
};
|
|
102
|
-
//# sourceMappingURL=request-body.js.map
|
|
@@ -1,64 +1,69 @@
|
|
|
1
|
-
import { inferSchemaFromExample } from
|
|
2
|
-
import { extractStatusCodesFromTests } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { inferSchemaFromExample } from './schemas.js';
|
|
2
|
+
import { extractStatusCodesFromTests } from './status-codes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts and converts Postman response objects to OpenAPI response objects.
|
|
5
|
+
* Processes response status codes, descriptions, headers, and body content,
|
|
6
|
+
* inferring schemas from example responses when possible.
|
|
7
|
+
*/
|
|
8
|
+
export function extractResponses(responses, item) {
|
|
9
|
+
// Extract status codes from tests
|
|
10
|
+
const statusCodes = item ? extractStatusCodesFromTests(item) : [];
|
|
11
|
+
// Create a map of status codes to descriptions from responses
|
|
12
|
+
const responseMap = responses.reduce((acc, response) => {
|
|
13
|
+
const statusCode = response.code?.toString() || 'default';
|
|
14
|
+
acc[statusCode] = {
|
|
15
|
+
description: response.status || 'Successful response',
|
|
16
|
+
headers: extractHeaders(response.header),
|
|
17
|
+
content: {
|
|
18
|
+
'application/json': {
|
|
19
|
+
schema: inferSchemaFromExample(response.body || ''),
|
|
20
|
+
examples: {
|
|
21
|
+
default: tryParseJson(response.body || ''),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
// Add status codes from tests if not already present
|
|
29
|
+
statusCodes.forEach((code) => {
|
|
30
|
+
const codeStr = code.toString();
|
|
31
|
+
if (!responseMap[codeStr]) {
|
|
32
|
+
responseMap[codeStr] = {
|
|
33
|
+
description: 'Successful response',
|
|
34
|
+
content: {
|
|
35
|
+
'application/json': {},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
16
38
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}, {});
|
|
21
|
-
statusCodes.forEach((code) => {
|
|
22
|
-
const codeStr = code.toString();
|
|
23
|
-
if (!responseMap[codeStr]) {
|
|
24
|
-
responseMap[codeStr] = {
|
|
25
|
-
description: "Successful response",
|
|
26
|
-
content: {
|
|
27
|
-
"application/json": {}
|
|
28
|
-
}
|
|
29
|
-
};
|
|
39
|
+
});
|
|
40
|
+
if (Object.keys(responseMap).length === 0) {
|
|
41
|
+
return undefined;
|
|
30
42
|
}
|
|
31
|
-
|
|
32
|
-
if (Object.keys(responseMap).length === 0) {
|
|
33
|
-
return void 0;
|
|
34
|
-
}
|
|
35
|
-
return responseMap;
|
|
43
|
+
return responseMap;
|
|
36
44
|
}
|
|
37
45
|
function extractHeaders(headers) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
if (!headers || typeof headers === 'string') {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const openapiHeaders = {};
|
|
50
|
+
if (Array.isArray(headers)) {
|
|
51
|
+
headers.forEach((header) => {
|
|
52
|
+
openapiHeaders[header.key] = {
|
|
53
|
+
schema: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
examples: [header.value],
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return openapiHeaders;
|
|
53
61
|
}
|
|
54
62
|
function tryParseJson(jsonString) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(jsonString);
|
|
65
|
+
}
|
|
66
|
+
catch (_e) {
|
|
67
|
+
return { rawContent: jsonString };
|
|
68
|
+
}
|
|
60
69
|
}
|
|
61
|
-
export {
|
|
62
|
-
extractResponses
|
|
63
|
-
};
|
|
64
|
-
//# sourceMappingURL=responses.js.map
|
package/dist/helpers/schemas.js
CHANGED
|
@@ -1,44 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Infers the schema of an OpenAPI object based on an example value.
|
|
3
|
+
* This function recursively analyzes the structure of the example value
|
|
4
|
+
* and returns a corresponding OpenAPI schema object.
|
|
5
|
+
*/
|
|
6
|
+
export function inferSchemaFromExample(example) {
|
|
7
|
+
if (Array.isArray(example)) {
|
|
8
|
+
return {
|
|
9
|
+
type: 'array',
|
|
10
|
+
items: example.length > 0 ? inferSchemaFromExample(example[0]) : {},
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (typeof example === 'object' && example !== null) {
|
|
14
|
+
const properties = {};
|
|
15
|
+
for (const [key, value] of Object.entries(example)) {
|
|
16
|
+
properties[key] = inferSchemaFromExample(value);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties,
|
|
21
|
+
};
|
|
12
22
|
}
|
|
13
23
|
return {
|
|
14
|
-
|
|
15
|
-
properties
|
|
24
|
+
type: typeof example,
|
|
16
25
|
};
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
type: typeof example
|
|
20
|
-
};
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Infers the schema type of a value based on its type.
|
|
29
|
+
* This function determines the OpenAPI schema type of a value
|
|
30
|
+
* by checking its JavaScript type and attempting to parse it
|
|
31
|
+
* as a number or boolean if it's a string.
|
|
32
|
+
*/
|
|
33
|
+
export function inferSchemaType(value) {
|
|
34
|
+
if (typeof value === 'number') {
|
|
35
|
+
return { type: Number.isInteger(value) ? 'integer' : 'number' };
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === 'boolean') {
|
|
38
|
+
return { type: 'boolean' };
|
|
33
39
|
}
|
|
34
|
-
if (
|
|
35
|
-
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
const num = Number(value);
|
|
42
|
+
if (!isNaN(num)) {
|
|
43
|
+
return { type: Number.isInteger(num) ? 'integer' : 'number' };
|
|
44
|
+
}
|
|
45
|
+
if (value.toLowerCase() === 'true' || value.toLowerCase() === 'false') {
|
|
46
|
+
return { type: 'boolean' };
|
|
47
|
+
}
|
|
36
48
|
}
|
|
37
|
-
|
|
38
|
-
return { type: "string" };
|
|
49
|
+
return { type: 'string' };
|
|
39
50
|
}
|
|
40
|
-
export {
|
|
41
|
-
inferSchemaFromExample,
|
|
42
|
-
inferSchemaType
|
|
43
|
-
};
|
|
44
|
-
//# sourceMappingURL=schemas.js.map
|
package/dist/helpers/servers.js
CHANGED
|
@@ -1,64 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a unique key for a path/method combination.
|
|
3
|
+
* Used to properly deduplicate operations in a Set since JavaScript Sets
|
|
4
|
+
* compare objects by reference, not by value.
|
|
5
|
+
*/
|
|
1
6
|
function createOperationKey(path, method) {
|
|
2
|
-
|
|
7
|
+
return `${path}::${method}`;
|
|
3
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Parses an operation key back into its path and method components.
|
|
11
|
+
*/
|
|
4
12
|
function parseOperationKey(key) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
13
|
+
const separatorIndex = key.lastIndexOf('::');
|
|
14
|
+
return {
|
|
15
|
+
path: key.substring(0, separatorIndex),
|
|
16
|
+
method: key.substring(separatorIndex + 2),
|
|
17
|
+
};
|
|
10
18
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Analyzes server usage and determines the optimal placement level for each server.
|
|
21
|
+
* Placement logic:
|
|
22
|
+
* - If server used in all paths → document level
|
|
23
|
+
* - If server used in multiple paths → document level
|
|
24
|
+
* - If server used in multiple operations within 1 path → path item level
|
|
25
|
+
* - If server used in only 1 operation → operation level
|
|
26
|
+
*/
|
|
27
|
+
export function analyzeServerDistribution(serverUsage, allUniquePaths) {
|
|
28
|
+
const placement = {
|
|
29
|
+
document: [],
|
|
30
|
+
pathItems: new Map(),
|
|
31
|
+
operations: new Map(),
|
|
32
|
+
};
|
|
33
|
+
if (serverUsage.length === 0) {
|
|
34
|
+
return placement;
|
|
35
|
+
}
|
|
36
|
+
// Build a map: serverUrl -> Set<operationKey>
|
|
37
|
+
// Using string keys instead of objects because JavaScript Sets compare by reference
|
|
38
|
+
const serverMap = new Map();
|
|
39
|
+
for (const usage of serverUsage) {
|
|
40
|
+
if (!serverMap.has(usage.serverUrl)) {
|
|
41
|
+
serverMap.set(usage.serverUrl, new Set());
|
|
42
|
+
}
|
|
43
|
+
serverMap.get(usage.serverUrl).add(createOperationKey(usage.path, usage.method));
|
|
24
44
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
// For each server, determine its placement
|
|
46
|
+
for (const [serverUrl, operationKeys] of serverMap.entries()) {
|
|
47
|
+
const serverObject = { url: serverUrl };
|
|
48
|
+
// Parse operation keys back to path/method pairs
|
|
49
|
+
const operations = Array.from(operationKeys).map(parseOperationKey);
|
|
50
|
+
// Count unique paths this server appears in
|
|
51
|
+
const uniquePaths = new Set(operations.map((op) => op.path));
|
|
52
|
+
const pathCount = uniquePaths.size;
|
|
53
|
+
// Check if server covers all paths in the document
|
|
54
|
+
const coversAllPaths = allUniquePaths.size > 0 &&
|
|
55
|
+
uniquePaths.size === allUniquePaths.size &&
|
|
56
|
+
Array.from(uniquePaths).every((path) => allUniquePaths.has(path));
|
|
57
|
+
if (coversAllPaths || pathCount > 1) {
|
|
58
|
+
// Server used in all paths or multiple paths → document level
|
|
59
|
+
placement.document.push(serverObject);
|
|
60
|
+
}
|
|
61
|
+
else if (operations.length > 1) {
|
|
62
|
+
// Server used in multiple operations within 1 path → path item level
|
|
63
|
+
const path = operations[0]?.path;
|
|
64
|
+
if (!path) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!placement.pathItems.has(path)) {
|
|
68
|
+
placement.pathItems.set(path, []);
|
|
69
|
+
}
|
|
70
|
+
placement.pathItems.get(path).push(serverObject);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Server used in only 1 operation → operation level
|
|
74
|
+
const operation = operations[0];
|
|
75
|
+
if (!operation) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
// Use nested Map structure: path -> method -> servers
|
|
79
|
+
if (!placement.operations.has(operation.path)) {
|
|
80
|
+
placement.operations.set(operation.path, new Map());
|
|
81
|
+
}
|
|
82
|
+
const methodsMap = placement.operations.get(operation.path);
|
|
83
|
+
if (!methodsMap.has(operation.method)) {
|
|
84
|
+
methodsMap.set(operation.method, []);
|
|
85
|
+
}
|
|
86
|
+
methodsMap.get(operation.method).push(serverObject);
|
|
87
|
+
}
|
|
57
88
|
}
|
|
58
|
-
|
|
59
|
-
return placement;
|
|
89
|
+
return placement;
|
|
60
90
|
}
|
|
61
|
-
export {
|
|
62
|
-
analyzeServerDistribution
|
|
63
|
-
};
|
|
64
|
-
//# sourceMappingURL=servers.js.map
|
|
@@ -1,35 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Extracts expected status codes from the test scripts of a Postman item.
|
|
3
|
+
* Looks for patterns like:
|
|
4
|
+
* - pm.response.to.have.status(201)
|
|
5
|
+
* - pm.expect(pm.response.code).to.eql(202)
|
|
6
|
+
* - pm.expect(pm.response.status).to.equal(201)
|
|
7
|
+
*/
|
|
8
|
+
export function extractStatusCodesFromTests(item) {
|
|
9
|
+
const statusCodes = [];
|
|
10
|
+
if (item.event?.length) {
|
|
11
|
+
item.event.forEach((event) => {
|
|
12
|
+
if (event.listen === 'test' && event.script?.exec) {
|
|
13
|
+
const scriptLines = Array.isArray(event.script.exec) ? event.script.exec : [event.script.exec];
|
|
14
|
+
scriptLines.forEach((line) => {
|
|
15
|
+
const statusCode = parseStatusCodeFromLine(line);
|
|
16
|
+
if (statusCode) {
|
|
17
|
+
statusCodes.push(statusCode);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
12
21
|
});
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
return statusCodes;
|
|
22
|
+
}
|
|
23
|
+
return statusCodes;
|
|
17
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Parses a line of script to extract a status code.
|
|
27
|
+
* Supports patterns like:
|
|
28
|
+
* - pm.response.to.have.status(201)
|
|
29
|
+
* - pm.expect(pm.response.code).to.eql(202)
|
|
30
|
+
* - pm.expect(pm.response.status).to.equal(201)
|
|
31
|
+
*/
|
|
18
32
|
function parseStatusCodeFromLine(line) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
const patterns = [
|
|
34
|
+
/pm\.response\.to\.have\.status\((\d{3})\)/,
|
|
35
|
+
/pm\.expect\(pm\.response\.code\)\.to\.(?:eql|equal)\((\d{3})\)/,
|
|
36
|
+
/pm\.expect\(pm\.response\.status\)\.to\.(?:eql|equal)\(['"](\d{3})['"]\)/,
|
|
37
|
+
];
|
|
38
|
+
for (const pattern of patterns) {
|
|
39
|
+
const match = pattern.exec(line)?.at(1);
|
|
40
|
+
if (match) {
|
|
41
|
+
return Number.parseInt(match, 10);
|
|
42
|
+
}
|
|
28
43
|
}
|
|
29
|
-
|
|
30
|
-
return null;
|
|
44
|
+
return null;
|
|
31
45
|
}
|
|
32
|
-
export {
|
|
33
|
-
extractStatusCodesFromTests
|
|
34
|
-
};
|
|
35
|
-
//# sourceMappingURL=status-codes.js.map
|