docusaurus/packages/docusaurus-plugin-content-docs/src/cli.ts

165 lines
5.1 KiB
TypeScript
Raw Normal View History

/**
* 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 {
getVersionsFilePath,
getVersionedDocsDirPath,
getVersionedSidebarsDirPath,
} from './versions';
import fs from 'fs-extra';
import path from 'path';
feat(v2): auto-generated sidebars, frontmatter-less sites (#4582) * POC of autogenerated sidebars * use combine-promises utility lib * autogenerated sidebar poc working * Revert "autogenerated sidebar poc working" This reverts commit c81da980 * POC of auto-generated sidebars for community docs * update tests * add initial test suite for autogenerated sidebars + fix some edge cases * Improve autogen sidebars: strip more number prefixes in folder breadcrumb + slugs * fix typo! * Add tests for partially generated sidebars + fix edge cases + extract sidebar generation code * Ability to read category metadatas file from a file in the category * fix tests * change position of API * ability to extract number prefix * stable system to enable position frontmatter * fix tests for autogen sidebar position * renamings * restore community sidebars * rename frontmatter position -> sidebar_position * make sidebarItemsGenerator fn configurable * minor changes * rename dirPath => dirName * Make the init template use autogenerated sidebars * fix options * fix docusaurus site: remove test docs * add _category_ file to docs pathsToWatch * add _category_ file to docs pathsToWatch * tutorial: use sidebar_position instead of file number prefixes * Adapt Docusaurus tutorial for autogenerated sidebars * remove slug: / * polish the homepage template * rename _category_ sidebar_position to just "position" * test for custom sidebarItemsGenerator fn * fix category metadata + add link to report tutorial issues * fix absolute path breaking tests * fix absolute path breaking tests * Add test for floating number sidebar_position * add sidebarItemsGenerator unit tests * add processSidebars unit tests * Fix init template broken links * windows test * increase code translations test timeout * cleanup mockCategoryMetadataFiles after windows test fixed * update init template positions * fix windows tests * fix comment * Add autogenerated sidebar items documentation + rewrite the full sidebars page doc * add useful comment * fix code block title
2021-04-15 10:20:11 -04:00
import {
PathOptions,
UnprocessedSidebarItem,
UnprocessedSidebars,
} from './types';
import {loadSidebars} from './sidebars';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
function createVersionedSidebarFile({
siteDir,
pluginId,
sidebarPath,
version,
}: {
siteDir: string;
pluginId: string;
sidebarPath: string | false | undefined;
version: string;
}) {
// Load current sidebar and create a new versioned sidebars file (if needed).
const loadedSidebars = loadSidebars(sidebarPath);
// Do not create a useless versioned sidebars file if sidebars file is empty or sidebars are disabled/false)
const shouldCreateVersionedSidebarFile =
Object.keys(loadedSidebars).length > 0;
if (shouldCreateVersionedSidebarFile) {
// TODO @slorber: this "version prefix" in versioned sidebars looks like a bad idea to me
// TODO try to get rid of it
// Transform id in original sidebar to versioned id.
const normalizeItem = (
item: UnprocessedSidebarItem,
): UnprocessedSidebarItem => {
switch (item.type) {
case 'category':
return {...item, items: item.items.map(normalizeItem)};
case 'ref':
case 'doc':
return {
type: item.type,
id: `version-${version}/${item.id}`,
};
default:
return item;
}
};
const versionedSidebar: UnprocessedSidebars = Object.entries(
loadedSidebars,
).reduce((acc: UnprocessedSidebars, [sidebarId, sidebarItems]) => {
const newVersionedSidebarId = `version-${version}/${sidebarId}`;
acc[newVersionedSidebarId] = sidebarItems.map(normalizeItem);
return acc;
}, {});
const versionedSidebarsDir = getVersionedSidebarsDirPath(siteDir, pluginId);
const newSidebarFile = path.join(
versionedSidebarsDir,
`version-${version}-sidebars.json`,
);
fs.ensureDirSync(path.dirname(newSidebarFile));
fs.writeFileSync(
newSidebarFile,
`${JSON.stringify(versionedSidebar, null, 2)}\n`,
'utf8',
);
}
}
// Tests depend on non-default export for mocking.
// eslint-disable-next-line import/prefer-default-export
export function cliDocsVersionCommand(
version: string | null | undefined,
siteDir: string,
pluginId: string,
options: PathOptions,
): void {
// It wouldn't be very user-friendly to show a [default] log prefix,
// so we use [docs] instead of [default]
const pluginIdLogPrefix =
pluginId === DEFAULT_PLUGIN_ID ? '[docs] ' : `[${pluginId}] `;
if (!version) {
throw new Error(
`${pluginIdLogPrefix}No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0`,
);
}
if (version.includes('/') || version.includes('\\')) {
throw new Error(
`${pluginIdLogPrefix}Invalid version tag specified! Do not include slash (/) or (\\). Try something like: 1.0.0`,
);
}
if (version.length > 32) {
throw new Error(
`${pluginIdLogPrefix}Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0`,
);
}
// Since we are going to create `version-${version}` folder, we need to make
// sure it's a valid pathname.
// eslint-disable-next-line no-control-regex
if (/[<>:"|?*\x00-\x1F]/g.test(version)) {
throw new Error(
`${pluginIdLogPrefix}Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0`,
);
}
if (/^\.\.?$/.test(version)) {
throw new Error(
`${pluginIdLogPrefix}Invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0`,
);
}
// Load existing versions.
let versions = [];
const versionsJSONFile = getVersionsFilePath(siteDir, pluginId);
if (fs.existsSync(versionsJSONFile)) {
versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8'));
}
// Check if version already exists.
if (versions.includes(version)) {
throw new Error(
`${pluginIdLogPrefix}This version already exists!. Use a version tag that does not already exist.`,
);
}
const {path: docsPath, sidebarPath} = options;
// Copy docs files.
const docsDir = path.join(siteDir, docsPath);
if (fs.existsSync(docsDir) && fs.readdirSync(docsDir).length > 0) {
const versionedDir = getVersionedDocsDirPath(siteDir, pluginId);
const newVersionDir = path.join(versionedDir, `version-${version}`);
fs.copySync(docsDir, newVersionDir);
} else {
throw new Error(`${pluginIdLogPrefix}There is no docs to version !`);
}
createVersionedSidebarFile({siteDir, pluginId, version, sidebarPath});
// Update versions.json file.
versions.unshift(version);
fs.ensureDirSync(path.dirname(versionsJSONFile));
fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
console.log(`${pluginIdLogPrefix}Version ${version} created!`);
}