Skip to content

Add PHP converter with lossless round-trip support#18

Merged
MelbourneDeveloper merged 2 commits into
mainfrom
php_fixed
Apr 19, 2026
Merged

Add PHP converter with lossless round-trip support#18
MelbourneDeveloper merged 2 commits into
mainfrom
php_fixed

Conversation

@MelbourneDeveloper
Copy link
Copy Markdown
Collaborator

TLDR

Adds a PHP DTO ↔ typeDiagram converter (8th language) that losslessly round-trips the canonical HOME_PAGE_SAMPLE, and wires PHP into the web converter playground.

Details

New

  • packages/typediagram/src/converters/php.ts — 564-line converter emitting final readonly class DTOs with constructor-promoted public params, declare(strict_types=1), PHPStan @template / @param list<...> / @param array<K,V> / |null docblocks, and sealed interface + implementing classes with @var 'Kind' tags for tagged unions. Parser supports nested generics, Option unwrapping, @typediagram-kind alias wrappers, and scan-state tracking for //, /* */, and string literals inside class bodies.
  • packages/typediagram/test/converters/php.test.ts — 12 tests across four describe blocks: [CONV-PHP-TO-COMPLEX], [CONV-PHP-FROM], [CONV-PHP-RT], and [CONV-PHP-EDGE].
  • PHP tab in the web playground — added to the LANGUAGES list, LANG_LABELS, highlight rules (PHP_RULES covering class/interface keywords, ?type nullables, $vars, PHPDoc), and both convertSource / convertFromTd converter maps.

Changed

  • converters/index.ts exports php.
  • Language union in converters/types.ts gains "php".
  • Web SupportedLang aligned across converter.ts, converter-render.ts, and converter-highlight.ts.

Known lossless limitation

Option<Unit> is NOT round-trippable because both Unit and Option<Unit> collapse to PHP null native type with no docblock — the nullability is indistinguishable on parse. HOME_PAGE_SAMPLE does not use Option<Unit>, so the byte-for-byte round-trip test still holds. Documented inline in the edge-case test.

How Do The Automated Tests Prove It Works?

  • [CONV-PHP-RT] losslessly round-trips the home-page example through PHP (TD text preserved) — the canonical expectLosslessRoundTrip(php) assertion (identical pattern to the other 7 converters) confirms TD → PHP → TD is byte-for-byte identical, including field order (which required removing the sortFields Option-reordering hack in the emitter).
  • [CONV-PHP-TO-COMPLEX] asserts specific emitted strings: final readonly class, @template T, public ?string $label, @param list<string>, @param array<string, int>, interface Shape, @var 'Circle', @implements Result<T>, @typediagram-kind alias.
  • [CONV-PHP-FROM] covers alias-only parsing and the NO_SUPPORTED_DEFINITIONS error path.
  • [CONV-PHP-EDGE] covers empty constructors, Option<List<Int>> / Option<Map<String,Int>> emission and parse, private-promoted params being skipped, inline // / /* */ / string-literal tolerance, and $kind mismatch handling.
  • Full suite: make ci green — 318 tests pass, bundle 74.55 KB within 75 KB budget, coverage 95.17% lines / 91.2% branches (above 95 / 90.89 thresholds); php.ts specifically at 96.2% / 92.16%.

Co-authored with @voku (original PHP converter work from the php branch).

🤖 Generated with Claude Code

MelbourneDeveloper and others added 2 commits April 19, 2026 17:01
Co-Authored-By: voku <voku@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@MelbourneDeveloper MelbourneDeveloper merged commit f5ed54b into main Apr 19, 2026
2 checks passed
@MelbourneDeveloper MelbourneDeveloper deleted the php_fixed branch April 19, 2026 07:14
MelbourneDeveloper added a commit that referenced this pull request Apr 19, 2026
## TLDR

Adds a PHP DTO ↔ typeDiagram converter (8th language) that losslessly
round-trips the canonical `HOME_PAGE_SAMPLE`, and wires PHP into the web
converter playground.

## Details

### New
- `packages/typediagram/src/converters/php.ts` — 564-line converter
emitting `final readonly class` DTOs with constructor-promoted `public`
params, `declare(strict_types=1)`, PHPStan `@template` / `@param
list<...>` / `@param array<K,V>` / `|null` docblocks, and sealed
`interface` + implementing classes with `@var 'Kind'` tags for tagged
unions. Parser supports nested generics, Option unwrapping,
`@typediagram-kind alias` wrappers, and scan-state tracking for `//`,
`/* */`, and string literals inside class bodies.
- `packages/typediagram/test/converters/php.test.ts` — 12 tests across
four describe blocks: `[CONV-PHP-TO-COMPLEX]`, `[CONV-PHP-FROM]`,
`[CONV-PHP-RT]`, and `[CONV-PHP-EDGE]`.
- PHP tab in the web playground — added to the `LANGUAGES` list,
`LANG_LABELS`, highlight rules (`PHP_RULES` covering class/interface
keywords, `?type` nullables, `$vars`, PHPDoc), and both `convertSource`
/ `convertFromTd` converter maps.

### Changed
- `converters/index.ts` exports `php`.
- `Language` union in `converters/types.ts` gains `"php"`.
- Web `SupportedLang` aligned across `converter.ts`,
`converter-render.ts`, and `converter-highlight.ts`.

### Known lossless limitation
`Option<Unit>` is NOT round-trippable because both `Unit` and
`Option<Unit>` collapse to PHP `null` native type with no docblock — the
nullability is indistinguishable on parse. `HOME_PAGE_SAMPLE` does not
use `Option<Unit>`, so the byte-for-byte round-trip test still holds.
Documented inline in the edge-case test.

## How Do The Automated Tests Prove It Works?

- `[CONV-PHP-RT] losslessly round-trips the home-page example through
PHP (TD text preserved)` — the canonical `expectLosslessRoundTrip(php)`
assertion (identical pattern to the other 7 converters) confirms `TD →
PHP → TD` is byte-for-byte identical, including field order (which
required removing the `sortFields` Option-reordering hack in the
emitter).
- `[CONV-PHP-TO-COMPLEX]` asserts specific emitted strings: `final
readonly class`, `@template T`, `public ?string $label`, `@param
list<string>`, `@param array<string, int>`, `interface Shape`, `@var
'Circle'`, `@implements Result<T>`, `@typediagram-kind alias`.
- `[CONV-PHP-FROM]` covers alias-only parsing and the
`NO_SUPPORTED_DEFINITIONS` error path.
- `[CONV-PHP-EDGE]` covers empty constructors, `Option<List<Int>>` /
`Option<Map<String,Int>>` emission and parse, `private`-promoted params
being skipped, inline `//` / `/* */` / string-literal tolerance, and
`$kind` mismatch handling.
- Full suite: `make ci` green — **318 tests pass**, bundle 74.55 KB
within 75 KB budget, coverage 95.17% lines / 91.2% branches (above 95 /
90.89 thresholds); php.ts specifically at 96.2% / 92.16%.

Co-authored with @voku (original PHP converter work from the `php`
branch).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: voku <voku@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant