import fse from 'fs-extra';
import os from 'node:os';
import path from 'node:path';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { convertPhpdoc } from '../src/sdk/converters/phpdoc.js';
import type { SdkReference } from '../src/sdk/types.js';
const STRUCTURE_XML = `
Greeter
\\Acme\\SDK\\Widget\\Greeter
Greets people politely.
Supports optional shouting.
\\Acme\\SDK\\Contract\\GreeterInterface
salutation
'Hello'
secret
greet
\\Acme\\SDK\\Widget\\Greeter::greet()
name
string
shout
false
?bool
Greet a person by name.
hidden
\\Acme\\SDK\\Widget\\Greeter::hidden()
`;
describe('convertPhpdoc', () => {
let dir: string;
let reference: SdkReference;
beforeAll(async () => {
dir = await fse.mkdtemp(path.join(os.tmpdir(), 'phpdoc-test-'));
await fse.writeFile(path.join(dir, 'structure.xml'), STRUCTURE_XML);
reference = await convertPhpdoc(dir);
});
afterAll(async () => {
await fse.remove(dir);
});
it('creates one page per class with a namespace-derived slug', () => {
expect(reference.pages).toHaveLength(1);
const page = reference.pages[0]!;
expect(page.slug).toBe('greeter');
expect(page.title).toBe('Greeter');
expect(page.tag).toBe('CLASS');
expect(page.description).toBe('Greets people politely.');
});
it('groups pages by namespace', () => {
expect(reference.groups).toEqual([{ group: 'Acme\\SDK\\Widget', pages: ['greeter'] }]);
});
it('reconstructs the method signature', () => {
const content = reference.pages[0]!.content;
expect(content).toContain(
'```php\npublic function greet(string $name, ?bool $shout = false): string\n```'
);
});
it('renders class heritage and sections', () => {
const content = reference.pages[0]!.content;
expect(content).toContain(
'```php\nfinal class Greeter implements \\Acme\\SDK\\Contract\\GreeterInterface\n```'
);
expect(content).toContain('## Properties');
expect(content).toContain('## Methods');
expect(content).toContain('### greet()');
expect(content).toContain('#### Returns');
expect(content).toContain('#### Throws');
});
it('emits ResponseField entries for properties and parameters', () => {
const content = reference.pages[0]!.content;
expect(content).toContain(
'\n The salutation to use.\n\n Default: `\'Hello\'`\n'
);
expect(content).toContain(
'\n Name of the person.\n'
);
expect(content).toContain(
'\n Whether to shout.\n'
);
});
it('excludes private members', () => {
const content = reference.pages[0]!.content;
expect(content).not.toContain('secret');
expect(content).not.toContain('hidden');
});
it('accepts the structure.xml file path directly', async () => {
const direct = await convertPhpdoc(path.join(dir, 'structure.xml'));
expect(direct.pages[0]?.slug).toBe('greeter');
});
});