@writedocs/generator 0.1.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/LICENSE +15 -0
- package/README.md +17 -0
- package/astro.config.mjs +419 -0
- package/bin/writedocs.js +73 -0
- package/package.json +79 -0
- package/src/assets/wd_watermark.png +0 -0
- package/src/assets/wd_watermark_dark.png +0 -0
- package/src/cli/build-auth.js +53 -0
- package/src/cli/build.js +40 -0
- package/src/cli/dev.js +12 -0
- package/src/cli/generate-api-pages.js +359 -0
- package/src/cli/init.js +81 -0
- package/src/cli/preflight.js +40 -0
- package/src/cli/run-astro.js +57 -0
- package/src/cli/run-pagefind.js +66 -0
- package/src/cli/write-redirects-file.js +80 -0
- package/src/components/Accordion.astro +164 -0
- package/src/components/AccordionGroup.astro +40 -0
- package/src/components/ApiLangSelect.astro +168 -0
- package/src/components/ApiPlayground.astro +281 -0
- package/src/components/ApiReferencePanel.astro +1754 -0
- package/src/components/ApiSchemaField.astro +54 -0
- package/src/components/AppIcon.astro +32 -0
- package/src/components/Badge.astro +128 -0
- package/src/components/Callout.astro +168 -0
- package/src/components/Card.astro +136 -0
- package/src/components/CardGroup.astro +20 -0
- package/src/components/CodeGroup.astro +184 -0
- package/src/components/CopyPageMenu.astro +246 -0
- package/src/components/Danger.astro +12 -0
- package/src/components/Expandable.astro +126 -0
- package/src/components/Frame.astro +102 -0
- package/src/components/Hint.astro +99 -0
- package/src/components/Icon.astro +70 -0
- package/src/components/Image.astro +147 -0
- package/src/components/Info.astro +12 -0
- package/src/components/Note.astro +12 -0
- package/src/components/Parameter.astro +119 -0
- package/src/components/RequestExample.astro +33 -0
- package/src/components/ResponseExample.astro +19 -0
- package/src/components/Searchbar.astro +117 -0
- package/src/components/Step.astro +10 -0
- package/src/components/Steps.astro +32 -0
- package/src/components/Tab.astro +9 -0
- package/src/components/Tabs.astro +52 -0
- package/src/components/Tip.astro +12 -0
- package/src/components/Video.astro +135 -0
- package/src/components/Warning.astro +12 -0
- package/src/components/index.ts +48 -0
- package/src/content.config.ts +223 -0
- package/src/layout/BaseLayout.astro +750 -0
- package/src/layout/components/AnalyticsScripts.astro +77 -0
- package/src/layout/components/AskAiWidget.astro +37 -0
- package/src/layout/components/Breadcrumbs.astro +97 -0
- package/src/layout/components/ImageZoom.astro +19 -0
- package/src/layout/components/MobileMenu.astro +200 -0
- package/src/layout/components/NavTree.astro +351 -0
- package/src/layout/components/SearchModal.astro +42 -0
- package/src/layout/components/Sidebar.astro +122 -0
- package/src/layout/components/SiteFooter.astro +85 -0
- package/src/layout/components/TableOfContents.astro +117 -0
- package/src/layout/components/TopBar.astro +311 -0
- package/src/layout/styles/banner.css +44 -0
- package/src/layout/styles/base.css +234 -0
- package/src/layout/styles/dropdown.css +133 -0
- package/src/layout/styles/footer.css +108 -0
- package/src/layout/styles/image-zoom.css +50 -0
- package/src/layout/styles/mobile-menu.css +258 -0
- package/src/layout/styles/search-modal.css +122 -0
- package/src/layout/styles/topbar.css +437 -0
- package/src/lib/config.ts +2131 -0
- package/src/lib/mdx-auto-hydrate.js +70 -0
- package/src/lib/mdx-inject-builtins.js +87 -0
- package/src/lib/mdx-substitute-variables.js +66 -0
- package/src/lib/mdx-title-anchor-ids.js +84 -0
- package/src/lib/mermaid-rehype.js +72 -0
- package/src/lib/openapi-render.ts +479 -0
- package/src/lib/shiki-code-block.js +102 -0
- package/src/lib/shiki-copy-button.js +45 -0
- package/src/lib/styles-asset-integration.js +210 -0
- package/src/lib/writedocs-temp-dir.js +93 -0
- package/src/pages/404.astro +62 -0
- package/src/pages/[...slug].astro +1270 -0
- package/src/pages/[...slug].md.ts +78 -0
- package/src/pages/llms-full.txt.ts +71 -0
- package/src/pages/llms.txt.ts +141 -0
- package/src/scripts/banner.ts +20 -0
- package/src/scripts/dropdowns.ts +61 -0
- package/src/scripts/image-zoom.ts +66 -0
- package/src/scripts/mobile-menu.ts +55 -0
- package/src/scripts/search.ts +155 -0
- package/src/scripts/sidebar-scroll.ts +65 -0
- package/src/scripts/theme-toggle.ts +35 -0
- package/src/scripts/topbar-offset.ts +141 -0
- package/src/styles/global.css +18 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import ApiSchemaField from './ApiSchemaField.astro';
|
|
4
|
+
import Tabs from './Tabs.astro';
|
|
5
|
+
import Tab from './Tab.astro';
|
|
6
|
+
import {
|
|
7
|
+
schemaRows,
|
|
8
|
+
exampleFromSchema,
|
|
9
|
+
primaryContentType,
|
|
10
|
+
methodClass,
|
|
11
|
+
pathSegments,
|
|
12
|
+
findOperationFile,
|
|
13
|
+
type OpenApiOperation,
|
|
14
|
+
} from '../lib/openapi-render';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
operation: string; // "METHOD /path", matching a page's `openapi` frontmatter
|
|
18
|
+
contentDir: string;
|
|
19
|
+
}
|
|
20
|
+
const { operation, contentDir } = Astro.props as Props;
|
|
21
|
+
|
|
22
|
+
const [method = '', urlPath = ''] = operation.trim().split(/\s+/, 2);
|
|
23
|
+
const opFile = findOperationFile(contentDir, method, urlPath);
|
|
24
|
+
const op: OpenApiOperation | null = opFile ? JSON.parse(fs.readFileSync(opFile, 'utf-8')) : null;
|
|
25
|
+
|
|
26
|
+
const pathParams = op?.parameters.filter((p) => p.in === 'path') ?? [];
|
|
27
|
+
const queryParams = op?.parameters.filter((p) => p.in === 'query') ?? [];
|
|
28
|
+
const headerParams = op?.parameters.filter((p) => p.in === 'header') ?? [];
|
|
29
|
+
|
|
30
|
+
const requestContentType = op ? primaryContentType(op.requestBody?.content) : null;
|
|
31
|
+
const requestSchema = requestContentType ? op?.requestBody?.content?.[requestContentType]?.schema : undefined;
|
|
32
|
+
const requestRows = requestSchema ? schemaRows(requestSchema) : [];
|
|
33
|
+
|
|
34
|
+
const responseEntries = op ? Object.entries(op.responses) : [];
|
|
35
|
+
const segments = op ? pathSegments(op.path) : [];
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
{!op && (
|
|
39
|
+
<div class="wd-api-error">
|
|
40
|
+
No OpenAPI operation found for <code>{operation}</code>. Check that this page's <code>openapi</code>
|
|
41
|
+
frontmatter matches an operation in writedocs.json's <code>openapi</code> spec exactly (e.g.
|
|
42
|
+
<code>"GET /pets/{petId}"</code>), and that the spec still defines it.
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
|
|
46
|
+
{op && (
|
|
47
|
+
<div class="wd-api-playground" data-operation={operation}>
|
|
48
|
+
<div class="wd-api-header">
|
|
49
|
+
<span class={`wd-api-method wd-api-method-${methodClass(op.method)}`}>{op.method}</span>
|
|
50
|
+
<code class="wd-api-path">
|
|
51
|
+
{segments.map((seg) =>
|
|
52
|
+
seg.isParam ? <span class="wd-api-path-param">{seg.text}</span> : <span>{seg.text}</span>
|
|
53
|
+
)}
|
|
54
|
+
</code>
|
|
55
|
+
</div>
|
|
56
|
+
{op.description && <p class="wd-api-description">{op.description}</p>}
|
|
57
|
+
|
|
58
|
+
{headerParams.length > 0 && (
|
|
59
|
+
<section class="wd-api-section">
|
|
60
|
+
<h4>Header Parameters</h4>
|
|
61
|
+
<div class="wd-api-param-list">
|
|
62
|
+
{headerParams.map((p) => (
|
|
63
|
+
<div class="wd-api-param">
|
|
64
|
+
<div class="wd-api-param-head">
|
|
65
|
+
<span class="wd-api-param-name">{p.name}</span>
|
|
66
|
+
<span class="wd-api-pill wd-api-pill-type">{p.schema?.type ?? 'string'}</span>
|
|
67
|
+
{p.required && <span class="wd-api-pill wd-api-pill-required">required</span>}
|
|
68
|
+
</div>
|
|
69
|
+
{p.description && <p class="wd-api-param-desc">{p.description}</p>}
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
</section>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
{pathParams.length > 0 && (
|
|
77
|
+
<section class="wd-api-section">
|
|
78
|
+
<h4>Path Parameters</h4>
|
|
79
|
+
<div class="wd-api-param-list">
|
|
80
|
+
{pathParams.map((p) => (
|
|
81
|
+
<div class="wd-api-param">
|
|
82
|
+
<div class="wd-api-param-head">
|
|
83
|
+
<span class="wd-api-param-name">{p.name}</span>
|
|
84
|
+
<span class="wd-api-pill wd-api-pill-type">{p.schema?.type ?? 'string'}</span>
|
|
85
|
+
{p.required && <span class="wd-api-pill wd-api-pill-required">required</span>}
|
|
86
|
+
</div>
|
|
87
|
+
{p.description && <p class="wd-api-param-desc">{p.description}</p>}
|
|
88
|
+
</div>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</section>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
{queryParams.length > 0 && (
|
|
95
|
+
<section class="wd-api-section">
|
|
96
|
+
<h4>Query Parameters</h4>
|
|
97
|
+
<div class="wd-api-param-list">
|
|
98
|
+
{queryParams.map((p) => (
|
|
99
|
+
<div class="wd-api-param">
|
|
100
|
+
<div class="wd-api-param-head">
|
|
101
|
+
<span class="wd-api-param-name">{p.name}</span>
|
|
102
|
+
<span class="wd-api-pill wd-api-pill-type">{p.schema?.type ?? 'string'}</span>
|
|
103
|
+
{p.required && <span class="wd-api-pill wd-api-pill-required">required</span>}
|
|
104
|
+
</div>
|
|
105
|
+
{p.description && <p class="wd-api-param-desc">{p.description}</p>}
|
|
106
|
+
</div>
|
|
107
|
+
))}
|
|
108
|
+
</div>
|
|
109
|
+
</section>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{requestSchema && requestRows.length > 0 && (
|
|
113
|
+
<section class="wd-api-section">
|
|
114
|
+
<h4>Body {requestContentType && <span class="wd-api-content-type">{requestContentType}</span>}</h4>
|
|
115
|
+
<div class="wd-api-param-list">
|
|
116
|
+
<ApiSchemaField rows={requestRows} />
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
{responseEntries.length > 0 && (
|
|
122
|
+
<section class="wd-api-section">
|
|
123
|
+
<h4>Response</h4>
|
|
124
|
+
<Tabs>
|
|
125
|
+
{responseEntries.map(([status, resp]) => {
|
|
126
|
+
const contentType = primaryContentType(resp.content);
|
|
127
|
+
const schema = contentType ? resp.content?.[contentType]?.schema : undefined;
|
|
128
|
+
const rows = schema ? schemaRows(schema) : [];
|
|
129
|
+
return (
|
|
130
|
+
<Tab title={status}>
|
|
131
|
+
{resp.description && (
|
|
132
|
+
<p class="wd-api-param-desc-inline wd-api-response-desc">{resp.description}</p>
|
|
133
|
+
)}
|
|
134
|
+
{rows.length > 0 && (
|
|
135
|
+
<div class="wd-api-param-list wd-api-param-list-nested">
|
|
136
|
+
<ApiSchemaField rows={rows} showRequired={false} />
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
</Tab>
|
|
140
|
+
);
|
|
141
|
+
})}
|
|
142
|
+
</Tabs>
|
|
143
|
+
</section>
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
<style is:global>
|
|
149
|
+
.wd-api-error {
|
|
150
|
+
padding: 1rem 1.25rem;
|
|
151
|
+
border-radius: 0.5rem;
|
|
152
|
+
border: 1px solid var(--wd-border);
|
|
153
|
+
background: var(--wd-surface);
|
|
154
|
+
color: var(--wd-text-muted);
|
|
155
|
+
font-size: 0.9rem;
|
|
156
|
+
margin: 1.25rem 0;
|
|
157
|
+
}
|
|
158
|
+
.wd-api-playground {
|
|
159
|
+
margin: 1.5rem 0;
|
|
160
|
+
}
|
|
161
|
+
.wd-api-header {
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
gap: 0.6rem;
|
|
165
|
+
flex-wrap: wrap;
|
|
166
|
+
padding: 0.6rem 0.9rem;
|
|
167
|
+
border: 1px solid var(--wd-border);
|
|
168
|
+
border-radius: 0.5rem;
|
|
169
|
+
background: var(--wd-surface);
|
|
170
|
+
}
|
|
171
|
+
.wd-api-method {
|
|
172
|
+
display: inline-block;
|
|
173
|
+
padding: 0.2rem 0.55rem;
|
|
174
|
+
border-radius: 0.3rem;
|
|
175
|
+
font-size: 0.72rem;
|
|
176
|
+
font-weight: 700;
|
|
177
|
+
letter-spacing: 0.02em;
|
|
178
|
+
color: #fff;
|
|
179
|
+
flex-shrink: 0;
|
|
180
|
+
}
|
|
181
|
+
.wd-api-method-get { background: #16a34a; }
|
|
182
|
+
.wd-api-method-post { background: #2563eb; }
|
|
183
|
+
.wd-api-method-put { background: #9333ea; }
|
|
184
|
+
.wd-api-method-patch { background: #d97706; }
|
|
185
|
+
.wd-api-method-delete { background: #dc2626; }
|
|
186
|
+
.wd-api-method-other { background: var(--wd-text-muted); }
|
|
187
|
+
.wd-api-path {
|
|
188
|
+
font-size: 0.88rem;
|
|
189
|
+
background: none;
|
|
190
|
+
padding: 0;
|
|
191
|
+
word-break: break-all;
|
|
192
|
+
color: var(--wd-text-muted);
|
|
193
|
+
}
|
|
194
|
+
.wd-api-path-param {
|
|
195
|
+
color: var(--wd-primary);
|
|
196
|
+
font-weight: 600;
|
|
197
|
+
}
|
|
198
|
+
.wd-api-description {
|
|
199
|
+
color: var(--wd-text-muted);
|
|
200
|
+
margin: 0.9rem 0 0;
|
|
201
|
+
}
|
|
202
|
+
.wd-api-section {
|
|
203
|
+
margin-top: 2rem;
|
|
204
|
+
}
|
|
205
|
+
.wd-api-section h4 {
|
|
206
|
+
font-size: 1rem;
|
|
207
|
+
font-weight: 600;
|
|
208
|
+
color: var(--wd-text);
|
|
209
|
+
margin: 0 0 0.9rem;
|
|
210
|
+
}
|
|
211
|
+
.wd-api-content-type {
|
|
212
|
+
font-weight: 400;
|
|
213
|
+
font-size: 0.78rem;
|
|
214
|
+
color: var(--wd-text-muted);
|
|
215
|
+
margin-left: 0.4rem;
|
|
216
|
+
}
|
|
217
|
+
.wd-api-param-list {
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-direction: column;
|
|
220
|
+
}
|
|
221
|
+
.wd-api-param {
|
|
222
|
+
padding: 0.9rem 0;
|
|
223
|
+
border-bottom: 1px solid var(--wd-border);
|
|
224
|
+
}
|
|
225
|
+
.wd-api-param:last-child {
|
|
226
|
+
border-bottom: none;
|
|
227
|
+
padding-bottom: 0;
|
|
228
|
+
}
|
|
229
|
+
.wd-api-param-list-nested {
|
|
230
|
+
margin-top: 0.6rem;
|
|
231
|
+
}
|
|
232
|
+
.wd-api-param-list-nested .wd-api-param {
|
|
233
|
+
padding: 0.6rem 0;
|
|
234
|
+
}
|
|
235
|
+
.wd-api-param-head {
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: center;
|
|
238
|
+
gap: 0.5rem;
|
|
239
|
+
flex-wrap: wrap;
|
|
240
|
+
}
|
|
241
|
+
.wd-api-param-name {
|
|
242
|
+
font-family: monospace;
|
|
243
|
+
font-size: 0.9rem;
|
|
244
|
+
font-weight: 600;
|
|
245
|
+
color: var(--wd-primary);
|
|
246
|
+
}
|
|
247
|
+
.wd-api-pill {
|
|
248
|
+
display: inline-block;
|
|
249
|
+
padding: 0.1rem 0.5rem;
|
|
250
|
+
border-radius: 999px;
|
|
251
|
+
font-size: 0.72rem;
|
|
252
|
+
font-weight: 500;
|
|
253
|
+
background: var(--wd-surface);
|
|
254
|
+
color: var(--wd-text-muted);
|
|
255
|
+
border: 1px solid var(--wd-border);
|
|
256
|
+
}
|
|
257
|
+
.wd-api-pill-required {
|
|
258
|
+
background: color-mix(in srgb, #dc2626 12%, transparent);
|
|
259
|
+
color: #dc2626;
|
|
260
|
+
border-color: transparent;
|
|
261
|
+
}
|
|
262
|
+
.wd-api-param-desc {
|
|
263
|
+
margin: 0.4rem 0 0;
|
|
264
|
+
color: var(--wd-text-muted);
|
|
265
|
+
font-size: 0.88rem;
|
|
266
|
+
}
|
|
267
|
+
.wd-api-param-desc-inline {
|
|
268
|
+
color: var(--wd-text-muted);
|
|
269
|
+
font-size: 0.85rem;
|
|
270
|
+
}
|
|
271
|
+
/* Sits above a response tab's own schema field list (when there's a
|
|
272
|
+
body to show) - a little breathing room below it, same as
|
|
273
|
+
Parameter.astro's own Expandable-spacing rule, so the description
|
|
274
|
+
doesn't crowd directly against the first field row. Only the
|
|
275
|
+
response tabs use this (a plain wd-api-param-desc-inline elsewhere -
|
|
276
|
+
the path/query/header param rows - sits right under a name/type
|
|
277
|
+
row that's already got its own margin, no gap needed there). */
|
|
278
|
+
.wd-api-response-desc {
|
|
279
|
+
margin: 0 0 0.75rem;
|
|
280
|
+
}
|
|
281
|
+
</style>
|