@scalar/openapi-to-markdown 1.5.3 → 1.6.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 (43) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +27 -1
  3. package/dist/create-markdown-from-openapi.d.ts +5 -2
  4. package/dist/create-markdown-from-openapi.d.ts.map +1 -1
  5. package/dist/create-markdown-from-openapi.js +7 -3
  6. package/dist/document-anchors.d.ts.map +1 -1
  7. package/dist/document-anchors.js +4 -2
  8. package/dist/document-examples.d.ts.map +1 -1
  9. package/dist/document-examples.js +10 -5
  10. package/dist/get-markdown-examples.d.ts.map +1 -1
  11. package/dist/get-markdown-examples.js +48 -24
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/load-document.d.ts +8 -1
  15. package/dist/load-document.d.ts.map +1 -1
  16. package/dist/load-document.js +34 -23
  17. package/dist/markdown/index.d.ts +5 -0
  18. package/dist/markdown/index.d.ts.map +1 -0
  19. package/dist/markdown/index.js +4 -0
  20. package/dist/markdown-nodes.d.ts.map +1 -1
  21. package/dist/markdown-nodes.js +1 -0
  22. package/dist/parse-description.d.ts.map +1 -1
  23. package/dist/parse-description.js +36 -18
  24. package/dist/render-document.d.ts.map +1 -1
  25. package/dist/render-document.js +50 -26
  26. package/dist/render-examples.d.ts.map +1 -1
  27. package/dist/render-examples.js +8 -4
  28. package/dist/render-operation-details.d.ts.map +1 -1
  29. package/dist/render-operation-details.js +28 -14
  30. package/dist/render-operation.d.ts.map +1 -1
  31. package/dist/render-operation.js +60 -31
  32. package/dist/render-schema.d.ts.map +1 -1
  33. package/dist/render-schema.js +145 -77
  34. package/dist/render-security.d.ts.map +1 -1
  35. package/dist/render-security.js +12 -6
  36. package/dist/render-tags.d.ts +7 -0
  37. package/dist/render-tags.d.ts.map +1 -0
  38. package/dist/render-tags.js +73 -0
  39. package/dist/restore-boolean-schemas.d.ts.map +1 -1
  40. package/dist/restore-boolean-schemas.js +22 -11
  41. package/dist/select-document.d.ts.map +1 -1
  42. package/dist/select-document.js +5 -1
  43. package/package.json +14 -9
