diff --git a/.changeset/every-years-lick.md b/.changeset/every-years-lick.md new file mode 100644 index 0000000..65fb93a --- /dev/null +++ b/.changeset/every-years-lick.md @@ -0,0 +1,5 @@ +--- +"sqlseal": minor +--- + +added interactive visualiser for SQL schema of external databases diff --git a/package.json b/package.json index 5e8e197..02ab3fc 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "jsonpath": "^1.1.1", "lodash": "^4.17.21", "markdown-table-ts": "^1.0.3", + "mermaid": "11.4.0", "ohm-js": "^17.1.0", "papaparse": "^5.5.3", "sql-parser-cst": "^0.33.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0226d9..123fa03 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: markdown-table-ts: specifier: ^1.0.3 version: 1.0.3 + mermaid: + specifier: 11.4.0 + version: 11.4.0 ohm-js: specifier: ^17.1.0 version: 17.1.0 @@ -244,6 +247,12 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -409,6 +418,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + '@bufbuild/protobuf@2.6.1': resolution: {integrity: sha512-DaG6XlyKpz08bmHY5SGX2gfIllaqtDJ/KwVoxsmP22COOLYwDBe7yD3DZGwXem/Xq7QOc9cuR7R3MpAv5CFfDw==} @@ -467,6 +479,21 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@codemirror/language@6.11.1': resolution: {integrity: sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==} @@ -728,6 +755,9 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -848,6 +878,9 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@mermaid-js/parser@0.3.0': + resolution: {integrity: sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1219,6 +1252,103 @@ packages: '@types/codemirror@5.60.8': resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/dompurify@3.2.0': + resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==} + deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed. + '@types/emscripten@1.40.1': resolution: {integrity: sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==} @@ -1234,6 +1364,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} @@ -1754,6 +1887,14 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1822,9 +1963,23 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -1835,6 +1990,12 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1850,6 +2011,165 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.0: + resolution: {integrity: sha512-2d2EwwhaxLWC8ahkH1PpQwCyu6EY3xDRdcEJXrLTb4fOUtVc+YWQalHU67rFS1a6ngj1fgv9dQLtJxP/KAFZEw==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.11: + resolution: {integrity: sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -1889,6 +2209,9 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -1924,6 +2247,9 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dompurify@3.1.6: + resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2103,6 +2429,9 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -2263,6 +2592,10 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2304,6 +2637,9 @@ packages: peerDependencies: graphology-types: '>=0.24.0' + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + handlebars@4.7.8: resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} engines: {node: '>=0.4.7'} @@ -2427,6 +2763,13 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} @@ -2711,13 +3054,33 @@ packages: jsonpath@1.1.1: resolution: {integrity: sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==} + katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + langium@3.0.0: + resolution: {integrity: sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -2733,6 +3096,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2741,6 +3108,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -2799,6 +3169,11 @@ packages: markdown-table-ts@1.0.3: resolution: {integrity: sha512-lYrp7FXmBqpmGmsEF92WnSukdgYvLm15FPIODZOx9+3nobkxJxjBYcszqZf5VqTjBtISPSNC7zjU9o3zwpL6AQ==} + marked@13.0.3: + resolution: {integrity: sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==} + engines: {node: '>= 18'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -2813,6 +3188,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.4.0: + resolution: {integrity: sha512-mxCfEYvADJqOiHfGpJXLs4/fAjHz448rH0pfY5fAoxiz70rQiDSzUUy4dNET2T08i46IVpjohPd6WWbzmRHiPA==} + micromark-util-character@2.1.1: resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} @@ -2901,6 +3279,9 @@ packages: engines: {node: '>=10'} hasBin: true + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + mnemonist@0.39.8: resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} @@ -3063,6 +3444,9 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + pandemonium@2.4.1: resolution: {integrity: sha512-wRqjisUyiUfXowgm7MFH2rwJzKIr20rca5FsHXCMNm1W5YPP1hCtrZfgmQ62kP7OZ7Xt+cR858aB28lu5NX55g==} @@ -3077,6 +3461,9 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3096,6 +3483,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -3126,6 +3516,18 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.2.0: + resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -3277,6 +3679,9 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.41.1: resolution: {integrity: sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3287,9 +3692,15 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -3580,6 +3991,9 @@ packages: style-mod@4.1.2: resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + superjson@2.2.2: resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} engines: {node: '>=16'} @@ -3619,6 +4033,9 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -3649,6 +4066,10 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + ts-jest@29.3.4: resolution: {integrity: sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -3706,6 +4127,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -3771,6 +4195,10 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -3876,6 +4304,26 @@ packages: postcss: optional: true + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + vue@3.5.16: resolution: {integrity: sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==} peerDependencies: @@ -4070,6 +4518,13 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.3.0 + tinyexec: 1.0.1 + + '@antfu/utils@8.1.1': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -4259,6 +4714,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@braintree/sanitize-url@7.1.1': {} + '@bufbuild/protobuf@2.6.1': {} '@changesets/apply-release-plan@7.0.12': @@ -4403,6 +4860,23 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/regexp-to-ast@11.0.3': {} + + '@chevrotain/types@11.0.3': {} + + '@chevrotain/utils@11.0.3': {} + '@codemirror/language@6.11.1': dependencies: '@codemirror/state': 6.5.2 @@ -4649,6 +5123,19 @@ snapshots: '@iconify/types@2.0.0': {} + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.1 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -4874,6 +5361,10 @@ snapshots: '@marijn/find-cluster-break@1.0.2': {} + '@mermaid-js/parser@0.3.0': + dependencies: + langium: 3.0.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5169,6 +5660,127 @@ snapshots: dependencies: '@types/tern': 0.23.9 + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/dompurify@3.2.0': + dependencies: + dompurify: 3.1.6 + '@types/emscripten@1.40.1': {} '@types/esprima@4.0.6': @@ -5183,6 +5795,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 22.15.29 @@ -5825,6 +6439,20 @@ snapshots: chardet@0.7.0: {} + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.21 + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -5875,8 +6503,16 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@7.2.0: {} + + commander@8.3.0: {} + concat-map@0.0.1: {} + confbox@0.1.8: {} + + confbox@0.2.2: {} + console-control-strings@1.1.0: {} convert-source-map@2.0.0: {} @@ -5885,6 +6521,14 @@ snapshots: dependencies: is-what: 4.1.16 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + create-jest@29.7.0(@types/node@22.15.29): dependencies: '@jest/types': 29.6.3 @@ -5910,6 +6554,192 @@ snapshots: csstype@3.1.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.0 + + cytoscape-fcose@2.2.0(cytoscape@3.33.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.0 + + cytoscape@3.33.0: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.11: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.21 + + dayjs@1.11.13: {} + debug@4.4.1: dependencies: ms: 2.1.3 @@ -5936,6 +6766,10 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + delegates@1.0.0: {} dequal@2.0.3: {} @@ -5959,6 +6793,8 @@ snapshots: dependencies: path-type: 4.0.0 + dompurify@3.1.6: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6190,6 +7026,8 @@ snapshots: exponential-backoff@3.1.2: {} + exsolve@1.0.7: {} + extendable-error@0.1.7: {} external-editor@3.1.0: @@ -6364,6 +7202,8 @@ snapshots: globals@14.0.0: {} + globals@15.15.0: {} + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -6415,6 +7255,8 @@ snapshots: events: 3.3.0 graphology-types: 0.24.8 + hachure-fill@0.5.2: {} + handlebars@4.7.8: dependencies: minimist: 1.2.8 @@ -6503,7 +7345,6 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - optional: true ieee754@1.2.1: {} @@ -6540,6 +7381,10 @@ snapshots: inherits@2.0.4: {} + internmap@1.0.1: {} + + internmap@2.0.3: {} + ip-address@9.0.5: dependencies: jsbn: 1.1.0 @@ -7003,12 +7848,32 @@ snapshots: static-eval: 2.0.2 underscore: 1.12.1 + katex@0.16.22: + dependencies: + commander: 8.3.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + khroma@2.1.0: {} + kleur@3.0.3: {} + kolorist@1.8.0: {} + + langium@3.0.0: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + leven@3.1.0: {} levn@0.3.0: @@ -7023,6 +7888,12 @@ snapshots: lines-and-columns@1.2.4: {} + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.2.0 + quansync: 0.2.10 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -7031,6 +7902,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} @@ -7102,6 +7975,8 @@ snapshots: markdown-table-ts@1.0.3: {} + marked@13.0.3: {} + math-intrinsics@1.1.0: {} mdast-util-to-hast@13.2.0: @@ -7120,6 +7995,32 @@ snapshots: merge2@1.4.1: {} + mermaid@11.4.0: + dependencies: + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 2.3.0 + '@mermaid-js/parser': 0.3.0 + '@types/d3': 7.4.3 + '@types/dompurify': 3.2.0 + cytoscape: 3.33.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.0) + cytoscape-fcose: 2.2.0(cytoscape@3.33.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.11 + dayjs: 1.11.13 + dompurify: 3.1.6 + katex: 0.16.22 + khroma: 2.1.0 + lodash-es: 4.17.21 + marked: 13.0.3 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + micromark-util-character@2.1.1: dependencies: micromark-util-symbol: 2.0.1 @@ -7203,6 +8104,13 @@ snapshots: mkdirp@1.0.4: {} + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + mnemonist@0.39.8: dependencies: obliterator: 2.0.5 @@ -7371,6 +8279,8 @@ snapshots: dependencies: quansync: 0.2.10 + package-manager-detector@1.3.0: {} + pandemonium@2.4.1: dependencies: mnemonist: 0.39.8 @@ -7388,6 +8298,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + path-data-parser@0.1.0: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -7398,6 +8310,8 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + perfect-debounce@1.0.0: {} picocolors@1.1.1: {} @@ -7416,6 +8330,25 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + pkg-types@2.2.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + possible-typed-array-names@1.1.0: {} postcss@8.5.4: @@ -7541,6 +8474,8 @@ snapshots: dependencies: glob: 7.2.3 + robust-predicates@3.0.2: {} + rollup@4.41.1: dependencies: '@types/estree': 1.0.7 @@ -7593,10 +8528,19 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.45.1 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -7851,6 +8795,8 @@ snapshots: style-mod@4.1.2: {} + stylis@4.3.6: {} + superjson@2.2.2: dependencies: copy-anything: 3.0.5 @@ -7890,6 +8836,8 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + tinyexec@1.0.1: {} + tinyglobby@0.2.14: dependencies: fdir: 6.4.5(picomatch@4.0.2) @@ -7915,6 +8863,8 @@ snapshots: dependencies: typescript: 5.8.3 + ts-dedent@2.2.0: {} + ts-jest@29.3.4(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(esbuild@0.25.5)(jest@29.7.0(@types/node@22.15.29))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 @@ -7956,6 +8906,8 @@ snapshots: typescript@5.8.3: {} + ufo@1.6.1: {} + uglify-js@3.19.3: optional: true @@ -8022,6 +8974,8 @@ snapshots: uuid@11.1.0: {} + uuid@9.0.1: {} + v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -8119,6 +9073,23 @@ snapshots: - universal-cookie - yaml + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} + vue@3.5.16(typescript@5.8.3): dependencies: '@vue/compiler-dom': 3.5.16 diff --git a/src/modules/explorer/Editor.ts b/src/modules/explorer/Editor.ts index c8bfb40..4365f37 100644 --- a/src/modules/explorer/Editor.ts +++ b/src/modules/explorer/Editor.ts @@ -47,9 +47,7 @@ export class Editor { this.createCodeblockProcessor(this.codeblockElement, this.query); if (this.db) { - // rendering structure - const schema = this.db.getSchema() - const vis = new SchemaVisualiser(schema) + const vis = new SchemaVisualiser(this.db) vis.show(structure) } else { } diff --git a/src/modules/explorer/database/memoryDatabase.ts b/src/modules/explorer/database/memoryDatabase.ts index dcfc6ae..52b9f19 100644 --- a/src/modules/explorer/database/memoryDatabase.ts +++ b/src/modules/explorer/database/memoryDatabase.ts @@ -39,6 +39,73 @@ export class MemoryDatabase { return this.query<{ name: string, type: string }>('select name, type from pragma_table_info(@tableName)', { '@tableName': tableName }) } + getDetailedTableInfo(tableName: string) { + const result = this.query<{ + name: string, + type: string, + pk: number, + dflt_value: any, + notnull: number + }>(` + SELECT name, type, pk, dflt_value, [notnull] + FROM pragma_table_info(@tableName) + `, { '@tableName': tableName }) + + return result.data.map(row => ({ + name: row.name, + type: row.type, + isPrimaryKey: row.pk === 1, + defaultValue: row.dflt_value, + notNull: row.notnull === 1 + })) + } + + getForeignKeys(tableName: string) { + const result = this.query<{ + id: number, + seq: number, + table: string, + from: string, + to: string, + on_update: string, + on_delete: string, + match: string + }>(` + SELECT id, seq, [table], [from], [to], on_update, on_delete, [match] + FROM pragma_foreign_key_list(@tableName) + `, { '@tableName': tableName }) + + return result.data.map(row => ({ + id: row.id, + seq: row.seq, + referencedTable: row.table, + fromColumn: row.from, + toColumn: row.to, + onUpdate: row.on_update, + onDelete: row.on_delete, + match: row.match + })) + } + + getAllTables() { + const result = this.query<{ name: string }>(` + SELECT name FROM sqlite_master + WHERE type='table' AND name NOT LIKE 'sqlite_%' + ORDER BY name + `) + + return result.data.map(row => row.name) + } + + getDetailedSchema() { + const tables = this.getAllTables() + return tables.map(tableName => ({ + name: tableName, + columns: this.getDetailedTableInfo(tableName), + foreignKeys: this.getForeignKeys(tableName) + })) + } + getSchema(): TableInfo[] { const tables = this.allTables().data return tables.map(t => { diff --git a/src/modules/explorer/schemaVisualiser/SchemaVisualiser.ts b/src/modules/explorer/schemaVisualiser/SchemaVisualiser.ts index 94c1186..02d39e7 100644 --- a/src/modules/explorer/schemaVisualiser/SchemaVisualiser.ts +++ b/src/modules/explorer/schemaVisualiser/SchemaVisualiser.ts @@ -1,14 +1,684 @@ -import { TableInfo, TableVisualiser } from "./TableVisualiser" +import mermaid from 'mermaid' +import { MemoryDatabase } from '../database/memoryDatabase' + +export interface DetailedColumnInfo { + name: string + type: string + isPrimaryKey: boolean + defaultValue: any + notNull: boolean +} + +export interface ForeignKeyInfo { + id: number + seq: number + referencedTable: string + fromColumn: string + toColumn: string + onUpdate: string + onDelete: string + match: string +} + +export interface DetailedTableInfo { + name: string + columns: DetailedColumnInfo[] + foreignKeys: ForeignKeyInfo[] +} export class SchemaVisualiser { - constructor(private info: TableInfo[]) { } + private initialized = false + + constructor(private database: MemoryDatabase) { + this.initializeMermaid() + } - show(container: HTMLElement) { + private initializeMermaid() { + if (this.initialized) return + + mermaid.initialize({ + startOnLoad: false, + theme: 'default', + securityLevel: 'loose', + er: { + diagramPadding: 20, + layoutDirection: 'TB', + minEntityWidth: 120, + minEntityHeight: 80, + entityPadding: 15, + stroke: '#666', + fill: '#f9f9f9', + fontSize: 12, + // Relationship line styling + relationshipLabelColor: '#333', + relationshipLabelBackground: '#fff', + relationshipLabelBorder: '#666', + // Make relationships more visible + primaryColor: '#4a90e2', + primaryTextColor: '#333', + primaryBorderColor: '#666', + lineColor: '#666', + arrowheadColor: '#666', + // Force full width usage + useMaxWidth: true + }, + flowchart: { + useMaxWidth: true, + htmlLabels: true + } + }) + + this.initialized = true + } + + async show(container: HTMLElement) { container.empty() - const c = container.createDiv({ cls: 'sqlseal-tv-container' }) - this.info - .map(i => new TableVisualiser(i)) - .forEach(v => v.show(c)) + try { + const schema = await this.buildSchema() + const mermaidCode = this.generateMermaidERD(schema) + + // Debug: Log the generated Mermaid code + console.log('Generated Mermaid ERD Code:', mermaidCode) + console.log('Schema tables detected:', schema.map(t => ({ + original: t.name, + escaped: this.escapeMermaidIdentifier(t.name) + }))) + + const diagramContainer = container.createDiv({ + cls: 'sqlseal-mermaid-container', + attr: { + id: `mermaid-${Date.now()}` + } + }) + + const { svg } = await mermaid.render(`diagram-${Date.now()}`, mermaidCode) + diagramContainer.innerHTML = svg + + // Ensure SVG takes full width + const svgElement = diagramContainer.querySelector('svg') + if (svgElement) { + svgElement.setAttribute('width', '100%') + svgElement.setAttribute('height', '100%') + svgElement.style.width = '100%' + svgElement.style.height = '100%' + svgElement.style.maxWidth = 'none' + // Set viewBox to preserve aspect ratio while filling container + const viewBox = svgElement.getAttribute('viewBox') + if (viewBox) { + svgElement.setAttribute('preserveAspectRatio', 'xMidYMid meet') + } + } + + // Add pan and zoom functionality + this.addPanZoom(diagramContainer) + + // Add interactive features + this.addInteractivity(diagramContainer, schema) + + // Remove relationship summary - user requested removal + + } catch (error) { + console.error('Error rendering Mermaid schema:', error) + console.error('Error details:', { + message: error instanceof Error ? error.message : 'Unknown error', + stack: error instanceof Error ? error.stack : undefined + }) + + // Fallback to simple schema display + this.showFallbackSchema(container, await this.buildSchema()) + } + } + + private async buildSchema(): Promise { + const schema = this.database.getDetailedSchema() + return schema + } + + private generateMermaidERD(schema: DetailedTableInfo[]): string { + let mermaidCode = 'erDiagram\n' + + // Define entities with their attributes + for (const table of schema) { + const escapedTableName = this.escapeMermaidIdentifier(table.name) + mermaidCode += ` ${escapedTableName} {\n` + + for (const column of table.columns) { + const typeAnnotation = this.getColumnTypeAnnotation(column) + const keyAnnotation = this.getKeyAnnotation(column, table.foreignKeys) + const escapedColumnName = this.escapeMermaidIdentifier(column.name) + + mermaidCode += ` ${column.type} ${escapedColumnName}${keyAnnotation}\n` + } + + mermaidCode += ' }\n\n' + } + + // Define relationships based on foreign keys + const relationships = new Set() + + for (const table of schema) { + for (const fk of table.foreignKeys) { + // Create a more descriptive relationship with column information + // Escape column names in the relationship label as well + const escapedFromColumn = fk.fromColumn.includes(' ') ? `"${fk.fromColumn}"` : fk.fromColumn + const escapedToColumn = fk.toColumn.includes(' ') ? `"${fk.toColumn}"` : fk.toColumn + const relationshipLabel = `"${escapedFromColumn} → ${escapedToColumn}"` + + // Determine cardinality based on foreign key constraints + const cardinality = this.determineCardinality(table, fk, schema) + + // Escape table names for Mermaid + const escapedSourceTable = this.escapeMermaidIdentifier(fk.referencedTable) + const escapedTargetTable = this.escapeMermaidIdentifier(table.name) + + const relationship = ` ${escapedSourceTable} ${cardinality} ${escapedTargetTable} : ${relationshipLabel}` + relationships.add(relationship) + } + } + + // Add relationships section with clear separation + if (relationships.size > 0) { + mermaidCode += '\n %% Relationships\n' + mermaidCode += Array.from(relationships).join('\n') + mermaidCode += '\n' + } + + return mermaidCode + } + + private escapeMermaidIdentifier(identifier: string): string { + // Mermaid requires identifiers with spaces or special characters to be quoted + // Also handle other problematic characters + + // Check if identifier contains spaces, hyphens, or other special characters + const needsQuoting = /[\s\-\.\(\)\[\]{}'"!@#$%^&*+=|\\:;,<>?/~`]/.test(identifier) + + if (needsQuoting) { + // Escape any existing quotes and wrap in quotes + const escaped = identifier.replace(/"/g, '\\"') + return `"${escaped}"` + } + + return identifier + } + + private determineCardinality(table: DetailedTableInfo, fk: ForeignKeyInfo, schema: DetailedTableInfo[]): string { + // Check if the foreign key column is also a primary key (indicates 1:1 relationship) + const fkColumn = table.columns.find(col => col.name === fk.fromColumn) + const isOneToOne = fkColumn?.isPrimaryKey + + // Check if there are unique constraints (would also indicate 1:1 or 1:0..1) + // For now, we'll use simple heuristics: + + if (isOneToOne) { + // One-to-one relationship + return '||--||' + } else { + // Default to one-to-many relationship (most common in normalized databases) + // Parent (referenced table) to Child (referencing table) + return '||--o{' + } + + // Future enhancements could include: + // - Detecting many-to-many through junction tables: }o--o{ + // - Optional relationships with: ||--o| + // - Zero-or-one relationships with: }o--|| + } + + private getColumnTypeAnnotation(column: DetailedColumnInfo): string { + const annotations = [] + if (column.notNull) annotations.push('NOT NULL') + if (column.defaultValue !== null) annotations.push(`DEFAULT ${column.defaultValue}`) + return annotations.length > 0 ? ` (${annotations.join(', ')})` : '' + } + + private getKeyAnnotation(column: DetailedColumnInfo, foreignKeys: ForeignKeyInfo[]): string { + if (column.isPrimaryKey) return ' PK' + + const fk = foreignKeys.find(fk => fk.fromColumn === column.name) + if (fk) return ' FK' + + return '' + } + + private addPanZoom(container: HTMLElement) { + const svg = container.querySelector('svg') + if (!svg) return + + // Create zoom and pan state with object references for proper binding + const zoomRef = { value: 1 } + const panRef = { x: 0, y: 0 } + let isDragging = false + let lastMousePos = { x: 0, y: 0 } + + // Set up SVG for pan/zoom + svg.style.cursor = 'grab' + svg.style.overflow = 'hidden' + + // Create a group element to contain all SVG content for transformations + const existingContent = svg.innerHTML + svg.innerHTML = `${existingContent}` + const panZoomGroup = svg.querySelector('.pan-zoom-group') as SVGGElement + + const updateTransform = () => { + if (panZoomGroup) { + panZoomGroup.setAttribute('transform', + `translate(${panRef.x}, ${panRef.y}) scale(${zoomRef.value})` + ) + } + } + + // Add zoom controls UI + this.addZoomControls(container, zoomRef, panRef, updateTransform) + + // Wheel zoom + svg.addEventListener('wheel', (e) => { + e.preventDefault() + + const rect = svg.getBoundingClientRect() + const mouseX = e.clientX - rect.left + const mouseY = e.clientY - rect.top + + const delta = e.deltaY > 0 ? 0.9 : 1.1 + const oldZoom = zoomRef.value + const newZoom = Math.max(0.1, Math.min(5, oldZoom * delta)) + + if (newZoom !== oldZoom) { + // Calculate mouse position in the transformed coordinate space + const mouseWorldX = (mouseX - panRef.x) / oldZoom + const mouseWorldY = (mouseY - panRef.y) / oldZoom + + // Update zoom + zoomRef.value = newZoom + + // Adjust pan to keep mouse position fixed in world space + panRef.x = mouseX - mouseWorldX * newZoom + panRef.y = mouseY - mouseWorldY * newZoom + + updateTransform() + this.updateZoomDisplay(container, zoomRef.value) + } + }) + + // Mouse drag panning + svg.addEventListener('mousedown', (e) => { + if (e.button === 0) { // Left mouse button + isDragging = true + lastMousePos = { x: e.clientX, y: e.clientY } + svg.style.cursor = 'grabbing' + e.preventDefault() + } + }) + + const handleMouseMove = (e: MouseEvent) => { + if (!isDragging) return + + const deltaX = e.clientX - lastMousePos.x + const deltaY = e.clientY - lastMousePos.y + + panRef.x += deltaX + panRef.y += deltaY + + lastMousePos = { x: e.clientX, y: e.clientY } + updateTransform() + e.preventDefault() + } + + const handleMouseUp = () => { + if (isDragging) { + isDragging = false + svg.style.cursor = 'grab' + } + } + + // Attach global mouse events for smooth dragging + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('mouseup', handleMouseUp) + + // Touch support for mobile + let lastTouchPos: { x: number, y: number } | null = null + let initialTouchDistance: number | null = null + let initialZoom = zoomRef.value + + svg.addEventListener('touchstart', (e) => { + e.preventDefault() + + if (e.touches.length === 1) { + // Single touch - panning + const touch = e.touches[0] + lastTouchPos = { x: touch.clientX, y: touch.clientY } + } else if (e.touches.length === 2) { + // Two finger pinch - zooming + const touch1 = e.touches[0] + const touch2 = e.touches[1] + initialTouchDistance = Math.hypot( + touch2.clientX - touch1.clientX, + touch2.clientY - touch1.clientY + ) + initialZoom = zoomRef.value + lastTouchPos = null + } + }) + + svg.addEventListener('touchmove', (e) => { + e.preventDefault() + + if (e.touches.length === 1 && lastTouchPos) { + // Single touch panning + const touch = e.touches[0] + const deltaX = touch.clientX - lastTouchPos.x + const deltaY = touch.clientY - lastTouchPos.y + + panRef.x += deltaX + panRef.y += deltaY + + lastTouchPos = { x: touch.clientX, y: touch.clientY } + updateTransform() + } else if (e.touches.length === 2 && initialTouchDistance) { + // Two finger pinch zoom + const touch1 = e.touches[0] + const touch2 = e.touches[1] + const currentDistance = Math.hypot( + touch2.clientX - touch1.clientX, + touch2.clientY - touch1.clientY + ) + + const scale = currentDistance / initialTouchDistance + zoomRef.value = Math.max(0.1, Math.min(5, initialZoom * scale)) + + updateTransform() + this.updateZoomDisplay(container, zoomRef.value) + } + }) + + svg.addEventListener('touchend', () => { + lastTouchPos = null + initialTouchDistance = null + }) + + // Double-click to reset zoom and pan + svg.addEventListener('dblclick', (e) => { + e.preventDefault() + zoomRef.value = 1 + panRef.x = 0 + panRef.y = 0 + updateTransform() + this.updateZoomDisplay(container, zoomRef.value) + }) + + } + + private addZoomControls(container: HTMLElement, localZoom: { value: number }, localPan: { x: number, y: number }, updateTransform: () => void) { + const controlsContainer = container.createDiv({ cls: 'sqlseal-zoom-controls' }) + + // Animation state + let isAnimating = false + + const animateZoom = (targetZoom: number, targetPanX: number, targetPanY: number, duration: number = 200) => { + if (isAnimating) return + isAnimating = true + + const startZoom = localZoom.value + const startPanX = localPan.x + const startPanY = localPan.y + const startTime = Date.now() + + const animate = () => { + const elapsed = Date.now() - startTime + const progress = Math.min(elapsed / duration, 1) + + // Easing function - ease out cubic + const easeProgress = 1 - Math.pow(1 - progress, 3) + + localZoom.value = startZoom + (targetZoom - startZoom) * easeProgress + localPan.x = startPanX + (targetPanX - startPanX) * easeProgress + localPan.y = startPanY + (targetPanY - startPanY) * easeProgress + + updateTransform() + this.updateZoomDisplay(container, localZoom.value) + + if (progress < 1) { + requestAnimationFrame(animate) + } else { + isAnimating = false + // Ensure final values are exact + localZoom.value = targetZoom + localPan.x = targetPanX + localPan.y = targetPanY + updateTransform() + this.updateZoomDisplay(container, localZoom.value) + } + } + + requestAnimationFrame(animate) + } + + // Reset button (home) - first + const resetBtn = controlsContainer.createEl('button', { + cls: 'sqlseal-zoom-btn', + text: '⌂', + attr: { title: 'Reset View' } + }) + resetBtn.addEventListener('click', () => { + animateZoom(1, 0, 0, 300) + }) + + // Zoom in button - second + const zoomInBtn = controlsContainer.createEl('button', { + cls: 'sqlseal-zoom-btn', + text: '+', + attr: { title: 'Zoom In' } + }) + zoomInBtn.addEventListener('click', () => { + const newZoom = Math.min(5, localZoom.value * 1.2) + animateZoom(newZoom, localPan.x, localPan.y, 150) + }) + + // Zoom out button - third + const zoomOutBtn = controlsContainer.createEl('button', { + cls: 'sqlseal-zoom-btn', + text: '−', + attr: { title: 'Zoom Out' } + }) + zoomOutBtn.addEventListener('click', () => { + const newZoom = Math.max(0.1, localZoom.value / 1.2) + animateZoom(newZoom, localPan.x, localPan.y, 150) + }) + + // Zoom level display + const zoomDisplay = controlsContainer.createDiv({ + cls: 'sqlseal-zoom-display' + }) + this.updateZoomDisplay(container, localZoom.value) + } + + private updateZoomDisplay(container: HTMLElement, zoom: number) { + const display = container.querySelector('.sqlseal-zoom-display') + if (display) { + display.textContent = `${Math.round(zoom * 100)}%` + } + } + + + private addInteractivity(container: HTMLElement, schema: DetailedTableInfo[]) { + // Add click handlers for tables to show detailed information + const tableElements = container.querySelectorAll('[id^="entity-"]') + + tableElements.forEach((element, index) => { + if (index < schema.length) { + const table = schema[index] + element.addEventListener('click', () => { + this.showTableDetails(table) + }) + + element.addEventListener('mouseenter', () => { + element.classList.add('highlighted') + }) + + element.addEventListener('mouseleave', () => { + element.classList.remove('highlighted') + }) + } + }) + } + + private showTableDetails(table: DetailedTableInfo) { + // Create a modal or popup with detailed table information + const modal = document.createElement('div') + modal.className = 'sqlseal-table-details-modal' + + const content = document.createElement('div') + content.className = 'sqlseal-modal-content' + + const title = document.createElement('h3') + title.textContent = `Table: ${table.name}` + content.appendChild(title) + + // Columns section + const columnsTitle = document.createElement('h4') + columnsTitle.textContent = 'Columns' + content.appendChild(columnsTitle) + + const columnsTable = document.createElement('table') + columnsTable.className = 'sqlseal-columns-table' + + const headerRow = columnsTable.createTHead().insertRow() + headerRow.insertCell().textContent = 'Name' + headerRow.insertCell().textContent = 'Type' + headerRow.insertCell().textContent = 'Key' + headerRow.insertCell().textContent = 'Nullable' + headerRow.insertCell().textContent = 'Default' + + const tbody = columnsTable.createTBody() + table.columns.forEach(column => { + const row = tbody.insertRow() + row.insertCell().textContent = column.name + row.insertCell().textContent = column.type + row.insertCell().textContent = column.isPrimaryKey ? 'PK' : '' + row.insertCell().textContent = column.notNull ? 'NO' : 'YES' + row.insertCell().textContent = column.defaultValue || '' + }) + + content.appendChild(columnsTable) + + // Foreign keys section + if (table.foreignKeys.length > 0) { + const fkTitle = document.createElement('h4') + fkTitle.textContent = 'Foreign Keys' + content.appendChild(fkTitle) + + const fkTable = document.createElement('table') + fkTable.className = 'sqlseal-fk-table' + + const fkHeaderRow = fkTable.createTHead().insertRow() + fkHeaderRow.insertCell().textContent = 'Column' + fkHeaderRow.insertCell().textContent = 'References' + fkHeaderRow.insertCell().textContent = 'On Update' + fkHeaderRow.insertCell().textContent = 'On Delete' + + const fkTbody = fkTable.createTBody() + table.foreignKeys.forEach(fk => { + const row = fkTbody.insertRow() + row.insertCell().textContent = fk.fromColumn + row.insertCell().textContent = `${fk.referencedTable}.${fk.toColumn}` + row.insertCell().textContent = fk.onUpdate + row.insertCell().textContent = fk.onDelete + }) + + content.appendChild(fkTable) + } + + // Close button + const closeBtn = document.createElement('button') + closeBtn.textContent = '×' + closeBtn.className = 'sqlseal-modal-close' + closeBtn.onclick = () => modal.remove() + + modal.appendChild(content) + modal.appendChild(closeBtn) + document.body.appendChild(modal) + + // Close on backdrop click + modal.onclick = (e) => { + if (e.target === modal) modal.remove() + } + } + + + private showFallbackSchema(container: HTMLElement, schema: DetailedTableInfo[]) { + container.empty() + + const fallbackContainer = container.createDiv({ + cls: 'sqlseal-fallback-schema' + }) + + const title = fallbackContainer.createEl('h3', { + text: 'Database Schema (Fallback View)' + }) + + if (schema.length === 0) { + fallbackContainer.createEl('p', { + text: 'No tables found in the database.', + cls: 'sqlseal-empty-schema' + }) + return + } + + schema.forEach(table => { + const tableContainer = fallbackContainer.createDiv({ + cls: 'sqlseal-fallback-table' + }) + + const tableTitle = tableContainer.createEl('h4', { + text: table.name, + cls: 'sqlseal-fallback-table-title' + }) + + if (table.columns.length > 0) { + const columnsTable = tableContainer.createEl('table', { + cls: 'sqlseal-fallback-columns-table' + }) + + const headerRow = columnsTable.createTHead().insertRow() + headerRow.insertCell().textContent = 'Column' + headerRow.insertCell().textContent = 'Type' + headerRow.insertCell().textContent = 'Key' + headerRow.insertCell().textContent = 'Constraints' + + const tbody = columnsTable.createTBody() + table.columns.forEach(column => { + const row = tbody.insertRow() + row.insertCell().textContent = column.name + row.insertCell().textContent = column.type + + let keyType = '' + if (column.isPrimaryKey) keyType = 'PK' + else if (table.foreignKeys.some(fk => fk.fromColumn === column.name)) keyType = 'FK' + row.insertCell().textContent = keyType + + const constraints = [] + if (column.notNull) constraints.push('NOT NULL') + if (column.defaultValue !== null) constraints.push(`DEFAULT ${column.defaultValue}`) + row.insertCell().textContent = constraints.join(', ') + }) + } + + if (table.foreignKeys.length > 0) { + const fkTitle = tableContainer.createEl('h5', { + text: 'Foreign Keys', + cls: 'sqlseal-fallback-fk-title' + }) + + const fkList = tableContainer.createEl('ul', { + cls: 'sqlseal-fallback-fk-list' + }) + + table.foreignKeys.forEach(fk => { + const fkItem = fkList.createEl('li') + fkItem.textContent = `${fk.fromColumn} → ${fk.referencedTable}.${fk.toColumn}` + }) + } + }) } } \ No newline at end of file diff --git a/src/modules/explorer/schemaVisualiser/schemaVisualiser.scss b/src/modules/explorer/schemaVisualiser/schemaVisualiser.scss index 62ebbf3..b6101cc 100644 --- a/src/modules/explorer/schemaVisualiser/schemaVisualiser.scss +++ b/src/modules/explorer/schemaVisualiser/schemaVisualiser.scss @@ -1,3 +1,4 @@ +// Legacy styles - kept for backward compatibility .sqlseal-tv-container { gap: 1em; } @@ -26,4 +27,362 @@ flex-direction: row; gap: 1em; justify-content: space-between; +} + +// New Mermaid-based schema visualizer styles +.sqlseal-mermaid-container { + width: 100%; + height: 100%; + overflow: hidden; + background: var(--background-primary); + + svg { + width: 100%; + height: 100%; + display: block; + } + + // Interactive elements + [id^="entity-"] { + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + opacity: 0.8; + } + + &.highlighted { + filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3)); + } + } + + // Relationship lines and arrows - make them more visible + .er.relationshipLine { + stroke: var(--text-accent) !important; + stroke-width: 2px !important; + opacity: 0.8; + } + + // Relationship labels + .er.relationshipLabel { + fill: var(--text-accent) !important; + font-family: var(--font-interface); + font-size: 11px !important; + font-weight: 500; + } + + // Arrow markers for relationships + .er marker { + fill: var(--text-accent) !important; + stroke: var(--text-accent) !important; + } + + // Entity boxes + .er.entityBox { + fill: var(--background-secondary); + stroke: var(--background-modifier-border); + stroke-width: 1px; + } + + // Entity labels + .er.entityLabel { + fill: var(--text-normal); + font-family: var(--font-interface); + font-size: 14px; + font-weight: 600; + } + + // Attribute text + .er.attributeBoxEven, + .er.attributeBoxOdd { + fill: var(--background-primary-alt); + stroke: var(--background-modifier-border); + } + + .er.attributeBoxEven { + fill: var(--background-primary); + } + + // Enhance cardinality symbols (crow's foot notation) + .er .cardinality text { + fill: var(--text-accent) !important; + font-family: var(--font-interface); + font-size: 14px !important; + font-weight: bold; + } + + // Ensure all relationship elements are visible + path[id*="relationship"] { + stroke: var(--text-accent) !important; + stroke-width: 2px !important; + marker-end: url(#arrowhead) !important; + } + + // Style the actual relationship paths + g[id*="relationship"] path { + stroke: var(--text-accent) !important; + stroke-width: 2px !important; + fill: none !important; + } + + // Make sure arrowheads are visible + defs marker path { + fill: var(--text-accent) !important; + stroke: var(--text-accent) !important; + } +} + +// Pan and zoom controls - minimalist bottom right +.sqlseal-zoom-controls { + position: absolute; + bottom: 10px; + right: 10px; + display: flex; + align-items: center; + gap: 2px; + z-index: 10; + + .sqlseal-zoom-btn { + width: 28px; + height: 28px; + background: var(--background-primary); + border: 1px solid var(--background-modifier-border); + border-radius: 4px; + color: var(--text-normal); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + font-weight: bold; + transition: all 0.2s ease; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + + &:hover { + background: var(--background-modifier-hover); + border-color: var(--text-accent); + transform: translateY(-1px); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); + } + + &:active { + transform: translateY(0) scale(0.95); + } + } + + .sqlseal-zoom-display { + font-size: 10px; + color: var(--text-muted); + font-family: var(--font-monospace); + padding: 2px 6px; + background: var(--background-primary); + border: 1px solid var(--background-modifier-border); + border-radius: 4px; + margin-left: 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + min-width: 42px; + text-align: center; + font-weight: 500; + } +} + +// Make the mermaid container relative for absolute positioning of controls +.sqlseal-mermaid-container { + position: relative; + + svg { + // Enable smooth transitions for pan/zoom + transition: none; // Disable transitions during interaction + + // Cursor styles for interaction states + &.grabbing { + cursor: grabbing !important; + } + } + + .pan-zoom-group { + transform-origin: 0 0; + } +} + +// Modal styles for table details +.sqlseal-table-details-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + + .sqlseal-modal-content { + background: var(--background-primary); + border: 1px solid var(--background-modifier-border); + border-radius: 8px; + padding: 24px; + max-width: 80vw; + max-height: 80vh; + overflow-y: auto; + position: relative; + + h3, h4 { + color: var(--text-normal); + margin: 0 0 16px 0; + } + + h4 { + margin-top: 24px; + font-size: 1.1em; + } + } + + .sqlseal-modal-close { + position: absolute; + top: 12px; + right: 16px; + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: var(--text-muted); + padding: 4px 8px; + border-radius: 4px; + + &:hover { + background: var(--background-modifier-hover); + color: var(--text-normal); + } + } +} + +// Table styles for modal content +.sqlseal-columns-table, +.sqlseal-fk-table { + width: 100%; + border-collapse: collapse; + margin: 12px 0; + font-family: var(--font-interface); + + th, td { + border: 1px solid var(--background-modifier-border); + padding: 8px 12px; + text-align: left; + } + + th { + background: var(--background-secondary); + font-weight: 600; + color: var(--text-normal); + } + + td { + background: var(--background-primary); + color: var(--text-normal); + } + + tr:nth-child(even) td { + background: var(--background-primary-alt); + } +} + +// Error message styling +.sqlseal-error { + color: var(--text-error); + padding: 16px; + text-align: center; + font-style: italic; +} + +// Fallback schema styles +.sqlseal-fallback-schema { + padding: 16px; + font-family: var(--font-interface); + + h3 { + color: var(--text-normal); + margin: 0 0 20px 0; + text-align: center; + } + + .sqlseal-empty-schema { + color: var(--text-muted); + text-align: center; + font-style: italic; + padding: 40px; + } +} + +.sqlseal-fallback-table { + margin-bottom: 24px; + border: 1px solid var(--background-modifier-border); + border-radius: 6px; + overflow: hidden; + + .sqlseal-fallback-table-title { + background: var(--background-secondary); + color: var(--text-normal); + margin: 0; + padding: 12px 16px; + font-size: 1.1em; + font-weight: 600; + border-bottom: 1px solid var(--background-modifier-border); + } + + .sqlseal-fallback-fk-title { + color: var(--text-normal); + margin: 16px 16px 8px 16px; + font-size: 0.95em; + font-weight: 600; + } + + .sqlseal-fallback-fk-list { + margin: 0 16px 16px 16px; + padding-left: 20px; + + li { + color: var(--text-muted); + font-size: 0.9em; + margin-bottom: 4px; + font-family: var(--font-monospace); + } + } +} + +.sqlseal-fallback-columns-table { + width: 100%; + border-collapse: collapse; + margin: 0; + + th, td { + border: none; + border-bottom: 1px solid var(--background-modifier-border); + padding: 8px 16px; + text-align: left; + font-size: 0.9em; + } + + th { + background: var(--background-primary-alt); + font-weight: 600; + color: var(--text-normal); + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.5px; + } + + td { + background: var(--background-primary); + color: var(--text-normal); + } + + tr:nth-child(even) td { + background: var(--background-primary-alt); + } + + tr:last-child td { + border-bottom: none; + } } \ No newline at end of file diff --git a/src/modules/globalTables/cells/StatsRenderer.ts b/src/modules/globalTables/cells/StatsRenderer.ts index 9848baa..29414d7 100644 --- a/src/modules/globalTables/cells/StatsRenderer.ts +++ b/src/modules/globalTables/cells/StatsRenderer.ts @@ -16,7 +16,7 @@ export class StatsRenderer implements ICellRendererComp { this.sync() } - public init(params: ICellRendererParams): void { + public init(params: ICellRendererParams) { const { value, data, context } = params; this.context = context this.data = data! @@ -30,11 +30,11 @@ export class StatsRenderer implements ICellRendererComp { requestAnimationFrame(async () => { this.sync() }) // Watching for the changes - this.setupWatchersAsync(context, data!) + this.setupWatchers(context, data!) } - async setupWatchersAsync(context: GlobalTablesView, data: TableConfiguration) { + async setupWatchers(context: GlobalTablesView, data: TableConfiguration) { this.reg = context.sync.getRegistrator() this.eventName = await context.sync.getEventNameForAlias('/', data!.name) this.reg.on(this.eventName, this.syncFn) diff --git a/styles.css b/styles.css deleted file mode 100644 index 4134ea6..0000000 --- a/styles.css +++ /dev/null @@ -1,2 +0,0 @@ -.sqlseal-table-container{overflow-y:scroll}.sqlseal-table-container table{width:100%;border-collapse:collapse}.sqlseal-grid-wrapper{height:auto;position:relative}.block-language-sqlseal{overflow-y:auto}.sqlseal-error{padding:1em;background:#b80f0f;color:#fff}.sqlseal-notice{padding:1em;background:#1f3f98;color:#fff}.sqlseal-grid-error-message{box-sizing:border-box;width:80%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;background:#b80f0f;font-size:.8em;color:#fff;padding:.5em 2em}.sqlseal-grid-error-message-overlay{content:"";position:absolute;inset:0;background:#fffc;z-index:5}.sqlseal-grid-error-message-overlay.hidden{display:none}.edit-block-button{z-index:1000}.sqlseal-markdown-table{font-family:monospace;white-space:pre-wrap}.sqlseal-markdown-table.no-wrap{display:inline-block;overflow-x:scroll;width:fit-content}.sqlseal-parse-error{background:#b80f0f;color:#fff;padding:.2em;border-radius:2px}.sqlseal-notice-error{color:#f26464}.sqlseal-notice-error:before{content:"";width:16px;height:16px;display:inline-block;margin-right:8px;transform:translateY(3px);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23ff0000' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z'/%3E%3C/svg%3E")}.sql-seal-csv-editor{display:flex;flex-direction:column;height:100%;gap:var(--size-4-4)}.sql-seal-csv-viewer{flex:1;display:flex;flex-direction:column}.sqlseal-grid-wrapper{height:100%;flex:1;display:flex;flex-direction:column}.ag-theme-quartz{flex:1}.sql-seal-csv-viewer-buttons{display:flex;gap:var(--size-4-4)}.sql-seal-modal-code{width:100%;font-family:monospace;padding:8px}.sqlseal-inline-result{display:inline-block;padding:0 4px;margin:0 2px;background-color:var(--background-secondary);border-radius:4px;font-size:.9em;cursor:pointer}.sqlseal-inline-result .error{color:var(--text-error);font-style:italic}.sqlseal-list-element-single .sqlseal-column-name{display:none}.sqlseal-list-element-single .sqlseal-column-name:after{content:": "}.sqlseal-list.show-column-names .sqlseal-list-element-single .sqlseal-column-name{display:inline}.sqlseal-element-inline-list{display:inline-block}.cm-sqlseal-block-query{--color: #297f30}.cm-sqlseal-block-view{--color: #c834dd}.cm-sqlseal-block-flag{--color: #d08306;font-weight:700;color:var(--color)}.cm-sqlseal-block-table{--color: #4985af}.cm-sqlseal-identifier{color:#2d7b33}.cm-sqlseal-function,.cm-sqlseal-parameter{color:#2c0e9b}.cm-sqlseal-comment{color:#7a7a7a;font-style:italic}.cm-sqlseal-keyword{color:var(--color);font-weight:700}.cm-sqlseal-literal{color:#03f}.cm-sqlseal-error{color:#eb2f2f;font-style:italic}.cm-sqlseal-template-keyword{color:#e3ab53}.theme-dark .cm-sqlseal-template-keyword{color:#dd8e10}.theme-dark .cm-sqlseal-block-error{color:red}.theme-dark .cm-sqlseal-block-query{--color: #5eff6a}.theme-dark .cm-sqlseal-comment{color:#898787}.theme-dark .cm-sqlseal-parameter{color:#95ed22}.theme-dark .cm-sqlseal-literal{color:#ff0}.theme-dark .cm-sqlseal-block-view{--color: #e945ff}.theme-dark .cm-sqlseal-block-flag{--color: #e3ab53}.theme-dark .cm-sqlseal-block-table{--color: #56b5fa}.theme-dark .cm-sqlseal-function{color:#c4b8ef}.theme-dark .cm-sqlseal-identifier{color:#6ff77a}:is(.cm-sqlseal-block-query,.cm-sqlseal-block-view,.cm-sqlseal-block-flag,.cm-sqlseal-block-table,.cm-sqlseal-explorer):before{background-color:var(--color);width:5px;top:-3px;bottom:-3px;left:0;content:"";display:block;position:absolute}.cm-indent+:is(.cm-sqlseal-block-query,.cm-sqlseal-block-view,.cm-sqlseal-block-flag,.cm-sqlseal-block-table):before{display:none}.cm-sqlseal-explorer .cm-line{position:relative}.cm-sqlseal-overlay{border:1px solid #AAA;padding:1em;border-radius:5px}.cm-sqlseal-overlay .cm-line{position:relative}.cm-sqlseal-overlay .cm-editor{outline:none}.sqlseal-modal-copycode .setting-item{border:0}.cm-sqlseal-explorer :is(.cm-sqlseal-block-query,.cm-sqlseal-block-view,.cm-sqlseal-block-flag,.cm-sqlseal-block-table):before{left:-3px}.cm-sqlseal-explorer .cm-focused{outline:none}.cm-sqlseal-explorer .cm-editor{border-left-width:0;background:var(--color-base-20);padding:8px}.markdown-source-view.mod-cm6.is-readable-line-width .cm-contentContainer.cm-contentContainer>.cm-content>:has(>.block-language-sqlseal table.dataview){width:var(--container-dataview-table-width);max-width:var(--container-table-max-width)}.ag-checkbox-input{opacity:1!important}.sqlseal-hidden-column{opacity:.5}.sqlseal-settings-warn{background:#ffa600;padding:16px;border:2px solid rgb(134,87,0);border-radius:5px;margin:.5em 2em}.sqlseal-autocomplete-container{position:relative;width:100%}.sqlseal-autocomplete-container input[type=text]{width:100%}.sqlseal-autocomplete-dropdown{position:absolute;top:100%;left:0;margin-top:.5em;right:0;text-align:left;background:#fff;max-height:200px;overflow-y:scroll;border-radius:5px;box-shadow:0 3px 5px #ccc}.modal-overflow{overflow:visible}.sqlseal-dropdown-el{padding:4px 16px 4px 8px;border-top:1px solid #EEE;overflow:hidden}.sqlseal-dropdown-el:first-child{border-top:0}.sqlseal-dropdown-el:hover{background:#a8c4ef}.sqlseal-dropdown-el-name{font-weight:700;font-size:.9em;text-overflow:ellipsis;max-width:100%;overflow:hidden;text-wrap:nowrap}.sqlseal-dropdown-el-path{opacity:.9;font-size:.7em;text-overflow:ellipsis;max-width:100%;overflow:hidden;text-wrap:nowrap}.sqlseal-global-tables-container{height:100%;display:flex;flex-direction:column;gap:1em}.sqlseal-tv-container{gap:1em}.sqlseal-tv-table{display:inline-block;border:1px solid black;margin-right:1em;margin-bottom:1em}.sqlseal-tv-table-name{padding:.5em 1em;background:#ddd;border-bottom:2px solid black}.sqlseal-tv-columns{list-style:none;margin:0;padding:.5em 1em}.sqlseal-tv-columns li{display:flex;flex-direction:row;gap:1em;justify-content:space-between}.sqlseal-explorer-container{height:100%;width:100%;max-height:100%;display:grid;grid-template-rows:auto 1fr}.sqlseal-explorer-grid-container{display:grid;grid-template-columns:50% 50%;gap:1em;height:100%;width:100%;padding:1em}.sqlseal-explorer-render{overflow:scroll}.sqlseal-menubar-container{padding:.2em 0;display:flex}.sqlseal-menubar-container .separator{flex:1}.sqlseal-menubar-button{border:0;--input-shadow: none}.sqlseal-explorer-right-pane{display:grid;container-type:inline-size;height:100%}.sqlseal-explorer-right-pane>*{grid-area:1/1;height:100%}.sqlseal-explorer-right-pane .ag-root-wrapper{height:100%}.sqlseal-explorer-right-pane .ag-root-wrapper-body{flex:1}.sqlseal-explorer-right-pane .ag-paging-page-size,.sqlseal-explorer-right-pane .ag-paging-row-summary-panel{display:none}.sqlseal-explorer-right-pane .ag-paging-panel{justify-content:center} -/*# sourceMappingURL=styles.css.map */