@scalar/openapi-to-markdown 0.5.44 → 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 +22 -0
- package/README.md +73 -34
- package/dist/create-markdown-from-openapi.d.ts +16 -15
- 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 -600
- 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 +16 -28
- 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 -9
- package/dist/components/Schema.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @scalar/openapi-to-markdown
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#10233](https://github.com/scalar/scalar/pull/10233): Generate Markdown directly from a Markdown syntax tree, avoiding Vue server rendering and the generated HTML conversion pipeline. Reuse normalized schemas and parsed descriptions across pages while preserving selection, schema coercion, reference resolution, and raw HTML description sanitization.
|
|
8
|
+
|
|
9
|
+
Keep the HTML API through an on-demand Markdown conversion. Markdown and HTML spacing and escaping may differ from previous output.
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#10224](https://github.com/scalar/scalar/pull/10224): Add a reusable renderer that loads an OpenAPI document once and generates multiple Markdown or HTML pages from it.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#10241](https://github.com/scalar/scalar/pull/10241): Simplify reference link rebuilding after OpenAPI document coercion.
|
|
18
|
+
|
|
19
|
+
## 0.6.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- [#10169](https://github.com/scalar/scalar/pull/10169): Render scoped operation, tag, model, webhook, and introduction pages in Markdown and HTML while preserving referenced schemas and inherited context.
|
|
24
|
+
|
|
3
25
|
## 0.5.44
|
|
4
26
|
|
|
5
27
|
## 0.5.43
|
package/README.md
CHANGED
|
@@ -68,13 +68,42 @@ const operationMarkdownByPointer = await createMarkdownFromOpenApi(content, {
|
|
|
68
68
|
})
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### Render multiple pages
|
|
72
|
+
|
|
73
|
+
Create a reusable renderer when exporting several pages from the same API description.
|
|
74
|
+
It loads, upgrades, coerces, and resolves the document once. Each call uses the same selectors as
|
|
75
|
+
`createMarkdownFromOpenApi`, and omitting a selector renders the complete document.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createOpenApiMarkdownRenderer } from '@scalar/openapi-to-markdown'
|
|
79
|
+
|
|
80
|
+
const renderer = await createOpenApiMarkdownRenderer(content)
|
|
81
|
+
|
|
82
|
+
const introduction = await renderer.render({ introduction: true })
|
|
83
|
+
const operation = await renderer.render({
|
|
84
|
+
operation: { path: '/users/{id}', method: 'get' },
|
|
85
|
+
})
|
|
86
|
+
const tag = await renderer.render({ tag: 'Users' })
|
|
87
|
+
const model = await renderer.render({ model: 'User' })
|
|
88
|
+
const webhook = await renderer.render({
|
|
89
|
+
webhook: { name: 'userCreated', method: 'post' },
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The factory accepts the same document objects, JSON/YAML strings, file paths, and URLs
|
|
94
|
+
as the one-shot functions. Source files and URLs are read during creation, including
|
|
95
|
+
references. Create a new renderer when the source changes. Reuse one renderer per API
|
|
96
|
+
description during a build, then release it when the build finishes. Renderers do not
|
|
97
|
+
share a global document cache. An invalid selection rejects that call without preventing
|
|
98
|
+
later calls on the same renderer.
|
|
99
|
+
|
|
71
100
|
### With Hono
|
|
72
101
|
|
|
73
102
|
You use the package with any Node.js framework. Here is an example for [Hono](https://hono.dev/):
|
|
74
103
|
|
|
75
104
|
```ts
|
|
76
|
-
import { Hono } from 'hono'
|
|
77
105
|
import { createMarkdownFromOpenApi } from '@scalar/openapi-to-markdown'
|
|
106
|
+
import { Hono } from 'hono'
|
|
78
107
|
|
|
79
108
|
// Generate Markdown from an OpenAPI document
|
|
80
109
|
const markdown = await createMarkdownFromOpenApi(content)
|
|
@@ -94,43 +123,21 @@ app.get('/llms.txt', (c) => c.text(markdown))
|
|
|
94
123
|
serve(app)
|
|
95
124
|
```
|
|
96
125
|
|
|
97
|
-
###
|
|
98
|
-
|
|
99
|
-
This is not really the purpose of the package, but maybe good to know: This package actually renders HTML at first, and
|
|
100
|
-
transforms the HTML to Markdown then.
|
|
126
|
+
### Markdown rendering
|
|
101
127
|
|
|
102
|
-
|
|
128
|
+
The renderer constructs a Markdown syntax tree directly from the resolved API description.
|
|
129
|
+
It preserves Markdown descriptions, GFM tables and code blocks without rendering a Vue app
|
|
130
|
+
or converting the generated document through HTML. Descriptions containing raw HTML or
|
|
131
|
+
Scalar alerts use a separate sanitization and conversion path. Images remain excluded.
|
|
103
132
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
133
|
+
Schema normalization and description parsing are cached within each renderer. Recursive
|
|
134
|
+
schema expansion still tracks ancestors and stops at a depth of ten. Output may use tighter
|
|
135
|
+
list spacing and normalized Markdown escaping compared with earlier versions.
|
|
107
136
|
|
|
108
|
-
|
|
109
|
-
const html = await createHtmlFromOpenApi(content)
|
|
110
|
-
|
|
111
|
-
const app = new Hono()
|
|
137
|
+
### HTML output
|
|
112
138
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
`<!doctype html>
|
|
116
|
-
<html lang="en" data-theme="light">
|
|
117
|
-
<head>
|
|
118
|
-
<meta charset="UTF-8" />
|
|
119
|
-
<title>Scalar Galaxy</title>
|
|
120
|
-
<!-- Basic styling for semantic HTML tags (optional) -->
|
|
121
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
|
|
122
|
-
</head>
|
|
123
|
-
<body>
|
|
124
|
-
<main class="container">
|
|
125
|
-
${html}
|
|
126
|
-
</main>
|
|
127
|
-
</body>
|
|
128
|
-
</html>`,
|
|
129
|
-
),
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
serve(app)
|
|
133
|
-
```
|
|
139
|
+
`createHtmlFromOpenApi` and `renderer.renderHtml` remain available. They convert the
|
|
140
|
+
Markdown output to HTML on demand, without loading a Vue renderer.
|
|
134
141
|
|
|
135
142
|
## Community
|
|
136
143
|
|
|
@@ -139,3 +146,35 @@ We are API nerds. You too? Let's chat on Discord: <https://discord.gg/scalar>
|
|
|
139
146
|
## License
|
|
140
147
|
|
|
141
148
|
The source code in this repository is licensed under [MIT](https://github.com/scalar/scalar/blob/main/LICENSE).
|
|
149
|
+
|
|
150
|
+
## Individual reference pages
|
|
151
|
+
|
|
152
|
+
`createMarkdownFromOpenApi` and `renderer.render` accept the same selection options. Choose one selector per call:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
await createMarkdownFromOpenApi(content, { tag: 'pets' })
|
|
156
|
+
await createMarkdownFromOpenApi(content, { model: 'Pet' })
|
|
157
|
+
await createMarkdownFromOpenApi(content, {
|
|
158
|
+
webhook: { name: 'petCreated', method: 'post' },
|
|
159
|
+
})
|
|
160
|
+
await createMarkdownFromOpenApi(content, { introduction: true })
|
|
161
|
+
await createMarkdownFromOpenApi(content, {
|
|
162
|
+
operation: { operationId: 'getUser' },
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- **Operation:** One operation, effective parameters, servers and authentication, its tags, and referenced component schemas. Existing path/method, operation ID, and JSON pointer selectors still work. Methods are case insensitive.
|
|
167
|
+
- **Tag:** Tag metadata and all path operations with that exact tag, plus their context and schema dependencies. A tag used only by operations is supported. A declared tag with no operations renders its metadata. Operations with multiple tags appear once, with only the selected tag shown.
|
|
168
|
+
- **Model:** One component schema and its referenced schemas. Primitive, array, composed, and recursive models use the shared schema renderer.
|
|
169
|
+
- **Webhook:** One operation selected by its exact OpenAPI webhook name and method, including parameters, payload and responses. The name is a label, not a delivery URL.
|
|
170
|
+
- **Introduction:** API title, versions, description, contact, license, terms of service, servers and global authentication requirements. No operations, tags, models or webhooks.
|
|
171
|
+
|
|
172
|
+
Selected pages retain API title, versions and description. They exclude unrelated reference content. Operation servers override path servers, which override document servers. Operation security overrides document security, including `security: []` for anonymous access. Parameter overrides use the parameter name and location. Required schemas are collected after reference resolution, so dependencies remain available even when their original section is omitted.
|
|
173
|
+
|
|
174
|
+
Omitting options, or passing `{}`, renders the whole document. OpenAPI 2.0 inputs are migrated before selection: use definition names with `model`. Webhooks require OpenAPI 3.1 or later.
|
|
175
|
+
|
|
176
|
+
### Errors and limitations
|
|
177
|
+
|
|
178
|
+
Invalid, combined, or missing selectors reject the returned promise with an error. Duplicate operation IDs are ambiguous and list matching paths and methods; use a path/method selector instead. Duplicate tag declarations are also rejected. Names are case sensitive. Operation JSON pointers must target `/paths/{path}/{method}`, with an optional leading `#` and standard `~0`/`~1` escaping.
|
|
179
|
+
|
|
180
|
+
Selection does not add support for every OpenAPI or JSON Schema keyword. Callbacks are not selectable pages. External references follow the existing workspace loader behavior. Recursive schema expansion stops on a repeated ancestor, with a depth limit of ten as a fallback. Shared dependencies have one component section, but may also appear inline where used. Authentication lists alternatives separately; schemes within one requirement must be used together.
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type
|
|
1
|
+
import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
import { type OpenApiRenderOptions } from './select-document.js';
|
|
3
3
|
type AnyDocument = OpenApiDocument | Record<string, unknown> | string;
|
|
4
|
-
|
|
5
|
-
export type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} | {
|
|
9
|
-
operationId: string;
|
|
10
|
-
} | {
|
|
11
|
-
pointer: string;
|
|
4
|
+
/** A resolved API description that can render multiple pages without loading it again. */
|
|
5
|
+
export type OpenApiMarkdownRenderer = {
|
|
6
|
+
render: (options?: OpenApiRenderOptions) => Promise<string>;
|
|
7
|
+
renderHtml: (options?: OpenApiRenderOptions) => Promise<string>;
|
|
12
8
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export declare
|
|
9
|
+
/**
|
|
10
|
+
* Load and resolve an API description once, then render any number of selections.
|
|
11
|
+
* Each renderer owns its document; create a new renderer to pick up source changes.
|
|
12
|
+
*/
|
|
13
|
+
export declare const createOpenApiMarkdownRenderer: (input: AnyDocument) => Promise<OpenApiMarkdownRenderer>;
|
|
14
|
+
/** Generate Markdown from an API description, optionally scoped to a single page. */
|
|
15
|
+
export declare const createMarkdownFromOpenApi: (input: AnyDocument, options?: OpenApiRenderOptions) => Promise<string>;
|
|
16
|
+
/** Generate HTML through the optional Markdown conversion path. */
|
|
17
|
+
export declare const createHtmlFromOpenApi: (input: AnyDocument, options?: OpenApiRenderOptions) => Promise<string>;
|
|
18
|
+
export {};
|
|
18
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,
|
|
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;AAInG,OAAO,EAAE,KAAK,oBAAoB,EAAkB,MAAM,mBAAmB,CAAA;AAE7E,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;IAC3D,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAChE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GAAU,OAAO,WAAW,KAAG,OAAO,CAAC,uBAAuB,CAoBvG,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,GACpC,OAAO,WAAW,EAClB,UAAU,oBAAoB,KAC7B,OAAO,CAAC,MAAM,CAGhB,CAAA;AAED,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,GAAU,OAAO,WAAW,EAAE,UAAU,oBAAoB,KAAG,OAAO,CAAC,MAAM,CAG9G,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { loadDocument } from './load-document.js';
|
|
2
|
+
import { createDocumentRenderer } from './render-document.js';
|
|
3
|
+
import { selectDocument } from './select-document.js';
|
|
4
|
+
/**
|
|
5
|
+
* Load and resolve an API description once, then render any number of selections.
|
|
6
|
+
* Each renderer owns its document; create a new renderer to pick up source changes.
|
|
7
|
+
*/
|
|
8
|
+
export const createOpenApiMarkdownRenderer = async (input) => {
|
|
9
|
+
const content = await loadDocument(input);
|
|
10
|
+
const renderDocument = createDocumentRenderer();
|
|
11
|
+
const render = async (options) => await renderDocument(selectDocument(content, options));
|
|
12
|
+
return {
|
|
13
|
+
render,
|
|
14
|
+
renderHtml: async (options) => {
|
|
15
|
+
const [{ unified }, { default: remarkParse }, { default: remarkRehype }, { default: rehypeStringify }] = await Promise.all([
|
|
16
|
+
import('unified'),
|
|
17
|
+
import('remark-parse'),
|
|
18
|
+
import('remark-rehype'),
|
|
19
|
+
import('rehype-stringify'),
|
|
20
|
+
]);
|
|
21
|
+
const processor = unified().use(remarkParse).use(remarkRehype).use(rehypeStringify);
|
|
22
|
+
return processor.processSync(await render(options)).toString();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/** Generate Markdown from an API description, optionally scoped to a single page. */
|
|
27
|
+
export const createMarkdownFromOpenApi = async (input, options) => {
|
|
28
|
+
const renderer = await createOpenApiMarkdownRenderer(input);
|
|
29
|
+
return renderer.render(options);
|
|
30
|
+
};
|
|
31
|
+
/** Generate HTML through the optional Markdown conversion path. */
|
|
32
|
+
export const createHtmlFromOpenApi = async (input, options) => {
|
|
33
|
+
const renderer = await createOpenApiMarkdownRenderer(input);
|
|
34
|
+
return renderer.renderHtml(options);
|
|
35
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export type { HttpMethod } from '@scalar/helpers/http/http-methods';
|
|
2
|
+
export type { OpenApiMarkdownRenderer } from './create-markdown-from-openapi.js';
|
|
3
|
+
export { createHtmlFromOpenApi, createMarkdownFromOpenApi, createOpenApiMarkdownRenderer, } from './create-markdown-from-openapi.js';
|
|
4
|
+
export type { OpenApiRenderOptions, OperationSelector } from './select-document.js';
|
|
3
5
|
//# 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,OAAO,EACL,qBAAqB,EACrB,yBAAyB,
|
|
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,qBAAqB,EACrB,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAA;AACvC,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA"}
|