@@ -41,10 +41,12 @@ const getReferenceName = (ref) => {
41
41
  /** Only references that add nothing structural can be replaced by the schema they point to. */
42
42
  const getSharedName = (input, view) => {
43
43
  const ref = isObject(input) ? input.$ref : undefined;
44
- if (typeof ref !== 'string' || typeof view.schema !== 'object')
44
+ if (typeof ref !== 'string' || typeof view.schema !== 'object') {
45
45
  return undefined;
46
- if (Object.keys(input).some((key) => structuralKeywords.has(key)))
46
+ }
47
+ if (Object.keys(input).some((key) => structuralKeywords.has(key))) {
47
48
  return undefined;
49
+ }
48
50
  const structured = Boolean(view.allOf?.length || view.anyOf?.length || view.oneOf?.length || view.properties.length) ||
49
51
  view.not !== undefined ||
50
52
  view.items !== undefined ||
@@ -67,13 +69,16 @@ const getSharedIdentity = (input) => {
67
69
  const resolveMarkdownSchema = (input) => {
68
70
  const target = getResolvedRef(input);
69
71
  const merged = getResolvedRef(input, mergeSiblingReferences);
70
- if (typeof target !== 'boolean')
72
+ if (typeof target !== 'boolean') {
71
73
  return merged;
74
+ }
72
75
  if (!isObject(merged) ||
73
- !Object.keys(merged).some((key) => !['$ref', '$ref-value', '$global', '$status'].includes(key)))
76
+ !Object.keys(merged).some((key) => !['$ref', '$ref-value', '$global', '$status'].includes(key))) {
74
77
  return target;
75
- if (target)
78
+ }
79
+ if (target) {
76
80
  return merged;
81
+ }
77
82
  // A false target remains impossible, even when siblings describe a type or annotations.
78
83
  return { ...merged, allOf: [false, ...(Array.isArray(merged.allOf) ? merged.allOf : [])] };
79
84
  };
@@ -85,19 +90,23 @@ const wrapperKeys = new Set([...annotationKeys, ...referenceKeys, '__scalar_', '
85
90
  const primitiveTypes = new Set(['string', 'number', 'integer', 'boolean', 'null']);
86
91
  /** Infer the JSON type of a literal, for `const` and `enum` schemas that do not declare one. */
87
92
  const getJsonType = (value) => {
88
- if (value === null)
93
+ if (value === null) {
89
94
  return 'null';
90
- if (Array.isArray(value))
95
+ }
96
+ if (Array.isArray(value)) {
91
97
  return 'array';
92
- if (typeof value === 'number')
98
+ }
99
+ if (typeof value === 'number') {
93
100
  return Number.isInteger(value) ? 'integer' : 'number';
101
+ }
94
102
  return typeof value;
95
103
  };
96
104
  /** A schema that only allows `null`, as in `anyOf: [X, { type: 'null' }]`. */
97
105
  const isNullSchema = (input) => {
98
106
  const schema = getResolvedRef(input);
99
- if (!isObject(schema))
107
+ if (!isObject(schema)) {
100
108
  return false;
109
+ }
101
110
  const type = Array.isArray(schema.type) && schema.type.length === 1 ? schema.type[0] : schema.type;
102
111
  return (type === 'null' &&
103
112
  Object.keys(schema).every((key) => key === 'type' || key === 'title' || key === 'description' || referenceKeys.has(key)));
@@ -114,37 +123,40 @@ const getWrapped = (value) => {
114
123
  value.not !== undefined ||
115
124
  value.discriminator ||
116
125
  value.enum ||
117
- value.const !== undefined)
126
+ value.const !== undefined) {
118
127
  return undefined;
128
+ }
119
129
  const allOf = value.allOf ?? [];
120
130
  const anyOf = value.anyOf ?? [];
121
131
  const oneOf = value.oneOf ?? [];
122
- if (allOf.length === 1 && !anyOf.length && !oneOf.length)
132
+ if (allOf.length === 1 && !anyOf.length && !oneOf.length) {
123
133
  return { core: allOf[0], nullable: false };
134
+ }
124
135
  const union = anyOf.length ? anyOf : oneOf;
125
- if (allOf.length || (anyOf.length && oneOf.length) || union.length !== 2)
136
+ if (allOf.length || (anyOf.length && oneOf.length) || union.length !== 2) {
126
137
  return undefined;
138
+ }
127
139
  const core = union.filter((branch) => !isNullSchema(branch));
128
140
  return core.length === 1 ? { core: core[0], nullable: true } : undefined;
129
141
  };
130
142
  /** Join alternatives with `|`, keeping neighbouring plain types in one code span. */
131
143
  const joinAlternatives = (alternatives) => {
132
144
  // `array of string | null` would read as an array of nullable strings.
133
- if (alternatives.length > 1)
134
- alternatives = alternatives.map((alternative) => {
135
- const only = alternative.length === 1 ? alternative[0] : undefined;
136
- return only?.type === 'inlineCode' && only.value.startsWith('array of ')
137
- ? [inlineCode(`(${only.value})`)]
138
- : alternative;
139
- });
145
+ const groupedAlternatives = alternatives.map((alternative) => {
146
+ const only = alternative.length === 1 ? alternative[0] : undefined;
147
+ return alternatives.length > 1 && only?.type === 'inlineCode' && only.value.startsWith('array of ')
148
+ ? [inlineCode(`(${only.value})`)]
149
+ : alternative;
150
+ });
140
151
  const nodes = [];
141
152
  let plain = [];
142
153
  const flushPlain = () => {
143
- if (plain.length)
154
+ if (plain.length) {
144
155
  nodes.push(...(nodes.length ? [text(' | ')] : []), inlineCode(plain.join(' | ')));
156
+ }
145
157
  plain = [];
146
158
  };
147
- for (const alternative of alternatives) {
159
+ for (const alternative of groupedAlternatives) {
148
160
  const only = alternative.length === 1 ? alternative[0] : undefined;
149
161
  if (only?.type === 'inlineCode') {
150
162
  plain.push(only.value);
@@ -163,8 +175,9 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
163
175
  const unwrapping = new Set();
164
176
  const view = (input) => {
165
177
  const cached = typeof input === 'object' ? views.get(input) : undefined;
166
- if (cached)
178
+ if (cached) {
167
179
  return cached;
180
+ }
168
181
  // Keep the linked document's nested identities and boolean schemas. Coercing a
169
182
  // second time here would discard boolean children and copy recursive targets.
170
183
  const schema = resolveMarkdownSchema(input);
@@ -173,9 +186,10 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
173
186
  const properties = Object.entries(value.properties ?? {})
174
187
  .filter(([, child]) => typeof child === 'boolean' || (child !== null && typeof child === 'object'))
175
188
  .sort(([a], [b]) => Number(required.has(b)) - Number(required.has(a)) || a.localeCompare(b));
189
+ const booleanType = schema ? 'any' : 'never';
176
190
  let result = {
177
191
  ...value,
178
- type: typeof schema === 'boolean' ? (schema ? 'any' : 'never') : value.type,
192
+ type: typeof schema === 'boolean' ? booleanType : value.type,
179
193
  schema: schema,
180
194
  required,
181
195
  properties,
@@ -189,18 +203,21 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
189
203
  const annotations = Object.fromEntries(annotationKeys.flatMap((key) => (result[key] === undefined ? [] : [[key, result[key]]])));
190
204
  result = { ...inner, ...annotations, core: wrapped.core, nullable: wrapped.nullable || inner.nullable };
191
205
  }
192
- if (typeof input === 'object')
206
+ if (typeof input === 'object') {
193
207
  views.set(input, result);
208
+ }
194
209
  return result;
195
210
  };
196
211
  const primitives = new WeakMap();
197
212
  /** Primitives, enums, consts and aliases of them, whose whole definition fits on one line. */
198
213
  const isPrimitive = (input) => {
199
- if (typeof input !== 'object')
214
+ if (typeof input !== 'object') {
200
215
  return true;
216
+ }
201
217
  const cached = primitives.get(input);
202
- if (cached !== undefined)
218
+ if (cached !== undefined) {
203
219
  return cached;
220
+ }
204
221
  // Assume a recursive alias is not primitive while it is being checked.
205
222
  primitives.set(input, false);
206
223
  const value = view(input);
@@ -248,16 +265,21 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
248
265
  ];
249
266
  /** The declared types, or the types implied by `const`, `enum`, properties or items. */
250
267
  const getTypes = (value) => {
251
- if (value.type !== undefined)
268
+ if (value.type !== undefined) {
252
269
  return [value.type].flat();
253
- if (value.const !== undefined)
270
+ }
271
+ if (value.const !== undefined) {
254
272
  return [getJsonType(value.const)];
255
- if (value.enum?.length)
273
+ }
274
+ if (value.enum?.length) {
256
275
  return [...new Set(value.enum.map(getJsonType))];
257
- if (value.properties.length || isObject(value.additionalProperties))
276
+ }
277
+ if (value.properties.length || isObject(value.additionalProperties)) {
258
278
  return ['object'];
259
- if (value.items !== undefined)
279
+ }
280
+ if (value.items !== undefined) {
260
281
  return ['array'];
282
+ }
261
283
  return [];
262
284
  };
263
285
  const forDocument = (models = {}, settings = {}, destinations) => {
@@ -270,14 +292,16 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
270
292
  let nodeCount = 0;
271
293
  /** The reference a nested schema links to in linked mode, instead of expanding its target. */
272
294
  const getLink = (input) => {
273
- if ((!linked && !destinations) || !isObject(input))
295
+ if ((!linked && !destinations) || !isObject(input)) {
274
296
  return undefined;
297
+ }
275
298
  const ref = getRef(input);
276
299
  if (ref !== undefined) {
277
300
  // A primitive alias is shorter than a link to it, and saves the reader a page.
278
301
  const resolved = getResolvedRef(input) !== undefined;
279
- if (!linked && !destinations?.has(getReferenceName(ref)))
302
+ if (!linked && !destinations?.has(getReferenceName(ref))) {
280
303
  return undefined;
304
+ }
281
305
  return resolved && inlinePrimitives && isPrimitive(input) ? undefined : ref;
282
306
  }
283
307
  const core = view(input).core;
@@ -300,11 +324,13 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
300
324
  (!structuralKeywords.has(key) ||
301
325
  numericAnnotations.some((annotation) => annotation === key) ||
302
326
  (key === 'additionalProperties' && entry === false)) &&
303
- !(key in own))
327
+ !(key in own)) {
304
328
  own[key] = entry;
329
+ }
305
330
  }
306
- if (getRef(current) !== undefined)
331
+ if (getRef(current) !== undefined) {
307
332
  break;
333
+ }
308
334
  current = view(current).core;
309
335
  }
310
336
  return view(own);
@@ -323,8 +349,9 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
323
349
  complete: !structural,
324
350
  };
325
351
  }
326
- if (typeof value.schema === 'boolean')
352
+ if (typeof value.schema === 'boolean') {
327
353
  return { nodes: [], complete: true };
354
+ }
328
355
  const types = getTypes(value);
329
356
  const alternatives = [];
330
357
  let complete = !value.properties.length &&
@@ -340,10 +367,12 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
340
367
  if (complete &&
341
368
  !types.length &&
342
369
  branches.length === union.length &&
343
- branches.every((branch, index) => branch.complete && branch.nodes.length && !hasAnnotations(getOwnView(union[index]))))
370
+ branches.every((branch, index) => branch.complete && branch.nodes.length && !hasAnnotations(getOwnView(union[index])))) {
344
371
  alternatives.push(...branches.map((branch) => branch.nodes));
345
- else
372
+ }
373
+ else {
346
374
  complete = false;
375
+ }
347
376
  }
348
377
  for (const type of types) {
349
378
  if (type !== 'array' || value.items === undefined) {
@@ -361,53 +390,67 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
361
390
  ? [inlineCode(only.value.includes(' | ') ? `array of (${only.value})` : `array of ${only.value}`)]
362
391
  : [text('array of '), ...(items.nodes.length > 1 ? [text('('), ...items.nodes, text(')')] : items.nodes)]);
363
392
  }
364
- if (!types.length && value.items !== undefined)
393
+ if (!types.length && value.items !== undefined) {
365
394
  complete = false;
395
+ }
366
396
  // Without a type to name, a nullable schema says so and leaves its structure to the lines below.
367
- if (value.nullable && !types.includes('null'))
397
+ if (value.nullable && !types.includes('null')) {
368
398
  alternatives.push(alternatives.length || complete ? [inlineCode('null')] : [text('nullable')]);
399
+ }
369
400
  // A schema without types or structure accepts any value.
370
- if (!alternatives.length && complete)
401
+ if (!alternatives.length && complete) {
371
402
  alternatives.push([inlineCode('any')]);
403
+ }
372
404
  return { nodes: joinAlternatives(alternatives), complete };
373
405
  };
