Skip to content

Commit

Permalink
feat: support multiple docs and blog folders #24
Browse files Browse the repository at this point in the history
  • Loading branch information
weareoutman committed Nov 14, 2020
1 parent 4bb0db4 commit d90f4ad
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 58 deletions.
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -72,12 +72,12 @@ yarn add nodejieba
| indexDocs | boolean | `true` | Whether to index docs. |
| indexBlog | boolean | `true` | Whether to index blog. |
| indexPages | boolean | `false` | Whether to index pages. |
| docsRouteBasePath | string | `"/docs"` | Base route path of docs. Slash at beginning is not required. |
| blogRouteBasePath | string | `"/blog"` | Base route path of blog. Slash at beginning is not required. |
| docsRouteBasePath | string \| string[] | `"/docs"` | Base route path of docs. Slash at beginning is not required. |
| blogRouteBasePath | string \| string[] | `"/blog"` | Base route path of blog. Slash at beginning is not required. |
| language | string \| string[] | `"en"` | All [lunr-languages](https://github.com/MihaiValentin/lunr-languages) supported languages, + `zh` 🔥. |
| hashed | boolean | `false` | Whether to add a hashed query when fetching index (based on the content hash of all `*.md`) |
| docsDir | string | `"docs"` | The dir of docs to get the content hash, it's relative to the dir of your project. |
| blogDir | string | `"blog"` | Just like the `docsDir` but applied to blog. |
| docsDir | string \| string[] | `"docs"` | The dir of docs to get the content hash, it's relative to the dir of your project. |
| blogDir | string \| string[] | `"blog"` | Just like the `docsDir` but applied to blog. |
| removeDefaultStopWordFilter | boolean | `false` | Sometimes people (E.g., us) want to keep the English stop words as indexed, since they maybe are relevant in programming docs. |
| searchResultLimits | number | `8` | Limit the search results. |
| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. results. |
Expand Down
8 changes: 4 additions & 4 deletions src/server/utils/getIndexHash.spec.ts
Expand Up @@ -57,14 +57,14 @@ jest.mock(
describe("getIndexHash", () => {
test.each<[Partial<ProcessedPluginOptions>, string | null, number]>([
[{ hashed: false }, null, 0],
[{ hashed: true, indexDocs: true, docsDir: "/tmp/docs" }, "87def35c", 0],
[{ hashed: true, indexBlog: true, blogDir: "/tmp/blog" }, null, 0],
[{ hashed: true, indexDocs: true, docsDir: ["/tmp/docs"] }, "87def35c", 0],
[{ hashed: true, indexBlog: true, blogDir: ["/tmp/blog"] }, null, 0],
[
{ hashed: true, indexDocs: true, docsDir: "/does-not-exist/docs" },
{ hashed: true, indexDocs: true, docsDir: ["/does-not-exist/docs"] },
null,
1,
],
[{ hashed: true, indexDocs: true, docsDir: "/tmp/index.js" }, null, 1],
[{ hashed: true, indexDocs: true, docsDir: ["/tmp/index.js"] }, null, 1],
])("getIndexHash(%j) should return '%s'", (config, hash, warnCount) => {
expect(getIndexHash(config as ProcessedPluginOptions)).toBe(hash);
expect(mockConsoleWarn).toBeCalledTimes(warnCount);
Expand Down
20 changes: 8 additions & 12 deletions src/server/utils/getIndexHash.ts
Expand Up @@ -16,18 +16,14 @@ export function getIndexHash(config: ProcessedPluginOptions): string | null {
dirField: "docsDir" | "blogDir"
): void => {
if (config[flagField]) {
if (!fs.existsSync(config[dirField])) {
console.warn(
`Warn: \`${dirField}\` doesn't exist: "${config[dirField]}".`
);
} else if (!fs.lstatSync(config[dirField]).isDirectory()) {
console.warn(
`Warn: \`${dirField}\` is not a directory: "${config[dirField]}".`
);
} else {
files.push(
...klawSync(config[dirField], { nodir: true, filter: markdownFilter })
);
for (const dir of config[dirField]) {
if (!fs.existsSync(dir)) {
console.warn(`Warn: \`${dirField}\` doesn't exist: "${dir}".`);
} else if (!fs.lstatSync(dir).isDirectory()) {
console.warn(`Warn: \`${dirField}\` is not a directory: "${dir}".`);
} else {
files.push(...klawSync(dir, { nodir: true, filter: markdownFilter }));
}
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/server/utils/processDocInfos.spec.ts
Expand Up @@ -34,8 +34,8 @@ describe("processDocInfos", () => {
indexDocs: true,
indexBlog: true,
indexPages: true,
docsRouteBasePath: "docs",
blogRouteBasePath: "blog",
docsRouteBasePath: ["docs"],
blogRouteBasePath: ["blog"],
},
[
{
Expand Down
16 changes: 12 additions & 4 deletions src/server/utils/processDocInfos.ts
Expand Up @@ -29,17 +29,25 @@ export function processDocInfos(
// Do not index error page and search page.
return;
}
if (indexBlog && urlMatchesPrefix(route, blogRouteBasePath)) {
if (
indexBlog &&
blogRouteBasePath.some((basePath) => urlMatchesPrefix(route, basePath))
) {
if (
route === blogRouteBasePath ||
urlMatchesPrefix(route, `${blogRouteBasePath}/tags`)
blogRouteBasePath.some(
(basePath) =>
route === basePath || urlMatchesPrefix(route, `${basePath}/tags`)
)
) {
// Do not index list of blog posts and tags filter pages
return;
}
return { route, url, type: "blog" };
}
if (indexDocs && urlMatchesPrefix(route, docsRouteBasePath)) {
if (
indexDocs &&
docsRouteBasePath.some((basePath) => urlMatchesPrefix(route, basePath))
) {
return { route, url, type: "docs" };
}
if (indexPages) {
Expand Down
16 changes: 12 additions & 4 deletions src/server/utils/processPluginOptions.spec.ts
Expand Up @@ -7,25 +7,33 @@ describe("processPluginOptions", () => {
test.each<[PluginOptions, Partial<ProcessedPluginOptions>]>([
[
{
docsRouteBasePath: "docs",
blogRouteBasePath: "/blog",
docsDir: "docs",
blogDir: "blog",
language: "en",
},
{
blogDir: "/tmp/blog",
docsDir: "/tmp/docs",
docsRouteBasePath: ["docs"],
blogRouteBasePath: ["blog"],
blogDir: ["/tmp/blog"],
docsDir: ["/tmp/docs"],
language: ["en"],
},
],
[
{
docsRouteBasePath: ["docs"],
blogRouteBasePath: ["/blog"],
docsDir: "docs",
blogDir: "blog",
language: ["en", "zh"],
},
{
blogDir: "/tmp/blog",
docsDir: "/tmp/docs",
docsRouteBasePath: ["docs"],
blogRouteBasePath: ["blog"],
blogDir: ["/tmp/blog"],
docsDir: ["/tmp/docs"],
language: ["en", "zh"],
},
],
Expand Down
24 changes: 19 additions & 5 deletions src/server/utils/processPluginOptions.ts
Expand Up @@ -6,10 +6,24 @@ export function processPluginOptions(
siteDir: string
): ProcessedPluginOptions {
const config = { ...options } as ProcessedPluginOptions;
config.docsDir = path.resolve(siteDir, config.docsDir);
config.blogDir = path.resolve(siteDir, config.blogDir);
if (!Array.isArray(config.language)) {
config.language = [config.language];
}
ensureArray(config, "docsRouteBasePath");
ensureArray(config, "blogRouteBasePath");
ensureArray(config, "language");
ensureArray(config, "docsDir");
ensureArray(config, "blogDir");
config.docsRouteBasePath = config.docsRouteBasePath.map((basePath) =>
basePath.replace(/^\//, "")
);
config.blogRouteBasePath = config.blogRouteBasePath.map((basePath) =>
basePath.replace(/^\//, "")
);
config.docsDir = config.docsDir.map((dir) => path.resolve(siteDir, dir));
config.blogDir = config.blogDir.map((dir) => path.resolve(siteDir, dir));
return config;
}

function ensureArray<T>(object: T, key: keyof T): void {
if (!Array.isArray(object[key])) {
(object as any)[key] = [object[key]];
}
}
64 changes: 53 additions & 11 deletions src/server/utils/validateOptions.spec.ts
Expand Up @@ -7,7 +7,9 @@ describe("validateOptions", () => {
schema: Joi.Schema,
options: PluginOptions | undefined
): Required<PluginOptions> {
const { error, value } = schema.validate(options);
const { error, value } = schema.validate(options, {
convert: false,
});
if (error) {
throw error;
}
Expand All @@ -18,10 +20,10 @@ describe("validateOptions", () => {
[
undefined,
{
blogRouteBasePath: "blog",
blogDir: "blog",
docsRouteBasePath: "docs",
docsDir: "docs",
blogRouteBasePath: ["blog"],
blogDir: ["blog"],
docsRouteBasePath: ["docs"],
docsDir: ["docs"],
hashed: false,
indexBlog: true,
indexDocs: true,
Expand All @@ -35,10 +37,10 @@ describe("validateOptions", () => {
[
{ language: ["en", "zh"] },
{
blogRouteBasePath: "blog",
blogDir: "blog",
docsRouteBasePath: "docs",
docsDir: "docs",
blogRouteBasePath: ["blog"],
blogDir: ["blog"],
docsRouteBasePath: ["docs"],
docsDir: ["docs"],
hashed: false,
indexBlog: true,
indexDocs: true,
Expand All @@ -58,9 +60,9 @@ describe("validateOptions", () => {
searchResultContextMaxLength: 30,
},
{
blogRouteBasePath: "blog",
blogRouteBasePath: ["blog"],
blogDir: "src/blog",
docsRouteBasePath: "docs",
docsRouteBasePath: ["docs"],
docsDir: "src/docs",
hashed: false,
indexBlog: true,
Expand All @@ -72,6 +74,46 @@ describe("validateOptions", () => {
searchResultContextMaxLength: 30,
},
],
[
{
docsRouteBasePath: "/dev/docs",
blogRouteBasePath: "/dev/blog",
},
{
blogRouteBasePath: "/dev/blog",
blogDir: ["blog"],
docsRouteBasePath: "/dev/docs",
docsDir: ["docs"],
hashed: false,
indexBlog: true,
indexDocs: true,
indexPages: false,
language: ["en"],
removeDefaultStopWordFilter: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
],
[
{
docsRouteBasePath: ["/dev/docs"],
blogRouteBasePath: ["/dev/blog"],
},
{
blogRouteBasePath: ["/dev/blog"],
blogDir: ["blog"],
docsRouteBasePath: ["/dev/docs"],
docsDir: ["docs"],
hashed: false,
indexBlog: true,
indexDocs: true,
indexPages: false,
language: ["en"],
removeDefaultStopWordFilter: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
],
])("validateOptions(...) should work", (options, config) => {
expect(validateOptions({ options, validate })).toEqual(config);
});
Expand Down
17 changes: 10 additions & 7 deletions src/server/utils/validateOptions.ts
Expand Up @@ -6,18 +6,21 @@ type ValidateFn = (
options: PluginOptions | undefined
) => Required<PluginOptions>;

const isStringOrArrayOfStrings = Joi.alternatives().try(
Joi.string(),
Joi.array().items(Joi.string())
);

const schema = Joi.object({
indexDocs: Joi.boolean().default(true),
indexBlog: Joi.boolean().default(true),
indexPages: Joi.boolean().default(false),
docsRouteBasePath: Joi.string().replace(/^\//, "").default("docs"),
blogRouteBasePath: Joi.string().replace(/^\//, "").default("blog"),
language: Joi.alternatives()
.try(Joi.string(), Joi.array().items(Joi.string()))
.default(["en"]),
docsRouteBasePath: isStringOrArrayOfStrings.default(["docs"]),
blogRouteBasePath: isStringOrArrayOfStrings.default(["blog"]),
language: isStringOrArrayOfStrings.default(["en"]),
hashed: Joi.boolean().default(false),
docsDir: Joi.string().default("docs"),
blogDir: Joi.string().default("blog"),
docsDir: isStringOrArrayOfStrings.default(["docs"]),
blogDir: isStringOrArrayOfStrings.default(["blog"]),
removeDefaultStopWordFilter: Joi.boolean().default(false),
searchResultLimits: Joi.number().default(8),
searchResultContextMaxLength: Joi.number().default(50),
Expand Down
21 changes: 16 additions & 5 deletions src/shared/interfaces.ts
Expand Up @@ -125,12 +125,12 @@ export interface PluginOptions {
indexDocs?: boolean;
indexBlog?: boolean;
indexPages?: boolean;
docsRouteBasePath?: string;
blogRouteBasePath?: string;
docsRouteBasePath?: string | string[];
blogRouteBasePath?: string | string[];
language?: string | string[];
hashed?: boolean;
docsDir?: string;
blogDir?: string;
docsDir?: string | string[];
blogDir?: string | string[];
removeDefaultStopWordFilter?: boolean;

searchResultLimits?: number;
Expand All @@ -151,9 +151,20 @@ export interface PluginOptions {
}

export type ProcessedPluginOptions = Required<
Omit<PluginOptions, "language">
Omit<
PluginOptions,
| "language"
| "docsRouteBasePath"
| "blogRouteBasePath"
| "docsDir"
| "blogDir"
>
> & {
docsRouteBasePath: string[];
blogRouteBasePath: string[];
language: string[];
docsDir: string[];
blogDir: string[];
};

export interface PostBuildData {
Expand Down

0 comments on commit d90f4ad

Please sign in to comment.