mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
wip
This commit is contained in:
parent
65affab608
commit
867b604919
|
|
@ -26,7 +26,7 @@ import {
|
|||
} from '@docusaurus/utils';
|
||||
import {validatePageFrontMatter} from './frontMatter';
|
||||
import type {LoadContext, Plugin, RouteMetadata} from '@docusaurus/types';
|
||||
import type {PagesContentPaths} from './types';
|
||||
import type {ShowcaseContentPaths} from './types';
|
||||
import type {
|
||||
PluginOptions,
|
||||
Metadata,
|
||||
|
|
@ -34,7 +34,9 @@ import type {
|
|||
PageFrontMatter,
|
||||
} from '@docusaurus/plugin-content-pages';
|
||||
|
||||
export function getContentPathList(contentPaths: PagesContentPaths): string[] {
|
||||
export function getContentPathList(
|
||||
contentPaths: ShowcaseContentPaths,
|
||||
): string[] {
|
||||
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +49,7 @@ export default function pluginContentPages(
|
|||
): Plugin<LoadedContent | null> {
|
||||
const {siteConfig, siteDir, generatedFilesDir, localizationDir} = context;
|
||||
|
||||
const contentPaths: PagesContentPaths = {
|
||||
const contentPaths: ShowcaseContentPaths = {
|
||||
contentPath: path.resolve(siteDir, options.path),
|
||||
contentPathLocalized: getPluginI18nPath({
|
||||
localizationDir,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
export type PagesContentPaths = {
|
||||
export type ShowcaseContentPaths = {
|
||||
contentPath: string;
|
||||
contentPathLocalized: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import path from 'path';
|
|||
import {loadContext} from '@docusaurus/core/src/server/site';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import {fromPartial} from '@total-typescript/shoehorn';
|
||||
import pluginContentPages from '../index';
|
||||
import pluginContentShowcase from '../index';
|
||||
import {validateOptions} from '../options';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-showcase';
|
||||
|
||||
const loadPluginContent = async (siteDir: string, options: PluginOptions) => {
|
||||
const context = await loadContext({siteDir});
|
||||
const plugin = await pluginContentPages(
|
||||
const plugin = await pluginContentShowcase(
|
||||
context,
|
||||
validateOptions({
|
||||
validate: normalizePluginOptions,
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ describe('normalizeShowcasePluginOptions', () => {
|
|||
},
|
||||
},
|
||||
};
|
||||
// todo fix ts error
|
||||
expect(testValidate(userOptions)).toEqual({
|
||||
...defaultOptions,
|
||||
...userOptions,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ const invalidTags = {
|
|||
message: 'Open-Source Docusaurus sites can be useful for inspiration!',
|
||||
id: 'showcase.tag.opensource.description',
|
||||
},
|
||||
// todo throw an error with `getTagsList tagSchema`
|
||||
color: '#39c',
|
||||
},
|
||||
};
|
||||
|
|
@ -55,7 +54,7 @@ describe('showcase tags', () => {
|
|||
});
|
||||
|
||||
await expect(() => tagList).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"There was an error extracting tags: Color must be a hexadecimal color string (e.g., #RRGGBB #rrggbb)"`,
|
||||
`"There was an error extracting tags: Color must be a hexadecimal color string (e.g., #14cfc3 #E9669E)"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ async function prepareSchema() {
|
|||
return createShowcaseItemSchema(tagList);
|
||||
}
|
||||
|
||||
// todo broken
|
||||
describe('showcase item schema', () => {
|
||||
it('accepts valid item', async () => {
|
||||
const item: ShowcaseItem = {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,11 @@
|
|||
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import {
|
||||
getFolderContainingFile,
|
||||
getPluginI18nPath,
|
||||
Globby,
|
||||
} from '@docusaurus/utils';
|
||||
import Yaml from 'js-yaml';
|
||||
import {createShowcaseItemSchema, validateShowcaseItem} from './validation';
|
||||
import {getPluginI18nPath} from '@docusaurus/utils';
|
||||
import {createShowcaseItemSchema} from './validation';
|
||||
import {getTagsList} from './tags';
|
||||
import {processContentLoaded} from './lifecycle/contentLoaded';
|
||||
import {processLoadContent} from './lifecycle/loadContent';
|
||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||
import type {
|
||||
PluginOptions,
|
||||
|
|
@ -34,14 +31,14 @@ export default async function pluginContentShowcase(
|
|||
): Promise<Plugin<ShowcaseItems | null>> {
|
||||
const {siteDir, localizationDir} = context;
|
||||
// todo check for better naming of path: sitePath
|
||||
const {include, exclude, tags, routeBasePath, path: sitePath} = options;
|
||||
const {include, exclude, tags, routeBasePath, path: sitePath, id} = options;
|
||||
|
||||
const contentPaths: ShowcaseContentPaths = {
|
||||
contentPath: path.resolve(siteDir, sitePath),
|
||||
contentPathLocalized: getPluginI18nPath({
|
||||
localizationDir,
|
||||
pluginName: 'docusaurus-plugin-content-showcase',
|
||||
pluginId: options.id,
|
||||
pluginId: id,
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -55,13 +52,16 @@ export default async function pluginContentShowcase(
|
|||
return {
|
||||
name: 'docusaurus-plugin-content-showcase',
|
||||
|
||||
// todo doesn't work
|
||||
// getPathsToWatch() {
|
||||
// const {include} = options;
|
||||
// return getContentPathList(contentPaths).flatMap((contentPath) =>
|
||||
// include.map((pattern) => `${contentPath}/${pattern}`),
|
||||
// );
|
||||
// },
|
||||
// TODO doesn't work
|
||||
getPathsToWatch() {
|
||||
console.log(
|
||||
'getContentPathList(contentPaths):',
|
||||
getContentPathList(contentPaths),
|
||||
);
|
||||
return getContentPathList(contentPaths).flatMap((contentPath) =>
|
||||
include.map((pattern) => `${contentPath}/${pattern}`),
|
||||
);
|
||||
},
|
||||
|
||||
async loadContent(): Promise<ShowcaseItems | null> {
|
||||
if (!(await fs.pathExists(contentPaths.contentPath))) {
|
||||
|
|
@ -70,45 +70,12 @@ export default async function pluginContentShowcase(
|
|||
);
|
||||
}
|
||||
|
||||
const showcaseFiles = await Globby(include, {
|
||||
cwd: contentPaths.contentPath,
|
||||
ignore: [...exclude],
|
||||
return processLoadContent({
|
||||
include,
|
||||
exclude,
|
||||
contentPaths,
|
||||
showcaseItemSchema,
|
||||
});
|
||||
|
||||
async function processShowcaseSourceFile(relativeSource: string) {
|
||||
// Lookup in localized folder in priority
|
||||
const contentPath = await getFolderContainingFile(
|
||||
getContentPathList(contentPaths),
|
||||
relativeSource,
|
||||
);
|
||||
|
||||
const sourcePath = path.join(contentPath, relativeSource);
|
||||
const data = await fs.readFile(sourcePath, 'utf-8');
|
||||
const item = Yaml.load(data);
|
||||
const showcaseItem = validateShowcaseItem({
|
||||
item,
|
||||
showcaseItemSchema,
|
||||
});
|
||||
|
||||
return showcaseItem;
|
||||
}
|
||||
|
||||
async function doProcessShowcaseSourceFile(relativeSource: string) {
|
||||
try {
|
||||
return await processShowcaseSourceFile(relativeSource);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Processing of page source file path=${relativeSource} failed.`,
|
||||
{cause: err},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
items: await Promise.all(
|
||||
showcaseFiles.map(doProcessShowcaseSourceFile),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
async contentLoaded({content, actions}) {
|
||||
|
|
@ -118,19 +85,11 @@ export default async function pluginContentShowcase(
|
|||
|
||||
const {addRoute, createData} = actions;
|
||||
|
||||
const showcaseAllData = await createData(
|
||||
'showcaseAll.json',
|
||||
JSON.stringify(content.items),
|
||||
);
|
||||
|
||||
addRoute({
|
||||
path: routeBasePath,
|
||||
component: '@theme/Showcase',
|
||||
modules: {
|
||||
content: showcaseAllData,
|
||||
// img: '@site/src/showcase/website/ozaki/aot.jpg',
|
||||
},
|
||||
exact: true,
|
||||
await processContentLoaded({
|
||||
content,
|
||||
routeBasePath,
|
||||
addRoute,
|
||||
createData,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {ShowcaseItems} from '@docusaurus/plugin-content-showcase';
|
||||
import type {PluginContentLoadedActions} from '@docusaurus/types';
|
||||
|
||||
export async function processContentLoaded({
|
||||
content,
|
||||
routeBasePath,
|
||||
addRoute,
|
||||
createData,
|
||||
}: {
|
||||
content: ShowcaseItems;
|
||||
routeBasePath: string;
|
||||
addRoute: PluginContentLoadedActions['addRoute'];
|
||||
createData: PluginContentLoadedActions['createData'];
|
||||
}): Promise<void> {
|
||||
const showcaseAllData = await createData(
|
||||
'showcaseAll.json',
|
||||
JSON.stringify(content.items),
|
||||
);
|
||||
|
||||
addRoute({
|
||||
path: routeBasePath,
|
||||
component: '@theme/Showcase',
|
||||
modules: {
|
||||
content: showcaseAllData,
|
||||
},
|
||||
exact: true,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import Yaml from 'js-yaml';
|
||||
import {
|
||||
Globby,
|
||||
getContentPathList,
|
||||
getFolderContainingFile,
|
||||
} from '@docusaurus/utils';
|
||||
import {validateShowcaseItem} from '../validation';
|
||||
import type {ShowcaseContentPaths} from '../types';
|
||||
import type {ShowcaseItems} from '@docusaurus/plugin-content-showcase';
|
||||
|
||||
export async function processLoadContent({
|
||||
include,
|
||||
exclude,
|
||||
contentPaths,
|
||||
showcaseItemSchema,
|
||||
}: {
|
||||
include: string[];
|
||||
exclude: string[];
|
||||
contentPaths: ShowcaseContentPaths;
|
||||
showcaseItemSchema: any;
|
||||
}): Promise<ShowcaseItems | null> {
|
||||
const showcaseFiles = await Globby(include, {
|
||||
cwd: contentPaths.contentPath,
|
||||
ignore: [...exclude],
|
||||
});
|
||||
|
||||
async function processShowcaseSourceFile(relativeSource: string) {
|
||||
// Lookup in localized folder in priority
|
||||
const contentPath = await getFolderContainingFile(
|
||||
getContentPathList(contentPaths),
|
||||
relativeSource,
|
||||
);
|
||||
|
||||
const sourcePath = path.join(contentPath, relativeSource);
|
||||
const data = await fs.readFile(sourcePath, 'utf-8');
|
||||
const item = Yaml.load(data);
|
||||
const showcaseItem = validateShowcaseItem({
|
||||
item,
|
||||
showcaseItemSchema,
|
||||
});
|
||||
|
||||
return showcaseItem;
|
||||
}
|
||||
|
||||
async function doProcessShowcaseSourceFile(relativeSource: string) {
|
||||
try {
|
||||
return await processShowcaseSourceFile(relativeSource);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Processing of page source file path=${relativeSource} failed.`,
|
||||
{cause: err},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
items: await Promise.all(showcaseFiles.map(doProcessShowcaseSourceFile)),
|
||||
};
|
||||
}
|
||||
|
|
@ -12,11 +12,10 @@ import type {OptionValidationContext} from '@docusaurus/types';
|
|||
import type {PluginOptions, Options} from '@docusaurus/plugin-content-showcase';
|
||||
|
||||
export const DEFAULT_OPTIONS: PluginOptions = {
|
||||
id: 'showcase',
|
||||
path: 'showcase', // Path to data on filesystem, relative to site dir.
|
||||
routeBasePath: '/showcase', // URL Route.
|
||||
include: ['**/*.{yml,yaml}'],
|
||||
// todo exclude won't work if user pass a custom file name
|
||||
// TODO exclude won't work if user pass a custom file name
|
||||
exclude: [...GlobExcludeDefault, 'tags.*'],
|
||||
tags: 'tags.yml',
|
||||
};
|
||||
|
|
@ -26,9 +25,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|||
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
||||
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
||||
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
||||
id: Joi.string().default(DEFAULT_OPTIONS.id),
|
||||
tags: Joi.alternatives()
|
||||
// todo ozaki understand this
|
||||
.try(Joi.string().default(DEFAULT_OPTIONS.tags), tagSchema)
|
||||
.default(DEFAULT_OPTIONS.tags),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ export const tagSchema = Joi.object().pattern(
|
|||
id: Joi.string().required(),
|
||||
}).required(),
|
||||
color: Joi.string()
|
||||
// todo doesnt work ???
|
||||
.pattern(/^#[\dA-Fa-f]{6}$/)
|
||||
.required()
|
||||
.messages({
|
||||
'string.pattern.base':
|
||||
'Color must be a hexadecimal color string (e.g., #RRGGBB #rrggbb)',
|
||||
'Color must be a hexadecimal color string (e.g., #14cfc3 #E9669E)',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
|
@ -38,8 +37,6 @@ export async function getTagsList({
|
|||
configPath: string;
|
||||
}): Promise<string[]> {
|
||||
if (typeof configTags === 'object') {
|
||||
console.log('Gettings Tag List and validating');
|
||||
tagSchema.describe();
|
||||
const tags = tagSchema.validate(configTags);
|
||||
if (tags.error) {
|
||||
throw new Error(
|
||||
|
|
@ -72,5 +69,5 @@ export async function getTagsList({
|
|||
}
|
||||
|
||||
export function createTagSchema(tags: string[]): Joi.Schema {
|
||||
return Joi.array().items(Joi.string().valid(...tags)); // Schema for array of strings
|
||||
return Joi.array().items(Joi.string().valid(...tags));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue