@scalar/openapi-to-markdown 0.6.0 → 1.0.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.
- package/CHANGELOG.md +16 -0
- package/README.md +44 -35
- package/dist/create-markdown-from-openapi.d.ts +15 -25
- package/dist/create-markdown-from-openapi.d.ts.map +1 -1
- package/dist/create-markdown-from-openapi.js +35 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -850
- package/dist/load-document.d.ts +4 -0
- package/dist/load-document.d.ts.map +1 -0
- package/dist/load-document.js +151 -0
- package/dist/markdown-nodes.d.ts +25 -0
- package/dist/markdown-nodes.d.ts.map +1 -0
- package/dist/markdown-nodes.js +34 -0
- package/dist/parse-description.d.ts +6 -0
- package/dist/parse-description.d.ts.map +1 -0
- package/dist/parse-description.js +116 -0
- package/dist/parse-html-description.d.ts +4 -0
- package/dist/parse-html-description.d.ts.map +1 -0
- package/dist/parse-html-description.js +11 -0
- package/dist/render-document.d.ts +4 -0
- package/dist/render-document.d.ts.map +1 -0
- package/dist/render-document.js +112 -0
- package/dist/render-operation.d.ts +13 -0
- package/dist/render-operation.d.ts.map +1 -0
- package/dist/render-operation.js +89 -0
- package/dist/render-schema.d.ts +31 -0
- package/dist/render-schema.d.ts.map +1 -0
- package/dist/render-schema.js +98 -0
- package/dist/render-security.d.ts +6 -0
- package/dist/render-security.d.ts.map +1 -0
- package/dist/render-security.js +33 -0
- package/dist/select-document.d.ts +29 -0
- package/dist/select-document.d.ts.map +1 -0
- package/dist/select-document.js +312 -0
- package/package.json +15 -27
- package/dist/components/MarkdownReference.test.d.ts +0 -2
- package/dist/components/MarkdownReference.test.d.ts.map +0 -1
- package/dist/components/MarkdownReference.vue.d.ts +0 -9
- package/dist/components/MarkdownReference.vue.d.ts.map +0 -1
- package/dist/components/Schema.test.d.ts +0 -2
- package/dist/components/Schema.test.d.ts.map +0 -1
- package/dist/components/Schema.vue.d.ts +0 -10
- package/dist/components/Schema.vue.d.ts.map +0 -1
- package/dist/components/Security.vue.d.ts +0 -9
- package/dist/components/Security.vue.d.ts.map +0 -1
- package/dist/components/XmlOrJson.vue.d.ts +0 -8
- package/dist/components/XmlOrJson.vue.d.ts.map +0 -1
- package/dist/create-markdown-from-openapi.test.d.ts +0 -2
- package/dist/create-markdown-from-openapi.test.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/selection.test.d.ts +0 -2
- package/dist/selection.test.d.ts.map +0 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
/** Coerce one plain document and keep references linked to shared targets. */
|
|
3
|
+
export declare const loadDocument: (input: OpenApiDocument | Record<string, unknown> | string) => Promise<OpenApiDocument>;
|
|
4
|
+
//# sourceMappingURL=load-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-document.d.ts","sourceRoot":"","sources":["../src/load-document.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8DAA8D,CAAA;AAyErE,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GACvB,OAAO,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,KACxD,OAAO,CAAC,eAAe,CAoFzB,CAAA"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { parseJsonPointerSegments } from '@scalar/helpers/json/parse-json-pointer-segments';
|
|
2
|
+
import { isObject } from '@scalar/helpers/object/is-object';
|
|
3
|
+
import { bundle } from '@scalar/json-magic/bundle';
|
|
4
|
+
import { convertToLocalRef } from '@scalar/json-magic/helpers/convert-to-local-ref';
|
|
5
|
+
import { getId, getSchemas } from '@scalar/json-magic/helpers/get-schemas';
|
|
6
|
+
import { getValueByPath } from '@scalar/json-magic/helpers/get-value-by-path';
|
|
7
|
+
import { normalize } from '@scalar/json-magic/helpers/normalize';
|
|
8
|
+
import { getRaw } from '@scalar/json-magic/magic-proxy';
|
|
9
|
+
import { upgrade } from '@scalar/openapi-upgrader';
|
|
10
|
+
import { deepClone } from '@scalar/workspace-store/helpers/deep-clone';
|
|
11
|
+
import { coerceValue } from '@scalar/workspace-store/schemas/typebox-coerce';
|
|
12
|
+
import { OpenAPIDocumentSchema, } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
13
|
+
/**
|
|
14
|
+
* Link references in a private, bundled document without proxies or expanded copies.
|
|
15
|
+
* JSON Magic owns `$id` and anchor indexing, which keeps local-reference behavior
|
|
16
|
+
* aligned with the external-reference bundler without retaining a second resolver.
|
|
17
|
+
* Non-enumerable links preserve serialization and share recursive schema targets.
|
|
18
|
+
* Casting temporarily uses enumerable links to satisfy TypeBox reference branches.
|
|
19
|
+
* Returns whether external references remain and require bundling.
|
|
20
|
+
*/
|
|
21
|
+
const attachRefValues = (document, enumerable = false, schemas = getSchemas(document)) => {
|
|
22
|
+
// A single traversal covers both normal trees and previously linked recursive objects.
|
|
23
|
+
const seen = new WeakSet();
|
|
24
|
+
let hasExternalReferences = false;
|
|
25
|
+
const visit = (node, context = getId(document) ?? '') => {
|
|
26
|
+
if (node === null || typeof node !== 'object' || seen.has(node)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
seen.add(node);
|
|
30
|
+
// Nested `$id` values redefine the base for relative references and anchors.
|
|
31
|
+
const base = getId(node) ?? context;
|
|
32
|
+
if (isObject(node) && typeof node.$ref === 'string') {
|
|
33
|
+
const ref = node.$ref;
|
|
34
|
+
const path = ref === '#' ? '' : convertToLocalRef(ref, base, schemas);
|
|
35
|
+
// Point to the bundled target instead of copying it into every reference.
|
|
36
|
+
const target = path === undefined ? undefined : getValueByPath(document, parseJsonPointerSegments(`/${path}`)).value;
|
|
37
|
+
// JSON Magic only needs to bundle references outside this document's resource index.
|
|
38
|
+
if (path === undefined && ref.split('#')[0]) {
|
|
39
|
+
hasExternalReferences = true;
|
|
40
|
+
}
|
|
41
|
+
if (enumerable) {
|
|
42
|
+
const followed = new WeakSet();
|
|
43
|
+
let resolved = target;
|
|
44
|
+
// TypeBox needs the final target, so collapse a pre-existing reference chain safely.
|
|
45
|
+
while (isObject(resolved) && '$ref-value' in resolved && !followed.has(resolved)) {
|
|
46
|
+
followed.add(resolved);
|
|
47
|
+
resolved = resolved['$ref-value'];
|
|
48
|
+
}
|
|
49
|
+
if (resolved !== undefined) {
|
|
50
|
+
Object.defineProperty(node, '$ref-value', {
|
|
51
|
+
value: resolved,
|
|
52
|
+
enumerable,
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (target !== undefined) {
|
|
59
|
+
Object.defineProperty(node, '$ref-value', {
|
|
60
|
+
value: target,
|
|
61
|
+
enumerable,
|
|
62
|
+
configurable: true,
|
|
63
|
+
writable: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Preserve the nearest resource base while walking into child schemas.
|
|
68
|
+
for (const child of Object.values(node)) {
|
|
69
|
+
visit(child, base);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
visit(document);
|
|
73
|
+
return hasExternalReferences;
|
|
74
|
+
};
|
|
75
|
+
/** Coerce one plain document and keep references linked to shared targets. */
|
|
76
|
+
export const loadDocument = async (input) => {
|
|
77
|
+
let raw;
|
|
78
|
+
let origin;
|
|
79
|
+
// Reference links are attached below, so never mutate the caller's document.
|
|
80
|
+
if (typeof input !== 'string') {
|
|
81
|
+
raw = deepClone(getRaw(input));
|
|
82
|
+
}
|
|
83
|
+
// Inline JSON and YAML avoid the I/O path; URLs and files are loaded afterward.
|
|
84
|
+
else {
|
|
85
|
+
const normalized = normalize(input);
|
|
86
|
+
if (isObject(normalized)) {
|
|
87
|
+
raw = normalized;
|
|
88
|
+
}
|
|
89
|
+
else if (/^https?:\/\//i.test(input)) {
|
|
90
|
+
const response = await fetch(input);
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
throw new Error(`Failed to load OpenAPI document (HTTP ${response.status})`);
|
|
93
|
+
}
|
|
94
|
+
raw = normalize(await response.text());
|
|
95
|
+
origin = input;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const [{ resolve }, { readFile }] = await Promise.all([import('node:path'), import('node:fs/promises')]);
|
|
99
|
+
origin = resolve(input);
|
|
100
|
+
raw = normalize(await readFile(origin, 'utf8'));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!isObject(raw)) {
|
|
104
|
+
throw new Error('Failed to load OpenAPI document');
|
|
105
|
+
}
|
|
106
|
+
// Upgrade before indexing so reference resolution sees one consistent dialect.
|
|
107
|
+
const upgraded = upgrade(raw, '3.2');
|
|
108
|
+
const upgradedSchemas = getSchemas(upgraded);
|
|
109
|
+
const hasExternalReferences = attachRefValues(upgraded, false, upgradedSchemas);
|
|
110
|
+
let document = upgraded;
|
|
111
|
+
let schemas = upgradedSchemas;
|
|
112
|
+
// Resolve external targets only when the initial local-reference pass finds them.
|
|
113
|
+
if (hasExternalReferences) {
|
|
114
|
+
const errors = [];
|
|
115
|
+
const plugins = typeof process === 'undefined'
|
|
116
|
+
? [(await import('@scalar/json-magic/bundle/plugins/browser')).fetchUrls()]
|
|
117
|
+
: [
|
|
118
|
+
(await import('@scalar/json-magic/bundle/plugins/node')).fetchUrls(),
|
|
119
|
+
(await import('@scalar/json-magic/bundle/plugins/node')).readFiles(),
|
|
120
|
+
];
|
|
121
|
+
document = await bundle(upgraded, {
|
|
122
|
+
plugins,
|
|
123
|
+
origin,
|
|
124
|
+
treeShake: false,
|
|
125
|
+
hooks: { onResolveError: (node) => errors.push(`Failed to resolve ${node.$ref}`) },
|
|
126
|
+
});
|
|
127
|
+
if (errors.length) {
|
|
128
|
+
throw new Error(errors.join('\n'));
|
|
129
|
+
}
|
|
130
|
+
schemas = getSchemas(document);
|
|
131
|
+
attachRefValues(document, false, schemas);
|
|
132
|
+
}
|
|
133
|
+
// TypeBox's reference branches require an enumerable $ref-value during casting.
|
|
134
|
+
// Restore non-enumerable shared links afterward so rendering never expands the graph.
|
|
135
|
+
attachRefValues(document, true, schemas);
|
|
136
|
+
const coerced = coerceValue(OpenAPIDocumentSchema, document);
|
|
137
|
+
// Keep extension resources that local and bundled references can target.
|
|
138
|
+
for (const [key, value] of Object.entries(document)) {
|
|
139
|
+
if (key.startsWith('x-') && !(key in coerced)) {
|
|
140
|
+
Object.defineProperty(coerced, key, {
|
|
141
|
+
value,
|
|
142
|
+
enumerable: true,
|
|
143
|
+
configurable: true,
|
|
144
|
+
writable: true,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Redefine TypeBox's temporary links as non-enumerable links to coerced targets.
|
|
149
|
+
attachRefValues(coerced, false, schemas);
|
|
150
|
+
return coerced;
|
|
151
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Heading, InlineCode, Link, List, ListItem, Paragraph, PhrasingContent, Strong, Text } from 'mdast';
|
|
2
|
+
/** Collapse HTML-style inline whitespace; the serializer escapes generated text as Markdown. */
|
|
3
|
+
export declare const text: (value: unknown) => Text;
|
|
4
|
+
/** Inline code fences are chosen by the serializer. */
|
|
5
|
+
export declare const inlineCode: (value: unknown) => InlineCode;
|
|
6
|
+
/** Construct a paragraph from phrasing nodes. */
|
|
7
|
+
export declare const paragraph: (...children: PhrasingContent[]) => Paragraph;
|
|
8
|
+
/** Construct an emphasized label. */
|
|
9
|
+
export declare const strong: (...children: PhrasingContent[]) => Strong;
|
|
10
|
+
/** Construct a section heading. */
|
|
11
|
+
export declare const heading: (depth: Heading["depth"], ...children: PhrasingContent[]) => Heading;
|
|
12
|
+
/** Construct a list item that may contain nested blocks. */
|
|
13
|
+
export declare const item: (...children: ListItem["children"]) => ListItem;
|
|
14
|
+
/** Construct an unordered list. */
|
|
15
|
+
export declare const list: (children: ListItem[]) => List;
|
|
16
|
+
/**
|
|
17
|
+
* Retain rehype-sanitize's protocol policy. The general sanitizeUrl helper allows
|
|
18
|
+
* additional schemes and excludes IRC/XMPP, so it is not compatible here.
|
|
19
|
+
*/
|
|
20
|
+
export declare const safeUrl: (url: string) => string;
|
|
21
|
+
/** Links from OpenAPI metadata follow the same URL policy as descriptions. */
|
|
22
|
+
export declare const link: (url: string, label: string) => Link;
|
|
23
|
+
/** Render a metadata label and value with the established nonbreaking separator. */
|
|
24
|
+
export declare const field: (label: string, value: PhrasingContent) => ListItem;
|
|
25
|
+
//# sourceMappingURL=markdown-nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-nodes.d.ts","sourceRoot":"","sources":["../src/markdown-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEhH,gGAAgG;AAChG,eAAO,MAAM,IAAI,GAAI,OAAO,OAAO,KAAG,IAGpC,CAAA;AACF,uDAAuD;AACvD,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,UAAkE,CAAA;AAC9G,iDAAiD;AACjD,eAAO,MAAM,SAAS,GAAI,GAAG,UAAU,eAAe,EAAE,KAAG,SAA8C,CAAA;AACzG,qCAAqC;AACrC,eAAO,MAAM,MAAM,GAAI,GAAG,UAAU,eAAe,EAAE,KAAG,MAAwC,CAAA;AAChG,mCAAmC;AACnC,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,UAAU,eAAe,EAAE,KAAG,OAIhF,CAAA;AACF,4DAA4D;AAC5D,eAAO,MAAM,IAAI,GAAI,GAAG,UAAU,QAAQ,CAAC,UAAU,CAAC,KAAG,QAA2D,CAAA;AACpH,mCAAmC;AACnC,eAAO,MAAM,IAAI,GAAI,UAAU,QAAQ,EAAE,KAAG,IAAmE,CAAA;AAC/G;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAIrC,CAAA;AACD,8EAA8E;AAC9E,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,KAAG,IAAsE,CAAA;AACxH,oFAAoF;AACpF,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,EAAE,OAAO,eAAe,KAAG,QACK,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Collapse HTML-style inline whitespace; the serializer escapes generated text as Markdown. */
|
|
2
|
+
export const text = (value) => ({
|
|
3
|
+
type: 'text',
|
|
4
|
+
value: String(value ?? '').replace(/[\t\n\f\r ]+/g, ' '),
|
|
5
|
+
});
|
|
6
|
+
/** Inline code fences are chosen by the serializer. */
|
|
7
|
+
export const inlineCode = (value) => ({ type: 'inlineCode', value: String(value ?? '') });
|
|
8
|
+
/** Construct a paragraph from phrasing nodes. */
|
|
9
|
+
export const paragraph = (...children) => ({ type: 'paragraph', children });
|
|
10
|
+
/** Construct an emphasized label. */
|
|
11
|
+
export const strong = (...children) => ({ type: 'strong', children });
|
|
12
|
+
/** Construct a section heading. */
|
|
13
|
+
export const heading = (depth, ...children) => ({
|
|
14
|
+
type: 'heading',
|
|
15
|
+
depth,
|
|
16
|
+
children,
|
|
17
|
+
});
|
|
18
|
+
/** Construct a list item that may contain nested blocks. */
|
|
19
|
+
export const item = (...children) => ({ type: 'listItem', spread: false, children });
|
|
20
|
+
/** Construct an unordered list. */
|
|
21
|
+
export const list = (children) => ({ type: 'list', ordered: false, spread: false, children });
|
|
22
|
+
/**
|
|
23
|
+
* Retain rehype-sanitize's protocol policy. The general sanitizeUrl helper allows
|
|
24
|
+
* additional schemes and excludes IRC/XMPP, so it is not compatible here.
|
|
25
|
+
*/
|
|
26
|
+
export const safeUrl = (url) => {
|
|
27
|
+
const normalized = url.replace(/[\u0000-\u0020\u007f-\u009f]/g, '');
|
|
28
|
+
const protocol = /^([^/?#]*):/.exec(normalized)?.[1];
|
|
29
|
+
return protocol && !['http', 'https', 'irc', 'ircs', 'mailto', 'xmpp'].includes(protocol.toLowerCase()) ? '' : url;
|
|
30
|
+
};
|
|
31
|
+
/** Links from OpenAPI metadata follow the same URL policy as descriptions. */
|
|
32
|
+
export const link = (url, label) => ({ type: 'link', url: safeUrl(url), children: [text(label)] });
|
|
33
|
+
/** Render a metadata label and value with the established nonbreaking separator. */
|
|
34
|
+
export const field = (label, value) => item(paragraph(strong(text(`${label}:`)), text('\u00a0'), value));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RootContent } from 'mdast';
|
|
2
|
+
/** Parse one description into blocks suitable for insertion into the current document. */
|
|
3
|
+
export type DescriptionParser = (value?: string) => Promise<RootContent[]>;
|
|
4
|
+
/** Share parsing across pages while giving every rendered document its own reference namespace. */
|
|
5
|
+
export declare const createDescriptionParser: () => (() => DescriptionParser);
|
|
6
|
+
//# sourceMappingURL=parse-description.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-description.d.ts","sourceRoot":"","sources":["../src/parse-description.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,OAAO,CAAA;AA2ErD,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,CA0ClE,CAAA"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import remarkGfm from 'remark-gfm';
|
|
2
|
+
import remarkParse from 'remark-parse';
|
|
3
|
+
import { unified } from 'unified';
|
|
4
|
+
import { safeUrl } from './markdown-nodes.js';
|
|
5
|
+
const parser = unified().use(remarkParse).use(remarkGfm).freeze();
|
|
6
|
+
const containsHtml = (node) => node.type === 'html' || ('children' in node && node.children.some(containsHtml));
|
|
7
|
+
/** Remove images and unsafe URLs without converting ordinary Markdown to HTML. */
|
|
8
|
+
const clean = (node) => {
|
|
9
|
+
if ('url' in node) {
|
|
10
|
+
node.url = safeUrl(node.url);
|
|
11
|
+
}
|
|
12
|
+
if ('children' in node) {
|
|
13
|
+
for (const child of node.children)
|
|
14
|
+
clean(child);
|
|
15
|
+
// The filter preserves the parent's existing child types.
|
|
16
|
+
const previousLength = node.children.length;
|
|
17
|
+
node.children = node.children.filter((child) => child.type !== 'image' &&
|
|
18
|
+
child.type !== 'imageReference' &&
|
|
19
|
+
!([
|
|
20
|
+
'strong',
|
|
21
|
+
'emphasis',
|
|
22
|
+
'delete',
|
|
23
|
+
'link',
|
|
24
|
+
'linkReference',
|
|
25
|
+
'paragraph',
|
|
26
|
+
'heading',
|
|
27
|
+
'blockquote',
|
|
28
|
+
'list',
|
|
29
|
+
'listItem',
|
|
30
|
+
].includes(child.type) &&
|
|
31
|
+
'children' in child &&
|
|
32
|
+
child.children.every((descendant) => descendant.type === 'text' && !descendant.value.trim())));
|
|
33
|
+
if (node.children.length !== previousLength) {
|
|
34
|
+
const first = node.children.at(0);
|
|
35
|
+
const last = node.children.at(-1);
|
|
36
|
+
if (first?.type === 'text')
|
|
37
|
+
first.value = first.value.trimStart();
|
|
38
|
+
if (last?.type === 'text')
|
|
39
|
+
last.value = last.value.trimEnd();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
delete node.position;
|
|
43
|
+
};
|
|
44
|
+
/** Removed images must not leave their reference definitions or empty paragraphs behind. */
|
|
45
|
+
const pruneDefinitions = (tree) => {
|
|
46
|
+
const links = new Set();
|
|
47
|
+
const footnotes = new Set();
|
|
48
|
+
const definitions = new Map(tree.children.filter((node) => node.type === 'footnoteDefinition').map((node) => [node.identifier, node]));
|
|
49
|
+
const collect = (node) => {
|
|
50
|
+
if (node.type === 'linkReference')
|
|
51
|
+
links.add(node.identifier);
|
|
52
|
+
if (node.type === 'footnoteReference')
|
|
53
|
+
footnotes.add(node.identifier);
|
|
54
|
+
if ('children' in node)
|
|
55
|
+
node.children.forEach(collect);
|
|
56
|
+
};
|
|
57
|
+
tree.children.filter((node) => node.type !== 'footnoteDefinition').forEach(collect);
|
|
58
|
+
// Set iteration also visits footnotes discovered inside another footnote.
|
|
59
|
+
for (const identifier of footnotes)
|
|
60
|
+
definitions.get(identifier)?.children.forEach(collect);
|
|
61
|
+
tree.children = tree.children.filter((node) => {
|
|
62
|
+
if (node.type === 'definition')
|
|
63
|
+
return links.has(node.identifier);
|
|
64
|
+
if (node.type === 'footnoteDefinition')
|
|
65
|
+
return footnotes.has(node.identifier);
|
|
66
|
+
if (node.type === 'paragraph')
|
|
67
|
+
return node.children.some((child) => child.type !== 'text' || child.value.trim());
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
/** Share parsing across pages while giving every rendered document its own reference namespace. */
|
|
72
|
+
export const createDescriptionParser = () => {
|
|
73
|
+
const cache = new Map();
|
|
74
|
+
const parse = async (value) => {
|
|
75
|
+
const parsed = parser.parse(value);
|
|
76
|
+
// Raw HTML and GitHub alerts retain Scalar's existing conversion behavior.
|
|
77
|
+
const tree = containsHtml(parsed) || /^\s*>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION|SUCCESS)\]/im.test(value)
|
|
78
|
+
? await (await import('./parse-html-description.js')).parseHtmlDescription(value)
|
|
79
|
+
: parsed;
|
|
80
|
+
clean(tree);
|
|
81
|
+
pruneDefinitions(tree);
|
|
82
|
+
return tree.children;
|
|
83
|
+
};
|
|
84
|
+
const namespace = (node, prefix) => {
|
|
85
|
+
const copy = { ...node };
|
|
86
|
+
if ('identifier' in copy) {
|
|
87
|
+
copy.identifier = `${prefix}${copy.identifier}`;
|
|
88
|
+
if ('label' in copy)
|
|
89
|
+
copy.label = copy.identifier;
|
|
90
|
+
if ('referenceType' in copy)
|
|
91
|
+
copy.referenceType = 'full';
|
|
92
|
+
}
|
|
93
|
+
if ('children' in copy)
|
|
94
|
+
copy.children = copy.children.map((child) => namespace(child, prefix));
|
|
95
|
+
return copy;
|
|
96
|
+
};
|
|
97
|
+
const hasReference = (node) => 'identifier' in node || ('children' in node && node.children.some(hasReference));
|
|
98
|
+
return () => {
|
|
99
|
+
const state = { nextId: 0 };
|
|
100
|
+
return async (value) => {
|
|
101
|
+
if (!value)
|
|
102
|
+
return [];
|
|
103
|
+
const prefix = `description-${state.nextId++}-`;
|
|
104
|
+
const cached = cache.get(value) ?? parse(value);
|
|
105
|
+
if (!cache.has(value)) {
|
|
106
|
+
if (cache.size >= 256)
|
|
107
|
+
cache.clear();
|
|
108
|
+
cache.set(value, cached);
|
|
109
|
+
}
|
|
110
|
+
const nodes = await cached;
|
|
111
|
+
// Ordinary Markdown can share immutable nodes. Reference definitions need a copy
|
|
112
|
+
// so repeated descriptions and concurrent page renders cannot affect one another.
|
|
113
|
+
return nodes.map((node) => (hasReference(node) ? namespace(node, prefix) : node));
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-html-description.d.ts","sourceRoot":"","sources":["../src/parse-html-description.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAQjC,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,IAGpD,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { htmlFromMarkdown } from '@scalar/code-highlight';
|
|
2
|
+
import rehypeParse from 'rehype-parse';
|
|
3
|
+
import rehypeRemark from 'rehype-remark';
|
|
4
|
+
import rehypeSanitize from 'rehype-sanitize';
|
|
5
|
+
import { unified } from 'unified';
|
|
6
|
+
const converter = unified().use(rehypeParse, { fragment: true }).use(rehypeSanitize).use(rehypeRemark).freeze();
|
|
7
|
+
/** Compatibility path loaded only for descriptions containing HTML or Scalar alerts. */
|
|
8
|
+
export const parseHtmlDescription = (value) => {
|
|
9
|
+
const html = htmlFromMarkdown(value, { removeTags: ['img', 'picture'] });
|
|
10
|
+
return converter.runSync(converter.parse(html));
|
|
11
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
/** Build Markdown directly, retaining caches only for this immutable document snapshot. */
|
|
3
|
+
export declare const createDocumentRenderer: () => ((document: OpenApiDocument) => Promise<string>);
|
|
4
|
+
//# sourceMappingURL=render-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-document.d.ts","sourceRoot":"","sources":["../src/render-document.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAmB,MAAM,8DAA8D,CAAA;AAcpH,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,QAAO,CAAC,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,CAgIxF,CAAA"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { forEachPathItemOperation, getResolvedPathItem, } from '@scalar/workspace-store/helpers/for-each-path-item-operation';
|
|
2
|
+
import { getResolvedRef, mergeSiblingReferences } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
import remarkStringify from 'remark-stringify';
|
|
5
|
+
import { unified } from 'unified';
|
|
6
|
+
import { field, heading, inlineCode, item, link, list, paragraph, strong, text } from './markdown-nodes.js';
|
|
7
|
+
import { createDescriptionParser } from './parse-description.js';
|
|
8
|
+
import { renderOperation } from './render-operation.js';
|
|
9
|
+
import { createSchemaRenderer } from './render-schema.js';
|
|
10
|
+
import { renderSecurity } from './render-security.js';
|
|
11
|
+
const serializer = unified().use(remarkGfm).use(remarkStringify, { bullet: '-' }).freeze();
|
|
12
|
+
/** Build Markdown directly, retaining caches only for this immutable document snapshot. */
|
|
13
|
+
export const createDocumentRenderer = () => {
|
|
14
|
+
const descriptions = createDescriptionParser();
|
|
15
|
+
const schemas = createSchemaRenderer();
|
|
16
|
+
return async (document) => {
|
|
17
|
+
const description = descriptions();
|
|
18
|
+
const { info } = document;
|
|
19
|
+
const metadata = [
|
|
20
|
+
field('OpenAPI Version', inlineCode(document.openapi)),
|
|
21
|
+
field('API Version', inlineCode(info.version)),
|
|
22
|
+
];
|
|
23
|
+
if (info.termsOfService)
|
|
24
|
+
metadata.push(field('Terms of service', link(info.termsOfService, info.termsOfService)));
|
|
25
|
+
if (info.contact) {
|
|
26
|
+
const contact = [text(info.contact.name ?? '')];
|
|
27
|
+
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)] : []))));
|
|
28
|
+
}
|
|
29
|
+
if (info.license)
|
|
30
|
+
metadata.push(field('License', info.license.url ? link(info.license.url, info.license.name ?? '') : text(info.license.name)));
|
|
31
|
+
const nodes = [
|
|
32
|
+
heading(1, text(info.title)),
|
|
33
|
+
list(metadata),
|
|
34
|
+
...(await description(info.description)),
|
|
35
|
+
];
|
|
36
|
+
if (document.servers?.length) {
|
|
37
|
+
nodes.push(heading(2, text('Servers')));
|
|
38
|
+
const servers = document.servers.map((server) => {
|
|
39
|
+
const nested = [];
|
|
40
|
+
if (server.description)
|
|
41
|
+
nested.push(field('Description', text(server.description)));
|
|
42
|
+
const variables = Object.entries(server.variables ?? {});
|
|
43
|
+
if (variables.length)
|
|
44
|
+
nested.push(item(paragraph(strong(text('Variables:'))), list(variables.map(([name, variable]) => item(paragraph(inlineCode(name), text(' (default: '), inlineCode(variable.default), text(`)${variable.description ? `: ${variable.description}` : ''}`)))))));
|
|
45
|
+
const entry = field('URL', inlineCode(server.url));
|
|
46
|
+
if (nested.length)
|
|
47
|
+
entry.children.push(list(nested));
|
|
48
|
+
return entry;
|
|
49
|
+
});
|
|
50
|
+
nodes.push(list(servers));
|
|
51
|
+
}
|
|
52
|
+
nodes.push(...(await renderSecurity(document.security, document.components?.securitySchemes, description)));
|
|
53
|
+
if (document.tags?.length) {
|
|
54
|
+
nodes.push(heading(2, text('Tags')));
|
|
55
|
+
for (const tag of document.tags) {
|
|
56
|
+
nodes.push(heading(3, text(tag.name)), ...(await description(tag.description)));
|
|
57
|
+
if (tag.externalDocs)
|
|
58
|
+
nodes.push(paragraph(link(tag.externalDocs.url, tag.externalDocs.description ?? tag.externalDocs.url)));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const sections = [];
|
|
62
|
+
const flush = () => {
|
|
63
|
+
if (nodes.length) {
|
|
64
|
+
const tree = { type: 'root', children: nodes.splice(0) };
|
|
65
|
+
sections.push(serializer.stringify(tree).trimEnd());
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
flush();
|
|
69
|
+
for (const group of [
|
|
70
|
+
{ title: 'Operations', paths: document.paths, webhook: false },
|
|
71
|
+
{ title: 'Webhooks', paths: document.webhooks, webhook: true },
|
|
72
|
+
]) {
|
|
73
|
+
let hasOperations = false;
|
|
74
|
+
for (const [path, reference] of Object.entries(group.paths ?? {})) {
|
|
75
|
+
const pathItem = getResolvedPathItem(reference);
|
|
76
|
+
if (!pathItem)
|
|
77
|
+
continue;
|
|
78
|
+
const entries = [];
|
|
79
|
+
forEachPathItemOperation(reference, (method, operation) => {
|
|
80
|
+
entries.push({ method, operation: getResolvedRef(operation, mergeSiblingReferences) });
|
|
81
|
+
});
|
|
82
|
+
for (const { method, operation } of entries) {
|
|
83
|
+
if (!hasOperations) {
|
|
84
|
+
nodes.push(heading(2, text(group.title)));
|
|
85
|
+
hasOperations = true;
|
|
86
|
+
}
|
|
87
|
+
nodes.push(...(await renderOperation(document, path, method, pathItem, operation, group.webhook, {
|
|
88
|
+
description,
|
|
89
|
+
schemas,
|
|
90
|
+
})));
|
|
91
|
+
flush();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const models = Object.entries(document.components?.schemas ?? {});
|
|
96
|
+
if (models.length)
|
|
97
|
+
nodes.push(heading(2, text('Schemas')));
|
|
98
|
+
for (const [name, schema] of models) {
|
|
99
|
+
const view = schemas.view(schema);
|
|
100
|
+
nodes.push(heading(3, text(view.title ?? name)), list([
|
|
101
|
+
view.type
|
|
102
|
+
? field('Type', inlineCode(Array.isArray(view.type) ? view.type.join(' | ') : view.type))
|
|
103
|
+
: item(paragraph(strong(text('Type:')))),
|
|
104
|
+
]), ...(await description(view.description)), ...schemas.render(schema));
|
|
105
|
+
if (view.type === 'object')
|
|
106
|
+
nodes.push(paragraph(strong(text('Example:'))), schemas.example(schema));
|
|
107
|
+
flush();
|
|
108
|
+
}
|
|
109
|
+
flush();
|
|
110
|
+
return `${sections.join('\n\n')}\n`;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OpenApiDocument, OperationObject, PathItemObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
import type { RootContent } from 'mdast';
|
|
3
|
+
import type { DescriptionParser } from './parse-description.js';
|
|
4
|
+
import type { SchemaRenderer } from './render-schema.js';
|
|
5
|
+
/** Dependencies shared by all sections of one prepared renderer. */
|
|
6
|
+
type RenderContext = {
|
|
7
|
+
description: DescriptionParser;
|
|
8
|
+
schemas: SchemaRenderer;
|
|
9
|
+
};
|
|
10
|
+
/** Render effective operation context without mutating the prepared document. */
|
|
11
|
+
export declare const renderOperation: (document: OpenApiDocument, path: string, method: string, pathItem: PathItemObject, operation: OperationObject, webhook: boolean, { description, schemas }: RenderContext) => Promise<RootContent[]>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=render-operation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-operation.d.ts","sourceRoot":"","sources":["../src/render-operation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAEf,cAAc,EAGf,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAY,WAAW,EAAE,MAAM,OAAO,CAAA;AAGlD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGrD,oEAAoE;AACpE,KAAK,aAAa,GAAG;IACnB,WAAW,EAAE,iBAAiB,CAAA;IAC9B,OAAO,EAAE,cAAc,CAAA;CACxB,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,eAAe,GAC1B,UAAU,eAAe,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,UAAU,cAAc,EACxB,WAAW,eAAe,EAC1B,SAAS,OAAO,EAChB,0BAA0B,aAAa,KACtC,OAAO,CAAC,WAAW,EAAE,CAgGvB,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getResolvedRef, mergeSiblingReferences } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
2
|
+
import { field, heading, inlineCode, item, list, paragraph, strong, text } from './markdown-nodes.js';
|
|
3
|
+
import { renderSecurity } from './render-security.js';
|
|
4
|
+
/** Render effective operation context without mutating the prepared document. */
|
|
5
|
+
export const renderOperation = async (document, path, method, pathItem, operation, webhook, { description, schemas }) => {
|
|
6
|
+
const stability = operation['x-scalar-stability'];
|
|
7
|
+
const title = (operation.summary || `${method.toUpperCase()} ${path}`) +
|
|
8
|
+
(stability ? ` (${stability})` : operation.deprecated ? ' ⚠️ Deprecated' : '');
|
|
9
|
+
const metadata = [
|
|
10
|
+
field('Method', inlineCode(method.toUpperCase())),
|
|
11
|
+
field(webhook ? 'Webhook' : 'Path', inlineCode(path)),
|
|
12
|
+
];
|
|
13
|
+
if (operation.tags)
|
|
14
|
+
metadata.push(field('Tags', text(operation.tags.join(', '))));
|
|
15
|
+
if (stability)
|
|
16
|
+
metadata.push(field('Stability', text(stability)));
|
|
17
|
+
const nodes = [heading(3, text(title)), list(metadata), ...(await description(operation.description))];
|
|
18
|
+
const servers = operation.servers ?? pathItem.servers ?? document.servers;
|
|
19
|
+
if (servers?.length) {
|
|
20
|
+
nodes.push(heading(4, text('Effective servers')));
|
|
21
|
+
const serverItems = [];
|
|
22
|
+
for (const server of servers) {
|
|
23
|
+
const blocks = [
|
|
24
|
+
paragraph(inlineCode(server.url)),
|
|
25
|
+
...(await description(server.description)),
|
|
26
|
+
];
|
|
27
|
+
const variables = Object.entries(server.variables ?? {});
|
|
28
|
+
if (variables.length)
|
|
29
|
+
blocks.push(list(variables.map(([name, variable]) => item(paragraph(text(`${name}: `), inlineCode(variable.default))))));
|
|
30
|
+
serverItems.push(item(...blocks));
|
|
31
|
+
}
|
|
32
|
+
nodes.push(list(serverItems));
|
|
33
|
+
}
|
|
34
|
+
nodes.push(...(await renderSecurity(operation.security ?? document.security, document.components?.securitySchemes, description)));
|
|
35
|
+
const parameters = new Map();
|
|
36
|
+
for (const reference of [...(pathItem.parameters ?? []), ...(operation.parameters ?? [])]) {
|
|
37
|
+
const parameter = getResolvedRef(reference, mergeSiblingReferences);
|
|
38
|
+
if (parameter)
|
|
39
|
+
parameters.set(`${parameter.in}:${parameter.name}`, parameter);
|
|
40
|
+
}
|
|
41
|
+
if (parameters.size)
|
|
42
|
+
nodes.push(heading(4, text('Parameters')));
|
|
43
|
+
for (const parameter of parameters.values()) {
|
|
44
|
+
nodes.push(heading(5, inlineCode(parameter.name), text(`${parameter.required ? ' required' : ''}${parameter.deprecated ? ' deprecated' : ''}`)));
|
|
45
|
+
const fields = [field('In', inlineCode(parameter.in))];
|
|
46
|
+
if ('style' in parameter && parameter.style)
|
|
47
|
+
fields.push(field('Style', inlineCode(parameter.style)));
|
|
48
|
+
if ('explode' in parameter && typeof parameter.explode === 'boolean')
|
|
49
|
+
fields.push(field('Explode', inlineCode(parameter.explode)));
|
|
50
|
+
if (parameter.allowEmptyValue)
|
|
51
|
+
fields.push(field('Allow Empty Value', text('true')));
|
|
52
|
+
if ('allowReserved' in parameter && parameter.allowReserved)
|
|
53
|
+
fields.push(field('Allow Reserved', text('true')));
|
|
54
|
+
nodes.push(list(fields), ...(await description(parameter.description)));
|
|
55
|
+
if ('schema' in parameter && parameter.schema)
|
|
56
|
+
nodes.push(...schemas.render(parameter.schema));
|
|
57
|
+
for (const [mediaType, content] of Object.entries('content' in parameter ? (parameter.content ?? {}) : {})) {
|
|
58
|
+
nodes.push(heading(6, text(`Content-Type: ${mediaType}`)));
|
|
59
|
+
if (content.schema)
|
|
60
|
+
nodes.push(...schemas.render(content.schema));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const body = getResolvedRef(operation.requestBody, mergeSiblingReferences);
|
|
64
|
+
if (body?.content) {
|
|
65
|
+
nodes.push(heading(4, text('Request Body')), ...(await description(body.description)));
|
|
66
|
+
if (body.required)
|
|
67
|
+
nodes.push(paragraph(strong(text('Required:')), text(' true')));
|
|
68
|
+
for (const [mediaType, content] of Object.entries(body.content)) {
|
|
69
|
+
nodes.push(heading(5, text(`Content-Type: ${mediaType}`)));
|
|
70
|
+
if (content.schema)
|
|
71
|
+
nodes.push(...schemas.render(content.schema), paragraph(strong(text('Example:'))), schemas.example(content.schema, mediaType.includes('xml')));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const responses = Object.entries(operation.responses ?? {}).flatMap(([status, reference]) => {
|
|
75
|
+
const response = getResolvedRef(reference, mergeSiblingReferences);
|
|
76
|
+
return response ? [{ status, response }] : [];
|
|
77
|
+
});
|
|
78
|
+
if (responses.length)
|
|
79
|
+
nodes.push(heading(4, text('Responses')));
|
|
80
|
+
for (const { status, response } of responses) {
|
|
81
|
+
nodes.push(heading(5, text(`Status: ${status}${response.description ? ` ${response.description}` : ''}`)));
|
|
82
|
+
for (const [mediaType, content] of Object.entries(response.content ?? {})) {
|
|
83
|
+
nodes.push(heading(6, text(`Content-Type: ${mediaType}`)));
|
|
84
|
+
if (content.schema)
|
|
85
|
+
nodes.push(...schemas.render(content.schema), paragraph(strong(text('Example:'))), schemas.example(content.schema, mediaType.includes('xml')));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return nodes;
|
|
89
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MaybeRefSchemaObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/schema';
|
|
2
|
+
import type { Code, RootContent } from 'mdast';
|
|
3
|
+
type SchemaView = {
|
|
4
|
+
schema: SchemaObject;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
type?: string | string[];
|
|
8
|
+
format?: string;
|
|
9
|
+
enum?: unknown[];
|
|
10
|
+
default?: unknown;
|
|
11
|
+
allOf?: MaybeRefSchemaObject[];
|
|
12
|
+
anyOf?: MaybeRefSchemaObject[];
|
|
13
|
+
oneOf?: MaybeRefSchemaObject[];
|
|
14
|
+
not?: MaybeRefSchemaObject;
|
|
15
|
+
properties: [string, MaybeRefSchemaObject][];
|
|
16
|
+
required: ReadonlySet<string>;
|
|
17
|
+
items?: MaybeRefSchemaObject;
|
|
18
|
+
minItems?: number;
|
|
19
|
+
maxItems?: number;
|
|
20
|
+
uniqueItems?: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** Schema normalization is cached separately from ancestry-dependent expansion. */
|
|
23
|
+
export type SchemaRenderer = {
|
|
24
|
+
view: (schema: MaybeRefSchemaObject) => SchemaView;
|
|
25
|
+
render: (schema: MaybeRefSchemaObject, depth?: number, ancestors?: readonly unknown[]) => RootContent[];
|
|
26
|
+
example: (schema: MaybeRefSchemaObject, xml?: boolean) => Code;
|
|
27
|
+
};
|
|
28
|
+
/** Keep merged reference siblings and sorted properties stable throughout an export. */
|
|
29
|
+
export declare const createSchemaRenderer: () => SchemaRenderer;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=render-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-schema.d.ts","sourceRoot":"","sources":["../src/render-schema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,oDAAoD,CAAA;AAC5G,OAAO,KAAK,EAAE,IAAI,EAA6B,WAAW,EAAE,MAAM,OAAO,CAAA;AAIzE,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAA;IAC9B,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAA;IAC9B,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAA;IAC9B,GAAG,CAAC,EAAE,oBAAoB,CAAA;IAC1B,UAAU,EAAE,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE,CAAA;IAC5C,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,oBAAoB,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAED,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,UAAU,CAAA;IAClD,MAAM,EAAE,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,KAAK,WAAW,EAAE,CAAA;IACvG,OAAO,EAAE,CAAC,MAAM,EAAE,oBAAoB,EAAE,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAC/D,CAAA;AAED,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,QAAO,cA0FvC,CAAA"}
|