dbml-erd-viewer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +329 -0
- package/dist/dbml-erd-viewer.css +2 -0
- package/dist/dbml-erd-viewer.js +902 -0
- package/dist/dbml-erd-viewer.umd.cjs +2 -0
- package/dist/index.d.ts +367 -0
- package/package.json +98 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@xyflow/react"),require("@dbml/core"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@xyflow/react`,`@dbml/core`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.DbmlErdViewer={},e.React,e.XYFlowReact,e.DbmlCore,e.jsxRuntime))})(this,function(e,t,n,r,i){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var a=Object.create,o=Object.defineProperty,s=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty,d=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=c(t),a=0,l=i.length,d;a<l;a++)d=i[a],!u.call(e,d)&&d!==n&&o(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=s(t,d))||r.enumerable});return e};r=((e,t,n)=>(n=e==null?{}:a(l(e)),d(t||!e||!e.__esModule?o(n,`default`,{value:e,enumerable:!0}):n,e)))(r,1);var f=r,p=f.Parser??f.default?.Parser;if(!p)throw Error("Could not resolve `Parser` export from @dbml/core.");var m=p,h=`public`,g=class extends Error{diagnostics;constructor(e,t){super(e,t),this.name=`DbmlParseError`,this.diagnostics=t?.diagnostics??[]}};function _(e){let t=e?.diags;return Array.isArray(t)?t.map(e=>({message:e.message??`Unknown error`,line:e.location?.start?.line,column:e.location?.start?.column,code:e.code})):[]}function v(e,t){if(e.length===0)return`Failed to parse DBML: ${t}`;let n=e.map(e=>` • ${e.line==null?``:`Line ${e.line}${e.column==null?``:`:${e.column}`} — `}${e.message}`);return`${e.length===1?`Failed to parse DBML:`:`Failed to parse DBML (${e.length} errors):`}\n${n.join(`
|
|
2
|
+
`)}`}function y(e){if(e)return typeof e==`string`?e:e.value??void 0}function b(e,t){return e&&e!==h?`${e}.${t}`:t}function x(e){let t=new Set;for(let n of e.fields)n.pk&&t.add(n.name);for(let n of e.indexes??[])if(n.pk)for(let e of n.columns??[])e.type===`column`&&e.value&&t.add(e.value);return t}function S(e){let t;try{t=new m().parse(e,`dbmlv2`)}catch(e){let t=_(e);throw new g(v(t,e instanceof Error?e.message:String(e)),{cause:e,diagnostics:t})}let n=new Map;for(let e of t.schemas)for(let t of e.tables){let r=b(e.name,t.name),i=x(t),a=new Map;for(let e of t.fields){let t=i.has(e.name);a.set(e.name,{pk:t,notNull:t||!!e.not_null,note:y(e.note)})}n.set(r,a)}let r=e=>{let t=n.get(e.tableId);return!t||e.columns.length===0?!1:e.columns.every(e=>t.get(e)?.pk===!0)},i=e=>e.columns.some(t=>{let r=n.get(e.tableId)?.get(t);return r?!r.notNull&&!r.pk:!0}),a=e=>e.columns.some(t=>n.get(e.tableId)?.get(t)?.note?.toLowerCase().includes(`optional`)??!1),o=[],s=new Set;for(let e of t.schemas)for(let t of e.refs){if(t.endpoints.length!==2)continue;let[n,c]=t.endpoints.map(t=>({tableId:b(t.schemaName??e.name,t.tableName),columns:t.fieldNames,relation:t.relation})),l,u,d=n.relation===`*`;if(d!==(c.relation===`*`))l=d?n:c,u=d?c:n;else{let e=r(n),t=r(c);e&&!t?(l=c,u=n):(l=n,u=c)}let f=r(l),p=i(l);l.columns.forEach(e=>s.add(`${l.tableId}::${e}`)),o.push({id:`${l.tableId}.${l.columns.join(`-`)}__${u.tableId}.${u.columns.join(`-`)}`,kind:f?`identifying`:`non-identifying`,from:{...l,optional:a(l)?!0:void 0},to:{...u,optional:p}})}let c=[];for(let e of t.schemas){let t=e.name;for(let n of e.tables){let e=b(t,n.name),r=x(n),i=n.fields.map(t=>({name:t.name,type:t.type?.type_name??`unknown`,pk:r.has(t.name),notNull:r.has(t.name)||!!t.not_null,unique:!!t.unique,increment:!!t.increment,defaultValue:t.dbdefault?.value,note:y(t.note),isForeignKey:s.has(`${e}::${t.name}`)}));c.push({id:e,name:n.name,schema:t===h?void 0:t,note:y(n.note),headerColor:n.headerColor??void 0,columns:i})}}return{tables:c,relations:o}}var C=240,w=40,T=28;function E(e){return 40+Math.max(e.columns.length,1)*28}function D(e){let t=new Map;for(let n of e.tables)t.set(n.id,0);let n=e.relations.map(e=>[e.from.tableId,e.to.tableId]).filter(([e,n])=>e!==n&&t.has(e)&&t.has(n));for(let r=0;r<e.tables.length;r++){let e=!1;for(let[r,i]of n){let n=t.get(r)+1;t.get(i)<n&&(t.set(i,n),e=!0)}if(!e)break}return t}function O(e,t={}){let n=t.horizontalGap??120,r=t.verticalGap??40,i=D(e),a=new Map;for(let t of e.tables){let e=i.get(t.id)??0,n=a.get(e);n||(n=[],a.set(e,n)),n.push(t)}let o=new Map;return[...a.keys()].sort((e,t)=>e-t).forEach((e,t)=>{let i=a.get(e).sort((e,t)=>e.name.localeCompare(t.name)),s=t*(240+n),c=0;for(let e of i){let t=E(e);o.set(e.id,{x:s,y:c,width:240,height:t}),c+=t+r}}),o}async function k(e,t={}){let n=await import(`@dagrejs/dagre`),r=t.horizontalGap??120,i=t.verticalGap??40,a=t.direction===`TB`?`TB`:`LR`,o=new n.graphlib.Graph;o.setGraph({rankdir:a,ranksep:r,nodesep:i}),o.setDefaultEdgeLabel(()=>({}));for(let t of e.tables)o.setNode(t.id,{width:240,height:E(t)});for(let t of e.relations)o.hasNode(t.from.tableId)&&o.hasNode(t.to.tableId)&&o.setEdge(t.from.tableId,t.to.tableId);n.layout(o);let s=new Map;for(let e of o.nodes()){let t=o.node(e);t&&s.set(e,{x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height})}return s}async function A(e,t={}){let n=new(await(import(`elkjs/lib/elk.bundled.js`))).default,r=t.horizontalGap??120,i=t.verticalGap??40,a={id:`root`,layoutOptions:{"elk.algorithm":`layered`,"elk.direction":t.direction===`TB`?`DOWN`:`RIGHT`,"elk.layered.spacing.nodeNodeBetweenLayers":String(r),"elk.spacing.nodeNode":String(i)},children:e.tables.map(e=>({id:e.id,width:240,height:E(e)})),edges:e.relations.map((e,t)=>({id:`e${t}`,sources:[e.from.tableId],targets:[e.to.tableId]}))},o=await n.layout(a),s=new Map;for(let e of o.children??[])s.set(e.id,{x:e.x??0,y:e.y??0,width:e.width??240,height:e.height??0});return s}var j=class extends Error{constructor(e,t){super(e,t),this.name=`LayoutError`}};async function M(e,t={}){let n=t.algorithm??`simple`;if(n===`simple`)return O(e,t);try{return n===`dagre`?await k(e,t):await A(e,t)}catch(e){throw new j(`"${n}" layout failed. Is the optional dependency "${n===`dagre`?`@dagrejs/dagre`:`elkjs`}" installed? (${e instanceof Error?e.message:String(e)})`,{cause:e})}}var N=[`--dv-canvas`,`--dv-bg`,`--dv-border`,`--dv-header-bg`,`--dv-header-fg`,`--dv-row-fg`,`--dv-type-fg`,`--dv-row-hover`,`--dv-row-highlight`,`--dv-pk`,`--dv-fk`,`--dv-null`,`--dv-edge`,`--dv-edge-active`,`--dv-font`],P=class extends Error{constructor(e,t){super(e,t),this.name=`ExportError`}};function F(e,t){let n=e.x,r=e.y,i=e.x+e.width,a=e.y+e.height;for(let e of t.querySelectorAll(`.dv-erd-edge`)){let t;try{t=e.getBBox()}catch{continue}t.width===0&&t.height===0||(n=Math.min(n,t.x),r=Math.min(r,t.y),i=Math.max(i,t.x+t.width),a=Math.max(a,t.y+t.height))}return{x:n,y:r,width:i-n,height:a-r}}async function I(e,t,n={}){let{type:r=`png`,padding:i=24,backgroundColor:a,pixelRatio:o=2}=n,s;try{s=await import(`html-to-image`)}catch(e){throw new P(`Export requires the optional dependency "html-to-image". Install it to enable PNG/SVG export.`,{cause:e})}if(typeof document<`u`&&document.fonts?.ready)try{await document.fonts.ready}catch{}let c=Math.ceil(t.width+i*2),l=Math.ceil(t.height+i*2),u=`translate(${-t.x+i}px, ${-t.y+i}px) scale(1)`,d={width:c,height:l,backgroundColor:a,style:{width:`${c}px`,height:`${l}px`,transform:u}},f=L(e,t,i);try{return r===`svg`?await s.toSvg(e,d):await s.toPng(e,{...d,pixelRatio:o})}catch(e){throw new P(`Failed to render diagram image: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{f()}}function L(e,t,n){let r=[],i=e.closest(`.dv-viewer`);if(i){let t=getComputedStyle(i);for(let n of N){let i=t.getPropertyValue(n);if(!i)continue;let a=e.style.getPropertyValue(n);e.style.setProperty(n,i),r.push(()=>{a?e.style.setProperty(n,a):e.style.removeProperty(n)})}}let a=`${Math.ceil(t.x+t.width+n)}px`,o=`${Math.ceil(t.y+t.height+n)}px`;for(let t of e.querySelectorAll(`.react-flow__edges svg`)){let{width:e,height:n}=t.style;t.style.width=a,t.style.height=o,r.push(()=>{t.style.width=e,t.style.height=n})}return()=>r.forEach(e=>e())}function R(e,t){let n=document.createElement(`a`);n.href=e,n.download=t,n.click()}function z(e,t,n){return`${e}__${t}__${n}`}function B(e){return 40+e*28+28/2}function V({column:e,top:t}){let r={top:t,opacity:0};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.Handle,{id:z(e,`left`,`target`),type:`target`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`left`,`source`),type:`source`,position:n.Position.Left,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`right`,`target`),type:`target`,position:n.Position.Right,style:r,isConnectable:!1}),(0,i.jsx)(n.Handle,{id:z(e,`right`,`source`),type:`source`,position:n.Position.Right,style:r,isConnectable:!1})]})}function H({data:e}){let{table:t,highlightedColumns:n}=e;return(0,i.jsxs)(`div`,{className:`dv-table`,style:{width:240},children:[(0,i.jsxs)(`div`,{className:`dv-table__header`,style:t.headerColor?{background:t.headerColor,height:40}:{height:40},title:t.note,children:[t.schema&&(0,i.jsxs)(`span`,{className:`dv-table__schema`,children:[t.schema,`.`]}),(0,i.jsx)(`span`,{className:`dv-table__name`,children:t.name})]}),(0,i.jsx)(`div`,{className:`dv-table__body`,children:t.columns.map((e,t)=>{let r=n?.has(e.name);return(0,i.jsxs)(`div`,{className:`dv-row${r?` dv-row--highlighted`:``}`,style:{height:28},title:e.note,children:[(0,i.jsxs)(`span`,{className:`dv-row__name${e.pk?` dv-row__name--pk`:``}`,children:[e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--pk`,title:`Primary key`,children:`PK`}),e.isForeignKey&&!e.pk&&(0,i.jsx)(`span`,{className:`dv-badge dv-badge--fk`,title:`Foreign key`,children:`FK`}),e.name]}),(0,i.jsxs)(`span`,{className:`dv-row__type`,children:[e.type,(0,i.jsx)(`span`,{className:`dv-row__null${e.notNull?` dv-row__null--notnull`:``}`,title:e.notNull?`Not null`:`Nullable`})]}),(0,i.jsx)(V,{column:e.name,top:B(t)})]},e.name)})})]})}var U=(0,t.memo)(H),W=8,G=13,K=7,q=13,J=16;function Y(e,t,r,a,o,s){let c=-(r===n.Position.Left?1:-1),l=[],u={stroke:o,strokeWidth:s},d=(n,r)=>l.push((0,i.jsx)(`line`,{x1:e+c*n,y1:t-W,x2:e+c*n,y2:t+W,style:u},r)),f=(n,r)=>l.push((0,i.jsx)(`circle`,{cx:e+c*n,cy:t,r:4,style:{stroke:o,strokeWidth:s,fill:`var(--dv-bg)`}},r));if(a.cardinality===`*`){let n=e+c*G;l.push((0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t-W,style:u},`cf1`),(0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t,style:u},`cf2`),(0,i.jsx)(`line`,{x1:n,y1:t,x2:e,y2:t+W,style:u},`cf3`)),a.optional===!0?f(17,`fr`):d(14,`fb`)}else d(K,`b1`),a.optional===!0?f(J,`r`):a.optional===!1&&d(q,`b2`);return(0,i.jsx)(`g`,{className:`dv-erd-marker`,children:l})}function X({sourceX:e,sourceY:t,targetX:r,targetY:a,sourcePosition:o,targetPosition:s,data:c,selected:l}){let[u]=(0,n.getSmoothStepPath)({sourceX:e,sourceY:t,sourcePosition:o,targetX:r,targetY:a,targetPosition:s,borderRadius:8}),d=c,f=d?.kind===`non-identifying`,p=l||d?.hovered,m=p?`var(--dv-edge-active)`:`var(--dv-edge)`,h=p?2:1.5;return(0,i.jsxs)(`g`,{className:`dv-erd-edge${p?` dv-erd-edge--active`:``}`,children:[(0,i.jsx)(`path`,{className:`dv-erd-edge__interaction`,d:u,fill:`none`}),(0,i.jsx)(`path`,{className:`dv-erd-edge__path`,d:u,fill:`none`,style:{stroke:m,strokeWidth:h},strokeDasharray:f?`6 4`:void 0}),d&&Y(e,t,o,d.sourceEnd,m,h),d&&Y(r,a,s,d.targetEnd,m,h)]})}var Z=(0,t.memo)(X);function ee(e,n,r){let[i,a]=(0,t.useState)(null),o=(0,t.useMemo)(()=>{let t=new Map;for(let n of e)t.set(n.id,n);return t},[e]),s=(0,t.useMemo)(()=>{let e=new Map,t=i?o.get(i):void 0;if(!t)return e;for(let n of[t.from,t.to]){let t=e.get(n.tableId)??new Set;n.columns.forEach(e=>t.add(e)),e.set(n.tableId,t)}return e},[i,o]);return{displayNodes:(0,t.useMemo)(()=>i?n.map(e=>{let t=s.get(e.id);return t?{...e,data:{...e.data,highlightedColumns:t}}:e}):n,[n,i,s]),displayEdges:(0,t.useMemo)(()=>i?r.map(e=>e.id===i?{...e,data:{...e.data,hovered:!0},zIndex:1}:e):r,[r,i]),onEdgeMouseEnter:(0,t.useCallback)((e,t)=>a(t.id),[]),onEdgeMouseLeave:(0,t.useCallback)(()=>a(null),[])}}var te={canvas:`--dv-canvas`,background:`--dv-bg`,border:`--dv-border`,headerBackground:`--dv-header-bg`,headerForeground:`--dv-header-fg`,rowForeground:`--dv-row-fg`,typeForeground:`--dv-type-fg`,rowHover:`--dv-row-hover`,rowHighlight:`--dv-row-highlight`,primaryKey:`--dv-pk`,foreignKey:`--dv-fk`,edge:`--dv-edge`,edgeActive:`--dv-edge-active`,fontFamily:`--dv-font`},ne={canvas:`#fafbfc`,background:`#ffffff`,border:`#d9dee5`,headerBackground:`#2d3748`,headerForeground:`#ffffff`,rowForeground:`#1a202c`,typeForeground:`#718096`,rowHover:`#f1f5f9`,rowHighlight:`#dbeafe`,primaryKey:`#b7791f`,foreignKey:`#2b6cb0`,edge:`#94a3b8`,edgeActive:`#2b6cb0`},re={canvas:`#0f172a`,background:`#1e293b`,border:`#334155`,headerBackground:`#334155`,headerForeground:`#f1f5f9`,rowForeground:`#e2e8f0`,typeForeground:`#94a3b8`,rowHover:`#334155`,rowHighlight:`#1e3a5f`,primaryKey:`#d69e2e`,foreignKey:`#4299e1`,edge:`#64748b`,edgeActive:`#60a5fa`};function Q(e){if(!e)return{};let t={};for(let n of Object.keys(e)){let r=e[n];r!=null&&(t[te[n]]=r)}return t}var ie=[],ae={table:U},oe={erd:Z};function se(){return(0,i.jsxs)(`svg`,{viewBox:`0 0 24 24`,width:`100%`,height:`100%`,fill:`currentColor`,"aria-hidden":`true`,children:[(0,i.jsx)(`rect`,{x:`3`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`3`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`3`,y:`13`,width:`8`,height:`8`,rx:`1.5`}),(0,i.jsx)(`rect`,{x:`13`,y:`13`,width:`8`,height:`8`,rx:`1.5`})]})}function ce(e,t,n,r){let i=new Map;for(let a of e.tables){let e=t.get(a.id);i.set(a.id,n?.[a.id]??r?.get(a.id)??{x:e?.x??0,y:e?.y??0})}return i}function le(e,t){if(e.length!==t.length)return!1;let n=new Set(e);return t.every(e=>n.has(e))}async function $(e,t,n){try{return await M(e,t)}catch(r){return n(r instanceof j?r:new j(String(r),{cause:r})),O(e,t)}}function ue(e,t){return e.tables.map(e=>({id:e.id,type:`table`,position:t.get(e.id)??{x:0,y:0},data:{table:e}}))}function de(e,t){return e.relations.map(e=>{let n=t.get(e.from.tableId),r=t.get(e.to.tableId),i=(n?.x??0)>(r?.x??0),a=i?`left`:`right`,o=i?`right`:`left`,s=e.from.columns[0]??``,c=e.to.columns[0]??``;return{id:e.id,source:e.from.tableId,target:e.to.tableId,sourceHandle:z(s,a,`source`),targetHandle:z(c,o,`target`),type:`erd`,data:{kind:e.kind,sourceEnd:{cardinality:e.from.relation,optional:e.from.optional},targetEnd:{cardinality:e.to.relation,optional:e.to.optional}}}})}var fe=(0,t.forwardRef)(function({dbml:e,className:r,style:a,theme:o,fitView:s=!0,showControls:c=!0,showMiniMap:l=!1,showBackground:u=!0,layoutOptions:d,onParseError:f,onLayoutError:p,nodePositions:m,onNodePositionsChange:h},_){let v=(0,t.useMemo)(()=>{try{return{ok:!0,schema:S(e)}}catch(e){return{ok:!1,error:e instanceof g?e:new g(String(e),{cause:e})}}},[e]),[y,b,x]=(0,n.useNodesState)([]),[C,w,T]=(0,n.useEdgesState)([]),E=(0,t.useRef)(null),D=(0,t.useRef)(null),O=(0,t.useRef)(y);O.current=y,(0,t.useImperativeHandle)(_,()=>{let e=async e=>{let t=E.current,r=D.current?.querySelector(`.react-flow__viewport`);if(!t||!r)throw new P(`The diagram is not ready to export yet.`);let i=F((0,n.getNodesBounds)(t.getNodes()),r),a=e?.backgroundColor??(D.current?getComputedStyle(D.current).backgroundColor:void 0);return I(r,i,{...e,backgroundColor:a})};return{toDataUrl:e,download:async(t,n)=>{R(await e(n),t)}}},[]);let k=(0,t.useRef)(p);k.current=p;let A=(0,t.useRef)(h);A.current=h;let j=(0,t.useRef)(m);j.current=m;let M=(0,t.useCallback)(()=>{let e=A.current;if(!e)return;let t={};for(let e of O.current)t[e.id]={x:e.position.x,y:e.position.y};e(t)},[]),{algorithm:N=`simple`,direction:L=`LR`,horizontalGap:z,verticalGap:B}=d??{},V=(0,t.useRef)(null),H=`${N}|${L}|${z}|${B}`,U=(0,t.useCallback)((e,t,n,r,i)=>{let a=ce(e,r,i.saved,i.prior);if(b(ue(e,a)),w(de(e,a)),V.current={ids:t,optionsKey:n},i.emit){let e={};a.forEach((t,n)=>{e[n]=t}),A.current?.(e)}i.fit&&requestAnimationFrame(()=>void E.current?.fitView())},[b,w]);(0,t.useEffect)(()=>{if(!v.ok){b([]),w([]),V.current=null;return}let e=v.schema,t={algorithm:N,direction:L,horizontalGap:z,verticalGap:B},n=e.tables.map(e=>e.id),r=new Map(O.current.map(e=>[e.id,{x:e.position.x,y:e.position.y}])),i=V.current,a=n.every(e=>r.has(e));if(i&&i.optionsKey===H&&a&&le(i.ids,n)){U(e,n,H,new Map,{prior:r});return}let o=i&&i.optionsKey===H?r:void 0,c=!1;return $(e,t,e=>k.current?.(e)).then(t=>{c||U(e,n,H,t,{saved:j.current,prior:o,fit:s})}),()=>{c=!0}},[v,N,L,z,B,H,s,U,b,w]);let W=(0,t.useCallback)(()=>{if(!v.ok)return;let e=v.schema,t={algorithm:N,direction:L,horizontalGap:z,verticalGap:B},n=e.tables.map(e=>e.id);$(e,t,e=>k.current?.(e)).then(t=>{U(e,n,H,t,{emit:!0,fit:!0})})},[v,N,L,z,B,H,U]),G=(0,t.useCallback)(()=>{v.ok||f?.(v.error)},[v,f]);(0,t.useEffect)(G,[G]);let{displayNodes:K,displayEdges:q,onEdgeMouseEnter:J,onEdgeMouseLeave:Y}=ee(v.ok?v.schema.relations:ie,y,C),X={width:`100%`,height:`100%`,...Q(o),...a};return v.ok?(0,i.jsx)(`div`,{ref:D,className:`dv-viewer${r?` ${r}`:``}`,style:X,children:(0,i.jsxs)(n.ReactFlow,{nodes:K,edges:q,nodeTypes:ae,edgeTypes:oe,onNodesChange:x,onEdgesChange:T,onEdgeMouseEnter:J,onEdgeMouseLeave:Y,onNodeDragStop:M,onInit:e=>{E.current=e},fitView:s,nodesConnectable:!1,elementsSelectable:!0,minZoom:.1,proOptions:{hideAttribution:!0},children:[u&&(0,i.jsx)(n.Background,{}),c&&(0,i.jsx)(n.Controls,{children:(0,i.jsx)(n.ControlButton,{onClick:W,title:`Auto layout`,"aria-label":`Auto layout`,children:(0,i.jsx)(se,{})})}),l&&(0,i.jsx)(n.MiniMap,{pannable:!0,zoomable:!0})]})}):(0,i.jsx)(`div`,{className:`dv-error${r?` ${r}`:``}`,style:X,children:(0,i.jsx)(`pre`,{className:`dv-error__message`,children:v.error.message})})});e.DbmlParseError=g,e.DbmlViewer=fe,e.ErdEdge=Z,e.ExportError=P,e.HEADER_HEIGHT=w,e.LayoutError=j,e.NODE_WIDTH=C,e.ROW_HEIGHT=T,e.TableNode=U,e.computeLayout=M,e.darkTheme=re,e.downloadDataUrl=R,e.layoutSchema=O,e.lightTheme=ne,e.parseDbml=S,e.renderDiagram=I,e.tableHeight=E,e.themeToCssVars=Q});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { EdgeProps } from '@xyflow/react';
|
|
3
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
4
|
+
import { JSX } from 'react';
|
|
5
|
+
import { MemoExoticComponent } from 'react';
|
|
6
|
+
import { Node as Node_2 } from '@xyflow/react';
|
|
7
|
+
import { NodeProps } from '@xyflow/react';
|
|
8
|
+
import { Rect } from '@xyflow/react';
|
|
9
|
+
import { RefAttributes } from 'react';
|
|
10
|
+
|
|
11
|
+
/** Cardinality of one side of a relation. `'1'` = one, `'*'` = many. */
|
|
12
|
+
export declare type Cardinality = '1' | '*';
|
|
13
|
+
|
|
14
|
+
/** A single column within a table. */
|
|
15
|
+
export declare interface ColumnInfo {
|
|
16
|
+
/** Column name. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Data type as written in the DBML (e.g. `varchar`, `int`, `timestamp`). */
|
|
19
|
+
type: string;
|
|
20
|
+
/** Whether the column is part of the primary key. */
|
|
21
|
+
pk: boolean;
|
|
22
|
+
/** Whether the column is `not null`. */
|
|
23
|
+
notNull: boolean;
|
|
24
|
+
/** Whether the column has a unique constraint. */
|
|
25
|
+
unique: boolean;
|
|
26
|
+
/** Whether the column auto-increments. */
|
|
27
|
+
increment: boolean;
|
|
28
|
+
/** Default value, if any. */
|
|
29
|
+
defaultValue?: string | number | boolean | null;
|
|
30
|
+
/** Inline note/comment for the column. */
|
|
31
|
+
note?: string;
|
|
32
|
+
/** True when this column participates as an endpoint of a relation. */
|
|
33
|
+
isForeignKey: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Compute node positions using the requested algorithm. Always async so the three
|
|
38
|
+
* strategies share one interface (`'simple'` resolves synchronously under the hood).
|
|
39
|
+
*
|
|
40
|
+
* @throws {LayoutError} when `'dagre'`/`'elk'` fails — typically because the optional
|
|
41
|
+
* dependency (`@dagrejs/dagre` / `elkjs`) is not installed.
|
|
42
|
+
*/
|
|
43
|
+
export declare function computeLayout(schema: ParsedSchema, options?: LayoutOptions): Promise<Map<string, NodeBox>>;
|
|
44
|
+
|
|
45
|
+
/** Dark theme preset (neutral slate palette). Pass directly: `<DbmlViewer theme={darkTheme} />`. */
|
|
46
|
+
export declare const darkTheme: DbmlViewerTheme;
|
|
47
|
+
|
|
48
|
+
/** A single parse diagnostic (one syntax/semantic problem found in the DBML). */
|
|
49
|
+
export declare interface DbmlDiagnostic {
|
|
50
|
+
/** Human-readable description of the problem. */
|
|
51
|
+
message: string;
|
|
52
|
+
/** 1-based line number, when the parser reported a location. */
|
|
53
|
+
line?: number;
|
|
54
|
+
/** 1-based column number, when the parser reported a location. */
|
|
55
|
+
column?: number;
|
|
56
|
+
/** Parser error code, when available. */
|
|
57
|
+
code?: string | number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Thrown when DBML text cannot be parsed. `diagnostics` holds the structured problems
|
|
62
|
+
* (line/column/message) and the original parser error is attached as `cause`.
|
|
63
|
+
*/
|
|
64
|
+
export declare class DbmlParseError extends Error {
|
|
65
|
+
readonly diagnostics: DbmlDiagnostic[];
|
|
66
|
+
constructor(message: string, options?: {
|
|
67
|
+
cause?: unknown;
|
|
68
|
+
diagnostics?: DbmlDiagnostic[];
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Render a DBML schema as an interactive diagram. Tables become draggable nodes and
|
|
74
|
+
* foreign-key relations become edges connecting the related columns.
|
|
75
|
+
*
|
|
76
|
+
* Pass a `ref` to access the imperative {@link DbmlViewerHandle} (image export).
|
|
77
|
+
*/
|
|
78
|
+
export declare const DbmlViewer: ForwardRefExoticComponent<DbmlViewerProps & RefAttributes<DbmlViewerHandle>>;
|
|
79
|
+
|
|
80
|
+
/** Imperative handle exposed via `ref` for exporting the diagram as an image. */
|
|
81
|
+
export declare interface DbmlViewerHandle {
|
|
82
|
+
/**
|
|
83
|
+
* Render the full diagram to an image data URL (`'png'` or `'svg'`).
|
|
84
|
+
* @throws {ExportError} when the optional `html-to-image` dependency is missing.
|
|
85
|
+
*/
|
|
86
|
+
toDataUrl(options?: DiagramExportOptions): Promise<string>;
|
|
87
|
+
/** Render the diagram and trigger a browser download. */
|
|
88
|
+
download(filename: string, options?: DiagramExportOptions): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export declare interface DbmlViewerProps {
|
|
92
|
+
/** DBML source text to render. */
|
|
93
|
+
dbml: string;
|
|
94
|
+
/** Class applied to the wrapping element. */
|
|
95
|
+
className?: string;
|
|
96
|
+
/** Inline style for the wrapping element. Defaults to filling its container. */
|
|
97
|
+
style?: CSSProperties;
|
|
98
|
+
/** Theme tokens applied as CSS variables on the viewer (partial overrides allowed). */
|
|
99
|
+
theme?: DbmlViewerTheme;
|
|
100
|
+
/** Fit the diagram into view on load. Default `true`. */
|
|
101
|
+
fitView?: boolean;
|
|
102
|
+
/** Show the zoom/pan controls. Default `true`. */
|
|
103
|
+
showControls?: boolean;
|
|
104
|
+
/** Show the minimap. Default `false`. */
|
|
105
|
+
showMiniMap?: boolean;
|
|
106
|
+
/** Show the dotted background. Default `true`. */
|
|
107
|
+
showBackground?: boolean;
|
|
108
|
+
/** Layout tuning: algorithm (`'simple'` | `'dagre'` | `'elk'`), direction, gaps. */
|
|
109
|
+
layoutOptions?: LayoutOptions;
|
|
110
|
+
/** Called when the DBML fails to parse. */
|
|
111
|
+
onParseError?: (error: DbmlParseError) => void;
|
|
112
|
+
/** Called when a non-default layout fails (e.g. optional dependency missing). */
|
|
113
|
+
onLayoutError?: (error: LayoutError) => void;
|
|
114
|
+
/**
|
|
115
|
+
* Saved table positions (`id → {x, y}`) to restore. Applied when the schema/layout
|
|
116
|
+
* (re)builds; tables without a saved position fall back to auto-layout. To return to a
|
|
117
|
+
* fresh auto-layout, pass `undefined`/`{}`.
|
|
118
|
+
*/
|
|
119
|
+
nodePositions?: NodePositions;
|
|
120
|
+
/** Called after the user finishes dragging a table, with the full positions map to persist. */
|
|
121
|
+
onNodePositionsChange?: (positions: NodePositions) => void;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Theme tokens for {@link DbmlViewer}. Every field maps to a `--dv-*` CSS custom
|
|
126
|
+
* property scoped to the viewer, so a partial theme overrides only the keys you set.
|
|
127
|
+
* For finer control, target the `.dv-*` classes in your own stylesheet.
|
|
128
|
+
*/
|
|
129
|
+
export declare interface DbmlViewerTheme {
|
|
130
|
+
/** Diagram canvas (pane) background. → `--dv-canvas` */
|
|
131
|
+
canvas?: string;
|
|
132
|
+
/** Table body background. → `--dv-bg` */
|
|
133
|
+
background?: string;
|
|
134
|
+
/** Table and row borders. → `--dv-border` */
|
|
135
|
+
border?: string;
|
|
136
|
+
/** Table header background. → `--dv-header-bg` */
|
|
137
|
+
headerBackground?: string;
|
|
138
|
+
/** Table header text color. → `--dv-header-fg` */
|
|
139
|
+
headerForeground?: string;
|
|
140
|
+
/** Column name text color. → `--dv-row-fg` */
|
|
141
|
+
rowForeground?: string;
|
|
142
|
+
/** Column type text color. → `--dv-type-fg` */
|
|
143
|
+
typeForeground?: string;
|
|
144
|
+
/** Row background on hover. → `--dv-row-hover` */
|
|
145
|
+
rowHover?: string;
|
|
146
|
+
/** Row background when highlighted by a hovered relation. → `--dv-row-highlight` */
|
|
147
|
+
rowHighlight?: string;
|
|
148
|
+
/** Primary-key badge color. → `--dv-pk` */
|
|
149
|
+
primaryKey?: string;
|
|
150
|
+
/** Foreign-key badge color. → `--dv-fk` */
|
|
151
|
+
foreignKey?: string;
|
|
152
|
+
/** Relation edge color. → `--dv-edge` */
|
|
153
|
+
edge?: string;
|
|
154
|
+
/** Relation edge color when hovered/selected. → `--dv-edge-active` */
|
|
155
|
+
edgeActive?: string;
|
|
156
|
+
/** Font family for table contents. → `--dv-font` */
|
|
157
|
+
fontFamily?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export declare interface DiagramExportOptions {
|
|
161
|
+
/** Output format. Default `'png'`. */
|
|
162
|
+
type?: ExportFormat;
|
|
163
|
+
/** Padding (px) around the diagram bounds. Default `24`. */
|
|
164
|
+
padding?: number;
|
|
165
|
+
/** Background color. Defaults to the viewer's current canvas color. */
|
|
166
|
+
backgroundColor?: string;
|
|
167
|
+
/** Device pixel ratio for PNG (higher = sharper). Default `2`. */
|
|
168
|
+
pixelRatio?: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Trigger a browser download of a data URL. */
|
|
172
|
+
export declare function downloadDataUrl(dataUrl: string, filename: string): void;
|
|
173
|
+
|
|
174
|
+
/** Cardinality + optionality of one rendered edge end. */
|
|
175
|
+
export declare interface EdgeEndSpec {
|
|
176
|
+
cardinality: Cardinality;
|
|
177
|
+
/** `true` = optional, `false` = mandatory, `undefined` = unspecified (pure cardinality). */
|
|
178
|
+
optional?: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export declare const ErdEdge: MemoExoticComponent<typeof ErdEdgeComponent>;
|
|
182
|
+
|
|
183
|
+
declare function ErdEdgeComponent({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected, }: EdgeProps): JSX.Element;
|
|
184
|
+
|
|
185
|
+
export declare interface ErdEdgeData {
|
|
186
|
+
kind: RelationKind;
|
|
187
|
+
/** Glyph at the source point. */
|
|
188
|
+
sourceEnd: EdgeEndSpec;
|
|
189
|
+
/** Glyph at the target point. */
|
|
190
|
+
targetEnd: EdgeEndSpec;
|
|
191
|
+
/** Set while the relation is hovered, to emphasize the edge. */
|
|
192
|
+
hovered?: boolean;
|
|
193
|
+
[key: string]: unknown;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Thrown when export fails — typically the optional `html-to-image` dependency is missing. */
|
|
197
|
+
export declare class ExportError extends Error {
|
|
198
|
+
constructor(message: string, options?: {
|
|
199
|
+
cause?: unknown;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Image format for diagram export. */
|
|
204
|
+
export declare type ExportFormat = 'png' | 'svg';
|
|
205
|
+
|
|
206
|
+
export declare const HEADER_HEIGHT = 40;
|
|
207
|
+
|
|
208
|
+
/** Layout algorithm to position the table nodes. */
|
|
209
|
+
export declare type LayoutAlgorithm = 'simple' | 'dagre' | 'elk';
|
|
210
|
+
|
|
211
|
+
/** Primary flow direction of the layout. */
|
|
212
|
+
export declare type LayoutDirection = 'LR' | 'TB';
|
|
213
|
+
|
|
214
|
+
/** Thrown when a non-default layout algorithm fails (often a missing optional dependency). */
|
|
215
|
+
export declare class LayoutError extends Error {
|
|
216
|
+
constructor(message: string, options?: {
|
|
217
|
+
cause?: unknown;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export declare interface LayoutOptions {
|
|
222
|
+
/**
|
|
223
|
+
* Algorithm used to place nodes. Default `'simple'` (built-in, no dependency).
|
|
224
|
+
* `'dagre'` requires `@dagrejs/dagre`; `'elk'` requires `elkjs` — both optional
|
|
225
|
+
* peer dependencies, loaded on demand.
|
|
226
|
+
*/
|
|
227
|
+
algorithm?: LayoutAlgorithm;
|
|
228
|
+
/** Primary direction: `'LR'` (left→right, default) or `'TB'` (top→bottom). */
|
|
229
|
+
direction?: LayoutDirection;
|
|
230
|
+
/** Horizontal gap between layers. */
|
|
231
|
+
horizontalGap?: number;
|
|
232
|
+
/** Vertical gap between stacked tables. */
|
|
233
|
+
verticalGap?: number;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Compute node positions for the parsed schema.
|
|
238
|
+
*
|
|
239
|
+
* Tables are arranged left-to-right by their layer in the FK graph and stacked
|
|
240
|
+
* vertically within each layer. The result is keyed by {@link TableInfo.id}.
|
|
241
|
+
*/
|
|
242
|
+
export declare function layoutSchema(schema: ParsedSchema, options?: LayoutOptions): Map<string, NodeBox>;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Light theme — matches the built-in stylesheet defaults. Useful as a base to spread
|
|
246
|
+
* and tweak: `{ ...lightTheme, headerBackground: '#1e3a8a' }`.
|
|
247
|
+
*/
|
|
248
|
+
export declare const lightTheme: DbmlViewerTheme;
|
|
249
|
+
|
|
250
|
+
/** Visual sizing used both for layout math and for the node component. */
|
|
251
|
+
export declare const NODE_WIDTH = 240;
|
|
252
|
+
|
|
253
|
+
/** Position and measured size of a laid-out table node. */
|
|
254
|
+
export declare interface NodeBox {
|
|
255
|
+
x: number;
|
|
256
|
+
y: number;
|
|
257
|
+
width: number;
|
|
258
|
+
height: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Map of table id → position, used to persist and restore where the user dragged tables. */
|
|
262
|
+
export declare type NodePositions = Record<string, XYPosition>;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Parse a DBML document into a normalized {@link ParsedSchema} of tables and relations.
|
|
266
|
+
*
|
|
267
|
+
* @param dbml - DBML source text.
|
|
268
|
+
* @throws {DbmlParseError} when the input is not valid DBML.
|
|
269
|
+
*/
|
|
270
|
+
export declare function parseDbml(dbml: string): ParsedSchema;
|
|
271
|
+
|
|
272
|
+
/** Result of parsing a DBML document. */
|
|
273
|
+
export declare interface ParsedSchema {
|
|
274
|
+
tables: TableInfo[];
|
|
275
|
+
relations: RelationInfo[];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** One end of a relation. */
|
|
279
|
+
export declare interface RelationEndpoint {
|
|
280
|
+
/** Id of the table this endpoint belongs to (matches {@link TableInfo.id}). */
|
|
281
|
+
tableId: string;
|
|
282
|
+
/** Column name(s) involved on this side. */
|
|
283
|
+
columns: string[];
|
|
284
|
+
/** Cardinality on this side. */
|
|
285
|
+
relation: Cardinality;
|
|
286
|
+
/**
|
|
287
|
+
* Participation, derived from foreign-key nullability — only meaningful on the referenced
|
|
288
|
+
* ("one"/parent) side: `true` = optional (nullable FK → "zero or one"), `false` = mandatory
|
|
289
|
+
* (`not null` FK → "one and only one"). `undefined` on the FK-holder side, whose minimum
|
|
290
|
+
* participation isn't expressible in DBML, so it renders pure cardinality with no ring.
|
|
291
|
+
*/
|
|
292
|
+
optional?: boolean;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** A relation (foreign key reference) between two tables. */
|
|
296
|
+
export declare interface RelationInfo {
|
|
297
|
+
/** Stable id for the relation. */
|
|
298
|
+
id: string;
|
|
299
|
+
/** Identifying vs non-identifying — controls solid vs dashed line. */
|
|
300
|
+
kind: RelationKind;
|
|
301
|
+
/** Child endpoint: the table that holds the foreign key (the "many" side of a 1:N). */
|
|
302
|
+
from: RelationEndpoint;
|
|
303
|
+
/** Parent endpoint: the referenced table (the "one" side of a 1:N). */
|
|
304
|
+
to: RelationEndpoint;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Relationship kind, mirroring MySQL Workbench's EER notation:
|
|
309
|
+
* - `identifying` — the child's foreign key is part of its primary key (drawn as a solid line).
|
|
310
|
+
* - `non-identifying` — the foreign key is not part of the primary key (drawn as a dashed line).
|
|
311
|
+
*/
|
|
312
|
+
export declare type RelationKind = 'identifying' | 'non-identifying';
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Render the React Flow viewport element to an image data URL, framing the full
|
|
316
|
+
* diagram (all nodes) at 100% scale. Requires the optional `html-to-image` dependency.
|
|
317
|
+
*
|
|
318
|
+
* @throws {ExportError} when `html-to-image` is unavailable or rendering fails.
|
|
319
|
+
*/
|
|
320
|
+
export declare function renderDiagram(viewport: HTMLElement, bounds: Rect, options?: DiagramExportOptions): Promise<string>;
|
|
321
|
+
|
|
322
|
+
export declare const ROW_HEIGHT = 28;
|
|
323
|
+
|
|
324
|
+
/** Height of a table node given its column count. */
|
|
325
|
+
export declare function tableHeight(table: TableInfo): number;
|
|
326
|
+
|
|
327
|
+
/** A table parsed from the DBML schema. */
|
|
328
|
+
export declare interface TableInfo {
|
|
329
|
+
/** Stable id: `schema.table` when a non-default schema is present, otherwise `table`. */
|
|
330
|
+
id: string;
|
|
331
|
+
/** Table name. */
|
|
332
|
+
name: string;
|
|
333
|
+
/** Schema name, when not the default `public` schema. */
|
|
334
|
+
schema?: string;
|
|
335
|
+
/** Table-level note/comment. */
|
|
336
|
+
note?: string;
|
|
337
|
+
/** Optional header color set in the DBML (`headercolor`). */
|
|
338
|
+
headerColor?: string;
|
|
339
|
+
/** Columns in declaration order. */
|
|
340
|
+
columns: ColumnInfo[];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export declare const TableNode: MemoExoticComponent<typeof TableNodeComponent>;
|
|
344
|
+
|
|
345
|
+
declare function TableNodeComponent({ data }: NodeProps<TableNodeType>): JSX.Element;
|
|
346
|
+
|
|
347
|
+
export declare type TableNodeData = {
|
|
348
|
+
table: TableInfo;
|
|
349
|
+
/** Columns currently highlighted (e.g. endpoints of a hovered relation). */
|
|
350
|
+
highlightedColumns?: Set<string>;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export declare type TableNodeType = Node_2<TableNodeData, 'table'>;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Convert a {@link DbmlViewerTheme} into inline CSS custom properties. Only the keys
|
|
357
|
+
* present in `theme` are emitted, so unset tokens keep their stylesheet defaults.
|
|
358
|
+
*/
|
|
359
|
+
export declare function themeToCssVars(theme?: DbmlViewerTheme): CSSProperties;
|
|
360
|
+
|
|
361
|
+
/** A 2D position. */
|
|
362
|
+
export declare interface XYPosition {
|
|
363
|
+
x: number;
|
|
364
|
+
y: number;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export { }
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dbml-erd-viewer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React component library that renders DBML database schemas as an interactive diagram.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"database",
|
|
7
|
+
"dbml",
|
|
8
|
+
"erd",
|
|
9
|
+
"react",
|
|
10
|
+
"react-flow",
|
|
11
|
+
"schema",
|
|
12
|
+
"viewer",
|
|
13
|
+
"xyflow"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/usingsky/dbml-erd-viewer#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/usingsky/dbml-erd-viewer/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Jinil Lee <usingsky@gmail.com>",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/usingsky/dbml-erd-viewer.git"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"sideEffects": [
|
|
30
|
+
"**/*.css"
|
|
31
|
+
],
|
|
32
|
+
"main": "./dist/dbml-erd-viewer.umd.cjs",
|
|
33
|
+
"module": "./dist/dbml-erd-viewer.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/dbml-erd-viewer.js",
|
|
39
|
+
"require": "./dist/dbml-erd-viewer.umd.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./styles.css": "./dist/dbml-erd-viewer.css",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "vite",
|
|
46
|
+
"build": "tsc -p tsconfig.build.json && vite build",
|
|
47
|
+
"build:demo": "vite build --config vite.config.demo.ts",
|
|
48
|
+
"preview": "vite preview",
|
|
49
|
+
"preview:demo": "vite preview --config vite.config.demo.ts",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"lint": "oxlint",
|
|
52
|
+
"lint:fix": "oxlint --fix",
|
|
53
|
+
"format": "oxfmt --write",
|
|
54
|
+
"format:check": "oxfmt --check",
|
|
55
|
+
"check": "oxlint && oxfmt --check && tsc --noEmit",
|
|
56
|
+
"prepublishOnly": "npm run build"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@dbml/core": "^8.2.5",
|
|
60
|
+
"@xyflow/react": "^12.3.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@dagrejs/dagre": "^3.0.0",
|
|
64
|
+
"@fontsource-variable/inter": "^5.2.8",
|
|
65
|
+
"@microsoft/api-extractor": "^7.58.8",
|
|
66
|
+
"@types/node": "^25.9.2",
|
|
67
|
+
"@types/react": "^19.0.0",
|
|
68
|
+
"@types/react-dom": "^19.0.0",
|
|
69
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
70
|
+
"elkjs": "^0.11.1",
|
|
71
|
+
"html-to-image": "^1.11.13",
|
|
72
|
+
"oxfmt": "^0.54.0",
|
|
73
|
+
"oxlint": "^1.69.0",
|
|
74
|
+
"react": "^19.0.0",
|
|
75
|
+
"react-dom": "^19.0.0",
|
|
76
|
+
"typescript": "^6.0.3",
|
|
77
|
+
"vite": "^8.0.16",
|
|
78
|
+
"vite-plugin-dts": "^5.0.2"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"@dagrejs/dagre": "^3.0.0",
|
|
82
|
+
"elkjs": "^0.11.0",
|
|
83
|
+
"html-to-image": "^1.11.0",
|
|
84
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
85
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependenciesMeta": {
|
|
88
|
+
"@dagrejs/dagre": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"elkjs": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"html-to-image": {
|
|
95
|
+
"optional": true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|