mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 10:55:57 +00:00
MDX: introduce official workspace API
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-mdx': minor
|
||||
---
|
||||
|
||||
Support Workspaces API [Experimental]
|
||||
@@ -36,21 +36,26 @@ export type CollectionItem =
|
||||
interface PrimitiveCollectionItem {
|
||||
name: string;
|
||||
cwd: string;
|
||||
/**
|
||||
* content directory (absolute)
|
||||
*/
|
||||
dir: string;
|
||||
hasFile: (filePath: string) => boolean;
|
||||
isFileSupported: (filePath: string) => boolean;
|
||||
patterns: string[];
|
||||
}
|
||||
|
||||
export type MetaCollectionItem = PrimitiveCollectionItem &
|
||||
Omit<MetaCollection, 'files'>;
|
||||
Omit<MetaCollection, 'files' | 'dir'>;
|
||||
export type DocCollectionItem = PrimitiveCollectionItem &
|
||||
Omit<DocCollection, 'files'>;
|
||||
Omit<DocCollection, 'files' | 'dir'>;
|
||||
|
||||
export interface DocsCollectionItem extends DocsCollection {
|
||||
name: string;
|
||||
export interface DocsCollectionItem
|
||||
extends
|
||||
Omit<DocsCollection, 'dir' | 'meta' | 'docs'>,
|
||||
Omit<PrimitiveCollectionItem, 'patterns'> {
|
||||
meta: MetaCollectionItem;
|
||||
docs: DocCollectionItem;
|
||||
hasFile: (filePath: string) => boolean;
|
||||
}
|
||||
|
||||
const SupportedFormats = {
|
||||
@@ -64,21 +69,29 @@ export function buildCollection(
|
||||
cwd: string,
|
||||
): CollectionItem {
|
||||
if (collection.type === 'docs') {
|
||||
return {
|
||||
...collection,
|
||||
const docs = buildCollection(
|
||||
name,
|
||||
meta: buildCollection(name, collection.meta, cwd),
|
||||
docs: buildCollection(name, collection.docs, cwd),
|
||||
hasFile(filePath) {
|
||||
return this.docs.hasFile(filePath) || this.meta.hasFile(filePath);
|
||||
},
|
||||
} as DocsCollectionItem;
|
||||
}
|
||||
|
||||
if (collection.type === 'doc') {
|
||||
collection.docs,
|
||||
cwd,
|
||||
) as DocCollectionItem;
|
||||
const meta = buildCollection(
|
||||
name,
|
||||
collection.meta,
|
||||
cwd,
|
||||
) as MetaCollectionItem;
|
||||
return {
|
||||
...collection,
|
||||
...buildPrimitiveCollection(name, collection, cwd),
|
||||
dir: docs.dir,
|
||||
name,
|
||||
meta,
|
||||
docs,
|
||||
hasFile(filePath) {
|
||||
return docs.hasFile(filePath) || meta.hasFile(filePath);
|
||||
},
|
||||
isFileSupported(filePath) {
|
||||
return docs.isFileSupported(filePath) || meta.isFileSupported(filePath);
|
||||
},
|
||||
cwd,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,9 +108,10 @@ function buildPrimitiveCollection(
|
||||
): PrimitiveCollectionItem {
|
||||
const supportedFormats = SupportedFormats[config.type];
|
||||
const patterns = config.files ?? [`**/*.{${supportedFormats.join(',')}}`];
|
||||
let matchers: picomatch.Matcher[];
|
||||
let matcher: picomatch.Matcher;
|
||||
|
||||
return {
|
||||
dir: path.resolve(cwd, config.dir),
|
||||
cwd,
|
||||
name,
|
||||
patterns,
|
||||
@@ -105,17 +119,11 @@ function buildPrimitiveCollection(
|
||||
return supportedFormats.some((format) => filePath.endsWith(`.${format}`));
|
||||
},
|
||||
hasFile(filePath) {
|
||||
matchers ??= (Array.isArray(config.dir) ? config.dir : [config.dir]).map(
|
||||
(dir) =>
|
||||
picomatch(patterns, {
|
||||
cwd: dir,
|
||||
}),
|
||||
);
|
||||
matcher ??= picomatch(patterns, {
|
||||
cwd: this.dir,
|
||||
});
|
||||
|
||||
return (
|
||||
this.isFileSupported(filePath) &&
|
||||
matchers.some((matcher) => matcher(filePath))
|
||||
);
|
||||
return this.isFileSupported(filePath) && matcher(filePath);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export interface EmitEntry {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface PluginContext extends CoreOptions {
|
||||
export interface PluginContext {
|
||||
core: Core;
|
||||
}
|
||||
|
||||
@@ -106,8 +106,6 @@ export interface CoreOptions {
|
||||
environment: string;
|
||||
configPath: string;
|
||||
outDir: string;
|
||||
|
||||
extend?: (core: Core) => Core;
|
||||
plugins?: PluginOption[];
|
||||
|
||||
/**
|
||||
@@ -185,7 +183,7 @@ export function createCore(options: CoreOptions) {
|
||||
return data as T;
|
||||
}
|
||||
|
||||
const core = {
|
||||
return {
|
||||
/**
|
||||
* Convenient cache store, reset when config changes
|
||||
*/
|
||||
@@ -223,6 +221,9 @@ export function createCore(options: CoreOptions) {
|
||||
);
|
||||
}
|
||||
},
|
||||
getWorkspaces() {
|
||||
return workspaces;
|
||||
},
|
||||
getOptions() {
|
||||
return options;
|
||||
},
|
||||
@@ -238,22 +239,15 @@ export function createCore(options: CoreOptions) {
|
||||
getPlugins() {
|
||||
return plugins;
|
||||
},
|
||||
getCollections(workspace?: string): CollectionItem[] {
|
||||
if (workspace) return workspaces.get(workspace)?.getCollections() ?? [];
|
||||
getCollections(): CollectionItem[] {
|
||||
return Array.from(config.collections.values());
|
||||
},
|
||||
getCollection(
|
||||
name: string,
|
||||
workspace?: string,
|
||||
): CollectionItem | undefined {
|
||||
if (workspace) return workspaces.get(workspace)?.getCollection(name);
|
||||
|
||||
getCollection(name: string): CollectionItem | undefined {
|
||||
return config.collections.get(name);
|
||||
},
|
||||
getPluginContext(): PluginContext {
|
||||
return {
|
||||
core: this,
|
||||
...options,
|
||||
};
|
||||
},
|
||||
async initServer(server: ServerContext): Promise<void> {
|
||||
@@ -364,12 +358,6 @@ export function createCore(options: CoreOptions) {
|
||||
return file;
|
||||
},
|
||||
};
|
||||
|
||||
if (options.extend) {
|
||||
return (options.extend as (v: typeof core) => typeof core)(core);
|
||||
}
|
||||
|
||||
return core;
|
||||
}
|
||||
|
||||
function postprocessPlugin(): Plugin {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { Core } from '@/core';
|
||||
import fs from 'node:fs/promises';
|
||||
import type { LoadedConfig } from '@/config/build';
|
||||
|
||||
export interface ConfigLoader {
|
||||
getConfig: () => LoadedConfig | Promise<LoadedConfig>;
|
||||
core: Core;
|
||||
getCore(): Promise<Core>;
|
||||
}
|
||||
|
||||
export function createStandaloneConfigLoader({
|
||||
@@ -22,7 +20,12 @@ export function createStandaloneConfigLoader({
|
||||
*/
|
||||
mode: 'dev' | 'production';
|
||||
}): ConfigLoader {
|
||||
let loaded: { config: Promise<LoadedConfig>; hash: string } | undefined;
|
||||
let prev:
|
||||
| {
|
||||
hash: string;
|
||||
init: Promise<void>;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
async function getConfigHash(): Promise<string> {
|
||||
if (mode === 'production') return 'static';
|
||||
@@ -34,26 +37,24 @@ export function createStandaloneConfigLoader({
|
||||
return stats.mtime.getTime().toString();
|
||||
}
|
||||
|
||||
async function newConfig() {
|
||||
const { loadConfig } = await import('../config/load-from-file');
|
||||
await core.init({
|
||||
config: loadConfig(core, buildConfig),
|
||||
});
|
||||
|
||||
return core.getConfig();
|
||||
}
|
||||
|
||||
return {
|
||||
core,
|
||||
async getConfig() {
|
||||
async getCore() {
|
||||
const hash = await getConfigHash();
|
||||
if (loaded && loaded.hash === hash) return loaded.config;
|
||||
if (!prev || hash !== prev.hash) {
|
||||
prev = {
|
||||
hash,
|
||||
init: (async () => {
|
||||
const { loadConfig } = await import('../config/load-from-file');
|
||||
|
||||
loaded = {
|
||||
hash,
|
||||
config: newConfig(),
|
||||
};
|
||||
return loaded.config;
|
||||
await core.init({
|
||||
config: loadConfig(core, buildConfig),
|
||||
});
|
||||
})(),
|
||||
};
|
||||
}
|
||||
|
||||
await prev.init;
|
||||
return core;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -63,9 +64,8 @@ export function createStandaloneConfigLoader({
|
||||
*/
|
||||
export function createIntegratedConfigLoader(core: Core): ConfigLoader {
|
||||
return {
|
||||
core,
|
||||
getConfig() {
|
||||
return core.getConfig();
|
||||
async getCore() {
|
||||
return core;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ const querySchema = z
|
||||
.object({
|
||||
only: z.literal(['frontmatter', 'all']).default('all'),
|
||||
collection: z.string().optional(),
|
||||
workspace: z.string().optional(),
|
||||
})
|
||||
.loose();
|
||||
|
||||
@@ -24,7 +25,7 @@ const cacheEntry = z.object({
|
||||
|
||||
type CacheEntry = z.infer<typeof cacheEntry>;
|
||||
|
||||
export function createMdxLoader({ core, getConfig }: ConfigLoader): Loader {
|
||||
export function createMdxLoader({ getCore }: ConfigLoader): Loader {
|
||||
return {
|
||||
test: mdxLoaderGlob,
|
||||
async load({
|
||||
@@ -34,16 +35,24 @@ export function createMdxLoader({ core, getConfig }: ConfigLoader): Loader {
|
||||
compiler,
|
||||
filePath,
|
||||
}) {
|
||||
const config = await getConfig();
|
||||
let core = await getCore();
|
||||
const value = await getSource();
|
||||
const matter = fumaMatter(value);
|
||||
const parsed = querySchema.parse(query);
|
||||
const {
|
||||
collection: collectionName,
|
||||
workspace,
|
||||
only,
|
||||
} = querySchema.parse(query);
|
||||
if (workspace) {
|
||||
core = core.getWorkspaces().get(workspace) ?? core;
|
||||
}
|
||||
|
||||
let after: (() => Promise<void>) | undefined;
|
||||
|
||||
if (!isDevelopment && config.global.experimentalBuildCache) {
|
||||
const cacheDir = config.global.experimentalBuildCache;
|
||||
const cacheKey = `${parsed.hash}_${parsed.collection ?? 'global'}_${generateCacheHash(filePath)}`;
|
||||
const { experimentalBuildCache = false } = core.getConfig().global;
|
||||
if (!isDevelopment && experimentalBuildCache) {
|
||||
const cacheDir = experimentalBuildCache;
|
||||
const cacheKey = `${collectionName ?? 'global'}_${generateCacheHash(filePath)}`;
|
||||
|
||||
const cached = await fs
|
||||
.readFile(path.join(cacheDir, cacheKey))
|
||||
@@ -63,8 +72,8 @@ export function createMdxLoader({ core, getConfig }: ConfigLoader): Loader {
|
||||
};
|
||||
}
|
||||
|
||||
const collection = parsed.collection
|
||||
? core.getCollection(parsed.collection)
|
||||
const collection = collectionName
|
||||
? core.getCollection(collectionName)
|
||||
: undefined;
|
||||
|
||||
let docCollection: DocCollectionItem | undefined;
|
||||
@@ -84,7 +93,7 @@ export function createMdxLoader({ core, getConfig }: ConfigLoader): Loader {
|
||||
);
|
||||
}
|
||||
|
||||
if (parsed.only === 'frontmatter') {
|
||||
if (only === 'frontmatter') {
|
||||
return {
|
||||
code: `export const frontmatter = ${JSON.stringify(matter.data)}`,
|
||||
map: null,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { MetaCollectionItem } from '@/config/build';
|
||||
const querySchema = z
|
||||
.object({
|
||||
collection: z.string().optional(),
|
||||
workspace: z.string().optional(),
|
||||
})
|
||||
.loose();
|
||||
|
||||
@@ -15,7 +16,7 @@ const querySchema = z
|
||||
* load meta files, fallback to bundler's built-in plugins when ?collection is unspecified.
|
||||
*/
|
||||
export function createMetaLoader(
|
||||
{ core, getConfig }: ConfigLoader,
|
||||
{ getCore }: ConfigLoader,
|
||||
resolve: {
|
||||
json?: 'json' | 'js';
|
||||
yaml?: 'yaml' | 'js';
|
||||
@@ -37,10 +38,14 @@ export function createMetaLoader(
|
||||
function onMeta(source: string, { filePath, query }: LoaderInput) {
|
||||
const parsed = querySchema.safeParse(query);
|
||||
if (!parsed.success || !parsed.data.collection) return null;
|
||||
const collectionName = parsed.data.collection;
|
||||
const { collection: collectionName, workspace } = parsed.data;
|
||||
|
||||
return async (): Promise<unknown> => {
|
||||
await getConfig();
|
||||
let core = await getCore();
|
||||
if (workspace) {
|
||||
core = core.getWorkspaces().get(workspace) ?? core;
|
||||
}
|
||||
|
||||
const collection = core.getCollection(collectionName);
|
||||
let metaCollection: MetaCollectionItem | undefined;
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@ async function init(dev: boolean, core: Core): Promise<void> {
|
||||
|
||||
watcher.add(configPath);
|
||||
for (const collection of core.getCollections()) {
|
||||
if (collection.type === 'docs') {
|
||||
watcher.add(collection.docs.dir);
|
||||
watcher.add(collection.meta.dir);
|
||||
} else {
|
||||
watcher.add(collection.dir);
|
||||
}
|
||||
for (const workspace of core.getWorkspaces().values()) {
|
||||
for (const collection of workspace.getCollections()) {
|
||||
watcher.add(collection.dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ export interface IndexFilePlugin {
|
||||
|
||||
interface FileGenContext {
|
||||
core: Core;
|
||||
workspace?: string;
|
||||
codegen: CodeGen;
|
||||
serverOptions: ServerOptions;
|
||||
tc: string;
|
||||
@@ -131,6 +132,7 @@ export default function indexFile(
|
||||
},
|
||||
async emit() {
|
||||
const globCache = new Map<string, Promise<string[]>>();
|
||||
const { workspace, outDir } = this.core.getOptions();
|
||||
const { serverOptions, tc } = generateConfigs(this.core);
|
||||
|
||||
const toEmitEntry = async (
|
||||
@@ -139,7 +141,7 @@ export default function indexFile(
|
||||
): Promise<EmitEntry> => {
|
||||
const codegen = createCodegen({
|
||||
target,
|
||||
outDir: this.outDir,
|
||||
outDir: outDir,
|
||||
jsExtension: addJsExtension,
|
||||
globCache,
|
||||
});
|
||||
@@ -148,6 +150,7 @@ export default function indexFile(
|
||||
codegen,
|
||||
serverOptions,
|
||||
tc,
|
||||
workspace: workspace?.name,
|
||||
});
|
||||
return {
|
||||
path,
|
||||
@@ -170,12 +173,8 @@ export default function indexFile(
|
||||
};
|
||||
}
|
||||
|
||||
async function generateServerIndexFile({
|
||||
core,
|
||||
codegen,
|
||||
serverOptions,
|
||||
tc,
|
||||
}: FileGenContext) {
|
||||
async function generateServerIndexFile(ctx: FileGenContext) {
|
||||
const { core, codegen, serverOptions, tc } = ctx;
|
||||
codegen.lines.push(
|
||||
`import { server } from 'fumadocs-mdx/runtime/server';`,
|
||||
`import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
|
||||
@@ -186,51 +185,49 @@ async function generateServerIndexFile({
|
||||
async function generateCollectionObject(
|
||||
collection: CollectionItem,
|
||||
): Promise<string | undefined> {
|
||||
const base = getBase(collection);
|
||||
|
||||
switch (collection.type) {
|
||||
case 'docs': {
|
||||
if (collection.docs.dynamic) return;
|
||||
|
||||
if (collection.docs.async) {
|
||||
const [metaGlob, headGlob, bodyGlob] = await Promise.all([
|
||||
generateMetaCollectionGlob(codegen, collection.meta, true),
|
||||
generateDocCollectionFrontmatterGlob(
|
||||
codegen,
|
||||
collection.docs,
|
||||
true,
|
||||
),
|
||||
generateDocCollectionGlob(codegen, collection.docs),
|
||||
generateMetaCollectionGlob(ctx, collection.meta, true),
|
||||
generateDocCollectionFrontmatterGlob(ctx, collection.docs, true),
|
||||
generateDocCollectionGlob(ctx, collection.docs),
|
||||
]);
|
||||
|
||||
return `await create.docsLazy("${collection.name}", "${collection.dir}", ${metaGlob}, ${headGlob}, ${bodyGlob})`;
|
||||
return `await create.docsLazy("${collection.name}", "${base}", ${metaGlob}, ${headGlob}, ${bodyGlob})`;
|
||||
}
|
||||
|
||||
const [metaGlob, docGlob] = await Promise.all([
|
||||
generateMetaCollectionGlob(codegen, collection.meta, true),
|
||||
generateDocCollectionGlob(codegen, collection.docs, true),
|
||||
generateMetaCollectionGlob(ctx, collection.meta, true),
|
||||
generateDocCollectionGlob(ctx, collection.docs, true),
|
||||
]);
|
||||
|
||||
return `await create.docs("${collection.name}", "${collection.dir}", ${metaGlob}, ${docGlob})`;
|
||||
return `await create.docs("${collection.name}", "${base}", ${metaGlob}, ${docGlob})`;
|
||||
}
|
||||
case 'doc':
|
||||
if (collection.dynamic) return;
|
||||
|
||||
if (collection.async) {
|
||||
const [headGlob, bodyGlob] = await Promise.all([
|
||||
generateDocCollectionFrontmatterGlob(codegen, collection, true),
|
||||
generateDocCollectionGlob(codegen, collection),
|
||||
generateDocCollectionFrontmatterGlob(ctx, collection, true),
|
||||
generateDocCollectionGlob(ctx, collection),
|
||||
]);
|
||||
|
||||
return `await create.docLazy("${collection.name}", "${collection.dir}", ${headGlob}, ${bodyGlob})`;
|
||||
return `await create.docLazy("${collection.name}", "${base}", ${headGlob}, ${bodyGlob})`;
|
||||
}
|
||||
|
||||
return `await create.doc("${collection.name}", "${collection.dir}", ${await generateDocCollectionGlob(
|
||||
codegen,
|
||||
return `await create.doc("${collection.name}", "${base}", ${await generateDocCollectionGlob(
|
||||
ctx,
|
||||
collection,
|
||||
true,
|
||||
)})`;
|
||||
case 'meta':
|
||||
return `await create.meta("${collection.name}", "${collection.dir}", ${await generateMetaCollectionGlob(
|
||||
codegen,
|
||||
return `await create.meta("${collection.name}", "${base}", ${await generateMetaCollectionGlob(
|
||||
ctx,
|
||||
collection,
|
||||
true,
|
||||
)})`;
|
||||
@@ -247,12 +244,8 @@ async function generateServerIndexFile({
|
||||
);
|
||||
}
|
||||
|
||||
async function generateDynamicIndexFile({
|
||||
core,
|
||||
codegen,
|
||||
serverOptions,
|
||||
tc,
|
||||
}: FileGenContext) {
|
||||
async function generateDynamicIndexFile(ctx: FileGenContext) {
|
||||
const { core, codegen, serverOptions, tc } = ctx;
|
||||
const { configPath, environment, outDir } = core.getOptions();
|
||||
// serializable config options
|
||||
const partialOptions: CoreOptions = {
|
||||
@@ -269,9 +262,9 @@ async function generateDynamicIndexFile({
|
||||
|
||||
async function generateCollectionObjectEntry(
|
||||
collection: DocCollectionItem,
|
||||
file: string,
|
||||
absolutePath: string,
|
||||
) {
|
||||
const fullPath = path.join(collection.dir, file);
|
||||
const fullPath = path.relative(process.cwd(), absolutePath);
|
||||
const content = await indexFileCache.read(fullPath).catch(() => '');
|
||||
const parsed = fumaMatter(content);
|
||||
const data = await core.transformFrontmatter(
|
||||
@@ -291,7 +284,7 @@ async function generateDynamicIndexFile({
|
||||
for (const [k, v] of Object.entries({
|
||||
info: {
|
||||
fullPath,
|
||||
path: file,
|
||||
path: path.relative(collection.dir, absolutePath),
|
||||
},
|
||||
data,
|
||||
hash,
|
||||
@@ -313,6 +306,7 @@ async function generateDynamicIndexFile({
|
||||
|
||||
const files = await glob(collection.patterns, {
|
||||
cwd: collection.dir,
|
||||
absolute: true,
|
||||
});
|
||||
const entries = await Promise.all(
|
||||
files.map((file) => generateCollectionObjectEntry(collection, file)),
|
||||
@@ -321,15 +315,15 @@ async function generateDynamicIndexFile({
|
||||
switch (parent.type) {
|
||||
case 'docs': {
|
||||
const metaGlob = await generateMetaCollectionGlob(
|
||||
codegen,
|
||||
ctx,
|
||||
parent.meta,
|
||||
true,
|
||||
);
|
||||
|
||||
return `await create.docs("${parent.name}", "${parent.dir}", ${metaGlob}, ${entries.join(', ')})`;
|
||||
return `await create.docs("${parent.name}", "${getBase(parent)}", ${metaGlob}, ${entries.join(', ')})`;
|
||||
}
|
||||
case 'doc':
|
||||
return `await create.doc("${collection.name}", "${collection.dir}", ${entries.join(', ')})`;
|
||||
return `await create.doc("${collection.name}", "${getBase(collection)}", ${entries.join(', ')})`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +337,8 @@ async function generateDynamicIndexFile({
|
||||
);
|
||||
}
|
||||
|
||||
async function generateBrowserIndexFile({ core, codegen, tc }: FileGenContext) {
|
||||
async function generateBrowserIndexFile(ctx: FileGenContext) {
|
||||
const { core, codegen, tc } = ctx;
|
||||
codegen.lines.push(
|
||||
`import { browser } from 'fumadocs-mdx/runtime/browser';`,
|
||||
`import type * as Config from '${codegen.formatImportPath(core.getOptions().configPath)}';`,
|
||||
@@ -363,7 +358,7 @@ async function generateBrowserIndexFile({ core, codegen, tc }: FileGenContext) {
|
||||
case 'doc':
|
||||
if (collection.dynamic) return;
|
||||
|
||||
return `create.doc("${collection.name}", ${await generateDocCollectionGlob(codegen, collection)})`;
|
||||
return `create.doc("${collection.name}", ${await generateDocCollectionGlob(ctx, collection)})`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +376,12 @@ async function generateBrowserIndexFile({ core, codegen, tc }: FileGenContext) {
|
||||
codegen.lines.push('};', 'export default browserCollections;');
|
||||
}
|
||||
|
||||
function getBase(collection: CollectionItem) {
|
||||
return path.relative(process.cwd(), collection.dir);
|
||||
}
|
||||
|
||||
function generateDocCollectionFrontmatterGlob(
|
||||
codegen: CodeGen,
|
||||
{ codegen, workspace }: FileGenContext,
|
||||
collection: DocCollectionItem,
|
||||
eager = false,
|
||||
) {
|
||||
@@ -390,6 +389,7 @@ function generateDocCollectionFrontmatterGlob(
|
||||
query: {
|
||||
collection: collection.name,
|
||||
only: 'frontmatter',
|
||||
workspace,
|
||||
},
|
||||
import: 'frontmatter',
|
||||
base: collection.dir,
|
||||
@@ -398,13 +398,14 @@ function generateDocCollectionFrontmatterGlob(
|
||||
}
|
||||
|
||||
function generateDocCollectionGlob(
|
||||
codegen: CodeGen,
|
||||
{ codegen, workspace }: FileGenContext,
|
||||
collection: DocCollectionItem,
|
||||
eager = false,
|
||||
) {
|
||||
return codegen.generateGlobImport(collection.patterns, {
|
||||
query: {
|
||||
collection: collection.name,
|
||||
workspace,
|
||||
},
|
||||
base: collection.dir,
|
||||
eager,
|
||||
@@ -412,13 +413,14 @@ function generateDocCollectionGlob(
|
||||
}
|
||||
|
||||
function generateMetaCollectionGlob(
|
||||
codegen: CodeGen,
|
||||
{ codegen, workspace }: FileGenContext,
|
||||
collection: MetaCollectionItem,
|
||||
eager = false,
|
||||
) {
|
||||
return codegen.generateGlobImport(collection.patterns, {
|
||||
query: {
|
||||
collection: collection.name,
|
||||
workspace,
|
||||
},
|
||||
import: 'default',
|
||||
base: collection.dir,
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function jsonSchema({
|
||||
|
||||
return {
|
||||
configureServer(server) {
|
||||
const { outDir } = this.core.getOptions();
|
||||
if (!server.watcher || !insert) return;
|
||||
|
||||
server.watcher.on('add', async (file) => {
|
||||
@@ -55,7 +56,7 @@ export default function jsonSchema({
|
||||
|
||||
if ('$schema' in obj) return;
|
||||
const schemaPath = path.join(
|
||||
this.outDir,
|
||||
outDir,
|
||||
getSchemaPath(parent ? `${parent.name}.meta` : match.name),
|
||||
);
|
||||
const updated = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { glob } from 'tinyglobby';
|
||||
|
||||
export interface GlobImportOptions {
|
||||
base: string;
|
||||
query?: Record<string, string>;
|
||||
query?: Record<string, string | undefined>;
|
||||
import?: string;
|
||||
eager?: boolean;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export function createCodegen({
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
for (const [k, v] of Object.entries(query)) {
|
||||
searchParams.set(k, v);
|
||||
if (v !== undefined) searchParams.set(k, v);
|
||||
}
|
||||
|
||||
const importPath =
|
||||
@@ -136,10 +136,9 @@ export function createCodegen({
|
||||
const ext = path.extname(file);
|
||||
let filename: string;
|
||||
|
||||
if (ext === '.ts' && jsExtension) {
|
||||
filename = file.substring(0, file.length - ext.length) + '.js';
|
||||
} else if (ext === '.ts') {
|
||||
if (ext === '.ts') {
|
||||
filename = file.substring(0, file.length - ext.length);
|
||||
if (jsExtension) filename += '.js';
|
||||
} else {
|
||||
filename = file;
|
||||
}
|
||||
|
||||
@@ -41,10 +41,7 @@ test('format errors', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
const baseDir = path.relative(
|
||||
process.cwd(),
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
);
|
||||
const baseDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const cases: {
|
||||
name: string;
|
||||
config: Record<string, unknown>;
|
||||
@@ -122,9 +119,12 @@ const cases: {
|
||||
for (const { name, config } of cases) {
|
||||
test(`generate JS index file: ${name}`, async () => {
|
||||
const core = createCore({
|
||||
configPath: path.join(baseDir, './fixtures/config.ts'),
|
||||
configPath: path.relative(
|
||||
process.cwd(),
|
||||
path.join(baseDir, './fixtures/config.ts'),
|
||||
),
|
||||
environment: 'test',
|
||||
outDir: path.join(baseDir, './fixtures'),
|
||||
outDir: path.relative(process.cwd(), path.join(baseDir, './fixtures')),
|
||||
plugins: [indexFile()],
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user