374
406
  /** The one-line summary of a schema: its type, then its annotations. */
375
407
  const summarize = (input, { nested, label = getLabel(input, nested), showType = true, }) => {
376
408
  const linkedLabel = (nested || destinations !== undefined) && getLink(input) !== undefined;
377
409
  const value = linkedLabel ? getLinkAnnotations(input) : view(input);
378
- if (typeof value.schema === 'boolean')
410
+ if (typeof value.schema === 'boolean') {
379
411
  return { line: [text(value.schema ? 'any (true schema)' : 'never (false schema)')] };
412
+ }
380
413
  const nodes = showType ? [...label.nodes] : [];
381
414
  const add = (name, entry) => {
382
- if (entry !== undefined)
415
+ if (entry !== undefined) {
383
416
  nodes.push(text(`${nodes.length ? ', ' : ''}${name}: `), inlineCode(entry));
417
+ }
384
418
  };
385
419
  const flag = (name, entry) => {
386
- if (entry)
420
+ if (entry) {
387
421
  nodes.push(text(`${nodes.length ? ', ' : ''}${name}`));
422
+ }
388
423
  };
389
424
  // Later references to a shared schema point back to this name.
390
425
  const ref = getRef(input);
391
426
  if (!linkedLabel && value.name !== undefined) {
392
427
  // In linked mode the expanded schema also has its own page.
393
- if (linked && ref !== undefined)
428
+ if (linked && ref !== undefined) {
394
429
  nodes.push(text(`${nodes.length ? ', ' : ''}schema: `), referenceNode(ref));
395
- else
430
+ }
431
+ else {
396
432
  add('schema', value.name);
433
+ }
397
434
  }
398
- if (linkedLabel && value.type !== undefined)
435
+ if (linkedLabel && value.type !== undefined) {
399
436
  add('type', [value.type].flat().join(' | '));
437
+ }
400
438
  add('format', value.format);
401
- if (value.enum)
439
+ if (value.enum) {
402
440
  add('possible values', value.enum.map((entry) => JSON.stringify(entry)).join(', '));
403
- if (value.const !== undefined)
441
+ }
442
+ if (value.const !== undefined) {
404
443
  add('const', JSON.stringify(value.const));
405
- if (value.default !== undefined)
444
+ }
445
+ if (value.default !== undefined) {
406
446
  add('default', JSON.stringify(value.default));
407
- for (const key of numericAnnotations)
447
+ }
448
+ for (const key of numericAnnotations) {
408
449
  add(key, value[key]);
409
- for (const key of ['readOnly', 'writeOnly', 'deprecated'])
450
+ }
451
+ for (const key of ['readOnly', 'writeOnly', 'deprecated']) {
410
452
  flag(key, value[key]);
453
+ }
411
454
  flag('no additional properties', value.additionalProperties === false);
412
455
  // A reference without its own description still says what it is, from the schema it links to.
413
456
  return { line: nodes, description: value.description ?? (linkedLabel ? view(input).description : undefined) };
@@ -420,18 +463,21 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
420
463
  : {};
421
464
  if (Object.keys(siblings).length && !options.hideDetails) {
422
465
  const { line, description } = summarize(siblings, { nested: false, showType: false });
423
- if (line.length)
466
+ if (line.length) {
424
467
  nodes.push(paragraph(...line));
425
- if (!options.hideDescription)
468
+ }
469
+ if (!options.hideDescription) {
426
470
  nodes.push(...describe(description));
471
+ }
427
472
  }
428
473
  nodes.push(paragraph(emphasis(text('Schema '), inlineCode(name), text(` is shown ${location}.`))));
429
474
  return nodes;
430
475
  };
