Core & Content: support fuma-content integration

This commit is contained in:
Fuma Nama
2026-03-13 16:23:04 +08:00
parent 14ab30e81a
commit f06540672f
9 changed files with 778 additions and 252 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'fumadocs-core': patch
'@fumadocs/content': patch
---
Support fuma-content integration
+15
View File
@@ -0,0 +1,15 @@
import library from 'eslint-config-custom/library.js';
export default [
{
ignores: ['dist/', 'node_modules/'],
},
...library,
{
rules: {
'import/no-named-as-default': 'off',
'import/no-named-as-default-member': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
},
];
+46
View File
@@ -0,0 +1,46 @@
{
"name": "@fumadocs/content",
"version": "0.0.0",
"description": "The Fuma Content adapter for Fumadocs",
"keywords": [
"Docs",
"Fumadocs"
],
"homepage": "https://fumadocs.dev",
"license": "MIT",
"author": "Fuma Nama",
"repository": "github:fuma-nama/fumadocs",
"files": [
"dist/*"
],
"type": "module",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsdown",
"clean": "rimraf dist",
"dev": "tsdown --watch",
"lint": "eslint .",
"types:check": "tsc --noEmit"
},
"dependencies": {
"@standard-schema/spec": "^1.1.0"
},
"devDependencies": {
"@types/node": "^25.4.0",
"eslint-config-custom": "workspace:*",
"fuma-content": "^1.2.0",
"fumadocs-core": "workspace:*",
"tsconfig": "workspace:*",
"tsdown": "0.21.1"
},
"peerDependencies": {
"fuma-content": "^1.2.0",
"fumadocs-core": "^16.6.17"
}
}
+82
View File
@@ -0,0 +1,82 @@
import type { StandardSchemaV1 } from '@standard-schema/spec';
import { Collection } from 'fuma-content/collections';
import {
dataCollection,
DataCollection,
DataCollectionConfig,
} from 'fuma-content/collections/data';
import { MDXCollection } from 'fuma-content/collections/mdx';
import { mdxCollection, type MDXCollectionConfig } from 'fuma-content/collections/mdx';
import { type MDXBundlerPresetOptions, mdxPreset } from 'fumadocs-core/content/mdx/preset-bundler';
import { metaSchema, pageSchema } from 'fumadocs-core/source/schema';
export interface DocsMDXCollectionConfig<
FrontmatterSchema extends StandardSchemaV1 | undefined,
> extends Omit<MDXCollectionConfig<FrontmatterSchema>, 'options'> {
options?:
| MDXBundlerPresetOptions
| (() => MDXBundlerPresetOptions | Promise<MDXBundlerPresetOptions>);
}
export function docsMdxCollection<
FrontmatterSchema extends StandardSchemaV1 | typeof pageSchema = typeof pageSchema,
>(config: DocsMDXCollectionConfig<FrontmatterSchema>) {
const { options = {}, frontmatter = pageSchema, ...rest } = config;
return mdxCollection<FrontmatterSchema>({
...rest,
frontmatter: frontmatter as never,
async options() {
const mdxOptions = typeof options === 'object' ? options : await options();
const { remarkInclude } = await import('fuma-content/plugins/remark/include');
return mdxPreset({
...mdxOptions,
_include: remarkInclude,
});
},
});
}
export interface DocsCollectionConfig<
FrontmatterSchema extends StandardSchemaV1 | undefined,
MetaSchema extends StandardSchemaV1 | undefined,
> {
dir: string;
docs: Omit<DocsMDXCollectionConfig<FrontmatterSchema>, 'dir'>;
meta: Omit<DataCollectionConfig<MetaSchema>, 'dir'>;
}
export function docsCollection<
FrontmatterSchema extends StandardSchemaV1 | typeof pageSchema = typeof pageSchema,
MetaSchema extends StandardSchemaV1 | typeof metaSchema = typeof metaSchema,
>(config: DocsCollectionConfig<FrontmatterSchema, MetaSchema>) {
return new DocsCollection(
docsMdxCollection({ dir: config.dir, ...config.docs }),
dataCollection({ dir: config.dir, ...config.meta }),
);
}
export class DocsCollection<
FrontmatterSchema extends StandardSchemaV1 | undefined,
MetaSchema extends StandardSchemaV1 | undefined,
> extends Collection {
constructor(
readonly mdx: MDXCollection<FrontmatterSchema>,
readonly meta: DataCollection<MetaSchema>,
) {
super();
this.onConfig.hook((config) => {
const collections = config.config.collections;
const mdxName = `$${this.name}_mdx`;
const metaName = `$${this.name}_meta`;
for (const name of [mdxName, metaName]) {
if (collections.has(name)) {
throw new Error(`collection ${name} is taken.`);
}
}
collections.set(mdxName, mdx as never);
collections.set(metaName, meta);
});
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
},
"types": ["@types/node"],
"jsx": "react-jsx",
"noEmit": true,
"lib": ["ESNext"],
"module": "ESNext",
"target": "ES2020"
},
"exclude": ["node_modules", "eslint.config.mjs", "dist"]
}
+15
View File
@@ -0,0 +1,15 @@
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: ['./src/index.ts'],
format: 'esm',
dts: true,
fixedExtension: false,
target: 'es2023',
deps: {
onlyAllowBundle: [],
},
exports: {
enabled: true,
},
});
+9
View File
@@ -0,0 +1,9 @@
import { defineProject } from 'vitest/config';
export default defineProject({
resolve: {
alias: {
'@/': new URL('./src/', import.meta.url).pathname,
},
},
});
@@ -1,6 +1,7 @@
import type { ProcessorOptions } from '@mdx-js/mdx';
import type * as Plugins from '@/mdx-plugins';
import { resolvePlugins, type ResolvePlugins } from '@/content/mdx/util';
import type { Pluggable } from 'unified';
export type MDXBundlerPresetOptions = Omit<
NonNullable<ProcessorOptions>,
@@ -9,6 +10,8 @@ export type MDXBundlerPresetOptions = Omit<
rehypePlugins?: ResolvePlugins;
remarkPlugins?: ResolvePlugins;
/** @private for `remark-include` */
_include?: Pluggable;
remarkStructureOptions?: Plugins.StructureOptions | false;
remarkHeadingOptions?: Plugins.RemarkHeadingOptions | false;
remarkImageOptions?: Plugins.RemarkImageOptions | false;
@@ -28,6 +31,7 @@ export async function mdxPreset(options: MDXBundlerPresetOptions = {}): Promise<
remarkStructureOptions,
remarkCodeTabOptions,
remarkNpmOptions,
_include,
...mdxOptions
} = options;
@@ -42,6 +46,7 @@ export async function mdxPreset(options: MDXBundlerPresetOptions = {}): Promise<
...remarkHeadingOptions,
},
]),
_include ?? false,
remarkImageOptions !== false &&
import('@/mdx-plugins/remark-image').then((mod) => [
mod.remarkImage,
+585 -252
View File
File diff suppressed because it is too large Load Diff