mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
MDX: json-schema support inserting $schema to JSON files
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-mdx': patch
|
||||
---
|
||||
|
||||
Plugin `json-schema`: support inserting `$schema` to JSON files
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from 'fumadocs-core/mdx-plugins';
|
||||
import { remarkAutoTypeTable } from 'fumadocs-typescript';
|
||||
import type { ElementContent } from 'hast';
|
||||
import jsonSchema from 'fumadocs-mdx/plugins/json-schema';
|
||||
|
||||
export const docs = defineDocs({
|
||||
docs: {
|
||||
@@ -50,6 +51,11 @@ export const blog = defineCollections({
|
||||
|
||||
export default defineConfig({
|
||||
lastModifiedTime: 'git',
|
||||
plugins: [
|
||||
jsonSchema({
|
||||
insert: true,
|
||||
}),
|
||||
],
|
||||
mdxOptions: {
|
||||
rehypeCodeOptions: {
|
||||
lazy: true,
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
"lru-cache": "^11.2.2",
|
||||
"mdast-util-to-markdown": "^2.1.2",
|
||||
"picocolors": "^1.1.1",
|
||||
"picomatch": "^4.0.3",
|
||||
"remark-mdx": "^3.1.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"tinyexec": "^1.0.1",
|
||||
@@ -106,6 +107,7 @@
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^24.9.1",
|
||||
"@types/picomatch": "^4.0.2",
|
||||
"@types/react": "^19.2.2",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"fumadocs-core": "workspace:*",
|
||||
|
||||
@@ -1,25 +1,78 @@
|
||||
import type { EmitEntry, Plugin } from '@/plugins';
|
||||
import type { LoadedConfig } from '@/loaders/config';
|
||||
import { z } from 'zod';
|
||||
import { isFileInCollection } from '@/utils/collections';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
export interface JSONSchemaOptions {
|
||||
/**
|
||||
* insert `$schema` field to JSON files on creation.
|
||||
*
|
||||
* @defaultValue false
|
||||
*/
|
||||
insert?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate JSON schemas locally for collection schemas
|
||||
*
|
||||
* note: **it only works with Zod**
|
||||
*/
|
||||
export default function jsonSchema(): Plugin {
|
||||
export default function jsonSchema({
|
||||
insert = false,
|
||||
}: JSONSchemaOptions = {}): Plugin {
|
||||
let config: LoadedConfig;
|
||||
|
||||
function getSchemaPath(name: string) {
|
||||
return `json-schema/${name}.json`;
|
||||
}
|
||||
|
||||
return {
|
||||
config(v) {
|
||||
config = v;
|
||||
},
|
||||
configureServer(server) {
|
||||
if (!server.watcher || !insert) return;
|
||||
|
||||
server.watcher.on('add', async (file) => {
|
||||
for (const [name, collection] of config.collections) {
|
||||
const single =
|
||||
collection.type === 'docs' ? collection.meta : collection;
|
||||
|
||||
if (single.type !== 'meta' || !isFileInCollection(file, single))
|
||||
continue;
|
||||
|
||||
let obj: object;
|
||||
try {
|
||||
const content = (await fs.readFile(file)).toString();
|
||||
obj = content.length > 0 ? JSON.parse(content) : {};
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('$schema' in obj) return;
|
||||
const schemaPath = path.join(
|
||||
this.outDir,
|
||||
getSchemaPath(collection.type === 'docs' ? `${name}.meta` : name),
|
||||
);
|
||||
const updated = {
|
||||
$schema: path.relative(path.dirname(file), schemaPath),
|
||||
...obj,
|
||||
};
|
||||
|
||||
// TODO: try persist formatting?
|
||||
await fs.writeFile(file, JSON.stringify(updated, null, 2));
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
emit() {
|
||||
const files: EmitEntry[] = [];
|
||||
|
||||
function onSchema(name: string, schema: z.ZodSchema) {
|
||||
files.push({
|
||||
path: `json-schema/${name}.json`,
|
||||
path: getSchemaPath(name),
|
||||
content: JSON.stringify(
|
||||
z.toJSONSchema(schema, {
|
||||
io: 'input',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { DocCollection, MetaCollection } from '@/config/define';
|
||||
import picomatch from 'picomatch';
|
||||
|
||||
export function getSupportedFormats(
|
||||
collection: DocCollection | MetaCollection,
|
||||
@@ -26,3 +27,17 @@ export function isFileSupported(
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isFileInCollection(
|
||||
file: string,
|
||||
collection: DocCollection | MetaCollection,
|
||||
): boolean {
|
||||
if (!isFileSupported(file, collection)) return false;
|
||||
|
||||
const patterns = getGlobPatterns(collection);
|
||||
const isMatch = picomatch(patterns, {
|
||||
cwd: Array.isArray(collection.dir) ? collection.dir[0] : collection.dir,
|
||||
});
|
||||
|
||||
return isMatch(file);
|
||||
}
|
||||
|
||||
Generated
+11
@@ -1817,6 +1817,9 @@ importers:
|
||||
picocolors:
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
picomatch:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3
|
||||
remark-mdx:
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
@@ -1860,6 +1863,9 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^24.9.1
|
||||
version: 24.9.1
|
||||
'@types/picomatch':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
'@types/react':
|
||||
specifier: ^19.2.2
|
||||
version: 19.2.2
|
||||
@@ -5640,6 +5646,9 @@ packages:
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==}
|
||||
|
||||
'@types/[email protected]':
|
||||
resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==}
|
||||
peerDependencies:
|
||||
@@ -15185,6 +15194,8 @@ snapshots:
|
||||
|
||||
'@types/[email protected]': {}
|
||||
|
||||
'@types/[email protected]': {}
|
||||
|
||||
'@types/[email protected](@types/[email protected])':
|
||||
dependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
Reference in New Issue
Block a user