431
476
  /** Print a schema's summary line and description, unless the caller already did. */
432
477
  const header = (input, depth, options, showType = true) => {
433
- if (options.hideDetails)
478
+ if (options.hideDetails) {
434
479
  return [];
480
+ }
435
481
  const { line, description } = summarize(input, { nested: depth > 0, showType });
436
482
  return [...(line.length ? [paragraph(...line)] : []), ...(options.hideDescription ? [] : describe(description))];
437
483
  };
@@ -471,8 +517,9 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
471
517
  // A wrapper prints its merged summary, then its core schema's structure.
472
518
  if (value.core !== undefined) {
473
519
  const nodes = header(input, depth, options);
474
- if (label.complete)
520
+ if (label.complete) {
475
521
  return nodes;
522
+ }
476
523
  return [
477
524
  ...nodes,
478
525
  ...render(value.core, depth, ancestors, {
@@ -492,18 +539,23 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
492
539
  const referenceOptions = options.name === undefined ? options : { ...options, hideDetails: true };
493
540
  return reference(input, referenceOptions, previous.name, 'above');
494
541
  }
495
- if (value.name !== undefined && options.name === undefined && depth >= MAX_DEPTH && sections.has(shared))
542
+ if (value.name !== undefined && options.name === undefined && depth >= MAX_DEPTH && sections.has(shared)) {
496
543
  return reference(input, options, value.name, 'below under Schemas');
544
+ }
497
545
  }
498
- if (depth >= MAX_DEPTH)
546
+ if (depth >= MAX_DEPTH) {
499
547
  return [paragraph(text('[Maximum schema depth reached]'))];
500
- if (nodeCount >= maxNodes)
548
+ }
549
+ if (nodeCount >= maxNodes) {
501
550
  return [paragraph(emphasis(text('[Schema output truncated]')))];
551
+ }
502
552
  nodeCount++;
503
- if (shared && name !== undefined && !shown.has(shared))
553
+ if (shared && name !== undefined && !shown.has(shared)) {
504
554
  shown.set(shared, { name, description: value.description });
505
- if (typeof value.schema === 'boolean')
555
+ }
556
+ if (typeof value.schema === 'boolean') {
506
557
  return header(input, depth, options);
558
+ }
507
559
  const childAncestors = [...ancestors, identity];
508
560
  const nodes = [];
509
561
  // Discriminator values that name a branch are printed beside it instead of in a separate list.
@@ -516,8 +568,9 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
516
568
  ['anyOf', 'Any of:'],
517
569
  ['oneOf', 'One of:'],
518
570
  ]) {
519
- if (!value[key]?.length)
571
+ if (!value[key]?.length) {
520
572
  continue;
573
+ }
521
574
  // One list item per branch keeps the boundary between branches visible.
522
575
  const branches = value[key].map((child) => {
523
576
  const blocks = render(child, depth + 1, childAncestors, { showType: true });
@@ -525,19 +578,22 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
525
578
  const values = key === 'allOf' || ref === undefined ? [] : mappings.filter(([, target]) => target === ref);
526
579
  const first = blocks[0];
527
580
  if (values.length && first?.type === 'paragraph') {
528
- for (const [name] of values)
581
+ for (const [name] of values) {
529
582
  mapped.add(name);
583
+ }
530
584
  first.children.push(text(`${first.children.length ? ', ' : ''}${value.discriminator.propertyName}: `), inlineCode(values.map(([name]) => name).join(', ')));
531
585
  }
532
586
  return item(...blocks);
533
587
  });
534
588
  const discriminated = key !== 'allOf' && value.discriminator;
535
589
  nodes.push(paragraph(strong(text(title)), ...(discriminated ? [text(' discriminated by '), inlineCode(value.discriminator.propertyName)] : [])), list(branches));
536
- if (discriminated)
590
+ if (discriminated) {
537
591
  discriminatorShown = true;
592
+ }
538
593
  }
