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

144 lines
4.3 KiB
TypeScript

/**
* 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 logger from '@docusaurus/logger';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
import {
getVersionsFilePath,
getVersionDocsDirPath,
getVersionSidebarsPath,
getDocsDirPathLocalized,
readVersionsFile,
} from './versions/files';
import {validateVersionName} from './versions/validation';
import {loadSidebarsFileUnsafe} from './sidebars';
import {CURRENT_VERSION_NAME} from './constants';
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
import type {LoadContext} from '@docusaurus/types';
async 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).
// Note: we don't need the sidebars file to be normalized: it's ok to let
// plugin option changes to impact older, versioned sidebars
// We don't validate here, assuming the user has already built the version
const sidebars = await loadSidebarsFileUnsafe(sidebarPath);
// Do not create a useless versioned sidebars file if sidebars file is empty
// or sidebars are disabled/false)
const shouldCreateVersionedSidebarFile = Object.keys(sidebars).length > 0;
if (shouldCreateVersionedSidebarFile) {
await fs.outputFile(
getVersionSidebarsPath(siteDir, pluginId, version),
`${JSON.stringify(sidebars, null, 2)}\n`,
'utf8',
);
}
}
// Tests depend on non-default export for mocking.
export async function cliDocsVersionCommand(
version: unknown,
{id: pluginId, path: docsPath, sidebarPath}: PluginOptions,
{siteDir, i18n}: LoadContext,
): Promise<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}]`;
try {
validateVersionName(version);
} catch (err) {
logger.info`${pluginIdLogPrefix}: Invalid version name provided. Try something like: 1.0.0`;
throw err;
}
const versions = (await readVersionsFile(siteDir, pluginId)) ?? [];
// 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.`,
);
}
if (i18n.locales.length > 1) {
logger.info`Versioned docs will be created for the following locales: name=${i18n.locales}`;
}
await Promise.all(
i18n.locales.map(async (locale) => {
const localizationDir = path.resolve(
siteDir,
i18n.path,
i18n.localeConfigs[locale]!.path,
);
// Copy docs files.
const docsDir =
locale === i18n.defaultLocale
? path.resolve(siteDir, docsPath)
: getDocsDirPathLocalized({
localizationDir,
pluginId,
versionName: CURRENT_VERSION_NAME,
});
if (
!(await fs.pathExists(docsDir)) ||
(await fs.readdir(docsDir)).length === 0
) {
if (locale === i18n.defaultLocale) {
throw new Error(
logger.interpolate`${pluginIdLogPrefix}: no docs found in path=${docsDir}.`,
);
} else {
logger.warn`${pluginIdLogPrefix}: no docs found in path=${docsDir}. Skipping.`;
return;
}
}
const newVersionDir =
locale === i18n.defaultLocale
? getVersionDocsDirPath(siteDir, pluginId, version)
: getDocsDirPathLocalized({
localizationDir,
pluginId,
versionName: version,
});
await fs.copy(docsDir, newVersionDir);
}),
);
await createVersionedSidebarFile({
siteDir,
pluginId,
version,
sidebarPath,
});
// Update versions.json file.
versions.unshift(version);
await fs.outputFile(
getVersionsFilePath(siteDir, pluginId),
`${JSON.stringify(versions, null, 2)}\n`,
);
logger.success`name=${pluginIdLogPrefix}: version name=${version} created!`;
}