@scalar/postman-to-openapi 0.6.1 → 0.6.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @scalar/postman-to-openapi
2
2
 
3
+ ## 0.6.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#8903](https://github.com/scalar/scalar/pull/8903): fix: share Postman collection detection from postman-to-openapi
8
+ - [#8902](https://github.com/scalar/scalar/pull/8902): Preserve merged Postman request variants by carrying request-specific examples for parameters and request bodies, unioning status-code responses derived from request names, and concatenating pre-request and post-response script extensions when operations collapse into one path/method.
9
+ - [#8898](https://github.com/scalar/scalar/pull/8898): merge structurally equivalent paths that only differ by path parameter names and align path parameter definitions with the canonical path
10
+ - [#8887](https://github.com/scalar/scalar/pull/8887): fix: invalid json body handling and add root document for bulk operation selection
11
+ - [#8897](https://github.com/scalar/scalar/pull/8897): fix postman-to-openapi response descriptions to use status-aware defaults and parse named examples
12
+
13
+ ## 0.6.2
14
+
3
15
  ## 0.6.1
4
16
 
5
17
  ## 0.6.0
package/README.md CHANGED
@@ -24,6 +24,21 @@ const result = await convert(myPostmanCollection)
24
24
  console.log(result)
25
25
  ```
26
26
 
27
+ ### Detect Postman collections
28
+
29
+ Use `isPostmanCollection` to decide whether an input string should be parsed as a Postman collection before converting.
30
+
31
+ ```ts
32
+ import { convert, isPostmanCollection } from '@scalar/postman-to-openapi'
33
+
34
+ if (isPostmanCollection(input)) {
35
+ const openApiDocument = convert(input)
36
+ console.log(openApiDocument)
37
+ }
38
+ ```
39
+
40
+ `isPostmanCollection` accepts exported collections that do not include `info._postman_id` as long as they contain a valid Postman schema URL and an `item` tree.
41
+
27
42
  ## Community
28
43
 
29
44
  We are API nerds. You too? Let's chat on Discord: <https://discord.gg/scalar>
@@ -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;AAaxD,OAAO,KAAK,EAAgC,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAE9E;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,MAAM,EAAE,CAAA;AA4SvD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAA;IACtD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAA;CAChC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,iBAAiB,EAAE,iBAAiB,GAAG,MAAM,EAC7C,OAAO,GAAE,cAA0C,GAClD,WAAW,CAAC,QAAQ,CAwLtB"}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAkBxD,OAAO,KAAK,EAAgC,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAE9E;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,MAAM,EAAE,CAAA;AA8iBvD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAA;IACtD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAA;CAChC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,iBAAiB,EAAE,iBAAiB,GAAG,MAAM,EAC7C,OAAO,GAAE,cAA0C,GAClD,WAAW,CAAC,QAAQ,CA4MtB"}
package/dist/convert.js CHANGED
@@ -4,10 +4,10 @@ import { processExternalDocs } from './helpers/external-docs.js';
4
4
  import { processLicense } from './helpers/license.js';
5
5
  import { processLogo } from './helpers/logo.js';
6
6
  import { DEFAULT_EXAMPLE_NAME, OPERATION_KEYS, mergePathItem } from './helpers/merge-path-item.js';
7
- import { processItem } from './helpers/path-items.js';
7
+ import { POSTMAN_EXAMPLE_NAME_EXTENSION, POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION, POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION, processItem, } from './helpers/path-items.js';
8
8
  import { pruneDocument } from './helpers/prune-document.js';
9
9
  import { analyzeServerDistribution } from './helpers/servers.js';
10
- import { normalizePath } from './helpers/urls.js';
10
+ import { getPathStructuralSignature, normalizePath } from './helpers/urls.js';
11
11
  const normalizeDescription = (description) => {
12
12
  if (typeof description === 'string') {
13
13
  return description;
@@ -237,9 +237,195 @@ const cleanupOperations = (paths) => {
237
237
  if (!operation.description) {
238
238
  delete operation.description;
239
239
  }
240
+ // Internal merge bookkeeping should not leak in final OpenAPI output.
241
+ delete operation[POSTMAN_EXAMPLE_NAME_EXTENSION];
242
+ delete operation[POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION];
243
+ delete operation[POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION];
240
244
  });
241
245
  });
242
246
  };
247
+ const getOrderedPathParameterNames = (path) => normalizePath(path)
248
+ .split('/')
249
+ .flatMap((segment) => {
250
+ const match = segment.match(/^\{([^{}]+)\}$/);
251
+ return match?.[1] ? [match[1]] : [];
252
+ });
253
+ const rewritePathParameterNames = (path, parameterNames) => {
254
+ const segments = normalizePath(path).split('/');
255
+ let parameterIndex = 0;
256
+ const rewrittenSegments = segments.map((segment) => {
257
+ if (!/^\{[^{}]+\}$/.test(segment)) {
258
+ return segment;
259
+ }
260
+ const canonicalName = parameterNames[parameterIndex];
261
+ parameterIndex += 1;
262
+ return canonicalName ? `{${canonicalName}}` : segment;
263
+ });
264
+ return rewrittenSegments.join('/');
265
+ };
266
+ const chooseMostCommonName = (names) => {
267
+ if (names.length === 0) {
268
+ return undefined;
269
+ }
270
+ const counts = new Map();
271
+ const firstIndex = new Map();
272
+ names.forEach((name, index) => {
273
+ counts.set(name, (counts.get(name) ?? 0) + 1);
274
+ if (!firstIndex.has(name)) {
275
+ firstIndex.set(name, index);
276
+ }
277
+ });
278
+ return [...counts.entries()].sort((a, b) => {
279
+ if (a[1] !== b[1]) {
280
+ return b[1] - a[1];
281
+ }
282
+ return (firstIndex.get(a[0]) ?? Number.POSITIVE_INFINITY) - (firstIndex.get(b[0]) ?? Number.POSITIVE_INFINITY);
283
+ })[0]?.[0];
284
+ };
285
+ const renameParameters = (parameters, renameMap) => {
286
+ if (!parameters || renameMap.size === 0) {
287
+ return parameters;
288
+ }
289
+ const mergedParameters = new Map();
290
+ parameters.forEach((parameter, index) => {
291
+ if (!parameter || '$ref' in parameter) {
292
+ mergedParameters.set(`$ref/${index}`, parameter);
293
+ return;
294
+ }
295
+ const nextName = parameter.in === 'path' ? (renameMap.get(parameter.name) ?? parameter.name) : parameter.name;
296
+ const renamedParameter = nextName === parameter.name ? parameter : { ...parameter, name: nextName };
297
+ const parameterKey = `${renamedParameter.name}/${renamedParameter.in}`;
298
+ const existingParameter = mergedParameters.get(parameterKey);
299
+ if (!existingParameter || '$ref' in existingParameter || '$ref' in renamedParameter) {
300
+ mergedParameters.set(parameterKey, renamedParameter);
301
+ return;
302
+ }
303
+ mergedParameters.set(parameterKey, {
304
+ ...existingParameter,
305
+ ...renamedParameter,
306
+ examples: {
307
+ ...(existingParameter.examples ?? {}),
308
+ ...(renamedParameter.examples ?? {}),
309
+ },
310
+ });
311
+ });
312
+ return [...mergedParameters.values()];
313
+ };
314
+ const renamePathParametersForOperation = (operation, renameMap) => {
315
+ if (!operation.parameters || renameMap.size === 0) {
316
+ return operation;
317
+ }
318
+ return {
319
+ ...operation,
320
+ parameters: renameParameters(operation.parameters, renameMap),
321
+ };
322
+ };
323
+ const renamePathItemParameterNames = (pathItem, sourceNames, targetNames) => {
324
+ const renameMap = new Map();
325
+ sourceNames.forEach((sourceName, index) => {
326
+ const targetName = targetNames[index];
327
+ if (sourceName && targetName && sourceName !== targetName) {
328
+ renameMap.set(sourceName, targetName);
329
+ }
330
+ });
331
+ if (renameMap.size === 0) {
332
+ return pathItem;
333
+ }
334
+ const renamedPathItem = {
335
+ ...pathItem,
336
+ parameters: renameParameters(pathItem.parameters, renameMap),
337
+ };
338
+ OPERATION_KEYS.forEach((operationKey) => {
339
+ const operation = pathItem[operationKey];
340
+ if (!operation) {
341
+ return;
342
+ }
343
+ renamedPathItem[operationKey] = renamePathParametersForOperation(operation, renameMap);
344
+ });
345
+ return renamedPathItem;
346
+ };
347
+ const findFolderTemplateHint = (pathItemGroup, signature) => {
348
+ for (const { pathItem, parameterNames } of pathItemGroup) {
349
+ for (const operationKey of OPERATION_KEYS) {
350
+ const operation = pathItem[operationKey];
351
+ if (!operation) {
352
+ continue;
353
+ }
354
+ for (const tag of operation.tags ?? []) {
355
+ const folderNames = tag.split(' > ').map((segment) => segment.trim());
356
+ for (const folderName of folderNames) {
357
+ if (!folderName.startsWith('/')) {
358
+ continue;
359
+ }
360
+ const normalizedFolderName = normalizePath(folderName);
361
+ if (getPathStructuralSignature(normalizedFolderName) !== signature) {
362
+ continue;
363
+ }
364
+ const folderParameterNames = getOrderedPathParameterNames(normalizedFolderName);
365
+ if (folderParameterNames.length === parameterNames.length) {
366
+ return folderParameterNames;
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ return undefined;
373
+ };
374
+ const unifyEquivalentPathParameters = (paths) => {
375
+ const pathEntries = Object.entries(paths).filter((entry) => Boolean(entry[1]));
376
+ const groups = new Map();
377
+ pathEntries.forEach(([pathKey, pathItem]) => {
378
+ const signature = getPathStructuralSignature(pathKey);
379
+ if (!groups.has(signature)) {
380
+ groups.set(signature, []);
381
+ }
382
+ groups.get(signature)?.push({
383
+ pathKey,
384
+ pathItem,
385
+ parameterNames: getOrderedPathParameterNames(pathKey),
386
+ });
387
+ });
388
+ const unifiedPaths = {};
389
+ const canonicalPathByPath = new Map();
390
+ const processedPathKeys = new Set();
391
+ pathEntries.forEach(([pathKey]) => {
392
+ if (processedPathKeys.has(pathKey)) {
393
+ return;
394
+ }
395
+ const signature = getPathStructuralSignature(pathKey);
396
+ const group = groups.get(signature) ?? [];
397
+ if (group.length < 2) {
398
+ const pathItem = paths[pathKey];
399
+ if (pathItem) {
400
+ unifiedPaths[pathKey] = pathItem;
401
+ canonicalPathByPath.set(pathKey, pathKey);
402
+ }
403
+ processedPathKeys.add(pathKey);
404
+ return;
405
+ }
406
+ const firstGroupEntry = group[0];
407
+ if (!firstGroupEntry || firstGroupEntry.pathKey !== pathKey) {
408
+ return;
409
+ }
410
+ const parameterCount = firstGroupEntry.parameterNames.length;
411
+ const folderTemplateHint = findFolderTemplateHint(group, signature);
412
+ const canonicalParameterNames = folderTemplateHint ??
413
+ Array.from({ length: parameterCount }, (_, parameterIndex) => {
414
+ const namesInOrder = group
415
+ .map((entry) => entry.parameterNames[parameterIndex])
416
+ .filter((name) => Boolean(name));
417
+ return chooseMostCommonName(namesInOrder) ?? namesInOrder[0] ?? '';
418
+ });
419
+ const canonicalPath = rewritePathParameterNames(firstGroupEntry.pathKey, canonicalParameterNames);
420
+ group.forEach(({ pathKey: groupedPathKey, pathItem, parameterNames }) => {
421
+ const normalizedPathItem = renamePathItemParameterNames(pathItem, parameterNames, canonicalParameterNames);
422
+ mergePathItem(unifiedPaths, canonicalPath, normalizedPathItem, true);
423
+ canonicalPathByPath.set(groupedPathKey, canonicalPath);
424
+ processedPathKeys.add(groupedPathKey);
425
+ });
426
+ });
427
+ return { paths: unifiedPaths, canonicalPathByPath };
428
+ };
243
429
  /**
244
430
  * Converts a Postman Collection to an OpenAPI 3.1.0 document.
245
431
  * This function processes the collection's information, servers, authentication,
@@ -306,7 +492,7 @@ export function convert(postmanCollection, options = { mergeOperation: false })
306
492
  continue;
307
493
  }
308
494
  const parentTags = collectParentTagSegments(collection.item, path);
309
- const { paths: itemPaths, components: itemComponents, serverUsage, } = processItem(node, DEFAULT_EXAMPLE_NAME, parentTags, '');
495
+ const { paths: itemPaths, components: itemComponents, serverUsage, } = processItem(node, DEFAULT_EXAMPLE_NAME, parentTags, '', mergeOperation);
310
496
  allServerUsage.push(...serverUsage);
311
497
  for (const [pathKey, pathItem] of Object.entries(itemPaths)) {
312
498
  const normalizedPathKey = normalizePath(pathKey);
@@ -324,7 +510,7 @@ export function convert(postmanCollection, options = { mergeOperation: false })
324
510
  const tags = extractTags(collection.item);
325
511
  assignTagsFromPostman(openapi, tags, isMergingIntoBase);
326
512
  collection.item.forEach((item) => {
327
- const { paths: itemPaths, components: itemComponents, serverUsage } = processItem(item, DEFAULT_EXAMPLE_NAME);
513
+ const { paths: itemPaths, components: itemComponents, serverUsage, } = processItem(item, DEFAULT_EXAMPLE_NAME, [], '', mergeOperation);
328
514
  allServerUsage.push(...serverUsage);
329
515
  openapi.paths = openapi.paths || {};
330
516
  for (const [pathKey, pathItem] of Object.entries(itemPaths)) {
@@ -341,6 +527,20 @@ export function convert(postmanCollection, options = { mergeOperation: false })
341
527
  }
342
528
  }
343
529
  // Extract all unique paths from the document
530
+ let canonicalPathByPath = new Map();
531
+ if (openapi.paths) {
532
+ const unificationResult = unifyEquivalentPathParameters(openapi.paths);
533
+ openapi.paths = unificationResult.paths;
534
+ canonicalPathByPath = unificationResult.canonicalPathByPath;
535
+ }
536
+ const normalizedServerUsage = allServerUsage.map((usage) => {
537
+ const normalizedUsagePath = normalizePath(usage.path);
538
+ return {
539
+ ...usage,
540
+ path: canonicalPathByPath.get(normalizedUsagePath) ?? normalizedUsagePath,
541
+ };
542
+ });
543
+ // Extract all unique paths from the document
344
544
  const allUniquePaths = new Set();
345
545
  if (openapi.paths) {
346
546
  for (const pathKey of Object.keys(openapi.paths)) {
@@ -348,7 +548,7 @@ export function convert(postmanCollection, options = { mergeOperation: false })
348
548
  }
349
549
  }
350
550
  // Analyze server distribution and place servers at appropriate levels
351
- const serverPlacement = analyzeServerDistribution(allServerUsage, allUniquePaths);
551
+ const serverPlacement = analyzeServerDistribution(normalizedServerUsage, allUniquePaths);
352
552
  // Add servers to document level
353
553
  if (serverPlacement.document.length > 0) {
354
554
  openapi.servers = isMergingIntoBase
@@ -1 +1 @@
1
- {"version":3,"file":"merge-operation.d.ts","sourceRoot":"","sources":["../../src/helpers/merge-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,eAAe,GAC1B,YAAY,WAAW,CAAC,eAAe,EACvC,YAAY,WAAW,CAAC,eAAe,KACtC,WAAW,CAAC,eAiFd,CAAA"}
1
+ {"version":3,"file":"merge-operation.d.ts","sourceRoot":"","sources":["../../src/helpers/merge-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAmBxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,eAAe,GAC1B,YAAY,WAAW,CAAC,eAAe,EACvC,YAAY,WAAW,CAAC,eAAe,KACtC,WAAW,CAAC,eA0Gd,CAAA"}
@@ -1,3 +1,14 @@
1
+ import { POSTMAN_EXAMPLE_NAME_EXTENSION, POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION, POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION, } from './path-items.js';
2
+ const SCRIPT_MERGE_CONFIG = [
3
+ {
4
+ extensionKey: POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION,
5
+ outputKey: 'x-pre-request',
6
+ },
7
+ {
8
+ extensionKey: POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION,
9
+ outputKey: 'x-post-response',
10
+ },
11
+ ];
1
12
  /**
2
13
  * Merges two OpenAPI OperationObject instances.
3
14
  * Assumes that all example names (keys in the 'examples' objects) are unique across both operations.
@@ -102,12 +113,20 @@ export const mergeOperations = (operation1, operation2) => {
102
113
  const mediaTypeObj = mediaType;
103
114
  if (contentMediaTypeMap.has(contentType)) {
104
115
  const existingMediaType = contentMediaTypeMap.get(contentType);
105
- if (existingMediaType && (existingMediaType.examples || mediaTypeObj.examples)) {
116
+ if (existingMediaType) {
117
+ if (mediaTypeObj.schema) {
118
+ existingMediaType.schema = mediaTypeObj.schema;
119
+ }
120
+ if (mediaTypeObj.example !== undefined && existingMediaType.example === undefined) {
121
+ existingMediaType.example = mediaTypeObj.example;
122
+ }
106
123
  // Assumption: example names (keys) are unique, so this merge is safe
107
- existingMediaType.examples = {
108
- ...existingMediaType.examples,
109
- ...mediaTypeObj.examples,
110
- };
124
+ if (existingMediaType.examples || mediaTypeObj.examples) {
125
+ existingMediaType.examples = {
126
+ ...existingMediaType.examples,
127
+ ...mediaTypeObj.examples,
128
+ };
129
+ }
111
130
  }
112
131
  }
113
132
  else {
@@ -121,5 +140,101 @@ export const mergeOperations = (operation1, operation2) => {
121
140
  content: Object.fromEntries(contentMediaTypeMap),
122
141
  };
123
142
  }
143
+ operation.responses = {
144
+ ...(operation1.responses ?? {}),
145
+ ...(operation.responses ?? {}),
146
+ };
147
+ operation.summary = mergeSummary(operation1.summary, operation.summary);
148
+ operation.description = mergeDescription(operation1.description, operation.description);
149
+ for (const config of SCRIPT_MERGE_CONFIG) {
150
+ const mergedScripts = mergeScriptsBySource(operation1, operation, config.extensionKey, config.outputKey);
151
+ if (mergedScripts) {
152
+ operation[config.extensionKey] = mergedScripts;
153
+ }
154
+ else {
155
+ delete operation[config.extensionKey];
156
+ }
157
+ updateRenderedScript(operation, config.extensionKey, config.outputKey);
158
+ }
124
159
  return operation;
125
160
  };
161
+ const mergeSummary = (firstSummary, secondSummary) => {
162
+ const first = firstSummary?.trim();
163
+ const second = secondSummary?.trim();
164
+ if (!first && !second) {
165
+ return undefined;
166
+ }
167
+ if (!first) {
168
+ return second;
169
+ }
170
+ if (!second) {
171
+ return first;
172
+ }
173
+ if (first.length < second.length) {
174
+ return first;
175
+ }
176
+ return second;
177
+ };
178
+ const mergeDescription = (firstDescription, secondDescription) => {
179
+ const values = [firstDescription?.trim(), secondDescription?.trim()].filter((candidate) => Boolean(candidate && candidate.length > 0));
180
+ if (values.length === 0) {
181
+ return undefined;
182
+ }
183
+ const unique = Array.from(new Set(values));
184
+ return unique.join('\n\n');
185
+ };
186
+ const mergeScriptsBySource = (operation1, operation2, extensionKey, outputKey) => {
187
+ const scripts = new Map();
188
+ const operation1HasScriptMap = addScriptsToMap(scripts, operation1[extensionKey]);
189
+ if (!operation1HasScriptMap) {
190
+ addLegacyScriptToMap(scripts, operation1, outputKey);
191
+ }
192
+ const operation2HasScriptMap = addScriptsToMap(scripts, operation2[extensionKey]);
193
+ if (!operation2HasScriptMap) {
194
+ addLegacyScriptToMap(scripts, operation2, outputKey);
195
+ }
196
+ if (scripts.size === 0) {
197
+ return undefined;
198
+ }
199
+ return Object.fromEntries(scripts);
200
+ };
201
+ const addScriptsToMap = (target, source) => {
202
+ if (!source || typeof source !== 'object' || Array.isArray(source)) {
203
+ return false;
204
+ }
205
+ let hasScripts = false;
206
+ for (const [name, script] of Object.entries(source)) {
207
+ if (!name || typeof script !== 'string' || script.length === 0) {
208
+ continue;
209
+ }
210
+ target.set(name, script);
211
+ hasScripts = true;
212
+ }
213
+ return hasScripts;
214
+ };
215
+ const addLegacyScriptToMap = (target, operation, outputKey) => {
216
+ const legacyScript = operation[outputKey];
217
+ if (typeof legacyScript !== 'string' || legacyScript.length === 0) {
218
+ return;
219
+ }
220
+ const sourceName = typeof operation[POSTMAN_EXAMPLE_NAME_EXTENSION] === 'string' &&
221
+ operation[POSTMAN_EXAMPLE_NAME_EXTENSION].length > 0
222
+ ? operation[POSTMAN_EXAMPLE_NAME_EXTENSION]
223
+ : 'Default example';
224
+ target.set(sourceName, legacyScript);
225
+ };
226
+ const updateRenderedScript = (operation, extensionKey, scriptKey) => {
227
+ const scripts = operation[extensionKey];
228
+ if (!scripts || typeof scripts !== 'object' || Array.isArray(scripts)) {
229
+ delete operation[scriptKey];
230
+ return;
231
+ }
232
+ const sections = Object.entries(scripts)
233
+ .filter((entry) => typeof entry[0] === 'string' && typeof entry[1] === 'string')
234
+ .map(([sourceName, script]) => `// --- ${sourceName} ---\n${script}`);
235
+ if (sections.length === 0) {
236
+ delete operation[scriptKey];
237
+ return;
238
+ }
239
+ operation[scriptKey] = sections.join('\n\n');
240
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"merge-path-item.d.ts","sourceRoot":"","sources":["../../src/helpers/merge-path-item.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAOxD,eAAO,MAAM,oBAAoB,oBAAoB,CAAA;AAErD,eAAO,MAAM,cAAc,EAAE,SAAS,CAAC,MAAM,WAAW,CAAC,cAAc,CAAC,EASvE,CAAA;AAED,eAAO,MAAM,aAAa,GACxB,OAAO,WAAW,CAAC,WAAW,EAC9B,mBAAmB,MAAM,EACzB,UAAU,WAAW,CAAC,cAAc,EACpC,iBAAgB,OAAe,KAC9B,IA8BF,CAAA"}
1
+ {"version":3,"file":"merge-path-item.d.ts","sourceRoot":"","sources":["../../src/helpers/merge-path-item.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAYxD,eAAO,MAAM,oBAAoB,oBAAoB,CAAA;AAErD,eAAO,MAAM,cAAc,EAAE,SAAS,CAAC,MAAM,WAAW,CAAC,cAAc,CAAC,EASvE,CAAA;AAED,eAAO,MAAM,aAAa,GACxB,OAAO,WAAW,CAAC,WAAW,EAC9B,mBAAmB,MAAM,EACzB,UAAU,WAAW,CAAC,cAAc,EACpC,iBAAgB,OAAe,KAC9B,IAuCF,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { generateUniqueValue } from '../helpers/generate-unique-value.js';
2
2
  import { getOperationExamples } from '../helpers/get-operation-examples.js';
3
3
  import { mergeOperations } from '../helpers/merge-operation.js';
4
+ import { POSTMAN_EXAMPLE_NAME_EXTENSION, POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION, POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION, } from '../helpers/path-items.js';
4
5
  import { renameOperationExamples } from '../helpers/rename-operation-example.js';
5
6
  export const DEFAULT_EXAMPLE_NAME = 'Default example';
6
7
  export const OPERATION_KEYS = [
@@ -21,17 +22,40 @@ export const mergePathItem = (paths, normalizedPathKey, pathItem, mergeOperation
21
22
  }
22
23
  const isOperationKey = OPERATION_KEYS.includes(key);
23
24
  if (isOperationKey && targetPath[key] && mergeOperation) {
25
+ const incomingOperation = pathItem[key];
26
+ const sourceName = typeof incomingOperation[POSTMAN_EXAMPLE_NAME_EXTENSION] === 'string'
27
+ ? incomingOperation[POSTMAN_EXAMPLE_NAME_EXTENSION]
28
+ : DEFAULT_EXAMPLE_NAME;
24
29
  // Get all example names from the target path
25
30
  const exampleNames = getOperationExamples(targetPath);
26
31
  // Generate a unique example name
27
- const newExampleName = generateUniqueValue(DEFAULT_EXAMPLE_NAME, (value) => !exampleNames.has(value), '#');
28
- // Rename operation examples from the new path item (we know it's gonna have only the default example)
29
- renameOperationExamples(pathItem[key], DEFAULT_EXAMPLE_NAME, newExampleName);
32
+ const newExampleName = generateUniqueValue(sourceName, (value) => !exampleNames.has(value), '#');
33
+ // Rename operation examples from the new path item if this source name already exists
34
+ renameOperationExamples(incomingOperation, sourceName, newExampleName);
35
+ updateExtensionKey(incomingOperation, POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION, sourceName, newExampleName);
36
+ updateExtensionKey(incomingOperation, POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION, sourceName, newExampleName);
37
+ incomingOperation[POSTMAN_EXAMPLE_NAME_EXTENSION] = newExampleName;
30
38
  // Merge the operations
31
- targetPath[key] = mergeOperations(targetPath[key], pathItem[key]);
39
+ targetPath[key] = mergeOperations(targetPath[key], incomingOperation);
32
40
  continue;
33
41
  }
34
42
  targetPath[key] = value;
35
43
  }
36
44
  paths[normalizedPathKey] = targetPath;
37
45
  };
46
+ const updateExtensionKey = (operation, extensionKey, oldKey, newKey) => {
47
+ if (oldKey === newKey) {
48
+ return;
49
+ }
50
+ const map = operation[extensionKey];
51
+ if (!map || typeof map !== 'object' || Array.isArray(map)) {
52
+ return;
53
+ }
54
+ const castedMap = map;
55
+ const value = castedMap[oldKey];
56
+ if (value === undefined) {
57
+ return;
58
+ }
59
+ delete castedMap[oldKey];
60
+ castedMap[newKey] = value;
61
+ };
@@ -1,6 +1,9 @@
1
1
  import type { OpenAPIV3_1 } from '@scalar/openapi-types';
2
2
  import type { Item, ItemGroup } from '../types.js';
3
3
  type HttpMethods = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace';
4
+ export declare const POSTMAN_EXAMPLE_NAME_EXTENSION = "x-postman-example-name";
5
+ export declare const POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION = "x-postman-pre-request-scripts";
6
+ export declare const POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION = "x-postman-post-response-scripts";
4
7
  /**
5
8
  * Information about server usage for an operation.
6
9
  */
@@ -15,10 +18,14 @@ export type ServerUsage = {
15
18
  * Handles nested item groups, extracts request details, and generates corresponding
16
19
  * OpenAPI path items and operations.
17
20
  */
18
- export declare function processItem(item: Item | ItemGroup, exampleName?: string, parentTags?: string[], parentPath?: string): {
21
+ export declare function processItem(item: Item | ItemGroup, exampleName?: string, parentTags?: string[], parentPath?: string, preserveCollapsedVariants?: boolean): {
19
22
  paths: OpenAPIV3_1.PathsObject;
20
23
  components: OpenAPIV3_1.ComponentsObject;
21
24
  serverUsage: ServerUsage[];
22
25
  };
26
+ export declare function parseStatusCodeFromRequestName(requestName: string | undefined): {
27
+ statusCode: string;
28
+ description: string;
29
+ } | null;
23
30
  export {};
24
31
  //# sourceMappingURL=path-items.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-items.d.ts","sourceRoot":"","sources":["../../src/helpers/path-items.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAW9C,KAAK,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAE7F;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,WAAW,CAAA;CACpB,CAAA;AAoBD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,GAAG,SAAS,EACtB,WAAW,GAAE,MAAkB,EAC/B,UAAU,GAAE,MAAM,EAAO,EACzB,UAAU,GAAE,MAAW,GACtB;IACD,KAAK,EAAE,WAAW,CAAC,WAAW,CAAA;IAC9B,UAAU,EAAE,WAAW,CAAC,gBAAgB,CAAA;IACxC,WAAW,EAAE,WAAW,EAAE,CAAA;CAC3B,CA2KA"}
1
+ {"version":3,"file":"path-items.d.ts","sourceRoot":"","sources":["../../src/helpers/path-items.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAW9C,KAAK,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAE7F,eAAO,MAAM,8BAA8B,2BAA2B,CAAA;AACtE,eAAO,MAAM,qCAAqC,kCAAkC,CAAA;AACpF,eAAO,MAAM,uCAAuC,oCAAoC,CAAA;AAExF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,WAAW,CAAA;CACpB,CAAA;AAoBD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,GAAG,SAAS,EACtB,WAAW,GAAE,MAAkB,EAC/B,UAAU,GAAE,MAAM,EAAO,EACzB,UAAU,GAAE,MAAW,EACvB,yBAAyB,GAAE,OAAe,GACzC;IACD,KAAK,EAAE,WAAW,CAAC,WAAW,CAAA;IAC9B,UAAU,EAAE,WAAW,CAAC,gBAAgB,CAAA;IACxC,WAAW,EAAE,WAAW,EAAE,CAAA;CAC3B,CAoMA;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkCpD"}
@@ -4,8 +4,11 @@ import { extractParameters } from './parameters.js';
4
4
  import { processPostResponseScripts } from './post-response-scripts.js';
5
5
  import { processPreRequestScripts } from './pre-request-scripts.js';
6
6
  import { extractRequestBody } from './request-body.js';
7
- import { extractResponses } from './responses.js';
7
+ import { DEFAULT_RESPONSE_DESCRIPTIONS, extractResponses } from './responses.js';
8
8
  import { extractPathFromUrl, extractPathParameterNames, extractServerFromUrl, normalizePath } from './urls.js';
9
+ export const POSTMAN_EXAMPLE_NAME_EXTENSION = 'x-postman-example-name';
10
+ export const POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION = 'x-postman-pre-request-scripts';
11
+ export const POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION = 'x-postman-post-response-scripts';
9
12
  function ensureRequestBodyContent(requestBody) {
10
13
  const content = requestBody.content ?? {};
11
14
  if (Object.keys(content).length === 0) {
@@ -27,14 +30,14 @@ function ensureRequestBodyContent(requestBody) {
27
30
  * Handles nested item groups, extracts request details, and generates corresponding
28
31
  * OpenAPI path items and operations.
29
32
  */
30
- export function processItem(item, exampleName = 'default', parentTags = [], parentPath = '') {
33
+ export function processItem(item, exampleName = 'default', parentTags = [], parentPath = '', preserveCollapsedVariants = false) {
31
34
  const paths = {};
32
35
  const components = {};
33
36
  const serverUsage = [];
34
37
  if ('item' in item && Array.isArray(item.item)) {
35
38
  const newParentTags = item.name ? [...parentTags, item.name] : parentTags;
36
39
  item.item.forEach((childItem) => {
37
- const childResult = processItem(childItem, exampleName, newParentTags, `${parentPath}/${item.name || ''}`);
40
+ const childResult = processItem(childItem, exampleName, newParentTags, `${parentPath}/${item.name || ''}`, preserveCollapsedVariants);
38
41
  // Merge child paths and components
39
42
  for (const [pathKey, pathItem] of Object.entries(childResult.paths)) {
40
43
  if (!paths[pathKey]) {
@@ -63,6 +66,8 @@ export function processItem(item, exampleName = 'default', parentTags = [], pare
63
66
  return { paths, components, serverUsage };
64
67
  }
65
68
  const { request, name, response } = item;
69
+ const sourceRequestName = name?.trim() || exampleName;
70
+ const operationExampleName = preserveCollapsedVariants ? sourceRequestName : exampleName;
66
71
  const method = (typeof request === 'string' ? 'get' : request.method || 'get').toLowerCase();
67
72
  const requestUrl = typeof request === 'string' ? request : typeof request.url === 'string' ? request.url : (request.url?.raw ?? '');
68
73
  const path = extractPathFromUrl(requestUrl);
@@ -93,15 +98,28 @@ export function processItem(item, exampleName = 'default', parentTags = [], pare
93
98
  responses: extractResponses(response || [], item),
94
99
  parameters: [],
95
100
  };
101
+ if (preserveCollapsedVariants) {
102
+ operationObject[POSTMAN_EXAMPLE_NAME_EXTENSION] = sourceRequestName;
103
+ }
96
104
  // Add pre-request scripts if present
97
105
  const preRequestScript = processPreRequestScripts(item.event);
98
106
  if (preRequestScript) {
99
107
  operationObject['x-pre-request'] = preRequestScript;
108
+ if (preserveCollapsedVariants) {
109
+ operationObject[POSTMAN_PRE_REQUEST_SCRIPTS_EXTENSION] = {
110
+ [sourceRequestName]: preRequestScript,
111
+ };
112
+ }
100
113
  }
101
114
  // Add post-response scripts if present
102
115
  const postResponseScript = processPostResponseScripts(item.event);
103
116
  if (postResponseScript) {
104
117
  operationObject['x-post-response'] = postResponseScript;
118
+ if (preserveCollapsedVariants) {
119
+ operationObject[POSTMAN_POST_RESPONSE_SCRIPTS_EXTENSION] = {
120
+ [sourceRequestName]: postResponseScript,
121
+ };
122
+ }
105
123
  }
106
124
  // Only add operationId if it was explicitly provided
107
125
  if (operationId) {
@@ -109,7 +127,7 @@ export function processItem(item, exampleName = 'default', parentTags = [], pare
109
127
  }
110
128
  // Extract parameters from the request (query, path, header)
111
129
  // This should always happen, regardless of whether a description exists
112
- const extractedParameters = extractParameters(request, exampleName);
130
+ const extractedParameters = extractParameters(request, operationExampleName);
113
131
  // Merge parameters, giving priority to those from the Markdown table if description exists
114
132
  const mergedParameters = new Map();
115
133
  // Add extracted parameters, filtering out path parameters not in the path
@@ -156,7 +174,7 @@ export function processItem(item, exampleName = 'default', parentTags = [], pare
156
174
  }
157
175
  // Allow request bodies for all methods (including GET) if body is present
158
176
  if (typeof request !== 'string' && request.body) {
159
- const requestBody = extractRequestBody(request.body, exampleName);
177
+ const requestBody = extractRequestBody(request.body, operationExampleName);
160
178
  ensureRequestBodyContent(requestBody);
161
179
  // Only add requestBody if it has content
162
180
  if (requestBody.content && Object.keys(requestBody.content).length > 0) {
@@ -168,8 +186,40 @@ export function processItem(item, exampleName = 'default', parentTags = [], pare
168
186
  }
169
187
  const pathItem = paths[path];
170
188
  pathItem[method] = operationObject;
189
+ if (preserveCollapsedVariants) {
190
+ addResponseFromRequestName(pathItem[method], name);
191
+ }
171
192
  return { paths, components, serverUsage };
172
193
  }
194
+ export function parseStatusCodeFromRequestName(requestName) {
195
+ if (!requestName) {
196
+ return null;
197
+ }
198
+ const trimmedStart = requestName.trimStart();
199
+ if (trimmedStart.length < 4) {
200
+ return null;
201
+ }
202
+ const statusCode = trimmedStart.slice(0, 3);
203
+ if (!isThreeDigitStatusCode(statusCode)) {
204
+ return null;
205
+ }
206
+ let separatorIndex = 3;
207
+ while (trimmedStart[separatorIndex] === ' ') {
208
+ separatorIndex += 1;
209
+ }
210
+ const separator = trimmedStart[separatorIndex];
211
+ if (separator !== '-' && separator !== ':') {
212
+ return null;
213
+ }
214
+ let descriptionIndex = separatorIndex + 1;
215
+ while (trimmedStart[descriptionIndex] === ' ') {
216
+ descriptionIndex += 1;
217
+ }
218
+ return {
219
+ statusCode,
220
+ description: trimmedStart.slice(descriptionIndex).trim() || 'Response',
221
+ };
222
+ }
173
223
  /** OpenAPI 3.1 parameter schema types (ParameterObject uses OpenAPIV3_1). */
174
224
  const OPENAPI_PARAM_SCHEMA_TYPES = ['string', 'number', 'integer', 'boolean', 'object', 'array'];
175
225
  function toOpenApiParamSchemaType(s) {
@@ -259,3 +309,37 @@ function extractOperationInfo(name) {
259
309
  const summary = name.substring(0, lastBracketIndex).trim();
260
310
  return { operationId, summary };
261
311
  }
312
+ function addResponseFromRequestName(operationObject, requestName) {
313
+ const parsedStatus = parseStatusCodeFromRequestName(requestName);
314
+ if (!parsedStatus) {
315
+ return;
316
+ }
317
+ operationObject.responses = operationObject.responses ?? {};
318
+ const existingResponse = operationObject.responses[parsedStatus.statusCode];
319
+ if (!existingResponse) {
320
+ operationObject.responses[parsedStatus.statusCode] = { description: parsedStatus.description };
321
+ return;
322
+ }
323
+ const defaultDescriptions = new Set([
324
+ 'Successful response',
325
+ 'Response',
326
+ ...Object.values(DEFAULT_RESPONSE_DESCRIPTIONS),
327
+ ]);
328
+ if (typeof existingResponse === 'object' &&
329
+ !('$ref' in existingResponse) &&
330
+ defaultDescriptions.has(existingResponse.description ?? '')) {
331
+ existingResponse.description = parsedStatus.description;
332
+ }
333
+ }
334
+ function isThreeDigitStatusCode(value) {
335
+ if (value.length !== 3) {
336
+ return false;
337
+ }
338
+ for (let index = 0; index < value.length; index += 1) {
339
+ const charCode = value.charCodeAt(index);
340
+ if (charCode < 48 || charCode > 57) {
341
+ return false;
342
+ }
343
+ }
344
+ return true;
345
+ }
@@ -25,21 +25,8 @@ export function extractRequestBody(body, exampleName) {
25
25
  function handleRawBody(body, requestBody, exampleName) {
26
26
  const rawBody = body.raw || '';
27
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
28
  // If we have valid JSON, use it
42
- if (isJsonBody) {
29
+ if (isJsonLanguage) {
43
30
  requestBody.content = {
44
31
  'application/json': {
45
32
  schema: {
@@ -47,26 +34,13 @@ function handleRawBody(body, requestBody, exampleName) {
47
34
  },
48
35
  examples: {
49
36
  [exampleName]: {
50
- value: jsonBody,
37
+ value: rawBody,
51
38
  },
52
39
  },
53
40
  },
54
41
  };
55
42
  return;
56
43
  }
57
- // If we have variables and JSON language but could not parse JSON,
58
- // create a JSON schema placeholder
59
- if (hasVariables && isJsonLanguage) {
60
- requestBody.content = {
61
- 'application/json': {
62
- schema: {
63
- type: 'object',
64
- description: 'Body data set via pre-request script',
65
- },
66
- },
67
- };
68
- return;
69
- }
70
44
  // Fallback to text/plain
71
45
  requestBody.content = {
72
46
  'text/plain': {
@@ -1,5 +1,6 @@
1
1
  import type { OpenAPIV3_1 } from '@scalar/openapi-types';
2
2
  import type { Item, Response } from '../types.js';
3
+ export declare const DEFAULT_RESPONSE_DESCRIPTIONS: Record<string, string>;
3
4
  /**
4
5
  * Extracts and converts Postman response objects to OpenAPI response objects.
5
6
  * Processes response status codes, descriptions, headers, and body content,
@@ -1 +1 @@
1
- {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../src/helpers/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAc,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAKzD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC,eAAe,GAAG,SAAS,CAwC5G"}
1
+ {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../src/helpers/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAc,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAKzD,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAchE,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,WAAW,CAAC,eAAe,GAAG,SAAS,CAwC5G"}
@@ -1,5 +1,20 @@
1
1
  import { inferSchemaFromExample } from './schemas.js';
2
2
  import { extractStatusCodesFromTests } from './status-codes.js';
3
+ export const DEFAULT_RESPONSE_DESCRIPTIONS = {
4
+ 200: 'OK',
5
+ 201: 'Created',
6
+ 202: 'Accepted',
7
+ 204: 'No content',
8
+ 301: 'Moved permanently',
9
+ 400: 'Bad request',
10
+ 401: 'Unauthorized',
11
+ 403: 'Forbidden',
12
+ 404: 'Not found',
13
+ 409: 'Conflict',
14
+ 422: 'Unprocessable entity',
15
+ 500: 'Internal server error',
16
+ default: 'Default response',
17
+ };
3
18
  /**
4
19
  * Extracts and converts Postman response objects to OpenAPI response objects.
5
20
  * Processes response status codes, descriptions, headers, and body content,
@@ -12,7 +27,7 @@ export function extractResponses(responses, item) {
12
27
  const responseMap = responses.reduce((acc, response) => {
13
28
  const statusCode = response.code?.toString() || 'default';
14
29
  acc[statusCode] = {
15
- description: response.status || 'Successful response',
30
+ description: getResponseDescription(response, statusCode),
16
31
  headers: extractHeaders(response.header),
17
32
  content: {
18
33
  'application/json': {
@@ -30,7 +45,7 @@ export function extractResponses(responses, item) {
30
45
  const codeStr = code.toString();
31
46
  if (!responseMap[codeStr]) {
32
47
  responseMap[codeStr] = {
33
- description: 'Successful response',
48
+ description: getDefaultResponseDescription(codeStr),
34
49
  content: {
35
50
  'application/json': {},
36
51
  },
@@ -42,6 +57,49 @@ export function extractResponses(responses, item) {
42
57
  }
43
58
  return responseMap;
44
59
  }
60
+ function getResponseDescription(response, statusCode) {
61
+ const descriptionFromName = extractDescriptionFromName(response.name, statusCode);
62
+ if (descriptionFromName) {
63
+ return descriptionFromName;
64
+ }
65
+ if (response.status) {
66
+ return response.status;
67
+ }
68
+ return getDefaultResponseDescription(statusCode);
69
+ }
70
+ function extractDescriptionFromName(name, statusCode) {
71
+ if (!name) {
72
+ return undefined;
73
+ }
74
+ const trimmedName = name.trim();
75
+ const separatorIndex = trimmedName.indexOf('-');
76
+ if (separatorIndex < 0) {
77
+ return undefined;
78
+ }
79
+ const code = trimmedName.slice(0, separatorIndex).trim();
80
+ if (!isThreeDigitStatusCode(code) || code !== statusCode) {
81
+ return undefined;
82
+ }
83
+ const description = trimmedName.slice(separatorIndex + 1).trim();
84
+ if (!description) {
85
+ return undefined;
86
+ }
87
+ return description;
88
+ }
89
+ function getDefaultResponseDescription(statusCode) {
90
+ return DEFAULT_RESPONSE_DESCRIPTIONS[statusCode] ?? DEFAULT_RESPONSE_DESCRIPTIONS.default ?? 'Default response';
91
+ }
92
+ function isThreeDigitStatusCode(value) {
93
+ if (value.length !== 3) {
94
+ return false;
95
+ }
96
+ for (const character of value) {
97
+ if (character < '0' || character > '9') {
98
+ return false;
99
+ }
100
+ }
101
+ return true;
102
+ }
45
103
  function extractHeaders(headers) {
46
104
  if (!headers || typeof headers === 'string') {
47
105
  return undefined;
@@ -11,6 +11,11 @@ export declare function extractPathFromUrl(url: string | undefined): string;
11
11
  * e.g., '/users/:id' becomes '/users/{id}'
12
12
  */
13
13
  export declare const normalizePath: (path: string) => string;
14
+ /**
15
+ * Generates a structural path signature by replacing parameter segments with `{*}`.
16
+ * Paths with the same signature are equivalent except for parameter names.
17
+ */
18
+ export declare const getPathStructuralSignature: (path: string) => string;
14
19
  /**
15
20
  * Extracts parameter names from a path string.
16
21
  * Handles double curly braces {{param}}, single curly braces {param}, and colon format :param.
@@ -1 +1 @@
1
- {"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/helpers/urls.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYlE;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAyC,CAAA;AAEtF;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAyBhF"}
1
+ {"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/helpers/urls.ts"],"names":[],"mappings":"AAgBA;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYlE;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAyC,CAAA;AAEtF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,KAAG,MAWzD,CAAA;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAyBhF"}
@@ -35,6 +35,19 @@ export function extractPathFromUrl(url) {
35
35
  * e.g., '/users/:id' becomes '/users/{id}'
36
36
  */
37
37
  export const normalizePath = (path) => path.replace(/:(\w+)/g, '{$1}');
38
+ /**
39
+ * Generates a structural path signature by replacing parameter segments with `{*}`.
40
+ * Paths with the same signature are equivalent except for parameter names.
41
+ */
42
+ export const getPathStructuralSignature = (path) => {
43
+ const normalizedPath = normalizePath(path);
44
+ if (normalizedPath === '') {
45
+ return '';
46
+ }
47
+ const segments = normalizedPath.split('/');
48
+ const signatureSegments = segments.map((segment) => (/^\{[^{}]+\}$/.test(segment) ? '{*}' : segment));
49
+ return signatureSegments.join('/');
50
+ };
38
51
  /**
39
52
  * Extracts parameter names from a path string.
40
53
  * Handles double curly braces {{param}}, single curly braces {param}, and colon format :param.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { type ConvertOptions, type PostmanRequestIndexPath, convert } from './convert.js';
2
+ export { isPostmanCollection } from './is-postman-collection.js';
2
3
  export { extractPathFromUrl, normalizePath } from './helpers/urls.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,uBAAuB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACtF,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,uBAAuB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { convert } from './convert.js';
2
+ export { isPostmanCollection } from './is-postman-collection.js';
2
3
  export { extractPathFromUrl, normalizePath } from './helpers/urls.js';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Checks whether a JSON string looks like a Postman collection.
3
+ *
4
+ * Exported collections are not guaranteed to include `_postman_id`,
5
+ * so we accept either `_postman_id` or a top-level `item` array,
6
+ * as long as the schema host matches Postman.
7
+ */
8
+ export declare const isPostmanCollection: (content: string) => boolean;
9
+ //# sourceMappingURL=is-postman-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-postman-collection.d.ts","sourceRoot":"","sources":["../src/is-postman-collection.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,OAiBrD,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Checks whether a JSON string looks like a Postman collection.
3
+ *
4
+ * Exported collections are not guaranteed to include `_postman_id`,
5
+ * so we accept either `_postman_id` or a top-level `item` array,
6
+ * as long as the schema host matches Postman.
7
+ */
8
+ export const isPostmanCollection = (content) => {
9
+ try {
10
+ const parsed = JSON.parse(content);
11
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
12
+ return false;
13
+ }
14
+ const hasPostmanId = parsed.info?._postman_id !== undefined;
15
+ const hasItemTree = Array.isArray(parsed.item);
16
+ const schema = parsed.info?.schema;
17
+ const hasValidSchema = typeof schema === 'string' && new URL(schema).host === 'schema.getpostman.com';
18
+ return hasValidSchema && (hasPostmanId || hasItemTree);
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ };
package/dist/types.d.ts CHANGED
@@ -189,6 +189,7 @@ export type FormParameter = {
189
189
  };
190
190
  export type Response = {
191
191
  id?: string;
192
+ name?: string;
192
193
  originalRequest?: Request;
193
194
  responseTime?: string | number | null;
194
195
  timings?: object | null;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -19,7 +19,7 @@
19
19
  "export",
20
20
  "scalar"
21
21
  ],
22
- "version": "0.6.1",
22
+ "version": "0.6.3",
23
23
  "engines": {
24
24
  "node": ">=22"
25
25
  },
@@ -38,17 +38,19 @@
38
38
  "CHANGELOG.md"
39
39
  ],
40
40
  "dependencies": {
41
- "@scalar/helpers": "0.4.3",
41
+ "@scalar/helpers": "0.5.1",
42
42
  "@scalar/openapi-types": "0.7.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^24.1.0",
46
- "vite": "8.0.0"
46
+ "vite": "8.0.0",
47
+ "@scalar/openapi-parser": "0.25.10"
47
48
  },
48
49
  "scripts": {
49
50
  "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
51
+ "evaluate": "tsx ./scripts/evaluate/run.ts",
50
52
  "generate:textures": "tsx ./scripts/generate-textures.ts",
51
- "test": "vitest",
53
+ "test": "vitest --run",
52
54
  "types:check": "tsc --noEmit"
53
55
  }
54
56
  }