539
- if (value.not !== undefined)
594
+ if (value.not !== undefined) {
540
595
  nodes.push(paragraph(strong(text('Not:'))), ...render(value.not, depth + 1, childAncestors));
596
+ }
541
597
  }
542
598
  // Child sections imply a single container type, but never its nullable alternatives.
543
599
  const impliedType = !options.showType &&
@@ -549,8 +605,9 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
549
605
  // A reference sibling may require a field declared only in the target schema.
550
606
  const declared = new Set(value.properties.map(([name]) => name));
551
607
  const required = [...value.required].filter((name) => !declared.has(name));
552
- if (required.length)
608
+ if (required.length) {
553
609
  nodes.push(paragraph(strong(text('Required fields:')), text(' '), inlineCode(required.join(', '))));
610
+ }
554
611
  }
555
612
  if (value.properties.length) {
556
613
  const properties = value.properties.map(([name, schema]) => {
@@ -559,15 +616,17 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
559
616
  const title = [
560
617
  strong(inlineCode(name), ...(value.required.has(name) ? [text(' (required)')] : [])),
561
618
  ];
562
- if (line.length)
619
+ if (line.length) {
563
620
  title.push(text(': '), ...line);
621
+ }
564
622
  const blocks = [paragraph(...title), ...describe(description)];
565
- if (!childLabel.complete)
623
+ if (!childLabel.complete) {
566
624
  blocks.push(...render(schema, depth + 1, childAncestors, {
567
625
  hideDetails: true,
568
626
  hideDescription: true,
569
627
  property: true,
570
628
  }));
629
+ }
571
630
  return item(...blocks);
572
631
  });
573
632
  nodes.push(list(properties));
@@ -577,13 +636,15 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
577
636
  (value.type === 'array' || value.type === undefined || [value.type].flat().includes('array'))) {
578
637
  nodes.push(paragraph(strong(text(options.property ? 'Items:' : 'Array of:'))), ...render(value.items, depth + 1, childAncestors));
579
638
  }
