@scalar/openapi-to-markdown 1.5.3 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +27 -1
- package/dist/create-markdown-from-openapi.d.ts +5 -2
- package/dist/create-markdown-from-openapi.d.ts.map +1 -1
- package/dist/create-markdown-from-openapi.js +7 -3
- 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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/load-document.d.ts +8 -1
- package/dist/load-document.d.ts.map +1 -1
- package/dist/load-document.js +34 -23
- package/dist/markdown/index.d.ts +5 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +4 -0
- package/dist/markdown-nodes.d.ts.map +1 -1
- package/dist/markdown-nodes.js +1 -0
- 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 +50 -26
- 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/render-tags.d.ts +7 -0
- package/dist/render-tags.d.ts.map +1 -0
- package/dist/render-tags.js +73 -0
- 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 +14 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @scalar/openapi-to-markdown
|
|
2
2
|
|
|
3
|
+
## 1.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#10586](https://github.com/scalar/scalar/pull/10586): Add AsyncAPI Markdown conversion with reusable renderers and individual reference pages. Share Markdown description parsing between the OpenAPI and AsyncAPI converters.
|
|
8
|
+
|
|
9
|
+
Include shared model links, contents navigation, tag pages, generated examples, and an interactive playground.
|
|
10
|
+
|
|
11
|
+
Preserve discriminators and linked schema descriptions, generate examples from primitive aliases, and compact property annotations.
|
|
12
|
+
|
|
13
|
+
Include full-export tag documentation, preserve XML schema examples, and normalize annotated primitive aliases.
|
|
14
|
+
|
|
15
|
+
Infer enum and const type labels and honor primitive-link settings in generated model examples.
|
|
16
|
+
|
|
17
|
+
Preserve AsyncAPI application and schema metadata, explain security alternatives, and render reply and unknown-address semantics accurately.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#10606](https://github.com/scalar/scalar/pull/10606): Block private-network document requests by default and require an explicit basePath for local files. Apply the same permissions to external references, with an opt-in for trusted private-network inputs.
|
|
22
|
+
- [#10598](https://github.com/scalar/scalar/pull/10598): Preserve OpenAPI 3.2 tag ancestry in Markdown exports with parent-first breadcrumb headings.
|
|
23
|
+
- [#10614](https://github.com/scalar/scalar/pull/10614): Clean up lint warnings while preserving runtime behavior, and document intentional schema and type syntax.
|
|
24
|
+
|
|
25
|
+
## 1.5.4
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- [#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.
|
|
30
|
+
- [#10505](https://github.com/scalar/scalar/pull/10505): Apply formatting and lint compatibility changes for Biome 2.5.15.
|
|
31
|
+
|
|
3
32
|
## 1.5.3
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -68,6 +68,27 @@ const operationMarkdownByPointer = await createMarkdownFromOpenApi(content, {
|
|
|
68
68
|
})
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### Document loading permissions
|
|
72
|
+
|
|
73
|
+
URL inputs and external references block private, loopback, and link-local addresses by default.
|
|
74
|
+
Protected requests also reject redirects. File access is disabled unless you provide an approved
|
|
75
|
+
`basePath`; paths and symlinks outside that directory are rejected.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const markdown = await createMarkdownFromOpenApi('./descriptions/openapi.yaml', {
|
|
79
|
+
documentLoading: { basePath: './descriptions' },
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const renderer = await createOpenApiMarkdownRenderer('./descriptions/openapi.yaml', {
|
|
83
|
+
basePath: './descriptions',
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For trusted local development inputs, set `allowPrivateNetworks: true` in the same loading options.
|
|
88
|
+
This also permits redirects. Keep these permissions under application control, rather than taking
|
|
89
|
+
them from uploaded API descriptions or request parameters. An approved directory applies to all
|
|
90
|
+
files loaded during that call, including references in remote documents.
|
|
91
|
+
|
|
71
92
|
### Render multiple pages
|
|
72
93
|
|
|
73
94
|
Create a reusable renderer when exporting several pages from the same API description.
|
|
@@ -144,7 +165,12 @@ schema expansion still tracks ancestors and stops at a depth of ten. Output may
|
|
|
144
165
|
list spacing and normalized Markdown escaping compared with earlier versions.
|
|
145
166
|
|
|
146
167
|
For OpenAPI 3.2 descriptions, tag headings use `summary` when present and otherwise
|
|
147
|
-
use `name`.
|
|
168
|
+
use `name`. Nested tags appear parent-first with breadcrumb headings such as
|
|
169
|
+
`### Accounts › Billing › Invoices`. Every tag uses the same heading level, including
|
|
170
|
+
deeply nested tags. Parent relationships use tag names, while breadcrumb labels use
|
|
171
|
+
summaries when available. Missing parents and circular relationships fall back to flat
|
|
172
|
+
headings. Tag selectors and operation tag metadata continue to use `name`; selecting
|
|
173
|
+
one tag still exports only that tag and its directly tagged operations.
|
|
148
174
|
|
|
149
175
|
The package only generates Markdown. To produce HTML, pass the Markdown output to a
|
|
150
176
|
Markdown renderer in your application.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
import { type DocumentLoadOptions } from './load-document.js';
|
|
2
3
|
import { type OpenApiRenderOptions } from './select-document.js';
|
|
3
4
|
type AnyDocument = OpenApiDocument | Record<string, unknown> | string;
|
|
4
5
|
/** A resolved API description that can render multiple pages without loading it again. */
|
|
@@ -9,8 +10,10 @@ export type OpenApiMarkdownRenderer = {
|
|
|
9
10
|
* Load and resolve an API description once, then render any number of selections.
|
|
10
11
|
* Each renderer owns its document; create a new renderer to pick up source changes.
|
|
11
12
|
*/
|
|
12
|
-
export declare const createOpenApiMarkdownRenderer: (input: AnyDocument) => Promise<OpenApiMarkdownRenderer>;
|
|
13
|
+
export declare const createOpenApiMarkdownRenderer: (input: AnyDocument, options?: DocumentLoadOptions) => Promise<OpenApiMarkdownRenderer>;
|
|
13
14
|
/** Generate Markdown from an API description, optionally scoped to a single page. */
|
|
14
|
-
export declare const createMarkdownFromOpenApi: (input: AnyDocument, options?: OpenApiRenderOptions
|
|
15
|
+
export declare const createMarkdownFromOpenApi: (input: AnyDocument, options?: OpenApiRenderOptions & {
|
|
16
|
+
documentLoading?: DocumentLoadOptions;
|
|
17
|
+
}) => Promise<string>;
|
|
15
18
|
export {};
|
|
16
19
|
//# sourceMappingURL=create-markdown-from-openapi.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-markdown-from-openapi.d.ts","sourceRoot":"","sources":["../src/create-markdown-from-openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;
|
|
1
|
+
{"version":3,"file":"create-markdown-from-openapi.d.ts","sourceRoot":"","sources":["../src/create-markdown-from-openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAEnG,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,iBAAiB,CAAA;AAExE,OAAO,EAAE,KAAK,oBAAoB,EAAwC,MAAM,mBAAmB,CAAA;AAEnG,KAAK,WAAW,GAAG,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAA;AACrE,0FAA0F;AAC1F,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,WAAW,EAClB,UAAU,mBAAmB,KAC5B,OAAO,CAAC,uBAAuB,CAQjC,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,GACpC,OAAO,WAAW,EAClB,UAAU,oBAAoB,GAAG;IAAE,eAAe,CAAC,EAAE,mBAAmB,CAAA;CAAE,KACzE,OAAO,CAAC,MAAM,CAOhB,CAAA"}
|
|
@@ -5,8 +5,8 @@ import { createDocumentLookup, selectDocument } from './select-document.js';
|
|
|
5
5
|
* Load and resolve an API description once, then render any number of selections.
|
|
6
6
|
* Each renderer owns its document; create a new renderer to pick up source changes.
|
|
7
7
|
*/
|
|
8
|
-
export const createOpenApiMarkdownRenderer = async (input) => {
|
|
9
|
-
const content = await loadDocument(input);
|
|
8
|
+
export const createOpenApiMarkdownRenderer = async (input, options) => {
|
|
9
|
+
const content = await loadDocument(input, options);
|
|
10
10
|
const renderDocument = createDocumentRenderer();
|
|
11
11
|
const lookup = createDocumentLookup(content);
|
|
12
12
|
const render = async (options) => await renderDocument(selectDocument(content, options, lookup), options);
|
|
@@ -14,6 +14,10 @@ export const createOpenApiMarkdownRenderer = async (input) => {
|
|
|
14
14
|
};
|
|
15
15
|
/** Generate Markdown from an API description, optionally scoped to a single page. */
|
|
16
16
|
export const createMarkdownFromOpenApi = async (input, options) => {
|
|
17
|
-
const renderer = await createOpenApiMarkdownRenderer(input);
|
|
17
|
+
const renderer = await createOpenApiMarkdownRenderer(input, options?.documentLoading);
|
|
18
|
+
if (options && 'documentLoading' in options) {
|
|
19
|
+
const { documentLoading: _, ...renderOptions } = options;
|
|
20
|
+
return renderer.render(renderOptions);
|
|
21
|
+
}
|
|
18
22
|
return renderer.render(options);
|
|
19
23
|
};
|
|
@@ -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,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { HttpMethod } from '@scalar/helpers/http/http-methods';
|
|
2
2
|
export type { OpenApiMarkdownRenderer } from './create-markdown-from-openapi.js';
|
|
3
3
|
export { createMarkdownFromOpenApi, createOpenApiMarkdownRenderer, } from './create-markdown-from-openapi.js';
|
|
4
|
+
export type { DocumentLoadOptions } from './load-document.js';
|
|
4
5
|
export type { OpenApiRenderOptions, OperationSelector, SchemaReferenceOptions } from './select-document.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAC7E,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAC7E,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/load-document.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
/** Permissions for loading an API description and its external references. */
|
|
3
|
+
export type DocumentLoadOptions = {
|
|
4
|
+
/** Allow private-network requests only for trusted input. Defaults to false. */
|
|
5
|
+
allowPrivateNetworks?: boolean;
|
|
6
|
+
/** Approved directory for local files and references. File access is disabled when omitted. */
|
|
7
|
+
basePath?: string;
|
|
8
|
+
};
|
|
2
9
|
/** Coerce one plain document and keep references linked to shared targets. */
|
|
3
|
-
export declare const loadDocument: (input: OpenApiDocument | Record<string, unknown> | string) => Promise<OpenApiDocument>;
|
|
10
|
+
export declare const loadDocument: (input: OpenApiDocument | Record<string, unknown> | string, options?: DocumentLoadOptions) => Promise<OpenApiDocument>;
|
|
4
11
|
//# sourceMappingURL=load-document.d.ts.map
|
|
@@ -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,MAAM,MAAM,mBAAmB,GAAG;IAChC,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GACvB,OAAO,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EACzD,UAAS,mBAAwB,KAChC,OAAO,CAAC,eAAe,CAoGzB,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
|
}
|
|
@@ -147,9 +153,12 @@ const attachRefValues = (document, schemas = getSchemas(document), { detectOnly
|
|
|
147
153
|
return hasExternalReferences;
|
|
148
154
|
};
|
|
149
155
|
/** Coerce one plain document and keep references linked to shared targets. */
|
|
150
|
-
export const loadDocument = async (input) => {
|
|
156
|
+
export const loadDocument = async (input, options = {}) => {
|
|
151
157
|
let raw;
|
|
152
158
|
let origin;
|
|
159
|
+
const { fetchUrls, readFiles } = await import('@scalar/json-magic/bundle/plugins/node');
|
|
160
|
+
const urlLoader = fetchUrls({ blockPrivateNetworks: !options.allowPrivateNetworks });
|
|
161
|
+
const fileLoader = options.basePath === undefined ? undefined : readFiles({ basePath: options.basePath });
|
|
153
162
|
// Reference links are attached below, so never mutate the caller's document.
|
|
154
163
|
if (typeof input !== 'string') {
|
|
155
164
|
raw = deepClone(getRaw(input));
|
|
@@ -161,17 +170,24 @@ export const loadDocument = async (input) => {
|
|
|
161
170
|
raw = normalized;
|
|
162
171
|
}
|
|
163
172
|
else if (/^https?:\/\//i.test(input)) {
|
|
164
|
-
const
|
|
165
|
-
if (!
|
|
166
|
-
throw new Error(
|
|
173
|
+
const result = await urlLoader.exec(input);
|
|
174
|
+
if (!result.ok) {
|
|
175
|
+
throw new Error('Failed to load OpenAPI document');
|
|
167
176
|
}
|
|
168
|
-
raw =
|
|
177
|
+
raw = result.data;
|
|
169
178
|
origin = input;
|
|
170
179
|
}
|
|
171
180
|
else {
|
|
172
|
-
|
|
181
|
+
if (!fileLoader) {
|
|
182
|
+
throw new Error('Local file access requires an explicit basePath');
|
|
183
|
+
}
|
|
184
|
+
const { resolve } = await import('node:path');
|
|
173
185
|
origin = resolve(input);
|
|
174
|
-
|
|
186
|
+
const result = await fileLoader.exec(origin);
|
|
187
|
+
if (!result.ok) {
|
|
188
|
+
throw new Error('Failed to load OpenAPI document');
|
|
189
|
+
}
|
|
190
|
+
raw = result.data;
|
|
175
191
|
}
|
|
176
192
|
}
|
|
177
193
|
if (!isObject(raw)) {
|
|
@@ -187,12 +203,7 @@ export const loadDocument = async (input) => {
|
|
|
187
203
|
// Resolve external targets only when the initial local-reference pass finds them.
|
|
188
204
|
if (hasExternalReferences) {
|
|
189
205
|
const errors = [];
|
|
190
|
-
const plugins =
|
|
191
|
-
? [(await import('@scalar/json-magic/bundle/plugins/browser')).fetchUrls()]
|
|
192
|
-
: [
|
|
193
|
-
(await import('@scalar/json-magic/bundle/plugins/node')).fetchUrls(),
|
|
194
|
-
(await import('@scalar/json-magic/bundle/plugins/node')).readFiles(),
|
|
195
|
-
];
|
|
206
|
+
const plugins = fileLoader ? [urlLoader, fileLoader] : [urlLoader];
|
|
196
207
|
document = await bundle(upgraded, {
|
|
197
208
|
plugins,
|
|
198
209
|
origin,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Format-neutral Markdown building blocks shared by API description renderers. */
|
|
2
|
+
export { anchor, createDocumentAnchors } from '../document-anchors.js';
|
|
3
|
+
export { describe, field, heading, inlineCode, item, link, list, paragraph, strong, text } from '../markdown-nodes.js';
|
|
4
|
+
export { createDescriptionParser, expandDescriptions } from '../parse-description.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/markdown/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACnH,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Format-neutral Markdown building blocks shared by API description renderers. */
|
|
2
|
+
export { anchor, createDocumentAnchors } from '../document-anchors.js';
|
|
3
|
+
export { describe, field, heading, inlineCode, item, link, list, paragraph, strong, text } from '../markdown-nodes.js';
|
|
4
|
+
export { createDescriptionParser, expandDescriptions } from '../parse-description.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-nodes.d.ts","sourceRoot":"","sources":["../src/markdown-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EACP,UAAU,EACV,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,eAAe,EACf,MAAM,EACN,IAAI,EACL,MAAM,OAAO,CAAA;AAEd;;;GAGG;AACH,KAAK,sBAAsB,GAAG,IAAI,GAAG;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtF,OAAO,QAAQ,OAAO,CAAC;IACrB,UAAU,eAAe;QACvB,sBAAsB,EAAE,sBAAsB,CAAA;KAC/C;IACD,UAAU,cAAc;QACtB,sBAAsB,EAAE,sBAAsB,CAAA;KAC/C;CACF;AAED,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,oEAAoE;AACpE,eAAO,MAAM,QAAQ,GAAI,GAAG,UAAU,eAAe,EAAE,KAAG,QAA4C,CAAA;AACtG,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,
|
|
1
|
+
{"version":3,"file":"markdown-nodes.d.ts","sourceRoot":"","sources":["../src/markdown-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EACP,UAAU,EACV,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,eAAe,EACf,MAAM,EACN,IAAI,EACL,MAAM,OAAO,CAAA;AAEd;;;GAGG;AACH,KAAK,sBAAsB,GAAG,IAAI,GAAG;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtF,OAAO,QAAQ,OAAO,CAAC;IACrB,UAAU,eAAe;QACvB,sBAAsB,EAAE,sBAAsB,CAAA;KAC/C;IACD,UAAU,cAAc;QACtB,sBAAsB,EAAE,sBAAsB,CAAA;KAC/C;CACF;AAED,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,oEAAoE;AACpE,eAAO,MAAM,QAAQ,GAAI,GAAG,UAAU,eAAe,EAAE,KAAG,QAA4C,CAAA;AACtG,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,MAKrC,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;AACnE,0FAA0F;AAC1F,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,sBAAsB,EAC8B,CAAA"}
|
package/dist/markdown-nodes.js
CHANGED
|
@@ -26,6 +26,7 @@ export const list = (children) => ({ type: 'list', ordered: false, spread: false
|
|
|
26
26
|
* additional schemes and excludes IRC/XMPP, so it is not compatible here.
|
|
27
27
|
*/
|
|
28
28
|
export const safeUrl = (url) => {
|
|
29
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters are intentionally matched to validate or sanitize input.
|
|
29
30
|
const normalized = url.replace(/[\u0000-\u0020\u007f-\u009f]/g, '');
|
|
30
31
|
const protocol = /^([^/?#]*):/.exec(normalized)?.[1];
|
|
31
32
|
return protocol && !['http', 'https', 'irc', 'ircs', 'mailto', 'xmpp'].includes(protocol.toLowerCase()) ? '' : url;
|
|
@@ -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"}
|