mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
Merge 131 upstream commits from fuma-nama/fumadocs dev branch, bringing framework packages to v16.6.17. All fumadocs-* and @fumadocs/* package references renamed to @hanzo/docs-* namespace. Upstream additions: - packages/content/ (@hanzo/docs-content) - Fuma Content adapter - packages/epub/ (@hanzo/docs-epub) - EPUB export support - MarkdownCopyButton, ViewOptionsPopover in docs page layout - Flexsearch, Orama search integration - Shiki v4 upgrade - Various UI framework improvements Hanzo customizations preserved: - apps/docs/content/ (all Hanzo service/project docs) - apps/docs/app/ (Hanzo homepage, AI chat, subdomain routing) - apps/docs/components/ (AI search, error boundaries, auth) - apps/docs/lib/ (source config, OpenAPI, metadata) - Webpack alias layer for upstream project doc imports - MdxErrorBoundary wrapper for graceful MDX failures
269 lines
6.7 KiB
TypeScript
269 lines
6.7 KiB
TypeScript
import { joinPath, splitPath } from '@/source/path';
|
|
import { describe, expect, test } from 'vitest';
|
|
import type { Root } from '@/page-tree/definitions';
|
|
import { findNeighbour, findSiblings } from '@/page-tree/utils';
|
|
import { getBreadcrumbItems } from '@/breadcrumb';
|
|
import { DefaultFormatter } from '@/i18n/middleware';
|
|
import { NextURL } from 'next/dist/server/web/next-url';
|
|
import { updateHref } from '@/dynamic-link';
|
|
|
|
test('Find Neighbours', () => {
|
|
const tree: Root = {
|
|
name: 'Docs',
|
|
children: [
|
|
{
|
|
type: 'folder',
|
|
name: 'Custom',
|
|
children: [{ type: 'page', name: 'hello', url: '/hello' }],
|
|
},
|
|
{ type: 'page', name: 'world', url: '/world' },
|
|
{ type: 'page', name: 'user', url: '/user' },
|
|
],
|
|
};
|
|
|
|
expect(findNeighbour(tree, '/hello')).toStrictEqual({
|
|
previous: undefined,
|
|
next: { type: 'page', name: 'world', url: '/world' },
|
|
});
|
|
|
|
expect(findNeighbour(tree, '/world')).toStrictEqual({
|
|
previous: { type: 'page', name: 'hello', url: '/hello' },
|
|
next: { type: 'page', name: 'user', url: '/user' },
|
|
});
|
|
|
|
expect(findNeighbour(tree, '/user')).toStrictEqual({
|
|
previous: { type: 'page', name: 'world', url: '/world' },
|
|
next: undefined,
|
|
});
|
|
});
|
|
|
|
describe('Path utilities', () => {
|
|
test('resolve paths', () => {
|
|
expect(joinPath('a', 'b')).toBe('a/b');
|
|
expect(joinPath('/a', '')).toBe('a');
|
|
expect(joinPath('a/', '/b')).toBe('a/b');
|
|
|
|
expect(joinPath('a/', '../b/c')).toBe('b/c');
|
|
expect(joinPath('a/', './b/c')).toBe('a/b/c');
|
|
});
|
|
|
|
test('split paths', () => {
|
|
expect(splitPath('a/b/c')).toEqual(['a', 'b', 'c']);
|
|
expect(splitPath('a//c')).toEqual(['a', 'c']);
|
|
expect(splitPath('/a/c')).toEqual(['a', 'c']);
|
|
});
|
|
});
|
|
|
|
test('Breadcrumbs', () => {
|
|
const tree: Root = {
|
|
name: 'Hello World',
|
|
children: [
|
|
{
|
|
type: 'page',
|
|
name: 'Introduction',
|
|
url: '/',
|
|
},
|
|
{
|
|
type: 'page',
|
|
name: 'Hello World',
|
|
url: '/docs',
|
|
},
|
|
{
|
|
type: 'page',
|
|
name: 'Hello World',
|
|
url: '/docs/test',
|
|
},
|
|
{
|
|
type: 'page',
|
|
name: 'Hanzo Docs',
|
|
url: '/docs/test2',
|
|
},
|
|
{
|
|
type: 'folder',
|
|
name: 'Hello World',
|
|
index: {
|
|
type: 'page',
|
|
name: 'World',
|
|
url: '/docs/folder',
|
|
},
|
|
children: [],
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(getBreadcrumbItems('/docs/folder', tree, { includePage: true })).toStrictEqual([
|
|
{ name: 'World', url: '/docs/folder' },
|
|
]);
|
|
|
|
expect(getBreadcrumbItems('/invalid', tree)).toMatchInlineSnapshot(`[]`);
|
|
|
|
const treeWithRoot: Root = {
|
|
name: 'Docs',
|
|
children: [
|
|
{
|
|
type: 'folder',
|
|
name: 'Docs',
|
|
root: true,
|
|
index: { type: 'page', name: 'Introduction', url: '/docs' },
|
|
children: [
|
|
{
|
|
type: 'folder',
|
|
name: 'Guides',
|
|
index: { type: 'page', name: 'Guides', url: '/docs/guides' },
|
|
children: [
|
|
{
|
|
type: 'page',
|
|
name: 'Getting Started',
|
|
url: '/docs/guides/getting-started',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
expect(
|
|
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
|
|
includeRoot: true,
|
|
includePage: true,
|
|
}),
|
|
).toStrictEqual([
|
|
{ name: 'Docs', url: '/docs' },
|
|
{ name: 'Guides', url: '/docs/guides' },
|
|
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
|
|
]);
|
|
|
|
expect(
|
|
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
|
|
includeRoot: false,
|
|
includePage: true,
|
|
}),
|
|
).toStrictEqual([
|
|
{ name: 'Guides', url: '/docs/guides' },
|
|
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
|
|
]);
|
|
|
|
expect(
|
|
getBreadcrumbItems('/docs/guides/getting-started', treeWithRoot, {
|
|
includeRoot: { url: '/custom-root' },
|
|
includePage: true,
|
|
}),
|
|
).toStrictEqual([
|
|
{ name: 'Docs', url: '/custom-root' },
|
|
{ name: 'Guides', url: '/docs/guides' },
|
|
{ name: 'Getting Started', url: '/docs/guides/getting-started' },
|
|
]);
|
|
});
|
|
|
|
test('I18n: Format URL', () => {
|
|
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai/en'))).toBe('en');
|
|
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai/en/test'))).toBe('en');
|
|
expect(DefaultFormatter.get(new NextURL('https://docs.hanzo.ai'))).toBeUndefined();
|
|
expect(
|
|
DefaultFormatter.get(
|
|
new NextURL('https://docs.hanzo.ai/docs', {
|
|
nextConfig: {
|
|
basePath: '/docs',
|
|
},
|
|
}),
|
|
),
|
|
).toBeUndefined();
|
|
expect(
|
|
DefaultFormatter.get(
|
|
new NextURL('https://docs.hanzo.ai/docs/en/test', {
|
|
nextConfig: {
|
|
basePath: '/docs',
|
|
},
|
|
}),
|
|
),
|
|
).toBe('en');
|
|
|
|
expect(DefaultFormatter.add(new NextURL('https://docs.hanzo.ai'), 'cn').href).toBe(
|
|
'https://docs.hanzo.ai/cn/',
|
|
);
|
|
expect(
|
|
DefaultFormatter.add(
|
|
new NextURL('https://docs.hanzo.ai/docs', {
|
|
nextConfig: {
|
|
basePath: '/docs',
|
|
},
|
|
}),
|
|
'cn',
|
|
).href,
|
|
).toBe('https://docs.hanzo.ai/docs/cn/');
|
|
|
|
expect(DefaultFormatter.remove(new NextURL('https://docs.hanzo.ai/en')).href).toBe(
|
|
'https://docs.hanzo.ai/',
|
|
);
|
|
expect(DefaultFormatter.remove(new NextURL('https://docs.hanzo.ai/en/test/hello')).href).toBe(
|
|
'https://docs.hanzo.ai/test/hello',
|
|
);
|
|
expect(
|
|
DefaultFormatter.remove(
|
|
new NextURL('https://docs.hanzo.ai/docs/en', {
|
|
nextConfig: {
|
|
basePath: '/docs',
|
|
},
|
|
}),
|
|
).href,
|
|
).toBe('https://docs.hanzo.ai/docs/');
|
|
});
|
|
|
|
const tree: Root = {
|
|
name: 'docs',
|
|
children: [
|
|
{
|
|
type: 'folder',
|
|
name: 'test',
|
|
index: {
|
|
type: 'page',
|
|
name: 'Page 1',
|
|
url: '/page-1',
|
|
},
|
|
children: [
|
|
{
|
|
type: 'page',
|
|
name: 'Page 2',
|
|
url: '/page-2',
|
|
},
|
|
{
|
|
type: 'page',
|
|
name: 'Page 3',
|
|
url: '/page-3',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'page',
|
|
name: 'Page 4',
|
|
url: '/page-4',
|
|
},
|
|
],
|
|
};
|
|
|
|
test('findSiblings', () => {
|
|
expect(findSiblings(tree, '/page-1')).toMatchInlineSnapshot(`
|
|
[
|
|
{
|
|
"name": "Page 2",
|
|
"type": "page",
|
|
"url": "/page-2",
|
|
},
|
|
{
|
|
"name": "Page 3",
|
|
"type": "page",
|
|
"url": "/page-3",
|
|
},
|
|
]
|
|
`);
|
|
});
|
|
|
|
test('Dynamic Link: update href', () => {
|
|
expect(updateHref('/[lang]/test', {})).toBe('/test');
|
|
expect(updateHref('/[lang]/test', { lang: 'en' })).toBe('/en/test');
|
|
expect(updateHref('/[lang]/test', { lang: ['en', 'cn'] })).toBe('/en/cn/test');
|
|
|
|
// relative -> relative
|
|
expect(updateHref('[lang]/test', {})).toBe('test');
|
|
});
|