@scalar/openapi-to-markdown 1.4.0 → 1.5.1
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 +32 -0
- package/README.md +66 -5
- package/dist/create-markdown-from-openapi.d.ts.map +1 -1
- package/dist/create-markdown-from-openapi.js +3 -2
- package/dist/document-anchors.d.ts +8 -0
- package/dist/document-anchors.d.ts.map +1 -0
- package/dist/document-anchors.js +25 -0
- package/dist/document-examples.d.ts +14 -0
- package/dist/document-examples.d.ts.map +1 -0
- package/dist/document-examples.js +54 -0
- package/dist/get-markdown-examples.d.ts +2 -0
- package/dist/get-markdown-examples.d.ts.map +1 -1
- package/dist/get-markdown-examples.js +11 -12
- package/dist/markdown-nodes.d.ts +22 -1
- package/dist/markdown-nodes.d.ts.map +1 -1
- package/dist/markdown-nodes.js +4 -0
- package/dist/parse-description.d.ts +2 -0
- package/dist/parse-description.d.ts.map +1 -1
- package/dist/parse-description.js +28 -1
- package/dist/render-document.d.ts +2 -2
- package/dist/render-document.d.ts.map +1 -1
- package/dist/render-document.js +217 -84
- package/dist/render-examples.d.ts +9 -1
- package/dist/render-examples.d.ts.map +1 -1
- package/dist/render-examples.js +26 -8
- package/dist/render-operation-details.d.ts +3 -2
- package/dist/render-operation-details.d.ts.map +1 -1
- package/dist/render-operation-details.js +8 -5
- package/dist/render-operation.d.ts +16 -1
- package/dist/render-operation.d.ts.map +1 -1
- package/dist/render-operation.js +168 -42
- package/dist/render-schema.d.ts +30 -3
- package/dist/render-schema.d.ts.map +1 -1
- package/dist/render-schema.js +474 -111
- package/dist/render-security.d.ts +7 -3
- package/dist/render-security.d.ts.map +1 -1
- package/dist/render-security.js +61 -12
- package/dist/select-document.d.ts +34 -3
- package/dist/select-document.d.ts.map +1 -1
- package/dist/select-document.js +58 -30
- package/package.json +18 -9
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
-
import type { RootContent } from 'mdast';
|
|
2
|
+
import type { Heading, RootContent } from 'mdast';
|
|
3
3
|
import type { DescriptionParser } from './parse-description.js';
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Preserve OR between requirements and AND between schemes within a requirement.
|
|
6
|
+
* Without declared requirements there is nothing to say: only an explicit empty list means that
|
|
7
|
+
* no authentication is required.
|
|
8
|
+
*/
|
|
9
|
+
export declare const renderSecurity: (requirements: OpenApiDocument["security"], schemes: NonNullable<OpenApiDocument["components"]>["securitySchemes"], description: DescriptionParser, level?: Heading["depth"]) => Promise<RootContent[]>;
|
|
6
10
|
//# sourceMappingURL=render-security.d.ts.map
|
|
@@ -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,
|
|
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"}
|
package/dist/render-security.js
CHANGED
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
2
|
-
import { heading, item, list, paragraph, strong, text } from './markdown-nodes.js';
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { heading, inlineCode, item, list, paragraph, strong, text } from './markdown-nodes.js';
|
|
3
|
+
const flowNames = {
|
|
4
|
+
implicit: 'implicit',
|
|
5
|
+
password: 'password',
|
|
6
|
+
clientCredentials: 'client credentials',
|
|
7
|
+
authorizationCode: 'authorization code',
|
|
8
|
+
deviceAuthorization: 'device authorization',
|
|
9
|
+
};
|
|
10
|
+
/** Summarize a security scheme on one line, for example "API key in header `X-Api-Key`". */
|
|
11
|
+
const summarizeScheme = (scheme) => {
|
|
12
|
+
const value = scheme;
|
|
13
|
+
switch (value.type) {
|
|
14
|
+
case 'apiKey':
|
|
15
|
+
return [text(`API key in ${String(value.in ?? 'header')} `), inlineCode(value.name)];
|
|
16
|
+
case 'http': {
|
|
17
|
+
const name = typeof value.scheme === 'string' ? value.scheme.toLowerCase() : '';
|
|
18
|
+
return [
|
|
19
|
+
text(`HTTP ${name || 'authentication'}`),
|
|
20
|
+
...(typeof value.bearerFormat === 'string' ? [text(' ('), inlineCode(value.bearerFormat), text(')')] : []),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
case 'oauth2': {
|
|
24
|
+
const flows = Object.entries(typeof value.flows === 'object' && value.flows ? value.flows : {});
|
|
25
|
+
const nodes = [text('OAuth 2.0')];
|
|
26
|
+
for (const [index, [flow, settings]] of flows.entries()) {
|
|
27
|
+
const urls = settings;
|
|
28
|
+
nodes.push(text(`${index ? '; ' : ': '}${flowNames[flow] ?? flow}`));
|
|
29
|
+
for (const [key, label] of [
|
|
30
|
+
['authorizationUrl', 'authorize'],
|
|
31
|
+
['deviceAuthorizationUrl', 'device authorization'],
|
|
32
|
+
['tokenUrl', 'token'],
|
|
33
|
+
['refreshUrl', 'refresh'],
|
|
34
|
+
]) {
|
|
35
|
+
// Coercion fills in optional URLs as empty strings.
|
|
36
|
+
if (typeof urls[key] === 'string' && urls[key])
|
|
37
|
+
nodes.push(text(`, ${label} `), inlineCode(urls[key]));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return nodes;
|
|
41
|
+
}
|
|
42
|
+
case 'openIdConnect':
|
|
43
|
+
return [text('OpenID Connect '), inlineCode(value.openIdConnectUrl)];
|
|
44
|
+
case 'mutualTLS':
|
|
45
|
+
return [text('Mutual TLS')];
|
|
46
|
+
default:
|
|
47
|
+
return [inlineCode(value.type)];
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Preserve OR between requirements and AND between schemes within a requirement.
|
|
52
|
+
* Without declared requirements there is nothing to say: only an explicit empty list means that
|
|
53
|
+
* no authentication is required.
|
|
54
|
+
*/
|
|
55
|
+
export const renderSecurity = async (requirements, schemes, description, level = 4) => {
|
|
5
56
|
if (!requirements)
|
|
6
57
|
return [];
|
|
7
|
-
const nodes = [heading(
|
|
58
|
+
const nodes = [heading(level, text('Authentication'))];
|
|
8
59
|
if (!requirements.length)
|
|
9
60
|
nodes.push(paragraph(text('No authentication required.')));
|
|
10
61
|
for (const [index, requirement] of requirements.entries()) {
|
|
@@ -17,15 +68,13 @@ export const renderSecurity = async (requirements, schemes, description) => {
|
|
|
17
68
|
}
|
|
18
69
|
const entriesNodes = [];
|
|
19
70
|
for (const [name, scopes] of entries) {
|
|
20
|
-
const blocks = [
|
|
21
|
-
paragraph(strong(text(name)), ...(scopes?.length ? [text(` Scopes: ${scopes.join(', ')}`)] : [])),
|
|
22
|
-
];
|
|
23
71
|
const scheme = getResolvedRef(schemes?.[name]);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
72
|
+
const line = [strong(text(name))];
|
|
73
|
+
if (scheme)
|
|
74
|
+
line.push(text(': '), ...summarizeScheme(scheme));
|
|
75
|
+
if (scopes?.length)
|
|
76
|
+
line.push(text(', scopes: '), inlineCode(scopes.join(', ')));
|
|
77
|
+
entriesNodes.push(item(paragraph(...line), ...(await description(scheme?.description))));
|
|
29
78
|
}
|
|
30
79
|
nodes.push(list(entriesNodes));
|
|
31
80
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OperationMethod } from '@scalar/workspace-store/schemas/navigation';
|
|
2
|
-
import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
import type { OpenApiDocument, PathItemObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
3
3
|
/** Identify one operation by path and method, operation ID, or JSON pointer. */
|
|
4
4
|
export type OperationSelector = {
|
|
5
5
|
path: string;
|
|
@@ -23,6 +23,11 @@ export type SchemaReferenceOptions = {
|
|
|
23
23
|
ref: string;
|
|
24
24
|
name: string;
|
|
25
25
|
}) => string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Render references to primitive, enum and `const` schemas, and to aliases of them, in place
|
|
28
|
+
* instead of linking them. Their whole definition fits on one line. Defaults to `true`.
|
|
29
|
+
*/
|
|
30
|
+
inlinePrimitives?: boolean;
|
|
26
31
|
};
|
|
27
32
|
};
|
|
28
33
|
type PageSelectors = {
|
|
@@ -35,7 +40,33 @@ type PageSelectors = {
|
|
|
35
40
|
};
|
|
36
41
|
introduction: true;
|
|
37
42
|
};
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
type OperationMatch = {
|
|
44
|
+
path: string;
|
|
45
|
+
method: OperationMethod;
|
|
46
|
+
};
|
|
47
|
+
type TaggedPathItem = {
|
|
48
|
+
path: string;
|
|
49
|
+
pathItem: PathItemObject;
|
|
50
|
+
methods: string[];
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Lookups that every selection from one document shares, built on first use.
|
|
54
|
+
* The document must not change while its lookup is in use.
|
|
55
|
+
*/
|
|
56
|
+
type DocumentLookup = {
|
|
57
|
+
/** Operations by operation ID, in document order. */
|
|
58
|
+
operationsById: () => ReadonlyMap<string, OperationMatch[]>;
|
|
59
|
+
/** Path items with the methods that carry each tag, in document order. */
|
|
60
|
+
operationsByTag: () => ReadonlyMap<string, TaggedPathItem[]>;
|
|
61
|
+
/** The position of each schema in `components.schemas`. */
|
|
62
|
+
schemaPositions: () => ReadonlyMap<string, number>;
|
|
63
|
+
};
|
|
64
|
+
/** Index a document once so that each selection costs time in proportion to what it selects. */
|
|
65
|
+
export declare const createDocumentLookup: (document: OpenApiDocument) => DocumentLookup;
|
|
66
|
+
/**
|
|
67
|
+
* Scope after resolving references and migrating older documents.
|
|
68
|
+
* Pass the same lookup to every selection from one document to reuse its indexes.
|
|
69
|
+
*/
|
|
70
|
+
export declare const selectDocument: (document: OpenApiDocument, options?: OpenApiRenderOptions, lookup?: DocumentLookup) => OpenApiDocument;
|
|
40
71
|
export {};
|
|
41
72
|
//# sourceMappingURL=select-document.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-document.d.ts","sourceRoot":"","sources":["../src/select-document.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAA;AACjF,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"select-document.d.ts","sourceRoot":"","sources":["../src/select-document.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAA;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAA;AAEnH,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,eAAe,CAAA;CACxB,GACD;IACE,WAAW,EAAE,MAAM,CAAA;CACpB,GACD;IACE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AACL,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GACvD,CACI;KACG,GAAG,IAAI,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,aAAa,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,GACrF,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC;CAC3B,CAAC,MAAM,aAAa,CAAC,GACtB,OAAO,CAAC,MAAM,CAAC,MAAM,aAAa,EAAE,KAAK,CAAC,CAAC,CAC9C,CAAA;AAEH,mFAAmF;AACnF,MAAM,MAAM,sBAAsB,GAAG;IACnC,4GAA4G;IAC5G,gBAAgB,CAAC,EAAE;QACjB,IAAI,EAAE,QAAQ,CAAA;QACd,oFAAoF;QACpF,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,KAAK,MAAM,GAAG,SAAS,CAAA;QAC7E;;;WAGG;QACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;CACF,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,iBAAiB,CAAA;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,eAAe,CAAA;KAAE,CAAA;IAClD,YAAY,EAAE,IAAI,CAAA;CACnB,CAAA;AACD,KAAK,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAA;AA+G/D,KAAK,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEnF;;;GAGG;AACH,KAAK,cAAc,GAAG;IACpB,qDAAqD;IACrD,cAAc,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAC3D,0EAA0E;IAC1E,eAAe,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAC5D,2DAA2D;IAC3D,eAAe,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnD,CAAA;AA8BD,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,GAAI,UAAU,eAAe,KAAG,cAWhE,CAAA;AAwDD;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,eAAe,EACzB,UAAS,oBAAyB,EAClC,SAAQ,cAA+C,KACtD,eA2NF,CAAA"}
|
package/dist/select-document.js
CHANGED
|
@@ -78,16 +78,43 @@ const findOperationByPathAndMethod = (document, selector) => {
|
|
|
78
78
|
method,
|
|
79
79
|
};
|
|
80
80
|
};
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
90
|
-
|
|
81
|
+
const indexOperations = (document) => {
|
|
82
|
+
const byId = new Map();
|
|
83
|
+
const byTag = new Map();
|
|
84
|
+
for (const [path, pathItem] of getPathEntries(document)) {
|
|
85
|
+
forEachPathItemOperation(pathItem, (method, operationRef) => {
|
|
86
|
+
const operation = getResolvedRef(operationRef);
|
|
87
|
+
if (typeof operation?.operationId === 'string') {
|
|
88
|
+
const matches = byId.get(operation.operationId) ?? [];
|
|
89
|
+
matches.push({ path, method });
|
|
90
|
+
byId.set(operation.operationId, matches);
|
|
91
|
+
}
|
|
92
|
+
for (const tag of new Set(operation?.tags)) {
|
|
93
|
+
const entries = byTag.get(tag) ?? [];
|
|
94
|
+
const last = entries.at(-1);
|
|
95
|
+
if (last?.path === path) {
|
|
96
|
+
last.methods.push(method);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
entries.push({ path, pathItem, methods: [method] });
|
|
100
|
+
}
|
|
101
|
+
byTag.set(tag, entries);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return { byId, byTag };
|
|
106
|
+
};
|
|
107
|
+
/** Index a document once so that each selection costs time in proportion to what it selects. */
|
|
108
|
+
export const createDocumentLookup = (document) => {
|
|
109
|
+
let operations;
|
|
110
|
+
let schemaPositions;
|
|
111
|
+
return {
|
|
112
|
+
operationsById: () => (operations ??= indexOperations(document)).byId,
|
|
113
|
+
operationsByTag: () => (operations ??= indexOperations(document)).byTag,
|
|
114
|
+
schemaPositions: () => (schemaPositions ??= new Map(Object.keys(document.components?.schemas ?? {}).map((name, position) => [name, position]))),
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
const resolveOperationMatch = (document, selector, lookup) => {
|
|
91
118
|
if ('pointer' in selector) {
|
|
92
119
|
const match = getOperationSelectorFromPointer(selector.pointer);
|
|
93
120
|
if (!getPathItemOperation(document.paths?.[match.path], match.method)) {
|
|
@@ -96,7 +123,7 @@ const resolveOperationMatch = (document, selector) => {
|
|
|
96
123
|
return match;
|
|
97
124
|
}
|
|
98
125
|
if ('operationId' in selector) {
|
|
99
|
-
const matches =
|
|
126
|
+
const matches = lookup.operationsById().get(selector.operationId) ?? [];
|
|
100
127
|
if (!matches.length) {
|
|
101
128
|
throw new Error(`Operation with operationId "${selector.operationId}" was not found`);
|
|
102
129
|
}
|
|
@@ -108,9 +135,9 @@ const resolveOperationMatch = (document, selector) => {
|
|
|
108
135
|
}
|
|
109
136
|
return findOperationByPathAndMethod(document, selector);
|
|
110
137
|
};
|
|
111
|
-
const filterDocumentByOperation = (document, selector) => {
|
|
112
|
-
const match = resolveOperationMatch(document, selector);
|
|
113
|
-
const pathItem =
|
|
138
|
+
const filterDocumentByOperation = (document, selector, lookup) => {
|
|
139
|
+
const match = resolveOperationMatch(document, selector, lookup);
|
|
140
|
+
const pathItem = getResolvedPathItem(document.paths?.[match.path]);
|
|
114
141
|
if (!pathItem) {
|
|
115
142
|
throw new Error(`Operation not found for path "${match.path}" and method "${match.method.toUpperCase()}"`);
|
|
116
143
|
}
|
|
@@ -121,8 +148,11 @@ const filterDocumentByOperation = (document, selector) => {
|
|
|
121
148
|
},
|
|
122
149
|
};
|
|
123
150
|
};
|
|
124
|
-
/**
|
|
125
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Scope after resolving references and migrating older documents.
|
|
153
|
+
* Pass the same lookup to every selection from one document to reuse its indexes.
|
|
154
|
+
*/
|
|
155
|
+
export const selectDocument = (document, options = {}, lookup = createDocumentLookup(document)) => {
|
|
126
156
|
if (!isObject(options)) {
|
|
127
157
|
throw new Error('Render options must be an object');
|
|
128
158
|
}
|
|
@@ -159,7 +189,7 @@ export const selectDocument = (document, options = {}) => {
|
|
|
159
189
|
const selected = { ...document, paths: {}, webhooks: {}, tags: [] };
|
|
160
190
|
const modelRoots = [];
|
|
161
191
|
if (options.operation) {
|
|
162
|
-
selected.paths = filterDocumentByOperation(document, options.operation).paths;
|
|
192
|
+
selected.paths = filterDocumentByOperation(document, options.operation, lookup).paths;
|
|
163
193
|
}
|
|
164
194
|
if (options.tag !== undefined) {
|
|
165
195
|
const metadata = document.tags?.filter((tag) => tag.name === options.tag) ?? [];
|
|
@@ -167,16 +197,8 @@ export const selectDocument = (document, options = {}) => {
|
|
|
167
197
|
throw new Error(`Multiple tags found for "${options.tag}"`);
|
|
168
198
|
}
|
|
169
199
|
selected.tags = metadata.length ? metadata : [{ name: options.tag }];
|
|
170
|
-
for (const
|
|
171
|
-
|
|
172
|
-
forEachPathItemOperation(item, (method, operation) => {
|
|
173
|
-
if (getResolvedRef(operation)?.tags?.includes(options.tag)) {
|
|
174
|
-
methods.push(method);
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
if (methods.length) {
|
|
178
|
-
selected.paths[path] = filterPathItemOperations(item, methods);
|
|
179
|
-
}
|
|
200
|
+
for (const { path, pathItem, methods } of lookup.operationsByTag().get(options.tag) ?? []) {
|
|
201
|
+
selected.paths[path] = filterPathItemOperations(pathItem, methods);
|
|
180
202
|
}
|
|
181
203
|
if (!metadata.length && !Object.keys(selected.paths ?? {}).length) {
|
|
182
204
|
throw new Error(`Tag "${options.tag}" was not found`);
|
|
@@ -231,8 +253,9 @@ export const selectDocument = (document, options = {}) => {
|
|
|
231
253
|
parameters.set(`${parameter.in}:${parameter.name}`, ref);
|
|
232
254
|
}
|
|
233
255
|
}
|
|
234
|
-
|
|
235
|
-
|
|
256
|
+
// Undeclared security stays undeclared: an empty list would claim that no authentication is required.
|
|
257
|
+
const security = operation.security ?? document.security;
|
|
258
|
+
for (const requirement of security ?? []) {
|
|
236
259
|
for (const name of Object.keys(requirement)) {
|
|
237
260
|
securityNames.add(name);
|
|
238
261
|
}
|
|
@@ -326,9 +349,14 @@ export const selectDocument = (document, options = {}) => {
|
|
|
326
349
|
visit(root);
|
|
327
350
|
}
|
|
328
351
|
}
|
|
352
|
+
const positions = lookup.schemaPositions();
|
|
329
353
|
selected.components = {
|
|
330
354
|
...document.components,
|
|
331
|
-
|
|
355
|
+
// Keep the document's schema order, which decides the order of the page's model sections.
|
|
356
|
+
schemas: Object.fromEntries([...needed]
|
|
357
|
+
.filter((name) => positions.has(name))
|
|
358
|
+
.sort((a, b) => positions.get(a) - positions.get(b))
|
|
359
|
+
.map((name) => [name, schemas[name]])),
|
|
332
360
|
securitySchemes: Object.fromEntries(Object.entries(document.components?.securitySchemes ?? {}).filter(([name]) => securityNames.has(name))),
|
|
333
361
|
};
|
|
334
362
|
return selected;
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"llm",
|
|
17
17
|
"swagger"
|
|
18
18
|
],
|
|
19
|
-
"version": "1.
|
|
19
|
+
"version": "1.5.1",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=22"
|
|
22
22
|
},
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"CHANGELOG.md"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@scalar/code-highlight": "0.4.
|
|
43
|
+
"@scalar/code-highlight": "0.4.8",
|
|
44
44
|
"@scalar/helpers": "0.16.0",
|
|
45
|
-
"@scalar/json-magic": "0.15.
|
|
45
|
+
"@scalar/json-magic": "0.15.4",
|
|
46
46
|
"@scalar/openapi-upgrader": "0.4.1",
|
|
47
|
-
"@scalar/workspace-store": "0.
|
|
47
|
+
"@scalar/workspace-store": "0.68.0",
|
|
48
48
|
"rehype-parse": "^9.0.1",
|
|
49
49
|
"rehype-remark": "^10.0.1",
|
|
50
50
|
"rehype-sanitize": "^6.0.0",
|
|
@@ -54,16 +54,25 @@
|
|
|
54
54
|
"unified": "^11.0.5"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@
|
|
57
|
+
"@scalar/components": "0.30.6",
|
|
58
58
|
"@scalar/galaxy": "0.7.1",
|
|
59
|
+
"@scalar/themes": "0.18.1",
|
|
60
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
59
61
|
"@types/mdast": "^4.0.4",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
63
|
+
"marked": "^14.0.0",
|
|
64
|
+
"rehype-stringify": "^10.0.1",
|
|
65
|
+
"tailwindcss": "^4.3.3",
|
|
66
|
+
"tsx": "4.19.4",
|
|
67
|
+
"vite": "8.1.5",
|
|
68
|
+
"vitest": "4.1.10",
|
|
69
|
+
"vue": "^3.5.40",
|
|
70
|
+
"vue-tsc": "^3.3.8"
|
|
62
71
|
},
|
|
63
72
|
"scripts": {
|
|
64
73
|
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
65
|
-
"dev": "
|
|
74
|
+
"dev": "cd playground && vite",
|
|
66
75
|
"test": "vitest --run",
|
|
67
|
-
"types:check": "tsgo --noEmit"
|
|
76
|
+
"types:check": "tsgo --noEmit && vue-tsc --noEmit -p playground/tsconfig.json"
|
|
68
77
|
}
|
|
69
78
|
}
|