580
- if (isObject(value.additionalProperties))
639
+ if (isObject(value.additionalProperties)) {
581
640
  nodes.push(paragraph(strong(text('Additional properties:'))), ...render(value.additionalProperties, depth + 1, childAncestors));
641
+ }
582
642
  const unmapped = mappings.filter(([name]) => !mapped.has(name));
583
643
  if (value.discriminator && (!discriminatorShown || unmapped.length)) {
584
644
  nodes.push(paragraph(strong(text('Discriminator:')), text(' '), inlineCode(value.discriminator.propertyName)));
585
- if (unmapped.length)
645
+ if (unmapped.length) {
586
646
  nodes.push(list(unmapped.map(([name, target]) => item(paragraph(inlineCode(name), text(': '), linked || destinations ? referenceNode(target) : inlineCode(target))))));
647
+ }
587
648
  }
588
649
  return nodes;
589
650
  };
@@ -600,34 +661,41 @@ export const createSchemaRenderer = ({ maxNodes = MAX_NODES } = {}) => {
600
661
  patternProperties: 'map',
601
662
  };
602
663
  const getExampleSchema = (input, root) => {
603
- if (!isObject(input))
664
+ if (!isObject(input)) {
604
665
  return input;
666
+ }
605
667
  if (!root && getLink(input) !== undefined) {
606
668
  const types = getTypes(view(input));
607
669
  return types.includes('array') && !types.includes('object') ? { type: 'array', items: {} } : { type: 'object' };
608
670
  }
609
671
  // Primitive references stay linked; a spread copy would lose the non-enumerable target.
610
672
  if (getRef(input) !== undefined) {
611
- if (!root)
673
+ if (!root) {
612
674
  return input;
675
+ }
613
676
  // Merging keeps the `$ref` key, which must not be followed again.
614
677
  const merged = getResolvedRef(input, mergeSiblingReferences);
615
- if (!isObject(merged))
678
+ if (!isObject(merged)) {
616
679
  return merged;
680
+ }
617
681
  const { $ref: _ref, ...target } = merged;
618
682
  return getExampleSchema(target, true);
619
683
  }
620
684
  const copy = { ...input };
621
685
  for (const [key, kind] of Object.entries(schemaKeywords)) {
622
686
  const value = input[key];
623
- if (kind === 'one')
687
+ if (kind === 'one') {
624
688
  copy[key] = getExampleSchema(value, false);
625
- else if (kind === 'list' && Array.isArray(value))
689
+ }
690
+ else if (kind === 'list' && Array.isArray(value)) {
626
691
  copy[key] = value.map((entry) => getExampleSchema(entry, false));
627
- else if (kind === 'map' && isObject(value))
692
+ }
693
+ else if (kind === 'map' && isObject(value)) {
628
694
  copy[key] = Object.fromEntries(Object.entries(value).map(([name, entry]) => [name, getExampleSchema(entry, false)]));
629
- if (copy[key] === undefined)
695
+ }
696
+ if (copy[key] === undefined) {
630
697
  delete copy[key];
698
+ }
631
699
  }
632
700
  return copy;
633
701
  };
