TypeScript: display deprecated properties

This commit is contained in:
Fuma Nama
2025-04-22 17:47:35 +08:00
parent 1fc5bf33d5
commit 3a5595aa65
10 changed files with 98 additions and 82 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'fumadocs-typescript': patch
'fumadocs-ui': patch
---
Support deprecated properties
@@ -1,7 +1,6 @@
---
title: Internationalization
description: Support multiple languages in your documentation
icon: Globe
---
## Introduction
@@ -20,31 +19,9 @@ You can define a config to share between utilities.
}
```
### Middleware
### Hide Locale Prefix
Redirects users to appropriate locale.
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
You can also customise the i18n middleware from `i18n.ts`.
#### Hide Locale Prefix
To hide the locale prefix, for example, use `/` instead of `/en`, use the `hideLocale` option.
| Mode | Description |
| ---------------- | -------------------------------------------------- |
| `always` | Always hide the prefix, detect locale from cookies |
| `default-locale` | Only hide the default locale |
| `never` | Never hide the prefix (default) |
To hide the locale prefix (e.g. `/en/page` -> `/page`), use the `hideLocale` option.
```ts
import type { I18nConfig } from 'fumadocs-core/i18n';
@@ -56,9 +33,32 @@ export const i18n: I18nConfig = {
};
```
> It uses `NextResponse.rewrite` to hide locale prefixes.
| Mode | Description |
| ---------------- | -------------------------------------------------- |
| `always` | Always hide the prefix, detect locale from cookies |
| `default-locale` | Only hide the default locale |
| `never` | Never hide the prefix (default) |
It's **not recommended** to use `always`.
On this mode, locale is stored as a cookie, read and set on the middleware.
<Callout type='warn' title={<>Using <code>always</code></>}>
This may cause undesired cache problems on your hosting platform, and need to pay extra attention on SEO to ensure search engines can index your pages correctly.
On `always` mode, locale is stored as a cookie (set by the middleware), which isn't optimal for static sites.
This may cause undesired cache problems, and need to pay extra attention on SEO to ensure search engines can index your pages correctly.
</Callout>
### Middleware
Redirects users to appropriate locale, it can be customised from `i18n.ts`.
```json doc-gen:file
{
"file": "../../examples/i18n/middleware.ts",
"codeblock": {
"lang": "ts",
"meta": "title=\"middleware.ts\""
}
}
```
> When `hideLocale` is enabled, it uses `NextResponse.rewrite` to hide locale prefixes.
+1 -1
View File
@@ -6,12 +6,12 @@
"pages": [
"---Guide---",
"index",
"internationalization",
"search",
"---Writing---",
"page-conventions",
"---API References---",
"page-tree",
"internationalization",
"components",
"utils",
"mdx",
@@ -96,12 +96,12 @@ Customise folders by creating a `meta.json` file in the folder.
By default, folder items are sorted alphabetically.
You can control the order of items using `pages`, items are not included unless they are listed inside.
You can add or control the order of items using `pages`, items are not included unless they are listed inside.
```json title="meta.json"
{
"title": "Name of Folder",
"pages": ["guide", "components", "./nested/page"]
"pages": ["guide", "components", "---My Separator---", "./nested/page"]
}
```
@@ -112,14 +112,6 @@ You can control the order of items using `pages`, items are not included unless
<File name="nested/page.mdx" />
</Files>
#### Separator
```json title="meta.json"
{
"pages": ["guide", "---My Separator---", "components"]
}
```
#### Rest
Add a `...` item to include remaining pages (sorted alphabetically), or `z...a` for descending order.
@@ -179,13 +171,11 @@ Marks the folder as a root folder, only items in the opened root folder will be
}
```
For example, when you are in a root folder called `framework`, the other folders (e.g. `headless`) are not shown on the sidebar and other navigation elements.
Index pages will also be hidden unless it is listed in the `pages` property.
For example, when you are opening a root folder `framework`, the other folders (e.g. `headless`) are not shown on the sidebar and other navigation elements.
<Files>
<Folder name="framework" defaultOpen>
<File name="index.mdx (hidden)" className="opacity-50" />
<File name="index.mdx" />
<File
name="current-page.mdx"
className="!text-fd-primary !bg-fd-primary/10"
+1
View File
@@ -12,6 +12,7 @@ export type StructureOptions = MDX.StructureOptions;
export type BreadcrumbItem = Breadcrumb.BreadcrumbItem;
export type SidebarProviderProps = Sidebar.SidebarProviderProps;
export type SidebarContentProps = Sidebar.SidebarContentProps<ElementType>;
export type SidebarTriggerProps = Sidebar.SidebarTriggerProps<ElementType>;
export type ScrollProviderProps = TOC.ScrollProviderProps;
@@ -20,6 +20,8 @@ Define the i18n configurations in a file, we will import it with `@/ilb/i18n` in
../../examples/i18n/lib/i18n.ts
</include>
> See [customisable options](/docs/headless/internationalization).
Pass it to the source loader.
```ts title="lib/source.ts"
@@ -60,8 +62,6 @@ Create a middleware that redirects users to appropriate locale.
}
```
See [Middleware](/docs/headless/internationalization#middleware) for customisable options.
<Callout title="Custom Middleware">
The default middleware is optional, you can instead use your own middleware or the one provided by i18n libraries.
+2 -2
View File
@@ -21,7 +21,7 @@ export async function start(
const outPath = path.resolve(outDir, `index.ts`);
async function updateMapFile() {
const start = Date.now();
const start = performance.now();
try {
await fs.writeFile(
@@ -36,7 +36,7 @@ export async function start(
}
}
console.log(`[MDX] updated map file in ${Date.now() - start}ms`);
console.log(`[MDX] updated map file in ${performance.now() - start}ms`);
}
await updateMapFile();
+4
View File
@@ -25,6 +25,7 @@ export interface DocEntry {
type: string;
tags: Record<string, string>;
required: boolean;
deprecated: boolean;
}
interface EntryContext {
@@ -205,6 +206,9 @@ function getDocEntry(
tags,
type: typeName,
required: !prop.isOptional(),
deprecated: prop
.getJsDocTags()
.some((tag) => tag.getName() === 'deprecated'),
};
transform?.call(context, entry, subType, prop);
@@ -36,6 +36,7 @@ export async function AutoTypeTable({
description: await renderMarkdown(entry.description),
default: entry.tags.default || entry.tags.defaultValue,
required: entry.required,
deprecated: entry.deprecated,
},
] as const,
);
+48 -34
View File
@@ -38,6 +38,7 @@ interface ObjectType {
default?: string;
required?: boolean;
deprecated?: boolean;
}
const field = cva('inline-flex flex-row items-center gap-1');
@@ -45,7 +46,10 @@ const code = cva(
'rounded-md bg-fd-secondary p-1 text-fd-secondary-foreground',
{
variants: {
color: { primary: 'bg-fd-primary/10 text-fd-primary' },
color: {
primary: 'bg-fd-primary/10 text-fd-primary',
deprecated: 'line-through text-fd-primary/50',
},
},
},
);
@@ -62,39 +66,49 @@ export function TypeTable({ type }: { type: Record<string, ObjectType> }) {
</tr>
</thead>
<tbody>
{Object.entries(type).map(([key, value]) => (
<tr key={key}>
<td>
<div className={field()}>
<code className={cn(code({ color: 'primary' }))}>
{key}
{!value.required && '?'}
</code>
{value.description ? <Info>{value.description}</Info> : null}
</div>
</td>
<td>
<div className={field()}>
<code className={code()}>{value.type}</code>
{value.typeDescription ? (
<Info>{value.typeDescription}</Info>
) : null}
{value.typeDescriptionLink ? (
<Link href={value.typeDescriptionLink}>
<InfoIcon className="size-4" />
</Link>
) : null}
</div>
</td>
<td>
{value.default ? (
<code className={code()}>{value.default}</code>
) : (
<span>-</span>
)}
</td>
</tr>
))}
{Object.entries(type)
.sort((a) => (a[1].deprecated ? 1 : -1))
.map(([key, value]) => (
<tr key={key}>
<td>
<div className={field()}>
<code
className={cn(
code({
color: value.deprecated ? 'deprecated' : 'primary',
}),
)}
>
{key}
{!value.required && '?'}
</code>
{value.description ? (
<Info>{value.description}</Info>
) : null}
</div>
</td>
<td>
<div className={field()}>
<code className={code()}>{value.type}</code>
{value.typeDescription ? (
<Info>{value.typeDescription}</Info>
) : null}
{value.typeDescriptionLink ? (
<Link href={value.typeDescriptionLink}>
<InfoIcon className="size-4" />
</Link>
) : null}
</div>
</td>
<td>
{value.default ? (
<code className={code()}>{value.default}</code>
) : (
'-'
)}
</td>
</tr>
))}
</tbody>
</table>
</div>