import type { Config , Measurer } from "./domain" ; import { Graphics } from "./Graphics" ; import { layout } from "./layouter" ; import { parse } from "./parser" ; import { render } from "./renderer" ; import { GraphicsCanvas } from "./GraphicsCanvas" ; import { GraphicsSvg } from "./GraphicsSvg" ; interface Rect { width : number ; height : number ; } function fitCanvasSize ( canvas , rect , zoom ) { canvas . width = rect . width * zoom ; canvas . height = rect . height * zoom ; } function createMeasurer ( config , graphics ) { return { setFont ( conf , bold , ital ) { graphics . setFont ( conf . font , bold , ital ?? null , config . fontSize ) ; } , textWidth : function ( s ) : number { return graphics . measureText ( s ) . width ; } , textHeight : function ( ) : number { return config . leading * config . fontSize ; } } ; } ; function parseAndRender ( code , graphics , canvas , scale ) { var parsedDiagram = parse ( code ) ; var config = parsedDiagram . config ; var measurer = createMeasurer ( config , graphics ) ; var graphLayout = layout ( measurer , config , parsedDiagram . root ) ; if ( canvas ) { fitCanvasSize ( canvas , graphLayout , config . zoom * scale ) ; } config . zoom *= scale ; render ( graphics , config , graphLayout , measurer . setFont ) ; return { config : config , layout : graphLayout } ; } export function draw ( canvas , code , scale ? ) { return parseAndRender ( code , GraphicsCanvas ( canvas ) , canvas , scale || 1 ) ; } export function renderSvg ( code , document ? ) { var skCanvas = GraphicsSvg ( '' , document ) ; var { config , layout } = parseAndRender ( code , skCanvas , null , 1 ) ; return skCanvas . serialize ( { width : layout . width , height : layout . height } , code , config . title ) ; } export class ImportDepthError extends Error { constructor ( ) { super ( 'max_import_depth exceeded' ) ; } } type FileLoaderAsync = ( filename : string ) => Promise < string > ; export async function processAsyncImports ( source , loadFile , maxImportDepth = 10 ) { if ( maxImportDepth == - 1 ) { throw new ImportDepthError ( ) ; } async function lenientLoadFile ( key ) { try { return ( await loadFile ( key ) ) || '' ; } catch ( e ) { return '' ; } } var imports = [ ] ; source . replace ( /#import: *(.*)/g , function ( a , file ) { var promise = lenientLoadFile ( file ) . then ( contents => processAsyncImports ( contents , loadFile , maxImportDepth - 1 ) ) ; imports . push ( { file , promise } ) ; return '' ; } ) ; var imported = { } ; for ( var imp of imports ) { imported [ imp . file ] = await imp . promise ; } return source . replace ( /#import: *(.*)/g , function ( a , file ) { return imported [ file ] ; } ) ; } type FileLoader = ( filename : string ) => string ; export function processImports ( source , loadFile , maxImportDepth = 10 ) { if ( maxImportDepth == - 1 ) { throw new ImportDepthError ( ) ; } function lenientLoadFile ( key ) { try { return loadFile ( key ) || '' ; } catch ( e ) { return '' ; } } return source . replace ( /#import: *(.*)/g , function ( a , file ) { return processImports ( lenientLoadFile ( file ) , loadFile , maxImportDepth - 1 ) ; } ) ; } export function compileFile ( filepath , maxImportDepth ? ) { var fs = require ( 'fs' ) ; var path = require ( 'path' ) ; var directory = path . dirname ( filepath ) ; var rootFileName = filepath . substr ( directory . length ) ; function loadFile ( filename ) { return fs . readFileSync ( path . join ( directory , filename ) , { encoding : 'utf8' } ) ; } return processImports ( loadFile ( rootFileName ) , loadFile , maxImportDepth ) ; }