mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
Hide internal docs from docs site (#4357)
This commit is contained in:
1 parent
707f1bdb5f
commit
59c283670e
9 files changed
+195
-8
No files matched your search
+4
-2
@@ -17,13 +17,15 @@ npm install
|
||||
|
||||
### Setup Content
|
||||
|
||||
Link the documentation content from the parent `docs` directory:
|
||||
Prepare the public documentation content from the parent `docs` directory:
|
||||
|
||||
```bash
|
||||
npm run link
|
||||
```
|
||||
|
||||
This creates a symbolic link from `../docs` to `content` in the project.
|
||||
This creates a `content` directory with copies of the public docs sections.
|
||||
Internal planning, design, and E2E notes remain outside the docs site content
|
||||
tree.
|
||||
|
||||
### Development
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"link": "ln -s ../docs content",
|
||||
"link": "node scripts/link-public-docs.mjs",
|
||||
"clean": "rm -rf .next",
|
||||
"dev": "npm run clean && next --turbopack",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "vitest run --config vitest.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^16.0.8",
|
||||
@@ -18,5 +18,8 @@
|
||||
"nextra-theme-docs": "^4.6.1",
|
||||
"react": "^19.2.1",
|
||||
"react-dom": "^19.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { cp, mkdir, rm, symlink } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { PUBLIC_DOC_ROOTS } from '../src/app/public-docs.js';
|
||||
|
||||
const contentDir = 'content';
|
||||
|
||||
async function linkPublicDocs() {
|
||||
try {
|
||||
await rm(contentDir, { force: true, recursive: true });
|
||||
await mkdir(contentDir);
|
||||
await cp('../docs/index.md', join(contentDir, 'index.md'));
|
||||
await cp('../docs/_meta.ts', join(contentDir, '_meta.ts'));
|
||||
|
||||
for (const root of PUBLIC_DOC_ROOTS) {
|
||||
await symlink(join('..', '..', 'docs', root), join(contentDir, root));
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(
|
||||
`Failed to link public docs into ${contentDir}: ${message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await linkPublicDocs();
|
||||
@@ -1,10 +1,23 @@
|
||||
import { generateStaticParamsFor, importPage } from 'nextra/pages';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { useMDXComponents as getMDXComponents } from '../../../mdx-components';
|
||||
import { filterPublicStaticParams, isPublicDocsPath } from '../public-docs';
|
||||
|
||||
export const generateStaticParams = generateStaticParamsFor('mdxPath');
|
||||
const generateAllStaticParams = generateStaticParamsFor('mdxPath');
|
||||
|
||||
export const dynamicParams = false;
|
||||
|
||||
export async function generateStaticParams(...args) {
|
||||
const staticParams = await generateAllStaticParams(...args);
|
||||
return filterPublicStaticParams(staticParams);
|
||||
}
|
||||
|
||||
export async function generateMetadata(props) {
|
||||
const params = await props.params;
|
||||
if (!isPublicDocsPath(params.mdxPath)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const { metadata } = await importPage(params.mdxPath);
|
||||
return metadata;
|
||||
}
|
||||
@@ -13,6 +26,10 @@ const Wrapper = getMDXComponents().wrapper;
|
||||
|
||||
export default async function Page(props) {
|
||||
const params = await props.params;
|
||||
if (!isPublicDocsPath(params.mdxPath)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const {
|
||||
default: MDXContent,
|
||||
toc,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const generateAllStaticParams = vi.fn();
|
||||
|
||||
return {
|
||||
generateAllStaticParams,
|
||||
generateStaticParamsFor: vi.fn(() => generateAllStaticParams),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('nextra/pages', () => ({
|
||||
generateStaticParamsFor: mocks.generateStaticParamsFor,
|
||||
importPage: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('next/navigation', () => ({
|
||||
notFound: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../mdx-components', () => ({
|
||||
useMDXComponents: () => ({
|
||||
wrapper: ({ children }) => children,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('generateStaticParams', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('filters internal docs from Nextra static params', async () => {
|
||||
mocks.generateAllStaticParams.mockResolvedValue([
|
||||
{ mdxPath: [] },
|
||||
{ mdxPath: ['users', 'foo'] },
|
||||
{ mdxPath: ['en', 'users'] },
|
||||
{ mdxPath: ['design', 'bar'] },
|
||||
{ mdxPath: ['plans'] },
|
||||
]);
|
||||
|
||||
const { generateStaticParams } = await import('./page.jsx');
|
||||
|
||||
await expect(generateStaticParams()).resolves.toEqual([
|
||||
{ mdxPath: [] },
|
||||
{ mdxPath: ['users', 'foo'] },
|
||||
{ mdxPath: ['en', 'users'] },
|
||||
]);
|
||||
});
|
||||
|
||||
it('fails closed if Nextra changes the static params shape', async () => {
|
||||
mocks.generateAllStaticParams.mockResolvedValue([{ slug: ['users'] }]);
|
||||
|
||||
const { generateStaticParams } = await import('./page.jsx');
|
||||
|
||||
await expect(generateStaticParams()).rejects.toThrow(
|
||||
'Expected generateStaticParamsFor("mdxPath") to return objects with an mdxPath array.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
const LOCALE_SEGMENTS = new Set(['en', 'zh', 'de', 'fr', 'ja', 'ru', 'pt-BR']);
|
||||
|
||||
// Keep this in sync with the public top-level page entries in docs/_meta.ts.
|
||||
// docs-site/scripts/link-public-docs.mjs consumes the same allowlist.
|
||||
export const PUBLIC_DOC_ROOTS = ['users', 'developers'];
|
||||
|
||||
const PUBLIC_DOC_ROOT_SET = new Set(PUBLIC_DOC_ROOTS);
|
||||
|
||||
function publicRootFromSegments(segments = []) {
|
||||
if (segments.length === 0 || (segments.length === 1 && segments[0] === '')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const rootIndex = LOCALE_SEGMENTS.has(segments[0]) ? 1 : 0;
|
||||
return segments[rootIndex];
|
||||
}
|
||||
|
||||
export function isPublicDocsPath(mdxPath = []) {
|
||||
const root = publicRootFromSegments(mdxPath);
|
||||
return root === undefined || PUBLIC_DOC_ROOT_SET.has(root);
|
||||
}
|
||||
|
||||
export function filterPublicStaticParams(staticParams = []) {
|
||||
return staticParams.filter((staticParam) => {
|
||||
if (!Array.isArray(staticParam?.mdxPath)) {
|
||||
throw new TypeError(
|
||||
'Expected generateStaticParamsFor("mdxPath") to return objects with an mdxPath array.',
|
||||
);
|
||||
}
|
||||
|
||||
return isPublicDocsPath(staticParam.mdxPath);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { filterPublicStaticParams, isPublicDocsPath } from './public-docs.js';
|
||||
|
||||
describe('isPublicDocsPath', () => {
|
||||
it.each([
|
||||
[[], true],
|
||||
[[''], true],
|
||||
[['users', 'foo'], true],
|
||||
[['design', 'bar'], false],
|
||||
[['en', 'users'], true],
|
||||
[['plans'], false],
|
||||
[['en'], true],
|
||||
])('returns %s for %j', (mdxPath, expected) => {
|
||||
expect(isPublicDocsPath(mdxPath)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterPublicStaticParams', () => {
|
||||
it('keeps public paths and rejects internal docs paths', () => {
|
||||
expect(
|
||||
filterPublicStaticParams([
|
||||
{ mdxPath: [] },
|
||||
{ mdxPath: [''] },
|
||||
{ mdxPath: ['users', 'foo'] },
|
||||
{ mdxPath: ['en', 'developers'] },
|
||||
{ mdxPath: ['design', 'bar'] },
|
||||
{ mdxPath: ['plans'] },
|
||||
]),
|
||||
).toEqual([
|
||||
{ mdxPath: [] },
|
||||
{ mdxPath: [''] },
|
||||
{ mdxPath: ['users', 'foo'] },
|
||||
{ mdxPath: ['en', 'developers'] },
|
||||
]);
|
||||
});
|
||||
|
||||
it('fails closed if Nextra changes the static params shape', () => {
|
||||
expect(() => filterPublicStaticParams([{ slug: ['users'] }])).toThrow(
|
||||
'Expected generateStaticParamsFor("mdxPath") to return objects with an mdxPath array.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['src/**/*.test.{js,jsx}'],
|
||||
},
|
||||
});
|
||||
@@ -1,9 +1,6 @@
|
||||
export default {
|
||||
settings: 'Settings',
|
||||
auth: 'Authentication',
|
||||
memory: {
|
||||
display: 'hidden',
|
||||
},
|
||||
'qwen-ignore': 'Ignoring Files',
|
||||
'trusted-folders': 'Trusted Folders',
|
||||
themes: 'Themes',
|
||||
|
||||
Reference in new issue
Block a user