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'); }); });