import { readFileSync } from 'node:fs'; import { Graphviz } from '@hpcc-js/wasm-graphviz'; const src = readFileSync( '/home/seb/src/dashdbschema/generate-schema-graph.js', 'utf8' ); const parser = src.slice( src.indexOf('function parseSchema'), src.indexOf('const EDGE_COLORS') ); const edgeColorsConst = src.slice( src.indexOf('const EDGE_COLORS'), src.indexOf('function edgeKey') ); const edgeKeyFn = src.slice( src.indexOf('function edgeKey'), src.indexOf('/**\n * Only a spanning forest') ); const ranking = src.slice( src.indexOf('function selectRankingEdgeKeys'), src.indexOf('function assignEdgeColors') ); const edgeColors = src.slice( src.indexOf('function assignEdgeColors'), src.indexOf('function escapeHtml') ); const escape = src.slice( src.indexOf('function escapeHtml'), src.indexOf('/**\n * Domain grouping') ); const clusters = src.slice( src.indexOf('const CLUSTERS'), src.indexOf('const COLORS =') ); const colors = src.slice( src.indexOf('const COLORS ='), src.indexOf('const COLORS =') + src.slice(src.indexOf('const COLORS =')).indexOf('};') + 2 ); const orderMembers = src.slice( src.indexOf('function orderClusterMembers'), src.indexOf('function buildTableLabel') ); const plainPositions = src.slice( src.indexOf('function parsePlainPositions'), src.indexOf('function flipCompassLR') ); const reorder = src.slice( src.indexOf('function reorderColumnsForCrossingReduction'), src.indexOf('function parsePlainPositions') ); const builder = src.slice( src.indexOf('function buildTableLabel'), src.indexOf('function countSvgCrossings') ); const crossingsFn = src.slice( src.indexOf('function countSvgCrossings'), src.indexOf('/**\n * Graphviz self-edges') ); const mod = await import( 'data:text/javascript,' + encodeURIComponent( parser + '\n' + edgeColorsConst + '\n' + clusters + '\n' + colors + '\n' + orderMembers + '\n' + plainPositions + '\n' + reorder + '\n' + edgeKeyFn + '\n' + ranking + '\n' + edgeColors + '\n' + escape + '\n' + builder + '\n' + crossingsFn + '\nexport { parseSchema, buildDot, assignEdgeAnchors, parsePlainPositions, reorderColumnsForCrossingReduction, orderClusterMembers, CLUSTERS, COLORS, countSvgCrossings };' ) ); const schemaSource = readFileSync( '/home/seb/src/dashdbschema/src/providers/mssql/schema.js', 'utf8' ); const { tables, edges } = mod.parseSchema(schemaSource); const graphviz = await Graphviz.load(); let positions = null; for (let pass = 0; pass < 3; pass++) { const probeDot = mod.buildDot(tables, edges, positions); const plain = graphviz.layout(probeDot, 'plain', 'dot'); positions = mod.parsePlainPositions(plain); mod.reorderColumnsForCrossingReduction(tables, edges, positions); } const anchors = mod.assignEdgeAnchors(edges, positions); const baseDot = mod.buildDot(tables, edges, positions, anchors); const variants = [ ['mclimit=4.0 splines=spline (current)', 'mclimit=4.0', 'splines=spline'], ['mclimit=1.0 splines=spline', 'mclimit=1.0', 'splines=spline'], ['mclimit=0.5 splines=spline', 'mclimit=0.5', 'splines=spline'], ['mclimit=1.0 splines=true', 'mclimit=1.0', 'splines=true'], ['mclimit=1.0 splines=polyline', 'mclimit=1.0', 'splines=polyline'], ]; for (const [label, mclimit, splines] of variants) { const dot = baseDot .replace('mclimit=4.0', mclimit) .replace('splines=spline', splines); const t = process.hrtime.bigint(); const svg = graphviz.layout(dot, 'svg', 'dot'); const ms = Number(process.hrtime.bigint() - t) / 1e6; const t2 = process.hrtime.bigint(); const crossings = mod.countSvgCrossings(svg); const cms = Number(process.hrtime.bigint() - t2) / 1e6; console.log( `${label}: layout=${ms.toFixed(0)}ms crossings=${crossings} (count=${cms.toFixed(0)}ms) total=${(ms + cms).toFixed(0)}ms` ); }