@@ -1 +1 @@
1
- {"version":3,"file":"render-security.d.ts","sourceRoot":"","sources":["../src/render-security.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AACnG,OAAO,KAAK,EAAE,OAAO,EAA6B,WAAW,EAAE,MAAM,OAAO,CAAA;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAsD5D;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,cAAc,eAAe,CAAC,UAAU,CAAC,EACzC,SAAS,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC,EACtE,aAAa,iBAAiB,EAC9B,QAAO,OAAO,CAAC,OAAO,CAAK,KAC1B,OAAO,CAAC,WAAW,EAAE,CAsBvB,CAAA"}
1
+ {"version":3,"file":"render-security.d.ts","sourceRoot":"","sources":["../src/render-security.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AACnG,OAAO,KAAK,EAAE,OAAO,EAA6B,WAAW,EAAE,MAAM,OAAO,CAAA;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAwD5D;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,cAAc,eAAe,CAAC,UAAU,CAAC,EACzC,SAAS,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC,EACtE,aAAa,iBAAiB,EAC9B,QAAO,OAAO,CAAC,OAAO,CAAK,KAC1B,OAAO,CAAC,WAAW,EAAE,CAgCvB,CAAA"}
@@ -33,8 +33,9 @@ const summarizeScheme = (scheme) => {
33
33
  ['refreshUrl', 'refresh'],
34
34
  ]) {
35
35
  // Coercion fills in optional URLs as empty strings.
36
- if (typeof urls[key] === 'string' && urls[key])
36
+ if (typeof urls[key] === 'string' && urls[key]) {
37
37
  nodes.push(text(`, ${label} `), inlineCode(urls[key]));
38
+ }
38
39
  }
39
40
  }
