Skip to content

Commit c94653a

Browse files
committed
Update openapi-fetch, add docs sitemap (#1108)
1 parent 8c1a4a8 commit c94653a

File tree

13 files changed

+179
-41
lines changed

13 files changed

+179
-41
lines changed

docs/astro.config.mjs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { defineConfig } from "astro/config";
22
import preact from "@astrojs/preact";
33
import react from "@astrojs/react";
4+
import sitemap from "@astrojs/sitemap";
45

56
// https://astro.build/config
67
export default defineConfig({
7-
integrations: [preact(), react()],
8-
site: `https://openapi-typescript.pages.dev`,
8+
integrations: [preact(), react(), sitemap()],
9+
site: `https://openapi-ts.pages.dev`,
910
vite: {
1011
define: {
1112
"import.meta.env.VITE_ALGOLIA_APP_ID": JSON.stringify(process.env.ALGOLIA_APP_ID ?? ""),

docs/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"sass": "^1.62.1"
2222
},
2323
"devDependencies": {
24+
"@astrojs/sitemap": "^1.3.1",
2425
"@types/node": "^20.1.1",
2526
"html-escaper": "^3.0.3",
2627
"typescript": "^5.0.4"

docs/src/components/HeadCommon.astro

+1-15
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@
22
import "../styles/app.scss";
33
---
44

5-
<!-- Global Metadata -->
65
<meta charset="utf-8" />
76
<meta name="viewport" content="width=device-width" />
87
<meta name="generator" content={Astro.generator} />
98
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
10-
<link rel="sitemap" href="/sitemap.xml" />
11-
12-
<!-- Scrollable a11y code helper -->
9+
<link rel="sitemap" href="/sitemap-index.xml" />
1310
<script src="/make-scrollable-code-focusable.js" is:inline></script>
14-
15-
<!-- This is intentionally inlined to avoid FOUC -->
1611
<script is:inline>
1712
const root = document.documentElement;
1813
const theme = localStorage.getItem("theme");
@@ -22,12 +17,3 @@ import "../styles/app.scss";
2217
root.classList.remove("theme-dark");
2318
}
2419
</script>
25-
26-
<!-- Global site tag (gtag.js) - Google Analytics -->
27-
<!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-TEL60V1WM9" is:inline></script>
28-
<script>
29-
window.dataLayer = window.dataLayer || [];
30-
function gtag(){dataLayer.push(arguments);}
31-
gtag('js', new Date());
32-
gtag('config', 'G-TEL60V1WM9');
33-
</script> -->

docs/src/components/HeadSEO.astro

-12
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ const canonicalImageSrc = new URL(imageSrc, Astro.site);
1111
const imageAlt = image?.alt ?? OPEN_GRAPH.image.alt;
1212
---
1313

14-
<!-- Page Metadata -->
1514
<link rel="canonical" href={canonicalUrl} />
16-
17-
<!-- OpenGraph Tags -->
1815
<meta property="og:title" content={formattedContentTitle} />
1916
<meta property="og:type" content="article" />
2017
<meta property="og:url" content={canonicalUrl} />
@@ -23,18 +20,9 @@ const imageAlt = image?.alt ?? OPEN_GRAPH.image.alt;
2320
<meta property="og:image:alt" content={imageAlt} />
2421
<meta name="description" property="og:description" content={description ?? SITE.description} />
2522
<meta property="og:site_name" content={SITE.title} />
26-
27-
<!-- Twitter Tags -->
2823
<meta name="twitter:card" content="summary_large_image" />
2924
<meta name="twitter:site" content={OPEN_GRAPH.twitter} />
3025
<meta name="twitter:title" content={formattedContentTitle} />
3126
<meta name="twitter:description" content={description ?? SITE.description} />
3227
<meta name="twitter:image" content={canonicalImageSrc} />
3328
<meta name="twitter:image:alt" content={imageAlt} />
34-
35-
<!--
36-
TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense?
37-
Docs: https://developers.google.com/search/docs/advanced/structured-data/intro-structured-data
38-
https://www.npmjs.com/package/schema-dts seems like a great resource for implementing this.
39-
Even better, there's a React component that integrates with `schema-dts`: https://github.com/google/react-schemaorg
40-
-->

docs/src/components/Header/Search.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/** @jsxImportSource react */
22
import { useState, useCallback, useRef } from "react";
33
import "@docsearch/css";
4-
import "./Search.css";
5-
6-
import { createPortal } from "react-dom";
74
import * as docSearchReact from "@docsearch/react";
5+
import { createPortal } from "react-dom";
6+
import "./Search.css";
87

98
/** FIXME: This is still kinda nasty, but DocSearch is not ESM ready. */
109
const DocSearchModal = docSearchReact.DocSearchModal || (docSearchReact as any).default.DocSearchModal;

docs/src/components/LeftSidebar/LeftSidebar.astro

-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
---
2-
import { SIDEBAR } from "../../consts.js";
3-
42
type Props = {
53
currentPage: string;
64
};

docs/src/layouts/MainLayout.astro

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ type Props = CollectionEntry<"docs">["data"] & {
1515
headings: MarkdownHeading[];
1616
};
1717
18+
interface Link {
19+
url: string;
20+
text: string;
21+
}
22+
1823
const { headings, ...data } = Astro.props;
1924
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
2025
const currentPage = Astro.url.pathname;
@@ -131,7 +136,7 @@ const nextLink: Record<string, Link | undefined> = {
131136
<slot />
132137
{currentPage === "/about" && <Contributors usernames={OPENAPI_TS_CONTRIBUTORS} />}
133138
{currentPage === "/openapi-fetch/about" && <Contributors usernames={OPENAPI_FETCH_CONTRIBUTORS} />}
134-
{nextLink[currentPage] && <NextLink href={nextLink[currentPage].url}>{nextLink[currentPage].text}</NextLink>}
139+
{nextLink[currentPage] && <NextLink href={nextLink[currentPage]!.url}>{nextLink[currentPage]!.text}</NextLink>}
135140
</PageContent>
136141
</div>
137142
<aside id="grid-right" class="grid-sidebar" title="Table of Contents">

packages/openapi-fetch/CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# openapi-fetch
22

3+
## 0.1.4
4+
5+
### Patch Changes
6+
7+
- 63ebe48: Fix request body type when optional (#48)
8+
9+
## 0.1.3
10+
11+
### Patch Changes
12+
13+
- 8c01480: Fix querySerializer signature
14+
315
## 0.1.2
416

517
### Patch Changes

packages/openapi-fetch/src/index.test.ts

+36
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,42 @@ describe("post()", () => {
351351
// assert error is empty
352352
expect(error).toBe(undefined);
353353
});
354+
355+
it("request body type when optional", async () => {
356+
fetchMocker.mockResponse(() => ({ status: 201, body: "{}" }));
357+
const client = createClient<paths>();
358+
359+
// expect error on wrong body type
360+
// @ts-expect-error
361+
await client.post("/post/optional", { body: { error: true } });
362+
363+
// (no error)
364+
await client.post("/post/optional", {
365+
body: {
366+
title: "",
367+
publish_date: 3,
368+
body: "",
369+
},
370+
});
371+
});
372+
373+
it("request body type when optional inline", async () => {
374+
fetchMocker.mockResponse(() => ({ status: 201, body: "{}" }));
375+
const client = createClient<paths>();
376+
377+
// expect error on wrong body type
378+
// @ts-expect-error
379+
await client.post("/post/optional/inline", { body: { error: true } });
380+
381+
// (no error)
382+
await client.post("/post/optional/inline", {
383+
body: {
384+
title: "",
385+
publish_date: 3,
386+
body: "",
387+
},
388+
});
389+
});
354390
});
355391

356392
describe("delete()", () => {

packages/openapi-fetch/src/index.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,19 @@ export type FilterKeys<Obj, Matchers> = { [K in keyof Obj]: K extends Matchers ?
3434
/** handle "application/json", "application/vnd.api+json", "appliacation/json;charset=utf-8" and more */
3535
export type JSONLike = `${string}json${string}`;
3636

37-
// fetch types
37+
// general purpose types
3838
export type Params<O> = O extends { parameters: any } ? { params: NonNullable<O["parameters"]> } : BaseParams;
39-
export type RequestBodyObj<O> = O extends { requestBody: any } ? O["requestBody"] : never;
39+
export type RequestBodyObj<O> = O extends { requestBody?: any } ? O["requestBody"] : never;
4040
export type RequestBodyContent<O> = undefined extends RequestBodyObj<O> ? FilterKeys<NonNullable<RequestBodyObj<O>>, "content"> | undefined : FilterKeys<RequestBodyObj<O>, "content">;
4141
export type RequestBodyJSON<O> = FilterKeys<RequestBodyContent<O>, JSONLike> extends never ? FilterKeys<NonNullable<RequestBodyContent<O>>, JSONLike> | undefined : FilterKeys<RequestBodyContent<O>, JSONLike>;
4242
export type RequestBody<O> = undefined extends RequestBodyJSON<O> ? { body?: RequestBodyJSON<O> } : { body: RequestBodyJSON<O> };
4343
export type QuerySerializer<O> = (query: O extends { parameters: { query: any } } ? O["parameters"]["query"] : Record<string, unknown>) => string;
44-
export type FetchOptions<T> = Params<T> & RequestBody<T> & Omit<RequestInit, "body"> & { querySerializer?: QuerySerializer<T> };
44+
export type RequestOptions<T> = Params<T> & RequestBody<T> & { querySerializer?: QuerySerializer<T> };
4545
export type Success<O> = FilterKeys<FilterKeys<O, OkStatus>, "content">;
4646
export type Error<O> = FilterKeys<FilterKeys<O, ErrorStatus>, "content">;
47+
48+
// fetch types
49+
export type FetchOptions<T> = RequestOptions<T> & Omit<RequestInit, "body">;
4750
export type FetchResponse<T> =
4851
| { data: T extends { responses: any } ? NonNullable<FilterKeys<Success<T["responses"]>, JSONLike>> : unknown; error?: never; response: Response }
4952
| { data?: never; error: T extends { responses: any } ? NonNullable<FilterKeys<Error<T["responses"]>, JSONLike>> : unknown; response: Response };

packages/openapi-fetch/test/v1.d.ts

+31
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,28 @@ export interface paths {
2323
};
2424
};
2525
};
26+
"/post/optional": {
27+
post: {
28+
requestBody: components["requestBodies"]["CreatePostOptional"];
29+
responses: {
30+
201: components["responses"]["CreatePost"];
31+
500: components["responses"]["Error"];
32+
};
33+
};
34+
};
35+
"/post/optional/inline": {
36+
post: {
37+
requestBody?: {
38+
content: {
39+
"application/json": components["schemas"]["Post"];
40+
};
41+
};
42+
responses: {
43+
201: components["responses"]["CreatePost"];
44+
500: components["responses"]["Error"];
45+
};
46+
};
47+
};
2648
"/posts": {
2749
get: {
2850
responses: {
@@ -271,6 +293,15 @@ export interface components {
271293
};
272294
};
273295
};
296+
CreatePostOptional?: {
297+
content: {
298+
"application/json": {
299+
title: string;
300+
body: string;
301+
publish_date: number;
302+
};
303+
};
304+
};
274305
CreateTag?: {
275306
content: {
276307
"application/json": {

packages/openapi-fetch/test/v1.yaml

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
openapi:
2-
version: '3.1'
1+
openapi: 3.1
2+
info:
3+
title: Test Specification
4+
version: '1.0'
35
paths:
46
/comment:
57
put:
@@ -19,6 +21,27 @@ paths:
1921
$ref: '#/components/responses/CreatePost'
2022
500:
2123
$ref: '#/components/responses/Error'
24+
/post/optional:
25+
post:
26+
requestBody:
27+
$ref: '#/components/requestBodies/CreatePostOptional'
28+
responses:
29+
201:
30+
$ref: '#/components/responses/CreatePost'
31+
500:
32+
$ref: '#/components/responses/Error'
33+
/post/optional/inline:
34+
post:
35+
requestBody:
36+
content:
37+
application/json:
38+
schema:
39+
$ref: '#/components/schemas/Post'
40+
responses:
41+
201:
42+
$ref: '#/components/responses/CreatePost'
43+
500:
44+
$ref: '#/components/responses/Error'
2245
/posts:
2346
get:
2447
responses:
@@ -214,6 +237,23 @@ components:
214237
- title
215238
- body
216239
- publish_date
240+
CreatePostOptional:
241+
required: false
242+
content:
243+
application/json:
244+
schema:
245+
type: object
246+
properties:
247+
title:
248+
type: string
249+
body:
250+
type: string
251+
publish_date:
252+
type: number
253+
required:
254+
- title
255+
- body
256+
- publish_date
217257
CreateTag:
218258
content:
219259
application/json:

0 commit comments

Comments
 (0)