@scalar/postman-to-openapi 0.3.58 → 0.4.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 (131) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/convert.d.ts.map +1 -1
  3. package/dist/convert.js +224 -159
  4. package/dist/convert.js.map +2 -2
  5. package/dist/helpers/{authHelpers.d.ts → auth.d.ts} +1 -1
  6. package/dist/helpers/auth.d.ts.map +1 -0
  7. package/dist/helpers/auth.js +113 -0
  8. package/dist/helpers/auth.js.map +7 -0
  9. package/dist/helpers/contact.d.ts +8 -0
  10. package/dist/helpers/contact.d.ts.map +1 -0
  11. package/dist/helpers/contact.js +25 -0
  12. package/dist/helpers/contact.js.map +7 -0
  13. package/dist/helpers/{externalDocsHelper.d.ts → external-docs.d.ts} +1 -1
  14. package/dist/helpers/external-docs.d.ts.map +1 -0
  15. package/dist/helpers/external-docs.js +32 -0
  16. package/dist/helpers/external-docs.js.map +7 -0
  17. package/dist/helpers/{formDataHelpers.d.ts → form-data.d.ts} +1 -1
  18. package/dist/helpers/form-data.d.ts.map +1 -0
  19. package/dist/helpers/form-data.js +39 -0
  20. package/dist/helpers/form-data.js.map +7 -0
  21. package/dist/helpers/license.d.ts +8 -0
  22. package/dist/helpers/license.d.ts.map +1 -0
  23. package/dist/helpers/license.js +22 -0
  24. package/dist/helpers/license.js.map +7 -0
  25. package/dist/helpers/{logoHelper.d.ts → logo.d.ts} +1 -1
  26. package/dist/helpers/logo.d.ts.map +1 -0
  27. package/dist/helpers/logo.js +23 -0
  28. package/dist/helpers/logo.js.map +7 -0
  29. package/dist/helpers/{md-utils.d.ts → markdown.d.ts} +1 -1
  30. package/dist/helpers/markdown.d.ts.map +1 -0
  31. package/dist/helpers/markdown.js +32 -0
  32. package/dist/helpers/markdown.js.map +7 -0
  33. package/dist/helpers/{parameterHelpers.d.ts → parameters.d.ts} +1 -1
  34. package/dist/helpers/parameters.d.ts.map +1 -0
  35. package/dist/helpers/parameters.js +103 -0
  36. package/dist/helpers/parameters.js.map +7 -0
  37. package/dist/helpers/{itemHelpers.d.ts → path-items.d.ts} +12 -1
  38. package/dist/helpers/path-items.d.ts.map +1 -0
  39. package/dist/helpers/path-items.js +204 -0
  40. package/dist/helpers/path-items.js.map +7 -0
  41. package/dist/helpers/post-response-scripts.d.ts +7 -0
  42. package/dist/helpers/post-response-scripts.d.ts.map +1 -0
  43. package/dist/helpers/post-response-scripts.js +13 -0
  44. package/dist/helpers/post-response-scripts.js.map +7 -0
  45. package/dist/helpers/pre-request-scripts.d.ts +7 -0
  46. package/dist/helpers/pre-request-scripts.d.ts.map +1 -0
  47. package/dist/helpers/pre-request-scripts.js +13 -0
  48. package/dist/helpers/pre-request-scripts.js.map +7 -0
  49. package/dist/helpers/prune-document.d.ts +8 -0
  50. package/dist/helpers/prune-document.d.ts.map +1 -0
  51. package/dist/helpers/prune-document.js +39 -0
  52. package/dist/helpers/prune-document.js.map +7 -0
  53. package/dist/helpers/{requestBodyHelpers.d.ts → request-body.d.ts} +1 -1
  54. package/dist/helpers/request-body.d.ts.map +1 -0
  55. package/dist/helpers/request-body.js +102 -0
  56. package/dist/helpers/request-body.js.map +7 -0
  57. package/dist/helpers/{responseHelpers.d.ts → responses.d.ts} +1 -1
  58. package/dist/helpers/responses.d.ts.map +1 -0
  59. package/dist/helpers/responses.js +64 -0
  60. package/dist/helpers/responses.js.map +7 -0
  61. package/dist/helpers/{schemaHelpers.d.ts → schemas.d.ts} +1 -1
  62. package/dist/helpers/schemas.d.ts.map +1 -0
  63. package/dist/helpers/schemas.js +44 -0
  64. package/dist/helpers/{schemaHelpers.js.map → schemas.js.map} +1 -1
  65. package/dist/helpers/servers.d.ts +21 -0
  66. package/dist/helpers/servers.d.ts.map +1 -0
  67. package/dist/helpers/servers.js +64 -0
  68. package/dist/helpers/servers.js.map +7 -0
  69. package/dist/helpers/{statusCodeHelpers.d.ts → status-codes.d.ts} +1 -1
  70. package/dist/helpers/status-codes.d.ts.map +1 -0
  71. package/dist/helpers/status-codes.js +35 -0
  72. package/dist/helpers/status-codes.js.map +7 -0
  73. package/dist/helpers/{urlHelpers.d.ts → urls.d.ts} +7 -1
  74. package/dist/helpers/urls.d.ts.map +1 -0
  75. package/dist/helpers/urls.js +58 -0
  76. package/dist/helpers/urls.js.map +7 -0
  77. package/dist/index.d.ts +1 -2
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +5 -2
  80. package/dist/index.js.map +1 -1
  81. package/dist/types.d.ts +12 -10
  82. package/dist/types.d.ts.map +1 -1
  83. package/dist/types.js +1 -1
  84. package/package.json +7 -6
  85. package/dist/helpers/authHelpers.d.ts.map +0 -1
  86. package/dist/helpers/authHelpers.js +0 -112
  87. package/dist/helpers/authHelpers.js.map +0 -7
  88. package/dist/helpers/externalDocsHelper.d.ts.map +0 -1
  89. package/dist/helpers/externalDocsHelper.js +0 -40
  90. package/dist/helpers/externalDocsHelper.js.map +0 -7
  91. package/dist/helpers/formDataHelpers.d.ts.map +0 -1
  92. package/dist/helpers/formDataHelpers.js +0 -41
  93. package/dist/helpers/formDataHelpers.js.map +0 -7
  94. package/dist/helpers/itemHelpers.d.ts.map +0 -1
  95. package/dist/helpers/itemHelpers.js +0 -194
  96. package/dist/helpers/itemHelpers.js.map +0 -7
  97. package/dist/helpers/licenseContactHelper.d.ts +0 -14
  98. package/dist/helpers/licenseContactHelper.d.ts.map +0 -1
  99. package/dist/helpers/licenseContactHelper.js +0 -71
  100. package/dist/helpers/licenseContactHelper.js.map +0 -7
  101. package/dist/helpers/logoHelper.d.ts.map +0 -1
  102. package/dist/helpers/logoHelper.js +0 -24
  103. package/dist/helpers/logoHelper.js.map +0 -7
  104. package/dist/helpers/md-utils.d.ts.map +0 -1
  105. package/dist/helpers/md-utils.js +0 -35
  106. package/dist/helpers/md-utils.js.map +0 -7
  107. package/dist/helpers/parameterHelpers.d.ts.map +0 -1
  108. package/dist/helpers/parameterHelpers.js +0 -106
  109. package/dist/helpers/parameterHelpers.js.map +0 -7
  110. package/dist/helpers/postResponseScripts.d.ts +0 -5
  111. package/dist/helpers/postResponseScripts.d.ts.map +0 -1
  112. package/dist/helpers/postResponseScripts.js +0 -12
  113. package/dist/helpers/postResponseScripts.js.map +0 -7
  114. package/dist/helpers/requestBodyHelpers.d.ts.map +0 -1
  115. package/dist/helpers/requestBodyHelpers.js +0 -79
  116. package/dist/helpers/requestBodyHelpers.js.map +0 -7
  117. package/dist/helpers/responseHelpers.d.ts.map +0 -1
  118. package/dist/helpers/responseHelpers.js +0 -69
  119. package/dist/helpers/responseHelpers.js.map +0 -7
  120. package/dist/helpers/schemaHelpers.d.ts.map +0 -1
  121. package/dist/helpers/schemaHelpers.js +0 -50
  122. package/dist/helpers/serverHelpers.d.ts +0 -7
  123. package/dist/helpers/serverHelpers.d.ts.map +0 -1
  124. package/dist/helpers/serverHelpers.js +0 -44
  125. package/dist/helpers/serverHelpers.js.map +0 -7
  126. package/dist/helpers/statusCodeHelpers.d.ts.map +0 -1
  127. package/dist/helpers/statusCodeHelpers.js +0 -45
  128. package/dist/helpers/statusCodeHelpers.js.map +0 -7
  129. package/dist/helpers/urlHelpers.d.ts.map +0 -1
  130. package/dist/helpers/urlHelpers.js +0 -53
  131. package/dist/helpers/urlHelpers.js.map +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @scalar/postman-to-openapi
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#7571](https://github.com/scalar/scalar/pull/7571): feat: major refactor, improves everything, keeps all the data now
8
+
9
+ ## 0.3.60
10
+
11
+ ### Patch Changes
12
+
13
+ #### Updated Dependencies
14
+
15
+ - **@scalar/helpers@0.2.8**
16
+ - [#7751](https://github.com/scalar/scalar/pull/7751): fix: auth persistence
17
+
18
+ ## 0.3.59
19
+
20
+ ### Patch Changes
21
+
22
+ - [#7626](https://github.com/scalar/scalar/pull/7626): fix: remove `@scalar/oas-utils` unused dependency
23
+
3
24
  ## 0.3.58
4
25
 
5
26
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AASxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AA2BhD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,MAAM,GAAG,WAAW,CAAC,QAAQ,CA+J3F"}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAYxD,OAAO,KAAK,EAAgC,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAkL9E;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,MAAM,GAAG,WAAW,CAAC,QAAQ,CA6I3F"}
package/dist/convert.js CHANGED
@@ -1,168 +1,233 @@
1
- import { processAuth } from './helpers/authHelpers.js';
2
- import { processExternalDocs } from './helpers/externalDocsHelper.js';
3
- import { processItem } from './helpers/itemHelpers.js';
4
- import { processLicenseAndContact } from './helpers/licenseContactHelper.js';
5
- import { processLogo } from './helpers/logoHelper.js';
6
- import { parseServers } from './helpers/serverHelpers.js';
7
- import { normalizePath } from './helpers/urlHelpers.js';
8
- /**
9
- * Extracts tags from Postman collection folders
10
- */
11
- function extractTags(items) {
12
- const tags = [];
13
- function processTagItem(item, parentPath = '') {
14
- if (item.item) {
15
- const currentPath = parentPath ? `${parentPath} > ${item.name}` : item.name;
16
- // Add tag for the current folder
17
- tags.push({
18
- name: currentPath,
19
- ...(item.description && { description: item.description }),
20
- });
21
- // Process nested folders
22
- item.item.forEach((subItem) => processTagItem(subItem, currentPath));
23
- }
1
+ import { processAuth } from "./helpers/auth.js";
2
+ import { processContact } from "./helpers/contact.js";
3
+ import { processExternalDocs } from "./helpers/external-docs.js";
4
+ import { processLicense } from "./helpers/license.js";
5
+ import { processLogo } from "./helpers/logo.js";
6
+ import { processItem } from "./helpers/path-items.js";
7
+ import { pruneDocument } from "./helpers/prune-document.js";
8
+ import { analyzeServerDistribution } from "./helpers/servers.js";
9
+ import { normalizePath } from "./helpers/urls.js";
10
+ const OPERATION_KEYS = [
11
+ "get",
12
+ "put",
13
+ "post",
14
+ "delete",
15
+ "options",
16
+ "head",
17
+ "patch",
18
+ "trace"
19
+ ];
20
+ const normalizeDescription = (description) => {
21
+ if (typeof description === "string") {
22
+ return description;
23
+ }
24
+ return description?.content;
25
+ };
26
+ const parseCollectionInput = (postmanCollection) => {
27
+ if (typeof postmanCollection !== "string") {
28
+ return postmanCollection;
29
+ }
30
+ try {
31
+ return JSON.parse(postmanCollection);
32
+ } catch (error) {
33
+ const details = error instanceof Error ? error.message : "Unknown parse error";
34
+ const parseError = new Error(`Invalid Postman collection JSON: ${details}`);
35
+ parseError.name = "PostmanCollectionParseError";
36
+ throw parseError;
37
+ }
38
+ };
39
+ const validateCollectionShape = (collection) => {
40
+ if (!collection || typeof collection !== "object") {
41
+ throw new Error("Invalid Postman collection: expected an object");
42
+ }
43
+ const candidate = collection;
44
+ if (!candidate.info) {
45
+ throw new Error("Missing required info on Postman collection");
46
+ }
47
+ if (!candidate.item || !Array.isArray(candidate.item)) {
48
+ throw new Error("Invalid Postman collection: item must be an array");
49
+ }
50
+ if (typeof candidate.info !== "object") {
51
+ throw new Error("Invalid Postman collection: info must be an object");
52
+ }
53
+ if (!candidate.info.name) {
54
+ throw new Error("Missing required info.name on Postman collection");
55
+ }
56
+ if (!candidate.info.schema) {
57
+ throw new Error("Invalid Postman collection: missing info.schema");
58
+ }
59
+ if (candidate.variable && !Array.isArray(candidate.variable)) {
60
+ throw new Error("Invalid Postman collection: variable must be an array when provided");
61
+ }
62
+ return candidate;
63
+ };
64
+ const isItemGroup = (item) => "item" in item && Array.isArray(item.item);
65
+ const extractTags = (items) => {
66
+ const collectTags = (item, parentPath = "") => {
67
+ if (!isItemGroup(item)) {
68
+ return [];
24
69
  }
25
- items.forEach((item) => processTagItem(item));
26
- return tags;
27
- }
28
- /**
29
- * Converts a Postman Collection to an OpenAPI 3.1.0 document.
30
- * This function processes the collection's information, servers, authentication,
31
- * and items to create a corresponding OpenAPI structure.
32
- */
33
- export function convert(postmanCollection) {
34
- // Parse string input if provided
35
- const collection = typeof postmanCollection === 'string' ? JSON.parse(postmanCollection) : postmanCollection;
36
- // Extract title from collection info, fallback to 'API' if not provided
37
- const title = collection.info.name || 'API';
38
- // Look for version in collection variables, default to '1.0.0'
39
- const version = collection.variable?.find((v) => v.key === 'version')?.value || '1.0.0';
40
- // Handle different description formats in Postman
41
- const description = typeof collection.info.description === 'string'
42
- ? collection.info.description
43
- : collection.info.description?.content || '';
44
- // Process license and contact information
45
- const { license, contact } = processLicenseAndContact(collection);
46
- // Process logo information
47
- const logo = processLogo(collection);
48
- // Initialize the OpenAPI document with required fields
49
- const openapi = {
50
- openapi: '3.1.0',
51
- info: {
52
- title,
53
- version,
54
- ...(description && { description }),
55
- ...(license && { license }),
56
- ...(contact && { contact }),
57
- ...(logo && { 'x-logo': logo }),
58
- },
59
- servers: parseServers(collection),
60
- paths: {},
61
- };
62
- // Process external docs
63
- const externalDocs = processExternalDocs(collection);
64
- if (externalDocs) {
65
- openapi.externalDocs = externalDocs;
70
+ const nextPath = item.name ? parentPath ? `${parentPath} > ${item.name}` : item.name : parentPath;
71
+ const description = normalizeDescription(item.description);
72
+ const currentTag = item.name?.length ? [
73
+ {
74
+ name: nextPath,
75
+ ...description && { description }
76
+ }
77
+ ] : [];
78
+ return [...currentTag, ...item.item.flatMap((subItem) => collectTags(subItem, nextPath))];
79
+ };
80
+ return items.flatMap((item) => collectTags(item));
81
+ };
82
+ const mergeSecuritySchemes = (openapi, securitySchemes) => {
83
+ if (!securitySchemes || Object.keys(securitySchemes).length === 0) {
84
+ return;
85
+ }
86
+ openapi.components = openapi.components || {};
87
+ openapi.components.securitySchemes = {
88
+ ...openapi.components.securitySchemes ?? {},
89
+ ...securitySchemes
90
+ };
91
+ };
92
+ const mergePathItem = (paths, normalizedPathKey, pathItem) => {
93
+ const targetPath = paths[normalizedPathKey] ?? {};
94
+ for (const [key, value] of Object.entries(pathItem)) {
95
+ if (value === void 0) {
96
+ continue;
97
+ }
98
+ const isOperationKey = OPERATION_KEYS.includes(key);
99
+ if (isOperationKey && targetPath[key]) {
100
+ const operationName = typeof key === "string" ? key.toUpperCase() : String(key);
101
+ console.warn(
102
+ `Duplicate operation detected for ${operationName} ${normalizedPathKey}. Last operation will overwrite previous.`
103
+ );
66
104
  }
67
- // Process authentication if present in the collection
68
- if (collection.auth) {
69
- const { securitySchemes, security } = processAuth(collection.auth);
70
- openapi.components = openapi.components || {};
71
- openapi.components.securitySchemes = {
72
- ...openapi.components.securitySchemes,
73
- ...securitySchemes,
74
- };
75
- openapi.security = security;
105
+ targetPath[key] = value;
106
+ }
107
+ paths[normalizedPathKey] = targetPath;
108
+ };
109
+ const cleanupOperations = (paths) => {
110
+ Object.values(paths).forEach((pathItem) => {
111
+ if (!pathItem) {
112
+ return;
76
113
  }
77
- // Process each item in the collection and merge into OpenAPI spec
78
- if (collection.item) {
79
- // Extract tags from folders
80
- const tags = extractTags(collection.item);
81
- if (tags.length > 0) {
82
- openapi.tags = tags;
114
+ OPERATION_KEYS.forEach((operationKey) => {
115
+ const operation = pathItem[operationKey];
116
+ if (!operation) {
117
+ return;
118
+ }
119
+ if ("parameters" in operation && operation.parameters?.length === 0) {
120
+ delete operation.parameters;
121
+ }
122
+ if ("requestBody" in operation && operation.requestBody && "content" in operation.requestBody) {
123
+ const content = operation.requestBody.content;
124
+ if (content && "text/plain" in content) {
125
+ const text = content["text/plain"];
126
+ if (!text?.schema || text.schema && Object.keys(text.schema).length === 0) {
127
+ content["text/plain"] = {};
128
+ }
83
129
  }
84
- collection.item.forEach((item) => {
85
- const { paths: itemPaths, components: itemComponents } = processItem(item);
86
- // Merge paths from the current item
87
- openapi.paths = openapi.paths || {};
88
- for (const [pathKey, pathItem] of Object.entries(itemPaths)) {
89
- // Convert colon-style params to curly brace style
90
- const normalizedPathKey = normalizePath(pathKey);
91
- if (!pathItem) {
92
- continue;
93
- }
94
- if (!openapi.paths[normalizedPathKey]) {
95
- openapi.paths[normalizedPathKey] = pathItem;
96
- }
97
- else {
98
- openapi.paths[normalizedPathKey] = {
99
- ...openapi.paths[normalizedPathKey],
100
- ...pathItem,
101
- };
102
- }
103
- }
104
- // Merge security schemes from the current item
105
- if (itemComponents?.securitySchemes) {
106
- openapi.components = openapi.components || {};
107
- openapi.components.securitySchemes = {
108
- ...openapi.components.securitySchemes,
109
- ...itemComponents.securitySchemes,
110
- };
111
- }
112
- });
130
+ }
131
+ if (!operation.description) {
132
+ delete operation.description;
133
+ }
134
+ });
135
+ });
136
+ };
137
+ function convert(postmanCollection) {
138
+ const collection = validateCollectionShape(parseCollectionInput(postmanCollection));
139
+ const title = collection.info.name || "API";
140
+ const version = collection.variable?.find((v) => v.key === "version")?.value || "1.0.0";
141
+ const description = normalizeDescription(collection.info.description) || "";
142
+ const license = processLicense(collection);
143
+ const contact = processContact(collection);
144
+ const logo = processLogo(collection);
145
+ const openapi = {
146
+ openapi: "3.1.0",
147
+ info: {
148
+ title,
149
+ version,
150
+ ...description && { description },
151
+ ...license && { license },
152
+ ...contact && { contact },
153
+ ...logo && { "x-logo": logo }
154
+ },
155
+ paths: {}
156
+ };
157
+ const externalDocs = processExternalDocs(collection);
158
+ if (externalDocs) {
159
+ openapi.externalDocs = externalDocs;
160
+ }
161
+ if (collection.auth) {
162
+ const { securitySchemes, security } = processAuth(collection.auth);
163
+ mergeSecuritySchemes(openapi, securitySchemes);
164
+ openapi.security = security;
165
+ }
166
+ const allServerUsage = [];
167
+ if (collection.item) {
168
+ const tags = extractTags(collection.item);
169
+ if (tags.length > 0) {
170
+ openapi.tags = tags;
113
171
  }
114
- // Clean up the generated paths
115
- if (openapi.paths) {
116
- Object.values(openapi.paths).forEach((path) => {
117
- if (path) {
118
- Object.values(path).forEach((method) => {
119
- if (method && 'parameters' in method) {
120
- // Remove empty parameters array to keep spec clean
121
- if (method.parameters?.length === 0) {
122
- delete method.parameters;
123
- }
124
- // Handle request bodies
125
- if (method.requestBody?.content) {
126
- const content = method.requestBody.content;
127
- if (Object.keys(content).length === 0) {
128
- // Keep an empty requestBody with text/plain content
129
- method.requestBody = {
130
- content: {
131
- 'text/plain': {},
132
- },
133
- };
134
- }
135
- else if ('text/plain' in content) {
136
- // Preserve schema if it exists, otherwise keep an empty object
137
- if (!content['text/plain'].schema || Object.keys(content['text/plain'].schema).length === 0) {
138
- content['text/plain'] = {};
139
- }
140
- }
141
- }
142
- // Ensure all methods have a description, but don't add an empty one if it doesn't exist
143
- if (!method.description) {
144
- delete method.description;
145
- }
146
- }
147
- });
148
- }
149
- });
172
+ collection.item.forEach((item) => {
173
+ const { paths: itemPaths, components: itemComponents, serverUsage } = processItem(item);
174
+ allServerUsage.push(...serverUsage);
175
+ openapi.paths = openapi.paths || {};
176
+ for (const [pathKey, pathItem] of Object.entries(itemPaths)) {
177
+ const normalizedPathKey = normalizePath(pathKey);
178
+ if (!pathItem) {
179
+ continue;
180
+ }
181
+ mergePathItem(openapi.paths, normalizedPathKey, pathItem);
182
+ }
183
+ if (itemComponents?.securitySchemes) {
184
+ mergeSecuritySchemes(openapi, itemComponents.securitySchemes);
185
+ }
186
+ });
187
+ }
188
+ const allUniquePaths = /* @__PURE__ */ new Set();
189
+ if (openapi.paths) {
190
+ for (const pathKey of Object.keys(openapi.paths)) {
191
+ allUniquePaths.add(pathKey);
150
192
  }
151
- // Remove empty components object
152
- if (Object.keys(openapi.components || {}).length === 0) {
153
- delete openapi.components;
193
+ }
194
+ const serverPlacement = analyzeServerDistribution(allServerUsage, allUniquePaths);
195
+ if (serverPlacement.document.length > 0) {
196
+ openapi.servers = serverPlacement.document;
197
+ }
198
+ if (openapi.paths) {
199
+ for (const [path, servers] of serverPlacement.pathItems.entries()) {
200
+ const normalizedPathKey = normalizePath(path);
201
+ const pathItem = openapi.paths[normalizedPathKey];
202
+ if (pathItem) {
203
+ pathItem.servers = servers;
204
+ }
154
205
  }
155
- // Remove undefined properties recursively
156
- const removeUndefined = (obj) => {
157
- if (Array.isArray(obj)) {
158
- return obj.map(removeUndefined).filter((item) => item !== undefined);
159
- }
160
- if (obj && typeof obj === 'object') {
161
- return Object.fromEntries(Object.entries(obj)
162
- .map(([key, value]) => [key, removeUndefined(value)])
163
- .filter(([_, value]) => value !== undefined));
206
+ for (const [path, methods] of serverPlacement.operations.entries()) {
207
+ const normalizedPathKey = normalizePath(path);
208
+ const pathItem = openapi.paths[normalizedPathKey];
209
+ if (!pathItem) {
210
+ continue;
211
+ }
212
+ for (const [method, servers] of methods.entries()) {
213
+ if (method in pathItem) {
214
+ const operation = pathItem[method];
215
+ if (operation && typeof operation === "object" && "responses" in operation) {
216
+ operation.servers = servers;
217
+ }
164
218
  }
165
- return obj;
166
- };
167
- return removeUndefined(openapi);
219
+ }
220
+ }
221
+ }
222
+ if (openapi.paths) {
223
+ cleanupOperations(openapi.paths);
224
+ }
225
+ if (Object.keys(openapi.components || {}).length === 0) {
226
+ delete openapi.components;
227
+ }
228
+ return pruneDocument(openapi);
168
229
  }
230
+ export {
231
+ convert
232
+ };
233
+ //# sourceMappingURL=convert.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/convert.ts"],
4
- "sourcesContent": ["import type { OpenAPIV3_1 } from '@scalar/openapi-types'\n\nimport { processAuth } from './helpers/authHelpers'\nimport { processExternalDocs } from './helpers/externalDocsHelper'\nimport { processItem } from './helpers/itemHelpers'\nimport { processLicenseAndContact } from './helpers/licenseContactHelper'\nimport { processLogo } from './helpers/logoHelper'\nimport { parseServers } from './helpers/serverHelpers'\nimport { normalizePath } from './helpers/urlHelpers'\nimport type { PostmanCollection } from './types'\n\n/**\n * Extracts tags from Postman collection folders\n */\nfunction extractTags(items: PostmanCollection['item']): OpenAPIV3_1.TagObject[] {\n const tags: OpenAPIV3_1.TagObject[] = []\n\n function processTagItem(item: any, parentPath: string = '') {\n if (item.item) {\n const currentPath = parentPath ? `${parentPath} > ${item.name}` : item.name\n\n // Add tag for the current folder\n tags.push({\n name: currentPath,\n ...(item.description && { description: item.description }),\n })\n\n // Process nested folders\n item.item.forEach((subItem: any) => processTagItem(subItem, currentPath))\n }\n }\n\n items.forEach((item) => processTagItem(item))\n return tags\n}\n\n/**\n * Converts a Postman Collection to an OpenAPI 3.1.0 document.\n * This function processes the collection's information, servers, authentication,\n * and items to create a corresponding OpenAPI structure.\n */\nexport function convert(postmanCollection: PostmanCollection | string): OpenAPIV3_1.Document {\n // Parse string input if provided\n const collection: PostmanCollection =\n typeof postmanCollection === 'string' ? JSON.parse(postmanCollection) : postmanCollection\n\n // Extract title from collection info, fallback to 'API' if not provided\n const title = collection.info.name || 'API'\n\n // Look for version in collection variables, default to '1.0.0'\n const version = (collection.variable?.find((v) => v.key === 'version')?.value as string) || '1.0.0'\n\n // Handle different description formats in Postman\n const description =\n typeof collection.info.description === 'string'\n ? collection.info.description\n : collection.info.description?.content || ''\n\n // Process license and contact information\n const { license, contact } = processLicenseAndContact(collection)\n\n // Process logo information\n const logo = processLogo(collection)\n\n // Initialize the OpenAPI document with required fields\n const openapi: OpenAPIV3_1.Document = {\n openapi: '3.1.0',\n info: {\n title,\n version,\n ...(description && { description }),\n ...(license && { license }),\n ...(contact && { contact }),\n ...(logo && { 'x-logo': logo }),\n },\n servers: parseServers(collection),\n paths: {},\n }\n\n // Process external docs\n const externalDocs = processExternalDocs(collection)\n if (externalDocs) {\n openapi.externalDocs = externalDocs\n }\n\n // Process authentication if present in the collection\n if (collection.auth) {\n const { securitySchemes, security } = processAuth(collection.auth)\n openapi.components = openapi.components || {}\n openapi.components.securitySchemes = {\n ...openapi.components.securitySchemes,\n ...securitySchemes,\n }\n openapi.security = security\n }\n\n // Process each item in the collection and merge into OpenAPI spec\n if (collection.item) {\n // Extract tags from folders\n const tags = extractTags(collection.item)\n if (tags.length > 0) {\n openapi.tags = tags\n }\n\n collection.item.forEach((item) => {\n const { paths: itemPaths, components: itemComponents } = processItem(item)\n\n // Merge paths from the current item\n openapi.paths = openapi.paths || {}\n for (const [pathKey, pathItem] of Object.entries(itemPaths)) {\n // Convert colon-style params to curly brace style\n const normalizedPathKey = normalizePath(pathKey)\n\n if (!pathItem) {\n continue\n }\n\n if (!openapi.paths[normalizedPathKey]) {\n openapi.paths[normalizedPathKey] = pathItem\n } else {\n openapi.paths[normalizedPathKey] = {\n ...openapi.paths[normalizedPathKey],\n ...pathItem,\n }\n }\n }\n\n // Merge security schemes from the current item\n if (itemComponents?.securitySchemes) {\n openapi.components = openapi.components || {}\n openapi.components.securitySchemes = {\n ...openapi.components.securitySchemes,\n ...itemComponents.securitySchemes,\n }\n }\n })\n }\n\n // Clean up the generated paths\n if (openapi.paths) {\n Object.values(openapi.paths).forEach((path) => {\n if (path) {\n Object.values(path).forEach((method) => {\n if (method && 'parameters' in method) {\n // Remove empty parameters array to keep spec clean\n if (method.parameters?.length === 0) {\n delete method.parameters\n }\n\n // Handle request bodies\n if (method.requestBody?.content) {\n const content = method.requestBody.content\n if (Object.keys(content).length === 0) {\n // Keep an empty requestBody with text/plain content\n method.requestBody = {\n content: {\n 'text/plain': {},\n },\n }\n } else if ('text/plain' in content) {\n // Preserve schema if it exists, otherwise keep an empty object\n if (!content['text/plain'].schema || Object.keys(content['text/plain'].schema).length === 0) {\n content['text/plain'] = {}\n }\n }\n }\n\n // Ensure all methods have a description, but don't add an empty one if it doesn't exist\n if (!method.description) {\n delete method.description\n }\n }\n })\n }\n })\n }\n\n // Remove empty components object\n if (Object.keys(openapi.components || {}).length === 0) {\n delete openapi.components\n }\n\n // Remove undefined properties recursively\n const removeUndefined = (obj: any): any => {\n if (Array.isArray(obj)) {\n return obj.map(removeUndefined).filter((item) => item !== undefined)\n }\n\n if (obj && typeof obj === 'object') {\n return Object.fromEntries(\n Object.entries(obj)\n .map(([key, value]) => [key, removeUndefined(value)])\n .filter(([_, value]) => value !== undefined),\n )\n }\n\n return obj\n }\n\n return removeUndefined(openapi)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { OpenAPIV3_1 } from '@scalar/openapi-types'\n\nimport { processAuth } from '@/helpers/auth'\nimport { processContact } from '@/helpers/contact'\nimport { processExternalDocs } from '@/helpers/external-docs'\nimport { processLicense } from '@/helpers/license'\nimport { processLogo } from '@/helpers/logo'\nimport { processItem } from '@/helpers/path-items'\nimport { pruneDocument } from '@/helpers/prune-document'\nimport { analyzeServerDistribution } from '@/helpers/servers'\nimport { normalizePath } from '@/helpers/urls'\n\nimport type { Description, Item, ItemGroup, PostmanCollection } from './types'\n\nconst OPERATION_KEYS: readonly (keyof OpenAPIV3_1.PathItemObject)[] = [\n 'get',\n 'put',\n 'post',\n 'delete',\n 'options',\n 'head',\n 'patch',\n 'trace',\n]\n\nconst normalizeDescription = (description?: Description): string | undefined => {\n if (typeof description === 'string') {\n return description\n }\n\n return description?.content\n}\n\nconst parseCollectionInput = (postmanCollection: PostmanCollection | string): unknown => {\n if (typeof postmanCollection !== 'string') {\n return postmanCollection\n }\n\n try {\n return JSON.parse(postmanCollection) as PostmanCollection\n } catch (error) {\n const details = error instanceof Error ? error.message : 'Unknown parse error'\n const parseError = new Error(`Invalid Postman collection JSON: ${details}`)\n parseError.name = 'PostmanCollectionParseError'\n throw parseError\n }\n}\n\nconst validateCollectionShape = (collection: unknown): PostmanCollection => {\n if (!collection || typeof collection !== 'object') {\n throw new Error('Invalid Postman collection: expected an object')\n }\n\n const candidate = collection as Partial<PostmanCollection>\n\n if (!candidate.info) {\n throw new Error('Missing required info on Postman collection')\n }\n\n if (!candidate.item || !Array.isArray(candidate.item)) {\n throw new Error('Invalid Postman collection: item must be an array')\n }\n\n if (typeof candidate.info !== 'object') {\n throw new Error('Invalid Postman collection: info must be an object')\n }\n\n if (!candidate.info.name) {\n throw new Error('Missing required info.name on Postman collection')\n }\n\n if (!candidate.info.schema) {\n throw new Error('Invalid Postman collection: missing info.schema')\n }\n\n if (candidate.variable && !Array.isArray(candidate.variable)) {\n throw new Error('Invalid Postman collection: variable must be an array when provided')\n }\n\n return candidate as PostmanCollection\n}\n\n/**\n * Extracts tags from Postman collection folders.\n * We keep folder nesting using \" > \" so tag names stay readable while preserving hierarchy.\n * Requests do not produce tags; only folders are reflected as tags.\n */\nconst isItemGroup = (item: Item | ItemGroup): item is ItemGroup => 'item' in item && Array.isArray(item.item)\n\nconst extractTags = (items: PostmanCollection['item']): OpenAPIV3_1.TagObject[] => {\n const collectTags = (item: Item | ItemGroup, parentPath: string = ''): OpenAPIV3_1.TagObject[] => {\n if (!isItemGroup(item)) {\n return []\n }\n\n const nextPath = item.name ? (parentPath ? `${parentPath} > ${item.name}` : item.name) : parentPath\n const description = normalizeDescription(item.description)\n const currentTag: OpenAPIV3_1.TagObject[] = item.name?.length\n ? [\n {\n name: nextPath,\n ...(description && { description }),\n },\n ]\n : []\n\n return [...currentTag, ...item.item.flatMap((subItem) => collectTags(subItem, nextPath))]\n }\n\n return items.flatMap((item) => collectTags(item))\n}\n\nconst mergeSecuritySchemes = (\n openapi: OpenAPIV3_1.Document,\n securitySchemes?: OpenAPIV3_1.ComponentsObject['securitySchemes'],\n): void => {\n if (!securitySchemes || Object.keys(securitySchemes).length === 0) {\n return\n }\n\n openapi.components = openapi.components || {}\n openapi.components.securitySchemes = {\n ...(openapi.components.securitySchemes ?? {}),\n ...securitySchemes,\n }\n}\n\nconst mergePathItem = (\n paths: OpenAPIV3_1.PathsObject,\n normalizedPathKey: string,\n pathItem: OpenAPIV3_1.PathItemObject,\n): void => {\n const targetPath = (paths[normalizedPathKey] ?? {}) as OpenAPIV3_1.PathItemObject\n\n for (const [key, value] of Object.entries(pathItem) as [\n keyof OpenAPIV3_1.PathItemObject,\n OpenAPIV3_1.PathItemObject[keyof OpenAPIV3_1.PathItemObject],\n ][]) {\n if (value === undefined) {\n continue\n }\n\n const isOperationKey = OPERATION_KEYS.includes(key)\n\n if (isOperationKey && targetPath[key]) {\n const operationName = typeof key === 'string' ? key.toUpperCase() : String(key)\n console.warn(\n `Duplicate operation detected for ${operationName} ${normalizedPathKey}. Last operation will overwrite previous.`,\n )\n }\n\n targetPath[key] = value\n }\n\n paths[normalizedPathKey] = targetPath\n}\n\nconst cleanupOperations = (paths: OpenAPIV3_1.PathsObject): void => {\n Object.values(paths).forEach((pathItem) => {\n if (!pathItem) {\n return\n }\n\n OPERATION_KEYS.forEach((operationKey) => {\n const operation = pathItem[operationKey]\n if (!operation) {\n return\n }\n\n if ('parameters' in operation && operation.parameters?.length === 0) {\n delete operation.parameters\n }\n\n if ('requestBody' in operation && operation.requestBody && 'content' in operation.requestBody) {\n const content = operation.requestBody.content\n if (content && 'text/plain' in content) {\n const text = content['text/plain']\n if (!text?.schema || (text.schema && Object.keys(text.schema).length === 0)) {\n content['text/plain'] = {}\n }\n }\n }\n\n if (!operation.description) {\n delete operation.description\n }\n })\n })\n}\n\n/**\n * Converts a Postman Collection to an OpenAPI 3.1.0 document.\n * This function processes the collection's information, servers, authentication,\n * and items to create a corresponding OpenAPI structure.\n */\nexport function convert(postmanCollection: PostmanCollection | string): OpenAPIV3_1.Document {\n const collection = validateCollectionShape(parseCollectionInput(postmanCollection))\n\n // Extract title from collection info, fallback to 'API' if not provided\n const title = collection.info.name || 'API'\n\n // Look for version in collection variables, default to '1.0.0'\n const version = (collection.variable?.find((v) => v.key === 'version')?.value as string) || '1.0.0'\n\n // Handle different description formats in Postman\n const description = normalizeDescription(collection.info.description) || ''\n\n // Process license and contact information\n const license = processLicense(collection)\n const contact = processContact(collection)\n\n // Process logo information\n const logo = processLogo(collection)\n\n // Initialize the OpenAPI document with required fields\n const openapi: OpenAPIV3_1.Document = {\n openapi: '3.1.0',\n info: {\n title,\n version,\n ...(description && { description }),\n ...(license && { license }),\n ...(contact && { contact }),\n ...(logo && { 'x-logo': logo }),\n },\n paths: {},\n }\n\n // Process external docs\n const externalDocs = processExternalDocs(collection)\n if (externalDocs) {\n openapi.externalDocs = externalDocs\n }\n\n // Process authentication if present in the collection\n if (collection.auth) {\n const { securitySchemes, security } = processAuth(collection.auth)\n mergeSecuritySchemes(openapi, securitySchemes)\n openapi.security = security\n }\n\n // Process each item in the collection and merge into OpenAPI spec\n const allServerUsage: Array<{\n serverUrl: string\n path: string\n method: 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace'\n }> = []\n\n if (collection.item) {\n // Extract tags from folders\n const tags = extractTags(collection.item)\n if (tags.length > 0) {\n openapi.tags = tags\n }\n\n collection.item.forEach((item) => {\n const { paths: itemPaths, components: itemComponents, serverUsage } = processItem(item)\n\n // Collect server usage information\n allServerUsage.push(...serverUsage)\n\n // Merge paths from the current item\n openapi.paths = openapi.paths || {}\n for (const [pathKey, pathItem] of Object.entries(itemPaths)) {\n // Convert colon-style params to curly brace style\n const normalizedPathKey = normalizePath(pathKey)\n\n if (!pathItem) {\n continue\n }\n\n mergePathItem(openapi.paths, normalizedPathKey, pathItem)\n }\n\n // Merge security schemes from the current item\n if (itemComponents?.securitySchemes) {\n mergeSecuritySchemes(openapi, itemComponents.securitySchemes)\n }\n })\n }\n\n // Extract all unique paths from the document\n const allUniquePaths = new Set<string>()\n if (openapi.paths) {\n for (const pathKey of Object.keys(openapi.paths)) {\n allUniquePaths.add(pathKey)\n }\n }\n\n // Analyze server distribution and place servers at appropriate levels\n const serverPlacement = analyzeServerDistribution(allServerUsage, allUniquePaths)\n\n // Add servers to document level\n if (serverPlacement.document.length > 0) {\n openapi.servers = serverPlacement.document\n }\n\n // Add servers to path items\n if (openapi.paths) {\n for (const [path, servers] of serverPlacement.pathItems.entries()) {\n const normalizedPathKey = normalizePath(path)\n const pathItem = openapi.paths[normalizedPathKey]\n if (pathItem) {\n pathItem.servers = servers\n }\n }\n\n // Add servers to operations\n for (const [path, methods] of serverPlacement.operations.entries()) {\n const normalizedPathKey = normalizePath(path)\n const pathItem = openapi.paths[normalizedPathKey]\n if (!pathItem) {\n continue\n }\n for (const [method, servers] of methods.entries()) {\n if (method in pathItem) {\n const operation = pathItem[method as keyof typeof pathItem]\n if (operation && typeof operation === 'object' && 'responses' in operation) {\n operation.servers = servers\n }\n }\n }\n }\n }\n\n // Clean up the generated paths\n if (openapi.paths) {\n cleanupOperations(openapi.paths)\n }\n\n // Remove empty components object\n if (Object.keys(openapi.components || {}).length === 0) {\n delete openapi.components\n }\n\n return pruneDocument(openapi)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,4 +9,4 @@ export declare function processAuth(auth: Auth): {
9
9
  securitySchemes: Record<string, OpenAPIV3_1.SecuritySchemeObject>;
10
10
  security: OpenAPIV3_1.SecurityRequirementObject[];
11
11
  };
12
- //# sourceMappingURL=authHelpers.d.ts.map
12
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/helpers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAkInC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG;IACvC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,oBAAoB,CAAC,CAAA;IACjE,QAAQ,EAAE,WAAW,CAAC,yBAAyB,EAAE,CAAA;CAClD,CAwBA"}
@@ -0,0 +1,113 @@
1
+ const AUTH_SCHEMES = {
2
+ API_KEY: "apikeyAuth",
3
+ BASIC: "basicAuth",
4
+ BEARER: "bearerAuth",
5
+ OAUTH2: "oauth2Auth"
6
+ };
7
+ const OAUTH2_DEFAULTS = {
8
+ AUTHORIZE_URL: "/oauth/authorize",
9
+ TOKEN_URL: "/oauth/token"
10
+ };
11
+ function createApiKeyConfig() {
12
+ return {
13
+ scheme: {
14
+ type: "apiKey",
15
+ name: "api_key",
16
+ in: "header"
17
+ },
18
+ requirement: { [AUTH_SCHEMES.API_KEY]: [] }
19
+ };
20
+ }
21
+ function createBasicConfig() {
22
+ return {
23
+ scheme: {
24
+ type: "http",
25
+ scheme: "basic"
26
+ },
27
+ requirement: { [AUTH_SCHEMES.BASIC]: [] }
28
+ };
29
+ }
30
+ function createBearerConfig() {
31
+ return {
32
+ scheme: {
33
+ type: "http",
34
+ scheme: "bearer"
35
+ },
36
+ requirement: { [AUTH_SCHEMES.BEARER]: [] }
37
+ };
38
+ }
39
+ function createOAuth2Config(auth) {
40
+ if (!auth) {
41
+ return {
42
+ scheme: {},
43
+ requirement: {}
44
+ };
45
+ }
46
+ const oauth2Attrs = auth.oauth2 || [];
47
+ const attrMap = /* @__PURE__ */ new Map();
48
+ oauth2Attrs.forEach((attr) => {
49
+ if (attr.key && attr.value !== void 0) {
50
+ attrMap.set(attr.key, String(attr.value));
51
+ }
52
+ });
53
+ const authUrl = attrMap.get("authUrl") || attrMap.get("authorizationUrl") || OAUTH2_DEFAULTS.AUTHORIZE_URL;
54
+ const tokenUrl = attrMap.get("accessTokenUrl") || attrMap.get("tokenUrl") || OAUTH2_DEFAULTS.TOKEN_URL;
55
+ const scopeValue = attrMap.get("scope") || "";
56
+ const scopes = {};
57
+ if (scopeValue) {
58
+ const scopeList = scopeValue.split(/[,\s]+/).filter(Boolean);
59
+ scopeList.forEach((scope) => {
60
+ scopes[scope] = scope;
61
+ });
62
+ }
63
+ return {
64
+ scheme: {
65
+ type: "oauth2",
66
+ flows: {
67
+ authorizationCode: {
68
+ authorizationUrl: authUrl,
69
+ tokenUrl,
70
+ scopes
71
+ }
72
+ }
73
+ },
74
+ requirement: { [AUTH_SCHEMES.OAUTH2]: Object.keys(scopes) }
75
+ };
76
+ }
77
+ function createNoAuthConfig() {
78
+ return {
79
+ scheme: {},
80
+ requirement: {}
81
+ };
82
+ }
83
+ const AUTH_TYPE_HANDLERS = {
84
+ apikey: createApiKeyConfig,
85
+ basic: createBasicConfig,
86
+ bearer: createBearerConfig,
87
+ oauth2: createOAuth2Config,
88
+ noauth: createNoAuthConfig
89
+ };
90
+ function processAuth(auth) {
91
+ const securitySchemes = {};
92
+ const security = [];
93
+ try {
94
+ const handler = AUTH_TYPE_HANDLERS[auth.type];
95
+ if (!handler) {
96
+ throw new Error(`Unsupported authentication type: ${auth.type}`);
97
+ }
98
+ const { scheme, requirement } = handler(auth);
99
+ if (Object.keys(scheme).length > 0) {
100
+ const schemeKey = `${auth.type}Auth`;
101
+ securitySchemes[schemeKey] = scheme;
102
+ security.push(requirement);
103
+ }
104
+ } catch (error) {
105
+ console.error("Error processing authentication:", error);
106
+ throw error;
107
+ }
108
+ return { securitySchemes, security };
109
+ }
110
+ export {
111
+ processAuth
112
+ };
113
+ //# sourceMappingURL=auth.js.map