async function migrateVersionedSidebar()

in packages/docusaurus-migrate/src/index.ts [522:638]


async function migrateVersionedSidebar(
  context: MigrationContext,
  versions: string[],
  versionRegex: RegExp,
) {
  const {siteDir, newDir} = context;
  if (await fs.pathExists(path.join(siteDir, 'versioned_sidebars'))) {
    await fs.mkdirp(path.join(newDir, 'versioned_sidebars'));
    const sidebars: {
      entries: SidebarEntries;
      version: string;
    }[] = [];
    // Order matters: if a sidebar file doesn't exist, we have to use the
    // previous version's
    for (let i = 0; i < versions.length; i += 1) {
      const version = versions[i]!;
      let sidebarEntries: SidebarEntries;
      const sidebarPath = path.join(
        siteDir,
        'versioned_sidebars',
        `version-${version}-sidebars.json`,
      );
      try {
        sidebarEntries = JSON.parse(await fs.readFile(sidebarPath, 'utf-8'));
      } catch {
        sidebars.push({version, entries: sidebars[i - 1]!.entries});
        return;
      }
      const newSidebar = Object.entries(sidebarEntries).reduce(
        (topLevel: SidebarEntries, value) => {
          const key = value[0].replace(versionRegex, '');
          topLevel[key] = Object.entries(value[1]).reduce((acc, val) => {
            acc[val[0].replace(versionRegex, '')] = (
              val[1] as SidebarEntry[]
            ).map((item) => {
              if (typeof item === 'string') {
                return item.replace(versionRegex, '');
              }
              return {
                type: 'category',
                label: item.label,
                ids: item.ids.map((id) => id.replace(versionRegex, '')),
              };
            });
            return acc;
          }, {} as {[key: string]: Array<string | {[key: string]: unknown}>});
          return topLevel;
        },
        {},
      );
      sidebars.push({version, entries: newSidebar});
    }
    await Promise.all(
      sidebars.map(async (sidebar) => {
        const newSidebar = Object.entries(sidebar.entries).reduce(
          (acc, val) => {
            const key = `version-${sidebar.version}/${val[0]}`;
            acc[key] = Object.entries(val[1]).map((value) => ({
              type: 'category',
              label: value[0],
              items: (value[1] as SidebarEntry[]).map((sidebarItem) => {
                if (typeof sidebarItem === 'string') {
                  return {
                    type: 'doc',
                    id: `version-${sidebar.version}/${sidebarItem}`,
                  };
                }
                return {
                  type: 'category',
                  label: sidebarItem.label,
                  items: sidebarItem.ids.map((id) => ({
                    type: 'doc',
                    id: `version-${sidebar.version}/${id}`,
                  })),
                };
              }),
            }));
            return acc;
          },
          {} as SidebarEntries,
        );
        await fs.outputFile(
          path.join(
            newDir,
            'versioned_sidebars',
            `version-${sidebar.version}-sidebars.json`,
          ),
          JSON.stringify(newSidebar, null, 2),
        );
      }),
    );
    context.v2Config.themeConfig.navbar.items.push({
      label: 'Version',
      to: 'docs',
      position: 'right',
      items: [
        {
          label: versions[versions.length - 1],
          to: 'docs/',
          activeBaseRegex: `docs/(?!${versions.join('|')}|next)`,
        },
        ...versions
          .reverse()
          .slice(1)
          .map((version) => ({
            label: version,
            to: `docs/${version}/`,
          })),
        {
          label: 'Main/Unreleased',
          to: `docs/next/`,
          activeBaseRegex: `docs/next/(?!support|team|resources)`,
        },
      ],
    });
  }
}