40
41
  return nodes;
@@ -53,14 +54,17 @@ const summarizeScheme = (scheme) => {
53
54
  * no authentication is required.
54
55
  */
55
56
  export const renderSecurity = async (requirements, schemes, description, level = 4) => {
56
- if (!requirements)
57
+ if (!requirements) {
57
58
  return [];
59
+ }
58
60
  const nodes = [heading(level, text('Authentication'))];
59
- if (!requirements.length)
61
+ if (!requirements.length) {
60
62
  nodes.push(paragraph(text('No authentication required.')));
63
+ }
61
64
  for (const [index, requirement] of requirements.entries()) {
62
- if (index)
65
+ if (index) {
63
66
  nodes.push(paragraph(text('Or:')));
67
+ }
64
68
  const entries = Object.entries(requirement);
65
69
  if (!entries.length) {
66
70
  nodes.push(paragraph(text('No authentication required.')));
@@ -70,10 +74,12 @@ export const renderSecurity = async (requirements, schemes, description, level =
70
74
  for (const [name, scopes] of entries) {
71
75
  const scheme = getResolvedRef(schemes?.[name]);
72
76
  const line = [strong(text(name))];
73
- if (scheme)
77
+ if (scheme) {
74
78
  line.push(text(': '), ...summarizeScheme(scheme));
75
- if (scopes?.length)
79
+ }
80
+ if (scopes?.length) {
76
81
  line.push(text(', scopes: '), inlineCode(scopes.join(', ')));
82
+ }
77
83
  entriesNodes.push(item(paragraph(...line), ...(await description(scheme?.description))));
78
84
  }
79
85
  nodes.push(list(entriesNodes));
@@ -0,0 +1,7 @@
1
+ import type { TagObject } from '@scalar/workspace-store/schemas/v3.2/strict/tag';
2
+ /** Keep tag ancestry visible without exceeding Markdown's six heading levels. */
3
+ export declare const getTagSections: (tags: TagObject[], openapiVersion: string) => {
4
+ tag: TagObject;
5
+ title: string;
6
+ }[];
7
+ //# sourceMappingURL=render-tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-tags.d.ts","sourceRoot":"","sources":["../src/render-tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iDAAiD,CAAA;AAEhF,iFAAiF;AACjF,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,EAAE,EAAE,gBAAgB,MAAM,KAAG;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAwE3G,CAAA"}