Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AI_PR_NOTICE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I am a sad, dumb little AI driver with no real skills.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* 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 {describe, expect, it, vi} from 'vitest';
import fs from 'fs-extra';
import path from 'path';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
import cliDocs from '../cli';
import {getVersionDocsDirPath, getVersionSidebarsPath} from '../versions/files';
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
import type {LoadContext} from '@docusaurus/types';

const {cliDocsVersionCommand} = cliDocs;
const fixtureDir = path.join(__dirname, '__fixtures__');
const simpleSiteDir = path.join(fixtureDir, 'simple-site');

describe('versionedDocsPath', () => {
it('writes versioned docs and sidebars under the configured path', async () => {
let versionedDocsDir!: string;
let versionedSidebarPath!: string;

using copyMock = vi.spyOn(fs, 'copy').mockImplementation((_, dest) => {
versionedDocsDir = dest as string;
});
using writeMock = vi.spyOn(fs, 'outputFile');
writeMock.mockImplementationOnce((filepath) => {
versionedSidebarPath = filepath;
});
writeMock.mockImplementationOnce(() => {});

const versionedDocsPath = '../external-versions';
const options = {
id: DEFAULT_PLUGIN_ID,
path: 'docs',
sidebarPath: path.join(simpleSiteDir, 'sidebars.json'),
versionedDocsPath,
} as PluginOptions;

await cliDocsVersionCommand('1.0.0', options, {
siteDir: simpleSiteDir,
i18n: {
locales: ['en'],
defaultLocale: 'en',
currentLocale: 'en',
path: 'i18n',
localeConfigs: {
en: {path: 'en', translate: true},
},
},
} as unknown as LoadContext);

expect(copyMock).toHaveBeenCalledWith(
path.join(simpleSiteDir, options.path),
expect.stringContaining('external-versions'),
);
expect(versionedDocsDir).toEqual(
getVersionDocsDirPath(
simpleSiteDir,
DEFAULT_PLUGIN_ID,
'1.0.0',
versionedDocsPath,
),
);
expect(versionedSidebarPath).toEqual(
getVersionSidebarsPath(
simpleSiteDir,
DEFAULT_PLUGIN_ID,
'1.0.0',
versionedDocsPath,
),
);
});
});
9 changes: 6 additions & 3 deletions packages/docusaurus-plugin-content-docs/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ async function createVersionedSidebarFile({
pluginId,
sidebarPath,
version,
versionedDocsPath,
}: {
siteDir: string;
pluginId: string;
sidebarPath: string | false | undefined;
version: string;
versionedDocsPath: string | undefined;
}) {
// 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
Expand All @@ -46,7 +48,7 @@ async function createVersionedSidebarFile({

if (shouldCreateVersionedSidebarFile) {
await fs.outputFile(
getVersionSidebarsPath(siteDir, pluginId, version),
getVersionSidebarsPath(siteDir, pluginId, version, versionedDocsPath),
`${JSON.stringify(sidebars, null, 2)}\n`,
'utf8',
);
Expand All @@ -56,7 +58,7 @@ async function createVersionedSidebarFile({
// Tests depend on non-default export for mocking.
async function cliDocsVersionCommand(
version: unknown,
{id: pluginId, path: docsPath, sidebarPath}: PluginOptions,
{id: pluginId, path: docsPath, sidebarPath, versionedDocsPath}: PluginOptions,
{siteDir, i18n}: LoadContext,
): Promise<void> {
// It wouldn't be very user-friendly to show a [default] log prefix,
Expand Down Expand Up @@ -117,7 +119,7 @@ async function cliDocsVersionCommand(

const newVersionDir =
locale === i18n.defaultLocale
? getVersionDocsDirPath(siteDir, pluginId, version)
? getVersionDocsDirPath(siteDir, pluginId, version, versionedDocsPath)
: getDocsDirPathLocalized({
localizationDir,
pluginId,
Expand Down Expand Up @@ -149,6 +151,7 @@ async function cliDocsVersionCommand(
pluginId,
version,
sidebarPath,
versionedDocsPath,
});

// Update versions.json file.
Expand Down
2 changes: 2 additions & 0 deletions packages/docusaurus-plugin-content-docs/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {PluginOptions, Options} from '@docusaurus/plugin-content-docs';

export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'> = {
path: 'docs', // Path to data on filesystem, relative to site dir.
versionedDocsPath: undefined, // Path to versioned docs root, relative to site dir.
routeBasePath: 'docs', // URL Route.
tagsBasePath: 'tags', // URL Tags Route.
include: ['**/*.{md,mdx}'], // Extensions to include.
Expand Down Expand Up @@ -75,6 +76,7 @@ const VersionsOptionsSchema = Joi.object()

const OptionsSchema = Joi.object<PluginOptions>({
path: Joi.string().default(DEFAULT_OPTIONS.path),
versionedDocsPath: Joi.string(),
editUrl: Joi.alternatives().try(URISchema, Joi.function()),
editCurrentVersion: Joi.boolean().default(DEFAULT_OPTIONS.editCurrentVersion),
editLocalizedFiles: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedFiles),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ declare module '@docusaurus/plugin-content-docs' {
* directory.
*/
path: string;
/**
* Path to the directory where versioned docs and sidebars are stored,
* relative to the site directory. This is where `docusaurus docs:version`
* writes version snapshots. Defaults to the site directory.
*/
versionedDocsPath?: string;
/**
* Path to sidebar configuration. Use `false` to disable sidebars, or
* `undefined` to create a fully autogenerated sidebar.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* 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 {describe, expect, it} from 'vitest';
import path from 'path';
import {
getVersionDocsDirPath,
getVersionSidebarsPath,
getVersionedContentRoot,
} from '../files';

describe('versioned docs path helpers', () => {
const siteDir = path.join(__dirname, 'site');

it('getVersionedContentRoot defaults to siteDir', () => {
expect(getVersionedContentRoot(siteDir, undefined)).toBe(siteDir);
});

it('getVersionedContentRoot resolves relative path from siteDir', () => {
expect(getVersionedContentRoot(siteDir, '../my-versions')).toBe(
path.resolve(siteDir, '../my-versions'),
);
});

it('getVersionDocsDirPath uses versionedDocsPath when provided', () => {
expect(
getVersionDocsDirPath(siteDir, 'default', '1.0.0', '../my-versions'),
).toBe(
path.join(
path.resolve(siteDir, '../my-versions'),
'versioned_docs',
'version-1.0.0',
),
);
});

it('getVersionDocsDirPath prefixes non-default plugin id', () => {
expect(
getVersionDocsDirPath(siteDir, 'community', '2.0.0', './versions'),
).toBe(
path.join(
path.resolve(siteDir, './versions'),
'community_versioned_docs',
'version-2.0.0',
),
);
});

it('getVersionSidebarsPath uses versionedDocsPath when provided', () => {
expect(
getVersionSidebarsPath(siteDir, 'default', '1.0.0', '../my-versions'),
).toBe(
path.join(
path.resolve(siteDir, '../my-versions'),
'versioned_sidebars',
'version-1.0.0-sidebars.json',
),
);
});
});
34 changes: 28 additions & 6 deletions packages/docusaurus-plugin-content-docs/src/versions/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,39 @@ function addPluginIdPrefix(fileOrDir: string, pluginId: string): string {
: `${pluginId}_${fileOrDir}`;
}

/** `[siteDir]/community_versioned_docs/version-1.0.0` */
/**
* Root directory for versioned docs/sidebars folders. Defaults to `siteDir`.
*/
export function getVersionedContentRoot(
siteDir: string,
versionedDocsPath: string | undefined,
): string {
return versionedDocsPath ? path.resolve(siteDir, versionedDocsPath) : siteDir;
}

/** `[versionedContentRoot]/community_versioned_docs/version-1.0.0` */
export function getVersionDocsDirPath(
siteDir: string,
pluginId: string,
versionName: string,
versionedDocsPath?: string,
): string {
return path.join(
siteDir,
getVersionedContentRoot(siteDir, versionedDocsPath),
addPluginIdPrefix(VERSIONED_DOCS_DIR, pluginId),
`version-${versionName}`,
);
}

/** `[siteDir]/community_versioned_sidebars/version-1.0.0-sidebars.json` */
/** Path to a versioned sidebars file. */
export function getVersionSidebarsPath(
siteDir: string,
pluginId: string,
versionName: string,
versionedDocsPath?: string,
): string {
return path.join(
siteDir,
getVersionedContentRoot(siteDir, versionedDocsPath),
addPluginIdPrefix(VERSIONED_SIDEBARS_DIR, pluginId),
`version-${versionName}-sidebars.json`,
);
Expand Down Expand Up @@ -202,10 +214,20 @@ export async function getVersionMetadataPaths({

const contentPath = isCurrent
? path.resolve(context.siteDir, options.path)
: getVersionDocsDirPath(context.siteDir, options.id, versionName);
: getVersionDocsDirPath(
context.siteDir,
options.id,
versionName,
options.versionedDocsPath,
);
const sidebarFilePath = isCurrent
? options.sidebarPath
: getVersionSidebarsPath(context.siteDir, options.id, versionName);
: getVersionSidebarsPath(
context.siteDir,
options.id,
versionName,
options.versionedDocsPath,
);

if (!(await fs.pathExists(contentPath))) {
throw new Error(
Expand Down
1 change: 1 addition & 0 deletions website/docs/api/plugins/plugin-content-docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Accepted fields:
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `path` | `string` | `'docs'` | Path to the docs content directory on the file system, relative to site directory. |
| `versionedDocsPath` | `string` | `undefined` | Path to the directory where versioned docs and sidebars are stored, relative to the site directory. This is where the `docusaurus docs:version` command writes version snapshots. Defaults to the site directory. |
| `editUrl` | <code>string \| [EditUrlFunction](#EditUrlFunction)</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. |
| `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. |
| `editCurrentVersion` | `boolean` | `false` | The edit URL will always target the current version doc instead of older versions. Ignored when `editUrl` is a function. |
Expand Down
2 changes: 2 additions & 0 deletions website/docs/guides/docs/versioning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ When tagging a new version, the document versioning mechanism will:
- Create a versioned sidebars file based from your current [sidebar](./sidebar/index.mdx) configuration (if it exists) - saved as `versioned_sidebars/version-[versionName]-sidebars.json`.
- Append the new version number to `versions.json`.

If you configure the docs plugin [`versionedDocsPath`](../../api/plugins/plugin-content-docs.mdx#configuration) option, Docusaurus creates the `versioned_docs` and `versioned_sidebars` folders under that custom directory instead of the site directory.

### Creating new docs {/* #creating-new-docs */}

1. Place the new file into the corresponding version folder.
Expand Down