feat(draw): d2 diagram template — compile d2 source to SVG (T-494)

The d2 drawing template compiles a diagram's source to SVG through the d2
binary (resolved via the D-104 path layer), then paints it with the same
renderer the svg card uses. `clide draw --file x.d2` infers the type from
the extension; `.svg` files render directly. Template handlers now return
a DrawResult so a compile failure or an unresolved d2 surface as an honest
userError with an install hint, not a generic "no SVG". Real d2 0.7.1
verified end to end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 11:19:48 +02:00
co-authored by Claude Opus 4.8
parent 67edf732f1
commit 64d77ec5dc
10 changed files with 234 additions and 19 deletions
+19 -1
View File
@@ -48,7 +48,7 @@ void main() {
test('template doc lowers via the registry before publishing', () async {
wire();
registry.register('d2', (doc) async => '<svg data-d2="${doc.fields['source']}"/>');
registry.register('d2', (doc) async => DrawOk('<svg data-d2="${doc.fields['source']}"/>'));
files['c.json'] = '{"template":"d2","source":"a -> b"}';
final r = await draw('c.json');
expect(r.ok, isTrue, reason: r.error?.message);
@@ -56,6 +56,24 @@ void main() {
expect(r.data['template'], 'd2');
});
test('a .d2 file is wrapped as a d2 template and lowered (T-494)', () async {
wire();
registry.register('d2', (doc) async => DrawOk('<svg data-d2="${doc.fields['source']}"/>'));
files['pipeline.d2'] = 'a -> b';
final r = await draw('pipeline.d2');
expect(r.ok, isTrue, reason: r.error?.message);
expect(published.single.data['svg'], '<svg data-d2="a -> b"/>');
expect(r.data['template'], 'd2');
});
test('a .svg file renders as a primitive card (T-494)', () async {
wire();
files['logo.svg'] = '<svg id="raw"/>';
final r = await draw('logo.svg');
expect(r.ok, isTrue, reason: r.error?.message);
expect(published.single.data['svg'], '<svg id="raw"/>');
});
test('a missing file → notFound, nothing published', () async {
wire();
final r = await draw('nope.json');