@scalar/openapi-to-markdown 1.5.3 → 1.5.4
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 +7 -0
- package/dist/document-anchors.d.ts.map +1 -1
- package/dist/document-anchors.js +4 -2
- package/dist/document-examples.d.ts.map +1 -1
- package/dist/document-examples.js +10 -5
- package/dist/get-markdown-examples.d.ts.map +1 -1
- package/dist/get-markdown-examples.js +48 -24
- package/dist/load-document.d.ts.map +1 -1
- package/dist/load-document.js +16 -10
- package/dist/parse-description.d.ts.map +1 -1
- package/dist/parse-description.js +36 -18
- package/dist/render-document.d.ts.map +1 -1
- package/dist/render-document.js +48 -24
- package/dist/render-examples.d.ts.map +1 -1
- package/dist/render-examples.js +8 -4
- package/dist/render-operation-details.d.ts.map +1 -1
- package/dist/render-operation-details.js +28 -14
- package/dist/render-operation.d.ts.map +1 -1
- package/dist/render-operation.js +60 -31
- package/dist/render-schema.d.ts.map +1 -1
- package/dist/render-schema.js +145 -77
- package/dist/render-security.d.ts.map +1 -1
- package/dist/render-security.js +12 -6
- package/dist/restore-boolean-schemas.d.ts.map +1 -1
- package/dist/restore-boolean-schemas.js +22 -11
- package/dist/select-document.d.ts.map +1 -1
- package/dist/select-document.js +5 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @scalar/openapi-to-markdown
|
|
2
2
|
|
|
3
|
+
## 1.5.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#10559](https://github.com/scalar/scalar/pull/10559): Clean up Biome warnings in package code and tests. Handle rejected debounced callbacks and await streaming writes.
|
|
8
|
+
- [#10505](https://github.com/scalar/scalar/pull/10505): Apply formatting and lint compatibility changes for Biome 2.5.15.
|
|
9
|
+
|
|
3
10
|
## 1.5.3
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-anchors.d.ts","sourceRoot":"","sources":["../src/document-anchors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,kGAAkG;AAClG,eAAO,MAAM,qBAAqB,QAAO;IACvC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"document-anchors.d.ts","sourceRoot":"","sources":["../src/document-anchors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,kGAAkG;AAClG,eAAO,MAAM,qBAAqB,QAAO;IACvC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAuBhE,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,MAAM,GAAI,IAAI,MAAM,KAAG,IAAuD,CAAA"}
|
package/dist/document-anchors.js
CHANGED
|
@@ -8,13 +8,15 @@ export const createDocumentAnchors = () => {
|
|
|
8
8
|
get: (kind, identity, label = identity) => {
|
|
9
9
|
const key = JSON.stringify([kind, identity]);
|
|
10
10
|
const previous = ids.get(key);
|
|
11
|
-
if (previous !== undefined)
|
|
11
|
+
if (previous !== undefined) {
|
|
12
12
|
return previous;
|
|
13
|
+
}
|
|
13
14
|
const base = `scalar-${kind}-${label}`;
|
|
14
15
|
let id = slugs.slug(base);
|
|
15
16
|
// A literal suffix in a later name can collide with the slugger's numeric suffix.
|
|
16
|
-
while (used.has(id))
|
|
17
|
+
while (used.has(id)) {
|
|
17
18
|
id = slugs.slug(base);
|
|
19
|
+
}
|
|
18
20
|
used.add(id);
|
|
19
21
|
ids.set(key, id);
|
|
20
22
|
return id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-examples.d.ts","sourceRoot":"","sources":["../src/document-examples.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,KAAK,aAAa,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAEjF,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,OAAO,mBAAmB,CAAA;IAC/B,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;CAC9F,CAAA;
|
|
1
|
+
{"version":3,"file":"document-examples.d.ts","sourceRoot":"","sources":["../src/document-examples.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,KAAK,aAAa,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAEjF,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,OAAO,mBAAmB,CAAA;IAC/B,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;CAC9F,CAAA;AAeD,uGAAuG;AACvG,eAAO,MAAM,sBAAsB,GAAI,SAAS,UAAU,CAAC,OAAO,qBAAqB,CAAC,KAAG,gBA4C1F,CAAA"}
|
|
@@ -4,8 +4,9 @@ import { getMarkdownExamples } from './get-markdown-examples.js';
|
|
|
4
4
|
const bookkeeping = new Set(['$ref', '$ref-value', '$global', '$status', '__scalar_']);
|
|
5
5
|
/** Sibling constraints make a reference a different example source from its target. */
|
|
6
6
|
const identity = (source) => {
|
|
7
|
-
if (!isObject(source.schema))
|
|
7
|
+
if (!isObject(source.schema)) {
|
|
8
8
|
return undefined;
|
|
9
|
+
}
|
|
9
10
|
const schema = source.schema;
|
|
10
11
|
const target = '$ref' in schema && Object.keys(schema).every((key) => bookkeeping.has(key)) ? getResolvedRef(schema) : schema;
|
|
11
12
|
return isObject(target) ? target : schema;
|
|
@@ -20,12 +21,14 @@ export const createDocumentExamples = (anchors) => {
|
|
|
20
21
|
get: (...args) => {
|
|
21
22
|
const [source, ...settings] = args;
|
|
22
23
|
const schema = identity(source);
|
|
23
|
-
if (!schema || source.example !== undefined || Object.keys(source.examples ?? {}).length)
|
|
24
|
+
if (!schema || source.example !== undefined || Object.keys(source.examples ?? {}).length) {
|
|
24
25
|
return getMarkdownExamples(...args);
|
|
26
|
+
}
|
|
25
27
|
const scope = JSON.stringify(settings);
|
|
26
28
|
const previous = cache.get(schema)?.get(scope);
|
|
27
|
-
if (previous)
|
|
29
|
+
if (previous) {
|
|
28
30
|
return previous;
|
|
31
|
+
}
|
|
29
32
|
// Large APIs must not retain every generated object until the export finishes.
|
|
30
33
|
if (cachedCount >= 256) {
|
|
31
34
|
cache.clear();
|
|
@@ -42,12 +45,14 @@ export const createDocumentExamples = (anchors) => {
|
|
|
42
45
|
const schema = identity(source);
|
|
43
46
|
const entries = schema ? (shown.get(schema) ?? new Map()) : new Map();
|
|
44
47
|
const previous = entries.get(scope);
|
|
45
|
-
if (previous?.value === code.value)
|
|
48
|
+
if (previous?.value === code.value) {
|
|
46
49
|
return { id: previous.id, previous: true };
|
|
50
|
+
}
|
|
47
51
|
const id = anchors.get('example', String(++nextId));
|
|
48
52
|
entries.set(scope, { id, value: code.value });
|
|
49
|
-
if (schema)
|
|
53
|
+
if (schema) {
|
|
50
54
|
shown.set(schema, entries);
|
|
55
|
+
}
|
|
51
56
|
return { id, previous: false };
|
|
52
57
|
},
|
|
53
58
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-markdown-examples.d.ts","sourceRoot":"","sources":["../src/get-markdown-examples.ts"],"names":[],"mappings":"AAMA,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC,CAAA;AAED,gFAAgF;AAChF,KAAK,eAAe,GAAG;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,CACA;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAClB;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CACpB,CAAA;AAYD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,OAAO,EAAE,cAAoC,KAAG,
|
|
1
|
+
{"version":3,"file":"get-markdown-examples.d.ts","sourceRoot":"","sources":["../src/get-markdown-examples.ts"],"names":[],"mappings":"AAMA,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC,CAAA;AAED,gFAAgF;AAChF,KAAK,eAAe,GAAG;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,CACA;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAClB;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CACpB,CAAA;AAYD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,OAAO,EAAE,cAAoC,KAAG,MAmEjG,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,aAAa,EACrB,WAAW,MAAM,EACjB,OAAO,MAAM,GAAG,OAAO,EACvB,uBAAwB,EAExB,6BAAqC,EACrC,gBAAc,KACb,eAAe,EA6DjB,CAAA"}
|
|
@@ -17,35 +17,47 @@ const MAX_GENERATED_EXAMPLE_VALUES = 10_000;
|
|
|
17
17
|
export const countGeneratedExampleValues = (root, limit = MAX_GENERATED_EXAMPLE_VALUES) => {
|
|
18
18
|
const counts = new WeakMap();
|
|
19
19
|
const count = (input, level) => {
|
|
20
|
-
if (level > EXAMPLE_DEPTH || !isObject(input))
|
|
20
|
+
if (level > EXAMPLE_DEPTH || !isObject(input)) {
|
|
21
21
|
return 1;
|
|
22
|
+
}
|
|
22
23
|
const cached = counts.get(input)?.get(level);
|
|
23
|
-
if (cached !== undefined)
|
|
24
|
+
if (cached !== undefined) {
|
|
24
25
|
return cached;
|
|
26
|
+
}
|
|
25
27
|
const schema = getResolvedRef(input, mergeSiblingReferences);
|
|
26
|
-
if (!isObject(schema))
|
|
28
|
+
if (!isObject(schema)) {
|
|
27
29
|
return 1;
|
|
30
|
+
}
|
|
28
31
|
// Supplied examples bypass schema expansion in the generator too.
|
|
29
|
-
if (schema.example !== undefined || (Array.isArray(schema.examples) && schema.examples.length > 0))
|
|
32
|
+
if (schema.example !== undefined || (Array.isArray(schema.examples) && schema.examples.length > 0)) {
|
|
30
33
|
return 1;
|
|
34
|
+
}
|
|
31
35
|
let total = 1;
|
|
32
36
|
const add = (child) => {
|
|
33
|
-
if (total <= limit)
|
|
37
|
+
if (total <= limit) {
|
|
34
38
|
total += count(child, level + 1);
|
|
39
|
+
}
|
|
35
40
|
};
|
|
36
|
-
if (isObject(schema.properties))
|
|
41
|
+
if (isObject(schema.properties)) {
|
|
37
42
|
Object.values(schema.properties).forEach(add);
|
|
38
|
-
|
|
43
|
+
}
|
|
44
|
+
if (isObject(schema.patternProperties)) {
|
|
39
45
|
Object.values(schema.patternProperties).forEach(add);
|
|
40
|
-
|
|
46
|
+
}
|
|
47
|
+
if (isObject(schema.additionalProperties)) {
|
|
41
48
|
add(schema.additionalProperties);
|
|
42
|
-
|
|
49
|
+
}
|
|
50
|
+
if (schema.items !== undefined) {
|
|
43
51
|
add(schema.items);
|
|
44
|
-
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(schema.prefixItems)) {
|
|
45
54
|
schema.prefixItems.forEach(add);
|
|
46
|
-
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(schema.allOf)) {
|
|
47
57
|
schema.allOf.forEach(add);
|
|
48
|
-
|
|
58
|
+
}
|
|
59
|
+
const anyOf = Array.isArray(schema.anyOf) ? schema.anyOf : [];
|
|
60
|
+
const variants = Array.isArray(schema.oneOf) ? schema.oneOf : anyOf;
|
|
49
61
|
// Object and array generation can use the first variant, while other unions skip null.
|
|
50
62
|
// A discriminator can choose any variant, so bound the largest candidate in that case.
|
|
51
63
|
const nonNull = variants.find((variant) => {
|
|
@@ -57,8 +69,9 @@ export const countGeneratedExampleValues = (root, limit = MAX_GENERATED_EXAMPLE_
|
|
|
57
69
|
: [variants[0], nonNull];
|
|
58
70
|
let variantCount = 0;
|
|
59
71
|
for (const candidate of candidates) {
|
|
60
|
-
if (candidate !== undefined && total <= limit && variantCount <= limit)
|
|
72
|
+
if (candidate !== undefined && total <= limit && variantCount <= limit) {
|
|
61
73
|
variantCount = Math.max(variantCount, count(candidate, level + 1));
|
|
74
|
+
}
|
|
62
75
|
}
|
|
63
76
|
total += variantCount;
|
|
64
77
|
const levels = counts.get(input) ?? new Map();
|
|
@@ -72,40 +85,51 @@ export const countGeneratedExampleValues = (root, limit = MAX_GENERATED_EXAMPLE_
|
|
|
72
85
|
export const getMarkdownExamples = (source, mediaType, mode, openapiVersion = '3.2.0',
|
|
73
86
|
// Schema metadata can be upgraded while example fields still follow the original version.
|
|
74
87
|
schemaOpenapiVersion = openapiVersion, linked = false) => {
|
|
75
|
-
if (source.example !== undefined)
|
|
88
|
+
if (source.example !== undefined) {
|
|
76
89
|
return [{ value: source.example }];
|
|
90
|
+
}
|
|
77
91
|
if (source.examples && Object.keys(source.examples).length) {
|
|
78
92
|
return Object.entries(source.examples).flatMap(([name, reference]) => {
|
|
79
93
|
const example = getResolvedRef(reference);
|
|
80
|
-
if (!isObject(example))
|
|
94
|
+
if (!isObject(example)) {
|
|
81
95
|
return [];
|
|
96
|
+
}
|
|
82
97
|
const metadata = {
|
|
83
98
|
name,
|
|
84
99
|
summary: typeof example.summary === 'string' ? example.summary : undefined,
|
|
85
100
|
description: typeof example.description === 'string' ? example.description : undefined,
|
|
86
101
|
};
|
|
87
|
-
if (example.value !== undefined)
|
|
102
|
+
if (example.value !== undefined) {
|
|
88
103
|
return [{ ...metadata, value: example.value }];
|
|
89
|
-
|
|
104
|
+
}
|
|
105
|
+
if (/^3\.2\./.test(openapiVersion) && typeof example.serializedValue === 'string') {
|
|
90
106
|
return [{ ...metadata, serializedValue: example.serializedValue }];
|
|
91
|
-
|
|
107
|
+
}
|
|
108
|
+
if (typeof example.externalValue === 'string') {
|
|
92
109
|
return [{ ...metadata, externalValue: example.externalValue }];
|
|
93
|
-
|
|
110
|
+
}
|
|
111
|
+
if (/^3\.2\./.test(openapiVersion) && example.dataValue !== undefined) {
|
|
94
112
|
return [{ ...metadata, dataValue: example.dataValue }];
|
|
113
|
+
}
|
|
95
114
|
return [];
|
|
96
115
|
});
|
|
97
116
|
}
|
|
98
117
|
const schema = getResolvedRef(source.schema, mergeSiblingReferences);
|
|
99
|
-
if (!isObject(schema))
|
|
118
|
+
if (!isObject(schema)) {
|
|
100
119
|
return [];
|
|
101
|
-
|
|
120
|
+
}
|
|
121
|
+
if (schema.example !== undefined) {
|
|
102
122
|
return [{ value: schema.example }];
|
|
103
|
-
|
|
123
|
+
}
|
|
124
|
+
if (Array.isArray(schema.examples) && schema.examples.length) {
|
|
104
125
|
return schema.examples.map((value) => ({ value }));
|
|
105
|
-
|
|
126
|
+
}
|
|
127
|
+
if (linked) {
|
|
106
128
|
return [];
|
|
107
|
-
|
|
129
|
+
}
|
|
130
|
+
if (countGeneratedExampleValues(source.schema) > MAX_GENERATED_EXAMPLE_VALUES) {
|
|
108
131
|
return [{ omitted: true }];
|
|
132
|
+
}
|
|
109
133
|
if (isXmlMediaType(mediaType)) {
|
|
110
134
|
const result = getXmlBodyExample(source.schema, undefined, {
|
|
111
135
|
mode,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-document.d.ts","sourceRoot":"","sources":["../src/load-document.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,8DAA8D,CAAA;
|
|
1
|
+
{"version":3,"file":"load-document.d.ts","sourceRoot":"","sources":["../src/load-document.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,8DAA8D,CAAA;AAiMrE,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GACvB,OAAO,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,KACxD,OAAO,CAAC,eAAe,CAgGzB,CAAA"}
|
package/dist/load-document.js
CHANGED
|
@@ -40,8 +40,9 @@ const attachRefValues = (document, schemas = getSchemas(document), { detectOnly
|
|
|
40
40
|
kind = kind && getChildKind(kind, key);
|
|
41
41
|
position = Array.isArray(parent) ? position : position && getChildPosition(position, key);
|
|
42
42
|
// Arbitrary extension and example data has not passed an OpenAPI object schema.
|
|
43
|
-
if (position === 'document' && kind === undefined)
|
|
43
|
+
if (position === 'document' && kind === undefined) {
|
|
44
44
|
position = undefined;
|
|
45
|
+
}
|
|
45
46
|
parent = getValueByPath(parent, [key]).value;
|
|
46
47
|
}
|
|
47
48
|
const schema = getTargetSchema(position, kind);
|
|
@@ -78,15 +79,20 @@ const attachRefValues = (document, schemas = getSchemas(document), { detectOnly
|
|
|
78
79
|
// support summary and description; casting them as their targets would add defaults.
|
|
79
80
|
// Path Item Objects declare their own $ref field, so their siblings are cast normally.
|
|
80
81
|
const reference = typeof value.$ref === 'string' ? value.$ref : undefined;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
let cast;
|
|
83
|
+
if (reference === undefined || schema === referenceTargetSchemas.pathItem) {
|
|
84
|
+
cast = coerceValue(schema, value);
|
|
85
|
+
}
|
|
86
|
+
else if (position === 'schema') {
|
|
87
|
+
cast = { ...coerceValue(SchemaObjectSchema, value), $ref: reference };
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
cast = {
|
|
91
|
+
$ref: reference,
|
|
92
|
+
...(typeof value.summary === 'string' ? { summary: value.summary } : {}),
|
|
93
|
+
...(typeof value.description === 'string' ? { description: value.description } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
90
96
|
if (fallback?.booleanSchemas) {
|
|
91
97
|
restoreBooleanSchemas(value, cast, position);
|
|
92
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-description.d.ts","sourceRoot":"","sources":["../src/parse-description.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,WAAW,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"parse-description.d.ts","sourceRoot":"","sources":["../src/parse-description.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,WAAW,EAAE,MAAM,OAAO,CAAA;AAsG7D,0FAA0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;AAE1E,mGAAmG;AACnG,eAAO,MAAM,uBAAuB,QAAO,CAAC,MAAM,iBAAiB,CAuDlE,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,kBAAkB,GAAU,OAAO,WAAW,EAAE,EAAE,aAAa,iBAAiB,KAAG,OAAO,CAAC,IAAI,CAkB3G,CAAA"}
|
|
@@ -10,8 +10,9 @@ const clean = (node) => {
|
|
|
10
10
|
node.url = safeUrl(node.url);
|
|
11
11
|
}
|
|
12
12
|
if ('children' in node) {
|
|
13
|
-
for (const child of node.children)
|
|
13
|
+
for (const child of node.children) {
|
|
14
14
|
clean(child);
|
|
15
|
+
}
|
|
15
16
|
// The filter preserves the parent's existing child types.
|
|
16
17
|
const previousLength = node.children.length;
|
|
17
18
|
node.children = node.children.filter((child) => child.type !== 'image' &&
|
|
@@ -33,10 +34,12 @@ const clean = (node) => {
|
|
|
33
34
|
if (node.children.length !== previousLength) {
|
|
34
35
|
const first = node.children.at(0);
|
|
35
36
|
const last = node.children.at(-1);
|
|
36
|
-
if (first?.type === 'text')
|
|
37
|
+
if (first?.type === 'text') {
|
|
37
38
|
first.value = first.value.trimStart();
|
|
38
|
-
|
|
39
|
+
}
|
|
40
|
+
if (last?.type === 'text') {
|
|
39
41
|
last.value = last.value.trimEnd();
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
delete node.position;
|
|
@@ -47,24 +50,31 @@ const pruneDefinitions = (tree) => {
|
|
|
47
50
|
const footnotes = new Set();
|
|
48
51
|
const definitions = new Map(tree.children.filter((node) => node.type === 'footnoteDefinition').map((node) => [node.identifier, node]));
|
|
49
52
|
const collect = (node) => {
|
|
50
|
-
if (node.type === 'linkReference')
|
|
53
|
+
if (node.type === 'linkReference') {
|
|
51
54
|
links.add(node.identifier);
|
|
52
|
-
|
|
55
|
+
}
|
|
56
|
+
if (node.type === 'footnoteReference') {
|
|
53
57
|
footnotes.add(node.identifier);
|
|
54
|
-
|
|
58
|
+
}
|
|
59
|
+
if ('children' in node) {
|
|
55
60
|
node.children.forEach(collect);
|
|
61
|
+
}
|
|
56
62
|
};
|
|
57
63
|
tree.children.filter((node) => node.type !== 'footnoteDefinition').forEach(collect);
|
|
58
64
|
// Set iteration also visits footnotes discovered inside another footnote.
|
|
59
|
-
for (const identifier of footnotes)
|
|
65
|
+
for (const identifier of footnotes) {
|
|
60
66
|
definitions.get(identifier)?.children.forEach(collect);
|
|
67
|
+
}
|
|
61
68
|
tree.children = tree.children.filter((node) => {
|
|
62
|
-
if (node.type === 'definition')
|
|
69
|
+
if (node.type === 'definition') {
|
|
63
70
|
return links.has(node.identifier);
|
|
64
|
-
|
|
71
|
+
}
|
|
72
|
+
if (node.type === 'footnoteDefinition') {
|
|
65
73
|
return footnotes.has(node.identifier);
|
|
66
|
-
|
|
74
|
+
}
|
|
75
|
+
if (node.type === 'paragraph') {
|
|
67
76
|
return node.children.some((child) => child.type !== 'text' || child.value.trim());
|
|
77
|
+
}
|
|
68
78
|
return true;
|
|
69
79
|
});
|
|
70
80
|
};
|
|
@@ -78,8 +88,9 @@ export const createDescriptionParser = () => {
|
|
|
78
88
|
const cache = new Map();
|
|
79
89
|
const parse = async (value) => {
|
|
80
90
|
// Most schema descriptions are one plain sentence. Parsing them costs more than the page's other text.
|
|
81
|
-
if (isPlainText(value))
|
|
91
|
+
if (isPlainText(value)) {
|
|
82
92
|
return [{ type: 'paragraph', children: [{ type: 'text', value: value.trim() }] }];
|
|
93
|
+
}
|
|
83
94
|
const parsed = parser.parse(value);
|
|
84
95
|
// Raw HTML and GitHub alerts retain Scalar's existing conversion behavior.
|
|
85
96
|
const tree = containsHtml(parsed) || /^\s*>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION|SUCCESS)\]/im.test(value)
|
|
@@ -93,26 +104,31 @@ export const createDescriptionParser = () => {
|
|
|
93
104
|
const copy = { ...node };
|
|
94
105
|
if ('identifier' in copy) {
|
|
95
106
|
copy.identifier = `${prefix}${copy.identifier}`;
|
|
96
|
-
if ('label' in copy)
|
|
107
|
+
if ('label' in copy) {
|
|
97
108
|
copy.label = copy.identifier;
|
|
98
|
-
|
|
109
|
+
}
|
|
110
|
+
if ('referenceType' in copy) {
|
|
99
111
|
copy.referenceType = 'full';
|
|
112
|
+
}
|
|
100
113
|
}
|
|
101
|
-
if ('children' in copy)
|
|
114
|
+
if ('children' in copy) {
|
|
102
115
|
copy.children = copy.children.map((child) => namespace(child, prefix));
|
|
116
|
+
}
|
|
103
117
|
return copy;
|
|
104
118
|
};
|
|
105
119
|
const hasReference = (node) => 'identifier' in node || ('children' in node && node.children.some(hasReference));
|
|
106
120
|
return () => {
|
|
107
121
|
const state = { nextId: 0 };
|
|
108
122
|
return async (value) => {
|
|
109
|
-
if (!value)
|
|
123
|
+
if (!value) {
|
|
110
124
|
return [];
|
|
125
|
+
}
|
|
111
126
|
const prefix = `description-${state.nextId++}-`;
|
|
112
127
|
const cached = cache.get(value) ?? parse(value);
|
|
113
128
|
if (!cache.has(value)) {
|
|
114
|
-
if (cache.size >= 8192)
|
|
129
|
+
if (cache.size >= 8192) {
|
|
115
130
|
cache.clear();
|
|
131
|
+
}
|
|
116
132
|
cache.set(value, cached);
|
|
117
133
|
}
|
|
118
134
|
const nodes = await cached;
|
|
@@ -127,10 +143,12 @@ export const expandDescriptions = async (nodes, description) => {
|
|
|
127
143
|
const found = [];
|
|
128
144
|
const collect = (siblings) => {
|
|
129
145
|
for (const node of siblings) {
|
|
130
|
-
if (node.type === 'descriptionPlaceholder')
|
|
146
|
+
if (node.type === 'descriptionPlaceholder') {
|
|
131
147
|
found.push({ siblings, node });
|
|
132
|
-
|
|
148
|
+
}
|
|
149
|
+
else if ('children' in node) {
|
|
133
150
|
collect(node.children);
|
|
151
|
+
}
|
|
134
152
|
}
|
|
135
153
|
};
|
|
136
154
|
collect(nodes);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-document.d.ts","sourceRoot":"","sources":["../src/render-document.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,8DAA8D,CAAA;AAcrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"render-document.d.ts","sourceRoot":"","sources":["../src/render-document.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,8DAA8D,CAAA;AAcrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAwD7D,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,QAAO,CAAC,CACzC,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,MAAM,CAAC,CA0RnB,CAAA"}
|
package/dist/render-document.js
CHANGED
|
@@ -18,14 +18,17 @@ const serializer = unified()
|
|
|
18
18
|
bullet: '-',
|
|
19
19
|
join: [
|
|
20
20
|
(left, right, parent) => {
|
|
21
|
-
if (!('spread' in parent))
|
|
21
|
+
if (!('spread' in parent)) {
|
|
22
22
|
return undefined;
|
|
23
|
+
}
|
|
23
24
|
// Inside a tight list item, content after a nested list would otherwise continue its last item.
|
|
24
|
-
if (left.type === 'list' && right.type !== 'list')
|
|
25
|
+
if (left.type === 'list' && right.type !== 'list') {
|
|
25
26
|
return 1;
|
|
27
|
+
}
|
|
26
28
|
// Code blocks in descriptions read better apart from the prose around them.
|
|
27
|
-
if (left.type === 'code' || right.type === 'code')
|
|
29
|
+
if (left.type === 'code' || right.type === 'code') {
|
|
28
30
|
return 1;
|
|
31
|
+
}
|
|
29
32
|
return undefined;
|
|
30
33
|
},
|
|
31
34
|
],
|
|
@@ -43,12 +46,14 @@ const renderShownModel = async (name, view, previous, description) => {
|
|
|
43
46
|
? [strong(text(view.title)), text(' ('), inlineCode(name), text(')')]
|
|
44
47
|
: [inlineCode(name)];
|
|
45
48
|
label.push(text(' — shown above'));
|
|
46
|
-
if (previous.name !== name)
|
|
49
|
+
if (previous.name !== name) {
|
|
47
50
|
label.push(text(' as '), inlineCode(previous.name));
|
|
51
|
+
}
|
|
48
52
|
label.push(text('.'));
|
|
49
53
|
const blocks = [paragraph(...label)];
|
|
50
|
-
if (view.description && view.description !== previous.description)
|
|
54
|
+
if (view.description && view.description !== previous.description) {
|
|
51
55
|
blocks.push(...(await description(view.description)));
|
|
56
|
+
}
|
|
52
57
|
return item(...blocks);
|
|
53
58
|
};
|
|
54
59
|
/** Build Markdown directly, retaining caches only for this immutable document snapshot. */
|
|
@@ -81,8 +86,9 @@ export const createDocumentRenderer = () => {
|
|
|
81
86
|
const entries = [];
|
|
82
87
|
for (const [path, reference] of Object.entries(group.paths ?? {})) {
|
|
83
88
|
const pathItem = getResolvedPathItem(reference);
|
|
84
|
-
if (!pathItem)
|
|
89
|
+
if (!pathItem) {
|
|
85
90
|
continue;
|
|
91
|
+
}
|
|
86
92
|
forEachPathItemOperation(reference, (method, operation) => {
|
|
87
93
|
const label = `${formatOperationMethod(method)} ${path}`;
|
|
88
94
|
entries.push({
|
|
@@ -107,8 +113,9 @@ export const createDocumentRenderer = () => {
|
|
|
107
113
|
const nodes = [];
|
|
108
114
|
const sections = [];
|
|
109
115
|
const flush = async () => {
|
|
110
|
-
if (!nodes.length)
|
|
116
|
+
if (!nodes.length) {
|
|
111
117
|
return;
|
|
118
|
+
}
|
|
112
119
|
const children = nodes.splice(0);
|
|
113
120
|
await expandDescriptions(children, description);
|
|
114
121
|
sections.push(serializer.stringify({ type: 'root', children }).trimEnd());
|
|
@@ -116,63 +123,74 @@ export const createDocumentRenderer = () => {
|
|
|
116
123
|
if (!single) {
|
|
117
124
|
const { info } = document;
|
|
118
125
|
const metadata = [field('OpenAPI Version', inlineCode(document.openapi))];
|
|
119
|
-
if (info.version)
|
|
126
|
+
if (info.version) {
|
|
120
127
|
metadata.push(field('API Version', inlineCode(info.version)));
|
|
121
|
-
|
|
128
|
+
}
|
|
129
|
+
if (info.termsOfService) {
|
|
122
130
|
metadata.push(field('Terms of service', link(info.termsOfService, info.termsOfService)));
|
|
131
|
+
}
|
|
123
132
|
if (info.contact) {
|
|
124
133
|
const contact = [text(info.contact.name ?? '')];
|
|
125
134
|
metadata.push(item(paragraph(strong(text('Contact:')), text(' '), ...contact, ...(info.contact.url ? [text(' '), link(info.contact.url, info.contact.url)] : []), ...(info.contact.email ? [text(' '), link(`mailto:${info.contact.email}`, info.contact.email)] : []))));
|
|
126
135
|
}
|
|
127
|
-
if (info.license)
|
|
136
|
+
if (info.license) {
|
|
128
137
|
metadata.push(field('License', info.license.url ? link(info.license.url, info.license.name ?? '') : text(info.license.name)));
|
|
138
|
+
}
|
|
129
139
|
nodes.push(heading(1, text(info.title)), list(metadata), ...(await description(info.description)));
|
|
130
140
|
if (whole) {
|
|
131
141
|
const contents = [];
|
|
132
142
|
for (const group of groups) {
|
|
133
|
-
if (!group.entries.length)
|
|
143
|
+
if (!group.entries.length) {
|
|
134
144
|
continue;
|
|
145
|
+
}
|
|
135
146
|
contents.push(paragraph(strong(text(group.title))), list(group.entries.map(({ id, label }) => item(paragraph(link(`#${encodeURIComponent(id)}`, label))))));
|
|
136
147
|
}
|
|
137
148
|
if (destinations?.size) {
|
|
138
149
|
contents.push(paragraph(strong(text('Schemas'))), list([...destinations].map(([name, url]) => item(paragraph(link(url, name))))));
|
|
139
150
|
}
|
|
140
|
-
if (contents.length)
|
|
151
|
+
if (contents.length) {
|
|
141
152
|
nodes.push(heading(2, text('Contents')), ...contents);
|
|
153
|
+
}
|
|
142
154
|
}
|
|
143
155
|
if (document.servers?.length || (whole && document.servers !== undefined)) {
|
|
144
|
-
if (documentContext?.servers)
|
|
156
|
+
if (documentContext?.servers) {
|
|
145
157
|
nodes.push(anchor(documentContext.servers));
|
|
158
|
+
}
|
|
146
159
|
nodes.push(heading(2, text('Servers')));
|
|
147
160
|
const effectiveServers = document.servers?.length
|
|
148
161
|
? document.servers
|
|
149
162
|
: [{ url: '/' }];
|
|
150
163
|
const servers = effectiveServers.map((server) => {
|
|
151
164
|
const nested = [];
|
|
152
|
-
if (server.description)
|
|
165
|
+
if (server.description) {
|
|
153
166
|
nested.push(field('Description', text(server.description)));
|
|
167
|
+
}
|
|
154
168
|
const variables = Object.entries(server.variables ?? {});
|
|
155
|
-
if (variables.length)
|
|
169
|
+
if (variables.length) {
|
|
156
170
|
nested.push(item(paragraph(strong(text('Variables:'))), list(variables.map(([name, variable]) => item(paragraph(inlineCode(name), text(' (default: '), inlineCode(variable.default), text(')'), ...(whole && variable.enum?.length
|
|
157
171
|
? [text(', possible values: '), inlineCode(variable.enum.join(', '))]
|
|
158
172
|
: []), text(variable.description ? `: ${variable.description}` : '')))))));
|
|
173
|
+
}
|
|
159
174
|
const entry = field('URL', inlineCode(server.url));
|
|
160
|
-
if (nested.length)
|
|
175
|
+
if (nested.length) {
|
|
161
176
|
entry.children.push(list(nested));
|
|
177
|
+
}
|
|
162
178
|
return entry;
|
|
163
179
|
});
|
|
164
180
|
nodes.push(list(servers));
|
|
165
181
|
}
|
|
166
|
-
if (documentContext?.authentication)
|
|
182
|
+
if (documentContext?.authentication) {
|
|
167
183
|
nodes.push(anchor(documentContext.authentication));
|
|
184
|
+
}
|
|
168
185
|
nodes.push(...(await renderSecurity(document.security, document.components?.securitySchemes, description, 2)));
|
|
169
186
|
if (document.tags?.length) {
|
|
170
187
|
nodes.push(heading(2, text('Tags')));
|
|
171
188
|
for (const tag of document.tags) {
|
|
172
189
|
const title = /^3\.2\./.test(openapiVersion) ? (tag.summary ?? tag.name) : tag.name;
|
|
173
190
|
nodes.push(heading(3, text(title)), ...(await description(tag.description)));
|
|
174
|
-
if (tag.externalDocs)
|
|
191
|
+
if (tag.externalDocs) {
|
|
175
192
|
nodes.push(paragraph(link(tag.externalDocs.url, tag.externalDocs.description ?? tag.externalDocs.url)));
|
|
193
|
+
}
|
|
176
194
|
}
|
|
177
195
|
}
|
|
178
196
|
await flush();
|
|
@@ -180,12 +198,14 @@ export const createDocumentRenderer = () => {
|
|
|
180
198
|
for (const group of groups) {
|
|
181
199
|
let hasOperations = false;
|
|
182
200
|
for (const { path, pathItem, method, operation, id } of group.entries) {
|
|
183
|
-
if (!hasOperations && !single)
|
|
201
|
+
if (!hasOperations && !single) {
|
|
184
202
|
nodes.push(heading(2, text(group.title)));
|
|
203
|
+
}
|
|
185
204
|
hasOperations = true;
|
|
186
205
|
schemas.beginSection();
|
|
187
|
-
if (id)
|
|
206
|
+
if (id) {
|
|
188
207
|
nodes.push(anchor(id));
|
|
208
|
+
}
|
|
189
209
|
nodes.push(...(await renderOperation(document, path, method, pathItem, operation, group.webhook, {
|
|
190
210
|
description,
|
|
191
211
|
schemas,
|
|
@@ -201,11 +221,13 @@ export const createDocumentRenderer = () => {
|
|
|
201
221
|
const renderModel = async (name, schema, level) => {
|
|
202
222
|
const view = schemas.view(schema);
|
|
203
223
|
const summary = schemas.summarize(schema);
|
|
204
|
-
if (whole)
|
|
224
|
+
if (whole) {
|
|
205
225
|
nodes.push(anchor(anchors.get('schema', name)));
|
|
226
|
+
}
|
|
206
227
|
nodes.push(heading(level, text(view.title ?? name)));
|
|
207
|
-
if (summary.length)
|
|
228
|
+
if (summary.length) {
|
|
208
229
|
nodes.push(paragraph(strong(text('Type:')), text('\u00a0'), ...summary));
|
|
230
|
+
}
|
|
209
231
|
nodes.push(...(await description(view.description)), ...schemas.render(schema, 0, [], { hideDetails: true, name }));
|
|
210
232
|
if (view.type === 'object' || hasAuthoredExamples(view)) {
|
|
211
233
|
// A model page's own schema is bounded, so it gets a generated example even in linked mode.
|
|
@@ -224,13 +246,15 @@ export const createDocumentRenderer = () => {
|
|
|
224
246
|
await renderModel(selected[0], selected[1], 1);
|
|
225
247
|
}
|
|
226
248
|
const dependencies = models.filter(([name]) => name !== options.model);
|
|
227
|
-
if (dependencies.length)
|
|
249
|
+
if (dependencies.length) {
|
|
228
250
|
nodes.push(heading(2, text('Schemas')));
|
|
251
|
+
}
|
|
229
252
|
// Models the page already expanded cost one line each, grouped into a single list.
|
|
230
253
|
const shownAbove = [];
|
|
231
254
|
const flushShownAbove = () => {
|
|
232
|
-
if (shownAbove.length)
|
|
255
|
+
if (shownAbove.length) {
|
|
233
256
|
nodes.push(list(shownAbove.splice(0)));
|
|
257
|
+
}
|
|
234
258
|
};
|
|
235
259
|
for (const [name, schema] of dependencies) {
|
|
236
260
|
schemas.beginSection();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-examples.d.ts","sourceRoot":"","sources":["../src/render-examples.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,WAAW,EAAE,MAAM,OAAO,CAAA;AAG9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,yBAAyB,CAAA;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,+EAA+E;AAC/E,eAAO,MAAM,cAAc,GACzB,QAAQ,aAAa,EACrB,aAAa,iBAAiB,EAC9B,kBAA8B,EAC9B,OAAO,MAAM,GAAG,OAAO,EACvB,uBAAwB,EAExB,6BAAqC,EACrC,+BAIG;IACD,yFAAyF;IACzF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oFAAoF;IACpF,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CACvB,KACL,OAAO,CAAC,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"render-examples.d.ts","sourceRoot":"","sources":["../src/render-examples.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,WAAW,EAAE,MAAM,OAAO,CAAA;AAG9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,yBAAyB,CAAA;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,+EAA+E;AAC/E,eAAO,MAAM,cAAc,GACzB,QAAQ,aAAa,EACrB,aAAa,iBAAiB,EAC9B,kBAA8B,EAC9B,OAAO,MAAM,GAAG,OAAO,EACvB,uBAAwB,EAExB,6BAAqC,EACrC,+BAIG;IACD,yFAAyF;IACzF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oFAAoF;IACpF,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CACvB,KACL,OAAO,CAAC,WAAW,EAAE,CAgFvB,CAAA"}
|