1import { describe, expect, it } from 'vitest'2import { dbmlAdapter } from '../src/adapters/dbml'3import { sanitizeAndDecorateSvg } from '../src/runtime/svg'4import type { RenderRequest } from '../src/runtime/types'5import { dbmlToDot } from '../artifacts/dbml/dbml-backend.js'67function request(source: string, options: Record<string, string> = {}): RenderRequest {8 return {9 engine: 'dbml',10 source,11 format: 'svg',12 options,13 metadata: { title: '', description: '' },14 presentation: { background: '', padding: 0, frame: false },15 }16}1718describe('DBML upstream lowering', () => {19 it('retains tables, fields, indexes, and refs in the DOT model', () => {20 const dot = dbmlToDot(`21 Project app { database_type: 'PostgreSQL' }22 Table users {23 id int [pk]24 email varchar [unique, not null]25 indexes { (email) [name: 'users_email'] }26 }27 Table posts {28 id int [pk]29 user_id int30 }31 Ref: posts.user_id > users.id32 `.trim() + '\n')33 expect(dot).toContain('"users"')34 expect(dot).toContain('"posts"')35 expect(dot).toContain('email')36 expect(dot).toContain('( ! )'.replaceAll(' ', ''))37 expect(dot).toMatch(/posts.*users|users.*posts/s)38 })3940 it('preserves useful parser locations for malformed input', () => {41 expect(() => dbmlToDot('Table users { id integer')).toThrow(/line 1:25|Expected/)42 })4344 it('renders through the shared GraphViz-Wasm backend', async () => {45 const result = await dbmlAdapter.render(request('Table users { id integer [primary key] }'), new AbortController().signal)46 expect(result.runtime).toBe('edge-wasm')47 expect(result.engineVersion).toBe('dbml@1.0.31+graphviz@15.1.1')48 expect(result.body).toMatch(/<svg[\s>]/i)49 expect(result.body).toContain('users')50 })5152 it('rejects renderer options and oversized or overly complex source', async () => {53 const signal = new AbortController().signal54 await expect(dbmlAdapter.render(request('Table users { id integer }', { layout: 'neato' }), signal))55 .rejects.toMatchObject({ status: 400, code: 'invalid_options' })56 await expect(dbmlAdapter.render(request('x'.repeat(262_145)), signal))57 .rejects.toMatchObject({ status: 413, code: 'request_too_large' })58 await expect(dbmlAdapter.render(request(Array.from({ length: 2_001 }, (_, index) => `Table t${index} { id int }`).join('\n')), signal))59 .rejects.toMatchObject({ status: 413, code: 'request_too_large' })60 })6162 it('removes external DBML table links from the final SVG', async () => {63 const result = await dbmlAdapter.render(request("Table users [url: 'https://example.com/private'] { id integer }"), new AbortController().signal)64 expect(result.body).toContain('https://example.com/private')65 const sanitized = sanitizeAndDecorateSvg(result.body, request('').metadata, request('').presentation, 'dbml')66 expect(sanitized).not.toContain('https://example.com/private')67 expect(sanitized).toContain('users')68 })69})