import fse from 'fs-extra';
import os from 'node:os';
import path from 'node:path';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { convertSphinx } from '../src/sdk/converters/sphinx.js';
import type { SdkReference } from '../src/sdk/types.js';
const indexPage = {
current_page_name: 'index',
title: 'Example SDK documentation',
body: 'Example SDK documentation
Welcome to the example SDK. It does things.
See the Widget docs and the docs site.
',
};
const widgetsPage = {
current_page_name: 'widgets',
title: 'widgets module',
body: 'widgets module
- class widgets.Widget(name)[source]
A widget.
- spin(speed=1)
Spins the widget.
',
};
const skippedPage = { current_page_name: 'genindex', title: 'Index', body: '
Index
' };
describe('convertSphinx', () => {
let dir: string;
let reference: SdkReference;
beforeAll(async () => {
dir = await fse.mkdtemp(path.join(os.tmpdir(), 'sphinx-test-'));
await fse.writeJson(path.join(dir, 'index.fjson'), indexPage);
await fse.writeJson(path.join(dir, 'widgets.fjson'), widgetsPage);
await fse.writeJson(path.join(dir, 'genindex.fjson'), skippedPage);
reference = await convertSphinx(dir);
});
afterAll(async () => {
await fse.remove(dir);
});
it('emits one page per content file with slugs from current_page_name', () => {
expect(reference.pages.map((page) => page.slug).sort()).toEqual(['index', 'widgets']);
});
it('groups guide pages and autodoc module pages separately', () => {
expect(reference.groups).toEqual([
{ group: 'Getting Started', pages: ['index'] },
{ group: 'API Reference', pages: ['widgets'] },
]);
});
it('tags autodoc pages as MODULE', () => {
const widgets = reference.pages.find((page) => page.slug === 'widgets');
expect(widgets?.tag).toBe('MODULE');
expect(reference.pages.find((page) => page.slug === 'index')?.tag).toBeUndefined();
});
it('converts signatures to python code blocks with headings', () => {
const content = reference.pages.find((page) => page.slug === 'widgets')?.content ?? '';
expect(content).toContain('### Widget');
expect(content).toContain('```python\nclass widgets.Widget(name)\n```');
expect(content).toContain('#### spin()');
expect(content).toContain('```python\nspin(speed=1)\n```');
});
it('strips headerlinks and viewcode links', () => {
for (const page of reference.pages) {
expect(page.content).not.toContain('');
expect(page.content).not.toContain('[source]');
expect(page.content).not.toContain('_modules');
}
});
it('rewrites internal links and keeps external ones', () => {
const index = reference.pages.find((page) => page.slug === 'index');
expect(index?.content).toContain('[Widget docs](/widgets)');
expect(index?.content).toContain('https://example.com/docs');
});
it('converts admonitions to callouts and extracts descriptions', () => {
const index = reference.pages.find((page) => page.slug === 'index');
expect(index?.content).toContain('');
expect(index?.content).toContain('Handle with care.');
expect(index?.description).toBe('Welcome to the example SDK.');
});
});