pax_global_header 0000666 0000000 0000000 00000000064 15114061606 0014512 g ustar 00root root 0000000 0000000 52 comment=4b95ad0a0bca6ce4cfa4cb83dfa9be19ca740e8f
tbo47-dagre-es-4b95ad0/ 0000775 0000000 0000000 00000000000 15114061606 0014550 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/.eslintignore 0000664 0000000 0000000 00000000021 15114061606 0017244 0 ustar 00root root 0000000 0000000 dist
node_modules tbo47-dagre-es-4b95ad0/.eslintrc.cjs 0000664 0000000 0000000 00000001544 15114061606 0017156 0 ustar 00root root 0000000 0000000 module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:import/recommended'],
overrides: [
{
files: ['**/*.test.js', 'test/**/*.js'],
env: {
// technically, we are using vitest, but that's pretty similar to jest
jest: true,
},
settings: {
'import/ignore': [
// for some reason, `import {it} from "vitest";` throws an error
/node_modules\/vitest\/dist\/index\.js$/.source,
],
},
},
],
parserOptions: {
sourceType: 'module',
},
rules: {
'import/no-cycle': 'error',
// make sure that all files have an extension (required by ESM)
'import/extensions': [
'error',
'always',
{
js: 'always',
jsx: 'never',
mjs: 'always',
},
],
},
};
tbo47-dagre-es-4b95ad0/.github/ 0000775 0000000 0000000 00000000000 15114061606 0016110 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/.github/FUNDING.yml 0000664 0000000 0000000 00000001274 15114061606 0017731 0 ustar 00root root 0000000 0000000 # These are supported funding model platforms
github: [tbo47]
patreon: teebo47
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
tbo47-dagre-es-4b95ad0/.github/workflows/ 0000775 0000000 0000000 00000000000 15114061606 0020145 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/.github/workflows/test.yml 0000664 0000000 0000000 00000002050 15114061606 0021644 0 ustar 00root root 0000000 0000000 name: CI
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- name: Check for linting errors (run `npm run lint:fix` to fix)
run: npm run lint
- name: Check for prettier errors (run `npm run format` to fix)
run: npx prettier --check .
- name: Check typescript types
# this is not the same as building, since this also checks unit tests
run: npx tsc
- name: Run unit tests
run: npm test
- name: Build the npm package to publish
run: npm pack
- uses: actions/upload-artifact@v4
with:
name: package-${{ matrix.node-version }}
path: '*.tgz'
tbo47-dagre-es-4b95ad0/.gitignore 0000664 0000000 0000000 00000000065 15114061606 0016541 0 ustar 00root root 0000000 0000000 node_modules
dist
.vscode
*.d.ts
tsconfig.tsbuildinfo tbo47-dagre-es-4b95ad0/.prettierrc 0000664 0000000 0000000 00000000057 15114061606 0016736 0 ustar 00root root 0000000 0000000 {
"singleQuote": true,
"printWidth": 100
}
tbo47-dagre-es-4b95ad0/LICENSE.md 0000664 0000000 0000000 00000002460 15114061606 0016156 0 ustar 00root root 0000000 0000000 Original dagre-d3 copyright: Copyright (c) 2013 Chris Pettitt
Original dagre copyright: Copyright (c) 2012-2014 Chris Pettitt
Original graphlib copyright: Copyright (c) 2012-2014 Chris Pettitt
Copyright (c) 2022-2024 Thibaut Lassalle, David Newell, Alois Klink, Sidharth Vinod and dagre-es contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
tbo47-dagre-es-4b95ad0/README.md 0000664 0000000 0000000 00000003323 15114061606 0016030 0 ustar 00root root 0000000 0000000
# dagre-d3-es
[dagre-d3-es](https://www.npmjs.com/package/dagre-d3-es) is a fork of [dagre-d3](https://github.com/dagrejs) using the more modern ES6 javascript syntax.
It uses [ES](https://262.ecma-international.org/6.0/) modules, thus the name [dagre-d3-es](https://www.npmjs.com/package/dagre-d3-es).
[dagre-d3-es](https://www.npmjs.com/package/dagre-d3-es) follows [d3](https://www.npmjs.com/package/d3) versions. Ex: dagre-d3-es version 7 depends on [d3](https://www.npmjs.com/package/d3) version 7.
## Demos
- [simple graph demo](https://codesandbox.io/s/dagre-d3-es-tree-9ywg9) using react
- clone and run [dagre-es-example](https://github.com/tbo47/dagre-es-example) using angular
- [vanilla javascript example](https://tbo47.github.io/dagre-d3-esm_example1/)
- [jsfiddle vanilla javascript example](https://jsfiddle.net/tbo47/fm9ovqeb/)
## Install
```
npm install dagre-d3-es
```
## Code example
Coming from the legacy `dagre-d3`, the main changes in your code will be:
```
import * as dagreD3 from 'dagre-d3-es';
...
const g = new dagreD3.graphlib.Graph().setGraph({});
...
const zoom = d3.zoom().on('zoom', (zoomEvent) => {
inner.attr('transform', zoomEvent.transform);
});
```
tbo47-dagre-es-4b95ad0/bundle.sh 0000775 0000000 0000000 00000000512 15114061606 0016356 0 ustar 00root root 0000000 0000000 rm -rf dist
OUTFILE=dist/dagre-d3.7.0.14.js
npx esbuild src/index.js --bundle --platform=neutral --packages=external --outfile=$OUTFILE
sed -i '' 's|from "d3";|from "https://cdn.jsdelivr.net/npm/d3@7.9.0/+esm";|' $OUTFILE
sed -i '' 's|from "lodash-es"|from "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.min.js"|' $OUTFILE tbo47-dagre-es-4b95ad0/package-lock.json 0000664 0000000 0000000 00000556542 15114061606 0020005 0 ustar 00root root 0000000 0000000 {
"name": "dagre-d3-es",
"version": "7.0.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dagre-d3-es",
"version": "7.0.14",
"license": "MIT",
"dependencies": {
"d3": "^7.9.0",
"lodash-es": "^4.17.21"
},
"devDependencies": {
"@types/d3": "^7.4.3",
"@types/lodash-es": "^4.17.12",
"esbuild": "^0.25.10",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.32.0",
"prettier": "^3.6.2",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
"integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
"integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
"integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
"integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
"integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
"integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
"integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
"integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
"integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
"integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
"integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
"integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
"integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
"integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
"integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
"integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
"integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
"integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
"integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
"integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
"integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
"integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
"integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
"integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
"integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
"integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
"integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/eslintrc": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": {
"node": ">=10.10.0"
}
},
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=12.22"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
}
},
"node_modules/@humanwhocodes/object-schema": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.stat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz",
"integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz",
"integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz",
"integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz",
"integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz",
"integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz",
"integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz",
"integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz",
"integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz",
"integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz",
"integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz",
"integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz",
"integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz",
"integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz",
"integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz",
"integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz",
"integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz",
"integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz",
"integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz",
"integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz",
"integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz",
"integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz",
"integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/chai": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
"integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/deep-eql": "*"
}
},
"node_modules/@types/d3": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
"integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-array": "*",
"@types/d3-axis": "*",
"@types/d3-brush": "*",
"@types/d3-chord": "*",
"@types/d3-color": "*",
"@types/d3-contour": "*",
"@types/d3-delaunay": "*",
"@types/d3-dispatch": "*",
"@types/d3-drag": "*",
"@types/d3-dsv": "*",
"@types/d3-ease": "*",
"@types/d3-fetch": "*",
"@types/d3-force": "*",
"@types/d3-format": "*",
"@types/d3-geo": "*",
"@types/d3-hierarchy": "*",
"@types/d3-interpolate": "*",
"@types/d3-path": "*",
"@types/d3-polygon": "*",
"@types/d3-quadtree": "*",
"@types/d3-random": "*",
"@types/d3-scale": "*",
"@types/d3-scale-chromatic": "*",
"@types/d3-selection": "*",
"@types/d3-shape": "*",
"@types/d3-time": "*",
"@types/d3-time-format": "*",
"@types/d3-timer": "*",
"@types/d3-transition": "*",
"@types/d3-zoom": "*"
}
},
"node_modules/@types/d3-array": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
"integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-axis": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz",
"integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
}
},
"node_modules/@types/d3-brush": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz",
"integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
}
},
"node_modules/@types/d3-chord": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz",
"integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-color": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-contour": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz",
"integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-array": "*",
"@types/geojson": "*"
}
},
"node_modules/@types/d3-delaunay": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
"integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-dispatch": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz",
"integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-drag": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
"integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
}
},
"node_modules/@types/d3-dsv": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz",
"integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-ease": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
"integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-fetch": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz",
"integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-dsv": "*"
}
},
"node_modules/@types/d3-force": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
"integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-format": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz",
"integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-geo": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz",
"integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/geojson": "*"
}
},
"node_modules/@types/d3-hierarchy": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz",
"integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-interpolate": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-color": "*"
}
},
"node_modules/@types/d3-path": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
"integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-polygon": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz",
"integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-quadtree": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz",
"integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-random": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz",
"integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-scale": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-time": "*"
}
},
"node_modules/@types/d3-scale-chromatic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
"integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-selection": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
"integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-shape": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
"integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-path": "*"
}
},
"node_modules/@types/d3-time": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
"integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-time-format": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz",
"integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-timer": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-transition": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
"integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
}
},
"node_modules/@types/d3-zoom": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
"integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-interpolate": "*",
"@types/d3-selection": "*"
}
},
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/geojson": {
"version": "7946.0.16",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@ungap/structured-clone": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
"dev": true,
"license": "ISC"
},
"node_modules/@vitest/expect": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/spy": "3.2.4",
"@vitest/utils": "3.2.4",
"chai": "^5.2.0",
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/mocker": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/spy": "3.2.4",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.17"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
},
"peerDependenciesMeta": {
"msw": {
"optional": true
},
"vite": {
"optional": true
}
}
},
"node_modules/@vitest/pretty-format": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
"dev": true,
"license": "MIT",
"dependencies": {
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/runner": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/utils": "3.2.4",
"pathe": "^2.0.3",
"strip-literal": "^3.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/snapshot": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "3.2.4",
"magic-string": "^0.30.17",
"pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/spy": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
"dev": true,
"license": "MIT",
"dependencies": {
"tinyspy": "^4.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/utils": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "3.2.4",
"loupe": "^3.1.4",
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"is-array-buffer": "^3.0.5"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array-includes": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
"integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.24.0",
"es-object-atoms": "^1.1.1",
"get-intrinsic": "^1.3.0",
"is-string": "^1.1.1",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.findlastindex": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
"integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"es-shim-unscopables": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.flat": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/array.prototype.flatmap": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/arraybuffer.prototype.slice": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.1",
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"is-array-buffer": "^3.0.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/async-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/chai": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"assertion-error": "^2.0.1",
"check-error": "^2.1.1",
"deep-eql": "^5.0.1",
"loupe": "^3.1.0",
"pathval": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/check-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 16"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true,
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/d3": {
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
"integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
"license": "ISC",
"dependencies": {
"d3-array": "3",
"d3-axis": "3",
"d3-brush": "3",
"d3-chord": "3",
"d3-color": "3",
"d3-contour": "4",
"d3-delaunay": "6",
"d3-dispatch": "3",
"d3-drag": "3",
"d3-dsv": "3",
"d3-ease": "3",
"d3-fetch": "3",
"d3-force": "3",
"d3-format": "3",
"d3-geo": "3",
"d3-hierarchy": "3",
"d3-interpolate": "3",
"d3-path": "3",
"d3-polygon": "3",
"d3-quadtree": "3",
"d3-random": "3",
"d3-scale": "4",
"d3-scale-chromatic": "3",
"d3-selection": "3",
"d3-shape": "3",
"d3-time": "3",
"d3-time-format": "4",
"d3-timer": "3",
"d3-transition": "3",
"d3-zoom": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"license": "ISC",
"dependencies": {
"internmap": "1 - 2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-axis": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
"integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-brush": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
"integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "3",
"d3-transition": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-chord": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
"integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
"license": "ISC",
"dependencies": {
"d3-path": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-contour": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
"integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
"license": "ISC",
"dependencies": {
"d3-array": "^3.2.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-delaunay": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
"license": "ISC",
"dependencies": {
"delaunator": "5"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-dispatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-drag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-dsv": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
"integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
"license": "ISC",
"dependencies": {
"commander": "7",
"iconv-lite": "0.6",
"rw": "1"
},
"bin": {
"csv2json": "bin/dsv2json.js",
"csv2tsv": "bin/dsv2dsv.js",
"dsv2dsv": "bin/dsv2dsv.js",
"dsv2json": "bin/dsv2json.js",
"json2csv": "bin/json2dsv.js",
"json2dsv": "bin/json2dsv.js",
"json2tsv": "bin/json2dsv.js",
"tsv2csv": "bin/dsv2dsv.js",
"tsv2json": "bin/dsv2json.js"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-fetch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
"integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
"license": "ISC",
"dependencies": {
"d3-dsv": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-force": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
"integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-quadtree": "1 - 3",
"d3-timer": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-format": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-geo": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
"integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
"license": "ISC",
"dependencies": {
"d3-array": "2.5.0 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-hierarchy": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
"integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"license": "ISC",
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-polygon": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
"integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-quadtree": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
"integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-random": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
"integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-scale": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"license": "ISC",
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
"d3-time-format": "2 - 4"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-scale-chromatic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
"integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
"license": "ISC",
"dependencies": {
"d3-color": "1 - 3",
"d3-interpolate": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-selection": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-shape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"license": "ISC",
"dependencies": {
"d3-path": "^3.1.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"license": "ISC",
"dependencies": {
"d3-array": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time-format": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"license": "ISC",
"dependencies": {
"d3-time": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-transition": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"license": "ISC",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
"d3-ease": "1 - 3",
"d3-interpolate": "1 - 3",
"d3-timer": "1 - 3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"d3-selection": "2 - 3"
}
},
"node_modules/d3-zoom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
"d3-interpolate": "1 - 3",
"d3-selection": "2 - 3",
"d3-transition": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/data-view-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/data-view-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/inspect-js"
}
},
"node_modules/data-view-byte-offset": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/deep-eql": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true,
"license": "MIT"
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delaunator": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
"license": "ISC",
"dependencies": {
"robust-predicates": "^3.0.2"
}
},
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-abstract": {
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
"integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.2",
"arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8",
"get-intrinsic": "^1.3.0",
"get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4",
"gopd": "^1.2.0",
"has-property-descriptors": "^1.0.2",
"has-proto": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"internal-slot": "^1.1.0",
"is-array-buffer": "^3.0.5",
"is-callable": "^1.2.7",
"is-data-view": "^1.0.2",
"is-negative-zero": "^2.0.3",
"is-regex": "^1.2.1",
"is-set": "^2.0.3",
"is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1",
"is-typed-array": "^1.1.15",
"is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0",
"object-inspect": "^1.13.4",
"object-keys": "^1.1.1",
"object.assign": "^4.1.7",
"own-keys": "^1.0.1",
"regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0",
"set-proto": "^1.0.0",
"stop-iteration-iterator": "^1.1.0",
"string.prototype.trim": "^1.2.10",
"string.prototype.trimend": "^1.0.9",
"string.prototype.trimstart": "^1.0.8",
"typed-array-buffer": "^1.0.3",
"typed-array-byte-length": "^1.0.3",
"typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0",
"which-typed-array": "^1.1.19"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-module-lexer": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
"dev": true,
"license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-shim-unscopables": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
"integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-to-primitive": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7",
"is-date-object": "^1.0.5",
"is-symbol": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/esbuild": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
"integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.10",
"@esbuild/android-arm": "0.25.10",
"@esbuild/android-arm64": "0.25.10",
"@esbuild/android-x64": "0.25.10",
"@esbuild/darwin-arm64": "0.25.10",
"@esbuild/darwin-x64": "0.25.10",
"@esbuild/freebsd-arm64": "0.25.10",
"@esbuild/freebsd-x64": "0.25.10",
"@esbuild/linux-arm": "0.25.10",
"@esbuild/linux-arm64": "0.25.10",
"@esbuild/linux-ia32": "0.25.10",
"@esbuild/linux-loong64": "0.25.10",
"@esbuild/linux-mips64el": "0.25.10",
"@esbuild/linux-ppc64": "0.25.10",
"@esbuild/linux-riscv64": "0.25.10",
"@esbuild/linux-s390x": "0.25.10",
"@esbuild/linux-x64": "0.25.10",
"@esbuild/netbsd-arm64": "0.25.10",
"@esbuild/netbsd-x64": "0.25.10",
"@esbuild/openbsd-arm64": "0.25.10",
"@esbuild/openbsd-x64": "0.25.10",
"@esbuild/openharmony-arm64": "0.25.10",
"@esbuild/sunos-x64": "0.25.10",
"@esbuild/win32-arm64": "0.25.10",
"@esbuild/win32-ia32": "0.25.10",
"@esbuild/win32-x64": "0.25.10"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4",
"@eslint/js": "8.57.1",
"@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
"eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
"text-table": "^0.2.0"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^3.2.7",
"is-core-module": "^2.13.0",
"resolve": "^1.22.4"
}
},
"node_modules/eslint-import-resolver-node/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-module-utils": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
"integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^3.2.7"
},
"engines": {
"node": ">=4"
},
"peerDependenciesMeta": {
"eslint": {
"optional": true
}
}
},
"node_modules/eslint-module-utils/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-import": {
"version": "2.32.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
"array.prototype.findlastindex": "^1.2.6",
"array.prototype.flat": "^1.3.3",
"array.prototype.flatmap": "^1.3.3",
"debug": "^3.2.7",
"doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.12.1",
"hasown": "^2.0.2",
"is-core-module": "^2.16.1",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
"object.fromentries": "^2.0.8",
"object.groupby": "^1.0.3",
"object.values": "^1.2.1",
"semver": "^6.3.1",
"string.prototype.trimend": "^1.0.9",
"tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esquery": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
"engines": {
"node": ">=4.0"
}
},
"node_modules/estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/expect-type": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
"integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true,
"license": "MIT"
},
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
"integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
"license": "MIT",
"dependencies": {
"flat-cache": "^3.0.4"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"license": "MIT",
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat-cache": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"flatted": "^3.2.9",
"keyv": "^4.5.3",
"rimraf": "^3.0.2"
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true,
"license": "ISC"
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true,
"license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/function.prototype.name": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"functions-have-names": "^1.2.3",
"hasown": "^2.0.2",
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generator-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
"integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/get-symbol-description": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/globals": {
"version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"type-fest": "^0.20.2"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globalthis": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true,
"license": "MIT"
},
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
"integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.19"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dev": true,
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true,
"license": "ISC"
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"hasown": "^2.0.2",
"side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/internmap": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"async-function": "^1.0.0",
"call-bound": "^1.0.3",
"get-proto": "^1.0.1",
"has-tostringtag": "^1.0.2",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-bigint": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-bigints": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-data-view": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"get-intrinsic": "^1.2.6",
"is-typed-array": "^1.1.13"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-date-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-finalizationregistry": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-generator-function": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
"integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.4",
"generator-function": "^2.0.0",
"get-proto": "^1.0.1",
"has-tostringtag": "^1.0.2",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-negative-zero": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number-object": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-set": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-shared-array-buffer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-string": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-symbol": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-symbols": "^1.1.0",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakref": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakset": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"dev": true,
"license": "MIT"
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true,
"license": "ISC"
},
"node_modules/js-tokens": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true,
"license": "MIT"
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true,
"license": "MIT"
},
"node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
"license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1",
"type-check": "~0.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"p-locate": "^5.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true,
"license": "MIT"
},
"node_modules/loupe": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
"dev": true,
"license": "MIT"
},
"node_modules/magic-string": {
"version": "0.30.19",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true,
"license": "MIT"
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.assign": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0",
"has-symbols": "^1.1.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object.fromentries": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.2",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object.groupby": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.values": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
"license": "MIT",
"dependencies": {
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
"type-check": "^0.4.0",
"word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/own-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.6",
"object-keys": "^1.1.1",
"safe-push-apply": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true,
"license": "MIT"
},
"node_modules/pathval": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.16"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"get-intrinsic": "^1.2.7",
"get-proto": "^1.0.1",
"which-builtin-type": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
"license": "Unlicense"
},
"node_modules/rollup": {
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz",
"integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.52.4",
"@rollup/rollup-android-arm64": "4.52.4",
"@rollup/rollup-darwin-arm64": "4.52.4",
"@rollup/rollup-darwin-x64": "4.52.4",
"@rollup/rollup-freebsd-arm64": "4.52.4",
"@rollup/rollup-freebsd-x64": "4.52.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.52.4",
"@rollup/rollup-linux-arm-musleabihf": "4.52.4",
"@rollup/rollup-linux-arm64-gnu": "4.52.4",
"@rollup/rollup-linux-arm64-musl": "4.52.4",
"@rollup/rollup-linux-loong64-gnu": "4.52.4",
"@rollup/rollup-linux-ppc64-gnu": "4.52.4",
"@rollup/rollup-linux-riscv64-gnu": "4.52.4",
"@rollup/rollup-linux-riscv64-musl": "4.52.4",
"@rollup/rollup-linux-s390x-gnu": "4.52.4",
"@rollup/rollup-linux-x64-gnu": "4.52.4",
"@rollup/rollup-linux-x64-musl": "4.52.4",
"@rollup/rollup-openharmony-arm64": "4.52.4",
"@rollup/rollup-win32-arm64-msvc": "4.52.4",
"@rollup/rollup-win32-ia32-msvc": "4.52.4",
"@rollup/rollup-win32-x64-gnu": "4.52.4",
"@rollup/rollup-win32-x64-msvc": "4.52.4",
"fsevents": "~2.3.2"
}
},
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/rw": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
"integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
"license": "BSD-3-Clause"
},
"node_modules/safe-array-concat": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
"integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
"get-intrinsic": "^1.2.6",
"has-symbols": "^1.1.0",
"isarray": "^2.0.5"
},
"engines": {
"node": ">=0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"isarray": "^2.0.5"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-regex-test": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-regex": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-function-name": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"functions-have-names": "^1.2.3",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-proto": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/siginfo": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
"dev": true,
"license": "ISC"
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
"dev": true,
"license": "MIT"
},
"node_modules/std-env": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
"dev": true,
"license": "MIT"
},
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
"integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"internal-slot": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/string.prototype.trim": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
"define-data-property": "^1.1.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.5",
"es-object-atoms": "^1.0.0",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimend": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.2",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimstart": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/strip-literal": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^9.0.1"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true,
"license": "MIT"
},
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true,
"license": "MIT"
},
"node_modules/tinyexec": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
"dev": true,
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinypool": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.0.0 || >=20.0.0"
}
},
"node_modules/tinyrainbow": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/tinyspy": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/typed-array-byte-length": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"for-each": "^0.3.3",
"gopd": "^1.2.0",
"has-proto": "^1.2.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typed-array-byte-offset": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"for-each": "^0.3.3",
"gopd": "^1.2.0",
"has-proto": "^1.2.0",
"is-typed-array": "^1.1.15",
"reflect.getprototypeof": "^1.0.9"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typed-array-length": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
"is-typed-array": "^1.1.13",
"possible-typed-array-names": "^1.0.0",
"reflect.getprototypeof": "^1.0.6"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"has-bigints": "^1.0.2",
"has-symbols": "^1.1.0",
"which-boxed-primitive": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/vite": {
"version": "7.1.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz",
"integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.6",
"rollup": "^4.43.0",
"tinyglobby": "^0.2.15"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
"lightningcss": "^1.21.0",
"sass": "^1.70.0",
"sass-embedded": "^1.70.0",
"stylus": ">=0.54.8",
"sugarss": "^5.0.0",
"terser": "^5.16.0",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"jiti": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
},
"tsx": {
"optional": true
},
"yaml": {
"optional": true
}
}
},
"node_modules/vite-node": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.4.1",
"es-module-lexer": "^1.7.0",
"pathe": "^2.0.3",
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
},
"bin": {
"vite-node": "vite-node.mjs"
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/vitest": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
"@vitest/mocker": "3.2.4",
"@vitest/pretty-format": "^3.2.4",
"@vitest/runner": "3.2.4",
"@vitest/snapshot": "3.2.4",
"@vitest/spy": "3.2.4",
"@vitest/utils": "3.2.4",
"chai": "^5.2.0",
"debug": "^4.4.1",
"expect-type": "^1.2.1",
"magic-string": "^0.30.17",
"pathe": "^2.0.3",
"picomatch": "^4.0.2",
"std-env": "^3.9.0",
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
"tinyglobby": "^0.2.14",
"tinypool": "^1.1.1",
"tinyrainbow": "^2.0.0",
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
"vite-node": "3.2.4",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
"@vitest/browser": "3.2.4",
"@vitest/ui": "3.2.4",
"happy-dom": "*",
"jsdom": "*"
},
"peerDependenciesMeta": {
"@edge-runtime/vm": {
"optional": true
},
"@types/debug": {
"optional": true
},
"@types/node": {
"optional": true
},
"@vitest/browser": {
"optional": true
},
"@vitest/ui": {
"optional": true
},
"happy-dom": {
"optional": true
},
"jsdom": {
"optional": true
}
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/which-boxed-primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-bigint": "^1.1.0",
"is-boolean-object": "^1.2.1",
"is-number-object": "^1.1.1",
"is-string": "^1.1.1",
"is-symbol": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-builtin-type": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"function.prototype.name": "^1.1.6",
"has-tostringtag": "^1.0.2",
"is-async-function": "^2.0.0",
"is-date-object": "^1.1.0",
"is-finalizationregistry": "^1.1.0",
"is-generator-function": "^1.0.10",
"is-regex": "^1.2.1",
"is-weakref": "^1.0.2",
"isarray": "^2.0.5",
"which-boxed-primitive": "^1.1.0",
"which-collection": "^1.0.2",
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-map": "^2.0.3",
"is-set": "^2.0.3",
"is-weakmap": "^2.0.2",
"is-weakset": "^2.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/why-is-node-running": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
"license": "MIT",
"dependencies": {
"siginfo": "^2.0.0",
"stackback": "0.0.2"
},
"bin": {
"why-is-node-running": "cli.js"
},
"engines": {
"node": ">=8"
}
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true,
"license": "ISC"
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
tbo47-dagre-es-4b95ad0/package.json 0000664 0000000 0000000 00000003156 15114061606 0017043 0 ustar 00root root 0000000 0000000 {
"name": "dagre-d3-es",
"version": "7.0.14",
"description": "",
"license": "MIT",
"main": "src/index.js",
"type": "module",
"scripts": {
"bundle": "chmod +x bundle.sh ; ./bundle.sh && cp dist/dagre-d3*.js ../tbo47.github.io",
"generate_types": "find src -name '*.d.ts' -type f -delete ; tsc --project tsconfig.build.json",
"prepack": "npm run generate_types",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier --write .",
"test": "vitest ",
"my_1_npm_login": "npm login",
"my_2_publish": "echo update_package_version ; git clean -xdf ; npm ci ; npm publish",
"compile_js_as_ts": "tsc src/index.js --AllowJs --checkJs --outDir dist/"
},
"keywords": [
"dagre-d3"
],
"repository": {
"type": "git",
"url": "git+https://github.com/tbo47/dagre-es.git"
},
"dependencies": {
"d3": "^7.9.0",
"lodash-es": "^4.17.21"
},
"devDependencies": {
"@types/d3": "^7.4.3",
"@types/lodash-es": "^4.17.12",
"esbuild": "^0.25.10",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.32.0",
"prettier": "^3.6.2",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
},
"contributors": [
{
"name": "Thibaut Lassalle",
"url": "https://tbo47.github.io/"
},
{
"name": "Alois Klink",
"url": "https://github.com/aloisklink"
},
{
"name": "David Newell",
"url": "https://github.com/rustedgrail"
},
{
"name": "Sidharth Vinod",
"url": "https://github.com/sidharthv96"
}
],
"files": [
"src/**/*",
"!src/**/*.test.js"
],
"types": "./src/index.d.ts"
}
tbo47-dagre-es-4b95ad0/src/ 0000775 0000000 0000000 00000000000 15114061606 0015337 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre-js/ 0000775 0000000 0000000 00000000000 15114061606 0017033 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre-js/arrows.js 0000664 0000000 0000000 00000003607 15114061606 0020714 0 ustar 00root root 0000000 0000000 import * as util from './util.js';
export { arrows, setArrows };
var arrows = {
normal,
vee,
undirected,
};
function setArrows(value) {
arrows = value;
}
function normal(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}
function vee(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 L 4 5 z')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}
function undirected(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 5 L 10 5')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}
tbo47-dagre-es-4b95ad0/src/dagre-js/create-clusters.js 0000664 0000000 0000000 00000002464 15114061606 0022504 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import { addLabel } from './label/add-label.js';
import * as util from './util.js';
export { createClusters, setCreateClusters };
var createClusters = function (selection, g) {
var clusters = g.nodes().filter(function (v) {
return util.isSubgraph(g, v);
});
var svgClusters = selection.selectAll('g.cluster').data(clusters, function (v) {
return v;
});
util.applyTransition(svgClusters.exit(), g).style('opacity', 0).remove();
var enterSelection = svgClusters
.enter()
.append('g')
.attr('class', 'cluster')
.attr('id', function (v) {
var node = g.node(v);
return node.id;
})
.style('opacity', 0)
.each(function (v) {
var node = g.node(v);
var thisGroup = d3.select(this);
d3.select(this).append('rect');
var labelGroup = thisGroup.append('g').attr('class', 'label');
addLabel(labelGroup, node, node.clusterLabelPos);
});
svgClusters = svgClusters.merge(enterSelection);
svgClusters = util.applyTransition(svgClusters, g).style('opacity', 1);
svgClusters.selectAll('rect').each(function (c) {
var node = g.node(c);
var domCluster = d3.select(this);
util.applyStyle(domCluster, node.style);
});
return svgClusters;
};
function setCreateClusters(value) {
createClusters = value;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/create-edge-labels.js 0000664 0000000 0000000 00000002610 15114061606 0022775 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import { addLabel } from './label/add-label.js';
import * as util from './util.js';
export { createEdgeLabels, setCreateEdgeLabels };
let createEdgeLabels = function (selection, g) {
var svgEdgeLabels = selection
.selectAll('g.edgeLabel')
.data(g.edges(), function (e) {
return util.edgeToId(e);
})
.classed('update', true);
svgEdgeLabels.exit().remove();
svgEdgeLabels.enter().append('g').classed('edgeLabel', true).style('opacity', 0);
svgEdgeLabels = selection.selectAll('g.edgeLabel');
svgEdgeLabels.each(function (e) {
var root = d3.select(this);
root.select('.label').remove();
var edge = g.edge(e);
var label = addLabel(root, g.edge(e), 0).classed('label', true);
var bbox = label.node().getBBox();
if (edge.labelId) {
label.attr('id', edge.labelId);
}
if (!Object.prototype.hasOwnProperty.call(edge, 'width')) {
edge.width = bbox.width;
}
if (!Object.prototype.hasOwnProperty.call(edge, 'height')) {
edge.height = bbox.height;
}
});
var exitSelection;
if (svgEdgeLabels.exit) {
exitSelection = svgEdgeLabels.exit();
} else {
exitSelection = svgEdgeLabels.selectAll(null); // empty selection
}
util.applyTransition(exitSelection, g).style('opacity', 0).remove();
return svgEdgeLabels;
};
function setCreateEdgeLabels(value) {
createEdgeLabels = value;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/create-edge-paths.js 0000664 0000000 0000000 00000006560 15114061606 0022662 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import * as _ from 'lodash-es';
import { intersectNode } from './intersect/intersect-node.js';
import * as util from './util.js';
export { createEdgePaths, setCreateEdgePaths };
var createEdgePaths = function (selection, g, arrows) {
var previousPaths = selection
.selectAll('g.edgePath')
.data(g.edges(), function (e) {
return util.edgeToId(e);
})
.classed('update', true);
var newPaths = enter(previousPaths, g);
exit(previousPaths, g);
var svgPaths = previousPaths.merge !== undefined ? previousPaths.merge(newPaths) : previousPaths;
util.applyTransition(svgPaths, g).style('opacity', 1);
// Save DOM element in the path group, and set ID and class
svgPaths.each(function (e) {
var domEdge = d3.select(this);
var edge = g.edge(e);
edge.elem = this;
if (edge.id) {
domEdge.attr('id', edge.id);
}
util.applyClass(
domEdge,
edge['class'],
(domEdge.classed('update') ? 'update ' : '') + 'edgePath',
);
});
svgPaths.selectAll('path.path').each(function (e) {
var edge = g.edge(e);
edge.arrowheadId = _.uniqueId('arrowhead');
var domEdge = d3
.select(this)
.attr('marker-end', function () {
return 'url(' + makeFragmentRef(location.href, edge.arrowheadId) + ')';
})
.style('fill', 'none');
util.applyTransition(domEdge, g).attr('d', function (e) {
return calcPoints(g, e);
});
util.applyStyle(domEdge, edge.style);
});
svgPaths.selectAll('defs *').remove();
svgPaths.selectAll('defs').each(function (e) {
var edge = g.edge(e);
var arrowhead = arrows[edge.arrowhead];
arrowhead(d3.select(this), edge.arrowheadId, edge, 'arrowhead');
});
return svgPaths;
};
function setCreateEdgePaths(value) {
createEdgePaths = value;
}
function makeFragmentRef(url, fragmentId) {
var baseUrl = url.split('#')[0];
return baseUrl + '#' + fragmentId;
}
function calcPoints(g, e) {
var edge = g.edge(e);
var tail = g.node(e.v);
var head = g.node(e.w);
var points = edge.points.slice(1, edge.points.length - 1);
points.unshift(intersectNode(tail, points[0]));
points.push(intersectNode(head, points[points.length - 1]));
return createLine(edge, points);
}
function createLine(edge, points) {
// @ts-expect-error
var line = (d3.line || d3.svg.line)()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
});
(line.curve || line.interpolate)(edge.curve);
return line(points);
}
function getCoords(elem) {
var bbox = elem.getBBox();
var matrix = elem.ownerSVGElement
.getScreenCTM()
.inverse()
.multiply(elem.getScreenCTM())
.translate(bbox.width / 2, bbox.height / 2);
return { x: matrix.e, y: matrix.f };
}
function enter(svgPaths, g) {
var svgPathsEnter = svgPaths.enter().append('g').attr('class', 'edgePath').style('opacity', 0);
svgPathsEnter
.append('path')
.attr('class', 'path')
.attr('d', function (e) {
var edge = g.edge(e);
var sourceElem = g.node(e.v).elem;
var points = _.range(edge.points.length).map(function () {
return getCoords(sourceElem);
});
return createLine(edge, points);
});
svgPathsEnter.append('defs');
return svgPathsEnter;
}
function exit(svgPaths, g) {
var svgPathExit = svgPaths.exit();
util.applyTransition(svgPathExit, g).style('opacity', 0).remove();
}
tbo47-dagre-es-4b95ad0/src/dagre-js/create-nodes.js 0000664 0000000 0000000 00000004571 15114061606 0021751 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import { pick } from 'lodash-es';
import { addLabel } from './label/add-label.js';
import * as util from './util.js';
export { createNodes, setCreateNodes };
var createNodes = function (selection, g, shapes) {
var simpleNodes = g.nodes().filter(function (v) {
return !util.isSubgraph(g, v);
});
var svgNodes = selection
.selectAll('g.node')
.data(simpleNodes, function (v) {
return v;
})
.classed('update', true);
svgNodes.exit().remove();
svgNodes.enter().append('g').attr('class', 'node').style('opacity', 0);
svgNodes = selection.selectAll('g.node');
svgNodes.each(function (v) {
var node = g.node(v);
var thisGroup = d3.select(this);
util.applyClass(
thisGroup,
node['class'],
(thisGroup.classed('update') ? 'update ' : '') + 'node',
);
thisGroup.select('g.label').remove();
var labelGroup = thisGroup.append('g').attr('class', 'label');
var labelDom = addLabel(labelGroup, node);
var shape = shapes[node.shape];
var bbox = pick(labelDom.node().getBBox(), 'width', 'height');
node.elem = this;
if (node.id) {
thisGroup.attr('id', node.id);
}
if (node.labelId) {
labelGroup.attr('id', node.labelId);
}
if (Object.prototype.hasOwnProperty.call(node, 'width')) {
bbox.width = node.width;
}
if (Object.prototype.hasOwnProperty.call(node, 'height')) {
bbox.height = node.height;
}
bbox.width += node.paddingLeft + node.paddingRight;
bbox.height += node.paddingTop + node.paddingBottom;
labelGroup.attr(
'transform',
'translate(' +
(node.paddingLeft - node.paddingRight) / 2 +
',' +
(node.paddingTop - node.paddingBottom) / 2 +
')',
);
var root = d3.select(this);
root.select('.label-container').remove();
var shapeSvg = shape(root, bbox, node).classed('label-container', true);
util.applyStyle(shapeSvg, node.style);
var shapeBBox = shapeSvg.node().getBBox();
node.width = shapeBBox.width;
node.height = shapeBBox.height;
});
var exitSelection;
if (svgNodes.exit) {
exitSelection = svgNodes.exit();
} else {
exitSelection = svgNodes.selectAll(null); // empty selection
}
util.applyTransition(exitSelection, g).style('opacity', 0).remove();
return svgNodes;
};
function setCreateNodes(value) {
createNodes = value;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/ 0000775 0000000 0000000 00000000000 15114061606 0021033 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/index.js 0000664 0000000 0000000 00000000443 15114061606 0022501 0 ustar 00root root 0000000 0000000 import * as node from './intersect-node.js';
import * as circle from './intersect-circle.js';
import * as ellipse from './intersect-ellipse.js';
import * as polygon from './intersect-polygon.js';
import * as rect from './intersect-rect.js';
export { node, circle, ellipse, polygon, rect };
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-circle.js 0000664 0000000 0000000 00000000267 15114061606 0024635 0 ustar 00root root 0000000 0000000 import { intersectEllipse } from './intersect-ellipse.js';
export { intersectCircle };
function intersectCircle(node, rx, point) {
return intersectEllipse(node, rx, rx, point);
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-ellipse.js 0000664 0000000 0000000 00000001006 15114061606 0025021 0 ustar 00root root 0000000 0000000 export { intersectEllipse };
function intersectEllipse(node, rx, ry, point) {
// Formulae from: http://mathworld.wolfram.com/Ellipse-LineIntersection.html
var cx = node.x;
var cy = node.y;
var px = cx - point.x;
var py = cy - point.y;
var det = Math.sqrt(rx * rx * py * py + ry * ry * px * px);
var dx = Math.abs((rx * ry * px) / det);
if (point.x < cx) {
dx = -dx;
}
var dy = Math.abs((rx * ry * py) / det);
if (point.y < cy) {
dy = -dy;
}
return { x: cx + dx, y: cy + dy };
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-line.js 0000664 0000000 0000000 00000003625 15114061606 0024324 0 ustar 00root root 0000000 0000000 export { intersectLine };
/*
* Returns the point at which two lines, p and q, intersect or returns
* undefined if they do not intersect.
*/
function intersectLine(p1, p2, q1, q2) {
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
// p7 and p473.
var a1, a2, b1, b2, c1, c2;
var r1, r2, r3, r4;
var denom, offset, num;
var x, y;
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
// b1 y + c1 = 0.
a1 = p2.y - p1.y;
b1 = p1.x - p2.x;
c1 = p2.x * p1.y - p1.x * p2.y;
// Compute r3 and r4.
r3 = a1 * q1.x + b1 * q1.y + c1;
r4 = a1 * q2.x + b1 * q2.y + c1;
// Check signs of r3 and r4. If both point 3 and point 4 lie on
// same side of line 1, the line segments do not intersect.
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
return /*DONT_INTERSECT*/;
}
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
a2 = q2.y - q1.y;
b2 = q1.x - q2.x;
c2 = q2.x * q1.y - q1.x * q2.y;
// Compute r1 and r2
r1 = a2 * p1.x + b2 * p1.y + c2;
r2 = a2 * p2.x + b2 * p2.y + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie
// on same side of second line segment, the line segments do
// not intersect.
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
return /*DONT_INTERSECT*/;
}
// Line segments intersect: compute intersection point.
denom = a1 * b2 - a2 * b1;
if (denom === 0) {
return /*COLLINEAR*/;
}
offset = Math.abs(denom / 2);
// The denom/2 is to get rounding instead of truncating. It
// is added or subtracted to the numerator, depending upon the
// sign of the numerator.
num = b1 * c2 - b2 * c1;
x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
num = a2 * c1 - a1 * c2;
y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
return { x: x, y: y };
}
function sameSign(r1, r2) {
return r1 * r2 > 0;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-node.js 0000664 0000000 0000000 00000000143 15114061606 0024312 0 ustar 00root root 0000000 0000000 export { intersectNode };
function intersectNode(node, point) {
return node.intersect(point);
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-polygon.js 0000664 0000000 0000000 00000003064 15114061606 0025061 0 ustar 00root root 0000000 0000000 import { intersectLine } from './intersect-line.js';
export { intersectPolygon };
/*
* Returns the point ({x, y}) at which the point argument intersects with the
* node argument assuming that it has the shape specified by polygon.
*/
function intersectPolygon(node, polyPoints, point) {
var x1 = node.x;
var y1 = node.y;
var intersections = [];
var minX = Number.POSITIVE_INFINITY;
var minY = Number.POSITIVE_INFINITY;
polyPoints.forEach(function (entry) {
minX = Math.min(minX, entry.x);
minY = Math.min(minY, entry.y);
});
var left = x1 - node.width / 2 - minX;
var top = y1 - node.height / 2 - minY;
for (var i = 0; i < polyPoints.length; i++) {
var p1 = polyPoints[i];
var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
var intersect = intersectLine(
node,
point,
{ x: left + p1.x, y: top + p1.y },
{ x: left + p2.x, y: top + p2.y },
);
if (intersect) {
intersections.push(intersect);
}
}
if (!intersections.length) {
console.log('NO INTERSECTION FOUND, RETURN NODE CENTER', node);
return node;
}
if (intersections.length > 1) {
// More intersections, find the one nearest to edge end point
intersections.sort(function (p, q) {
var pdx = p.x - point.x;
var pdy = p.y - point.y;
var distp = Math.sqrt(pdx * pdx + pdy * pdy);
var qdx = q.x - point.x;
var qdy = q.y - point.y;
var distq = Math.sqrt(qdx * qdx + qdy * qdy);
return distp < distq ? -1 : distp === distq ? 0 : 1;
});
}
return intersections[0];
}
tbo47-dagre-es-4b95ad0/src/dagre-js/intersect/intersect-rect.js 0000664 0000000 0000000 00000001306 15114061606 0024324 0 ustar 00root root 0000000 0000000 export { intersectRect };
function intersectRect(node, point) {
var x = node.x;
var y = node.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = node.width / 2;
var h = node.height / 2;
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx;
}
return { x: x + sx, y: y + sy };
}
tbo47-dagre-es-4b95ad0/src/dagre-js/label/ 0000775 0000000 0000000 00000000000 15114061606 0020112 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre-js/label/add-html-label.js 0000664 0000000 0000000 00000001455 15114061606 0023224 0 ustar 00root root 0000000 0000000 import * as util from '../util.js';
export { addHtmlLabel };
function addHtmlLabel(root, node) {
var fo = root.append('foreignObject').attr('width', '100000');
var div = fo.append('xhtml:div');
div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
var label = node.label;
switch (typeof label) {
case 'function':
div.insert(label);
break;
case 'object':
// Currently we assume this is a DOM object.
div.insert(function () {
return label;
});
break;
default:
div.html(label);
}
util.applyStyle(div, node.labelStyle);
div.style('display', 'inline-block');
// Fix for firefox
div.style('white-space', 'nowrap');
var client = div.node();
fo.attr('width', client.offsetWidth).attr('height', client.offsetHeight);
return fo;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/label/add-label.js 0000664 0000000 0000000 00000001717 15114061606 0022263 0 ustar 00root root 0000000 0000000 import { addHtmlLabel } from './add-html-label.js';
import { addSVGLabel } from './add-svg-label.js';
import { addTextLabel } from './add-text-label.js';
export { addLabel };
function addLabel(root, node, location) {
var label = node.label;
var labelSvg = root.append('g');
// Allow the label to be a string, a function that returns a DOM element, or
// a DOM element itself.
if (node.labelType === 'svg') {
addSVGLabel(labelSvg, node);
} else if (typeof label !== 'string' || node.labelType === 'html') {
addHtmlLabel(labelSvg, node);
} else {
addTextLabel(labelSvg, node);
}
var labelBBox = labelSvg.node().getBBox();
var y;
switch (location) {
case 'top':
y = -node.height / 2;
break;
case 'bottom':
y = node.height / 2 - labelBBox.height;
break;
default:
y = -labelBBox.height / 2;
}
labelSvg.attr('transform', 'translate(' + -labelBBox.width / 2 + ',' + y + ')');
return labelSvg;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/label/add-svg-label.js 0000664 0000000 0000000 00000000345 15114061606 0023054 0 ustar 00root root 0000000 0000000 import * as util from '../util.js';
export { addSVGLabel };
function addSVGLabel(root, node) {
var domNode = root;
domNode.node().appendChild(node.label);
util.applyStyle(domNode, node.labelStyle);
return domNode;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/label/add-text-label.js 0000664 0000000 0000000 00000001724 15114061606 0023243 0 ustar 00root root 0000000 0000000 import * as util from '../util.js';
export { addTextLabel };
/*
* Attaches a text label to the specified root. Handles escape sequences.
*/
function addTextLabel(root, node) {
var domNode = root.append('text');
var lines = processEscapeSequences(node.label).split('\n');
for (var i = 0; i < lines.length; i++) {
domNode
.append('tspan')
.attr('xml:space', 'preserve')
.attr('dy', '1em')
.attr('x', '1')
.text(lines[i]);
}
util.applyStyle(domNode, node.labelStyle);
return domNode;
}
function processEscapeSequences(text) {
var newText = '';
var escaped = false;
var ch;
for (var i = 0; i < text.length; ++i) {
ch = text[i];
if (escaped) {
switch (ch) {
case 'n':
newText += '\n';
break;
default:
newText += ch;
}
escaped = false;
} else if (ch === '\\') {
escaped = true;
} else {
newText += ch;
}
}
return newText;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/position-clusters.js 0000664 0000000 0000000 00000001550 15114061606 0023100 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import * as util from './util.js';
export { positionClusters };
function positionClusters(selection, g) {
var created = selection.filter(function () {
return !d3.select(this).classed('update');
});
function translate(v) {
var node = g.node(v);
return 'translate(' + node.x + ',' + node.y + ')';
}
created.attr('transform', translate);
util.applyTransition(selection, g).style('opacity', 1).attr('transform', translate);
util
.applyTransition(created.selectAll('rect'), g)
.attr('width', function (v) {
return g.node(v).width;
})
.attr('height', function (v) {
return g.node(v).height;
})
.attr('x', function (v) {
var node = g.node(v);
return -node.width / 2;
})
.attr('y', function (v) {
var node = g.node(v);
return -node.height / 2;
});
}
tbo47-dagre-es-4b95ad0/src/dagre-js/position-edge-labels.js 0000664 0000000 0000000 00000001044 15114061606 0023376 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import * as util from './util.js';
export { positionEdgeLabels };
function positionEdgeLabels(selection, g) {
var created = selection.filter(function () {
return !d3.select(this).classed('update');
});
function translate(e) {
var edge = g.edge(e);
return Object.prototype.hasOwnProperty.call(edge, 'x')
? 'translate(' + edge.x + ',' + edge.y + ')'
: '';
}
created.attr('transform', translate);
util.applyTransition(selection, g).style('opacity', 1).attr('transform', translate);
}
tbo47-dagre-es-4b95ad0/src/dagre-js/position-nodes.js 0000664 0000000 0000000 00000000727 15114061606 0022351 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import * as util from './util.js';
export { positionNodes };
function positionNodes(selection, g) {
var created = selection.filter(function () {
return !d3.select(this).classed('update');
});
function translate(v) {
var node = g.node(v);
return 'translate(' + node.x + ',' + node.y + ')';
}
created.attr('transform', translate);
util.applyTransition(selection, g).style('opacity', 1).attr('transform', translate);
}
tbo47-dagre-es-4b95ad0/src/dagre-js/render.js 0000664 0000000 0000000 00000012474 15114061606 0020660 0 ustar 00root root 0000000 0000000 import * as d3 from 'd3';
import { defaults } from 'lodash-es';
import { layout } from '../dagre/index.js';
import { arrows, setArrows } from './arrows.js';
import { createClusters, setCreateClusters } from './create-clusters.js';
import { createEdgeLabels, setCreateEdgeLabels } from './create-edge-labels.js';
import { createEdgePaths, setCreateEdgePaths } from './create-edge-paths.js';
import { createNodes, setCreateNodes } from './create-nodes.js';
import { positionClusters } from './position-clusters.js';
import { positionEdgeLabels } from './position-edge-labels.js';
import { positionNodes } from './position-nodes.js';
import { shapes, setShapes } from './shapes.js';
export { render };
// This design is based on http://bost.ocks.org/mike/chart/.
function render() {
var fn = function (svg, g) {
preProcessGraph(g);
var outputGroup = createOrSelectGroup(svg, 'output');
var clustersGroup = createOrSelectGroup(outputGroup, 'clusters');
var edgePathsGroup = createOrSelectGroup(outputGroup, 'edgePaths');
var edgeLabels = createEdgeLabels(createOrSelectGroup(outputGroup, 'edgeLabels'), g);
var nodes = createNodes(createOrSelectGroup(outputGroup, 'nodes'), g, shapes);
layout(g);
positionNodes(nodes, g);
positionEdgeLabels(edgeLabels, g);
createEdgePaths(edgePathsGroup, g, arrows);
var clusters = createClusters(clustersGroup, g);
positionClusters(clusters, g);
postProcessGraph(g);
};
fn.createNodes = function (value) {
if (!arguments.length) return createNodes;
setCreateNodes(value);
return fn;
};
fn.createClusters = function (value) {
if (!arguments.length) return createClusters;
setCreateClusters(value);
return fn;
};
fn.createEdgeLabels = function (value) {
if (!arguments.length) return createEdgeLabels;
setCreateEdgeLabels(value);
return fn;
};
fn.createEdgePaths = function (value) {
if (!arguments.length) return createEdgePaths;
setCreateEdgePaths(value);
return fn;
};
fn.shapes = function (value) {
if (!arguments.length) return shapes;
setShapes(value);
return fn;
};
fn.arrows = function (value) {
if (!arguments.length) return arrows;
setArrows(value);
return fn;
};
return fn;
}
var NODE_DEFAULT_ATTRS = {
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
rx: 0,
ry: 0,
shape: 'rect',
};
var EDGE_DEFAULT_ATTRS = {
arrowhead: 'normal',
curve: d3.curveLinear,
};
/**
* @typedef {Object} Node
* @property {string} label - The label of the node.
* @property {number} [paddingX] - The horizontal padding of the node.
* @property {number} [paddingY] - The vertical padding of the node.
* @property {number} [padding] - The padding of the node for all directions. Overrides `paddingX` and `paddingY`.
* @property {number} [paddingLeft] - The left padding of the node.
* @property {number} [paddingRight] - The right padding of the node.
* @property {number} [_prevWidth]
* @property {number} [width]
* @property {number} [_prevHeight]
* @property {number} [height]
*/
/**
* Pre-processes the graph by setting default labels and padding for nodes.
* @param {Object} g - The graph object.
*/
function preProcessGraph(g) {
g.nodes().forEach((v) => {
/** @type {Node} */
const node = g.node(v);
if (!Object.prototype.hasOwnProperty.call(node, 'label') && !g.children(v).length) {
node.label = v;
}
if (Object.prototype.hasOwnProperty.call(node, 'paddingX')) {
defaults(node, {
paddingLeft: node.paddingX,
paddingRight: node.paddingX,
});
}
if (Object.prototype.hasOwnProperty.call(node, 'paddingY')) {
defaults(node, {
paddingTop: node.paddingY,
paddingBottom: node.paddingY,
});
}
if (Object.prototype.hasOwnProperty.call(node, 'padding')) {
defaults(node, {
paddingLeft: node.padding,
paddingRight: node.padding,
paddingTop: node.padding,
paddingBottom: node.padding,
});
}
defaults(node, NODE_DEFAULT_ATTRS);
['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'].forEach((k) => {
node[k] = Number(node[k]);
});
// Save dimensions for restore during post-processing
if (Object.prototype.hasOwnProperty.call(node, 'width')) {
node._prevWidth = node.width;
}
if (Object.prototype.hasOwnProperty.call(node, 'height')) {
node._prevHeight = node.height;
}
});
g.edges().forEach(function (e) {
var edge = g.edge(e);
if (!Object.prototype.hasOwnProperty.call(edge, 'label')) {
edge.label = '';
}
defaults(edge, EDGE_DEFAULT_ATTRS);
});
}
function postProcessGraph(g) {
g.nodes().forEach((v) => {
/** @type {Node} */
var node = g.node(v);
// Restore original dimensions
if (Object.prototype.hasOwnProperty.call(node, '_prevWidth')) {
node.width = node._prevWidth;
} else {
delete node.width;
}
if (Object.prototype.hasOwnProperty.call(node, '_prevHeight')) {
node.height = node._prevHeight;
} else {
delete node.height;
}
delete node._prevWidth;
delete node._prevHeight;
});
}
function createOrSelectGroup(root, name) {
var selection = root.select('g.' + name);
if (selection.empty()) {
selection = root.append('g').attr('class', name);
}
return selection;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/shapes.js 0000664 0000000 0000000 00000004252 15114061606 0020657 0 ustar 00root root 0000000 0000000 import { intersectCircle } from './intersect/intersect-circle.js';
import { intersectEllipse } from './intersect/intersect-ellipse.js';
import { intersectPolygon } from './intersect/intersect-polygon.js';
import { intersectRect } from './intersect/intersect-rect.js';
export { shapes, setShapes };
var shapes = {
rect,
ellipse,
circle,
diamond,
};
function setShapes(value) {
shapes = value;
}
function rect(parent, bbox, node) {
var shapeSvg = parent
.insert('rect', ':first-child')
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('x', -bbox.width / 2)
.attr('y', -bbox.height / 2)
.attr('width', bbox.width)
.attr('height', bbox.height);
node.intersect = function (point) {
return intersectRect(node, point);
};
return shapeSvg;
}
function ellipse(parent, bbox, node) {
var rx = bbox.width / 2;
var ry = bbox.height / 2;
var shapeSvg = parent
.insert('ellipse', ':first-child')
.attr('x', -bbox.width / 2)
.attr('y', -bbox.height / 2)
.attr('rx', rx)
.attr('ry', ry);
node.intersect = function (point) {
return intersectEllipse(node, rx, ry, point);
};
return shapeSvg;
}
function circle(parent, bbox, node) {
var r = Math.max(bbox.width, bbox.height) / 2;
var shapeSvg = parent
.insert('circle', ':first-child')
.attr('x', -bbox.width / 2)
.attr('y', -bbox.height / 2)
.attr('r', r);
node.intersect = function (point) {
return intersectCircle(node, r, point);
};
return shapeSvg;
}
// Circumscribe an ellipse for the bounding box with a diamond shape. I derived
// the function to calculate the diamond shape from:
// http://mathforum.org/kb/message.jspa?messageID=3750236
function diamond(parent, bbox, node) {
var w = (bbox.width * Math.SQRT2) / 2;
var h = (bbox.height * Math.SQRT2) / 2;
var points = [
{ x: 0, y: -h },
{ x: -w, y: 0 },
{ x: 0, y: h },
{ x: w, y: 0 },
];
var shapeSvg = parent.insert('polygon', ':first-child').attr(
'points',
points
.map(function (p) {
return p.x + ',' + p.y;
})
.join(' '),
);
node.intersect = function (p) {
return intersectPolygon(node, points, p);
};
return shapeSvg;
}
tbo47-dagre-es-4b95ad0/src/dagre-js/util.js 0000664 0000000 0000000 00000002006 15114061606 0020344 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
// Public utility functions
export { isSubgraph, edgeToId, applyStyle, applyClass, applyTransition };
/*
* Returns true if the specified node in the graph is a subgraph node. A
* subgraph node is one that contains other nodes.
*/
function isSubgraph(g, v) {
return !!g.children(v).length;
}
function edgeToId(e) {
return escapeId(e.v) + ':' + escapeId(e.w) + ':' + escapeId(e.name);
}
var ID_DELIM = /:/g;
function escapeId(str) {
return str ? String(str).replace(ID_DELIM, '\\:') : '';
}
function applyStyle(dom, styleFn) {
if (styleFn) {
dom.attr('style', styleFn);
}
}
function applyClass(dom, classFn, otherClasses) {
if (classFn) {
dom.attr('class', classFn).attr('class', otherClasses + ' ' + dom.attr('class'));
}
}
function applyTransition(selection, g) {
var graph = g.graph();
if (_.isPlainObject(graph)) {
var transition = graph.transition;
if (_.isFunction(transition)) {
return transition(selection);
}
}
return selection;
}
tbo47-dagre-es-4b95ad0/src/dagre/ 0000775 0000000 0000000 00000000000 15114061606 0016421 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre/acyclic.js 0000664 0000000 0000000 00000002361 15114061606 0020370 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { greedyFAS } from './greedy-fas.js';
export { run, undo };
function run(g) {
var fas = g.graph().acyclicer === 'greedy' ? greedyFAS(g, weightFn(g)) : dfsFAS(g);
_.forEach(fas, function (e) {
var label = g.edge(e);
g.removeEdge(e);
label.forwardName = e.name;
label.reversed = true;
g.setEdge(e.w, e.v, label, _.uniqueId('rev'));
});
function weightFn(g) {
return function (e) {
return g.edge(e).weight;
};
}
}
function dfsFAS(g) {
var fas = [];
var stack = {};
var visited = {};
function dfs(v) {
if (Object.prototype.hasOwnProperty.call(visited, v)) {
return;
}
visited[v] = true;
stack[v] = true;
_.forEach(g.outEdges(v), function (e) {
if (Object.prototype.hasOwnProperty.call(stack, e.w)) {
fas.push(e);
} else {
dfs(e.w);
}
});
delete stack[v];
}
_.forEach(g.nodes(), dfs);
return fas;
}
function undo(g) {
_.forEach(g.edges(), function (e) {
var label = g.edge(e);
if (label.reversed) {
g.removeEdge(e);
var forwardName = label.forwardName;
delete label.reversed;
delete label.forwardName;
g.setEdge(e.w, e.v, label, forwardName);
}
});
}
tbo47-dagre-es-4b95ad0/src/dagre/acyclic.test.js 0000664 0000000 0000000 00000006150 15114061606 0021346 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import * as acyclic from './acyclic.js';
import { Graph } from '../graphlib/index.js';
import { findCycles } from '../graphlib/alg/find-cycles.js';
describe('acyclic', function () {
var ACYCLICERS = ['greedy', 'dfs', 'unknown-should-still-work'];
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ multigraph: true }).setDefaultEdgeLabel(function () {
return { minlen: 1, weight: 1 };
});
});
_.forEach(ACYCLICERS, function (acyclicer) {
describe(acyclicer, function () {
beforeEach(function () {
g.setGraph({ acyclicer: acyclicer });
});
describe('run', function () {
it('does not change an already acyclic graph', function () {
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
acyclic.run(g);
var results = _.map(g.edges(), stripLabel);
expect(_.sortBy(results, ['v', 'w'])).to.eql([
{ v: 'a', w: 'b' },
{ v: 'a', w: 'c' },
{ v: 'b', w: 'd' },
{ v: 'c', w: 'd' },
]);
});
it('breaks cycles in the input graph', function () {
g.setPath(['a', 'b', 'c', 'd', 'a']);
acyclic.run(g);
expect(findCycles(g)).to.eql([]);
});
it('creates a multi-edge where necessary', function () {
g.setPath(['a', 'b', 'a']);
acyclic.run(g);
expect(findCycles(g)).to.eql([]);
if (g.hasEdge('a', 'b')) {
expect(g.outEdges('a', 'b')).to.have.length(2);
} else {
expect(g.outEdges('b', 'a')).to.have.length(2);
}
expect(g.edgeCount()).to.equal(2);
});
});
describe('undo', function () {
it('does not change edges where the original graph was acyclic', function () {
g.setEdge('a', 'b', { minlen: 2, weight: 3 });
acyclic.run(g);
acyclic.undo(g);
expect(g.edge('a', 'b')).to.eql({ minlen: 2, weight: 3 });
expect(g.edges()).to.have.length(1);
});
it('can restore previosuly reversed edges', function () {
g.setEdge('a', 'b', { minlen: 2, weight: 3 });
g.setEdge('b', 'a', { minlen: 3, weight: 4 });
acyclic.run(g);
acyclic.undo(g);
expect(g.edge('a', 'b')).to.eql({ minlen: 2, weight: 3 });
expect(g.edge('b', 'a')).to.eql({ minlen: 3, weight: 4 });
expect(g.edges()).to.have.length(2);
});
});
});
});
describe('greedy-specific functionality', function () {
it('prefers to break cycles at low-weight edges', function () {
g.setGraph({ acyclicer: 'greedy' });
g.setDefaultEdgeLabel(function () {
return { minlen: 1, weight: 2 };
});
g.setPath(['a', 'b', 'c', 'd', 'a']);
g.setEdge('c', 'd', { weight: 1 });
acyclic.run(g);
expect(findCycles(g)).to.eql([]);
expect(g.hasEdge('c', 'd')).to.be.false;
});
});
});
function stripLabel(edge) {
var c = _.clone(edge);
delete c.label;
return c;
}
tbo47-dagre-es-4b95ad0/src/dagre/add-border-segments.js 0000664 0000000 0000000 00000001762 15114061606 0022613 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import * as util from './util.js';
export { addBorderSegments };
function addBorderSegments(g) {
function dfs(v) {
var children = g.children(v);
var node = g.node(v);
if (children.length) {
_.forEach(children, dfs);
}
if (Object.prototype.hasOwnProperty.call(node, 'minRank')) {
node.borderLeft = [];
node.borderRight = [];
for (var rank = node.minRank, maxRank = node.maxRank + 1; rank < maxRank; ++rank) {
addBorderNode(g, 'borderLeft', '_bl', v, node, rank);
addBorderNode(g, 'borderRight', '_br', v, node, rank);
}
}
}
_.forEach(g.children(), dfs);
}
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
var label = { width: 0, height: 0, rank: rank, borderType: prop };
var prev = sgNode[prop][rank - 1];
var curr = util.addDummyNode(g, 'border', label, prefix);
sgNode[prop][rank] = curr;
g.setParent(curr, sg);
if (prev) {
g.setEdge(prev, curr, { weight: 1 });
}
}
tbo47-dagre-es-4b95ad0/src/dagre/add-border-segments.test.js 0000664 0000000 0000000 00000007220 15114061606 0023564 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { addBorderSegments } from './add-border-segments.js';
import { Graph } from '../graphlib/index.js';
describe('addBorderSegments', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ compound: true });
});
it('does not add border nodes for a non-compound graph', function () {
var g = new Graph();
g.setNode('a', { rank: 0 });
addBorderSegments(g);
expect(g.nodeCount()).to.equal(1);
expect(g.node('a')).to.eql({ rank: 0 });
});
it('does not add border nodes for a graph with no clusters', function () {
g.setNode('a', { rank: 0 });
addBorderSegments(g);
expect(g.nodeCount()).to.equal(1);
expect(g.node('a')).to.eql({ rank: 0 });
});
it('adds a border for a single-rank subgraph', function () {
g.setNode('sg', { minRank: 1, maxRank: 1 });
addBorderSegments(g);
var bl = g.node('sg').borderLeft[1];
var br = g.node('sg').borderRight[1];
expect(g.node(bl)).eqls({
dummy: 'border',
borderType: 'borderLeft',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(bl)).equals('sg');
expect(g.node(br)).eqls({
dummy: 'border',
borderType: 'borderRight',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(br)).equals('sg');
});
it('adds a border for a multi-rank subgraph', function () {
g.setNode('sg', { minRank: 1, maxRank: 2 });
addBorderSegments(g);
var sgNode = g.node('sg');
var bl2 = sgNode.borderLeft[1];
var br2 = sgNode.borderRight[1];
expect(g.node(bl2)).eqls({
dummy: 'border',
borderType: 'borderLeft',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(bl2)).equals('sg');
expect(g.node(br2)).eqls({
dummy: 'border',
borderType: 'borderRight',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(br2)).equals('sg');
var bl1 = sgNode.borderLeft[2];
var br1 = sgNode.borderRight[2];
expect(g.node(bl1)).eqls({
dummy: 'border',
borderType: 'borderLeft',
rank: 2,
width: 0,
height: 0,
});
expect(g.parent(bl1)).equals('sg');
expect(g.node(br1)).eqls({
dummy: 'border',
borderType: 'borderRight',
rank: 2,
width: 0,
height: 0,
});
expect(g.parent(br1)).equals('sg');
expect(g.hasEdge(sgNode.borderLeft[1], sgNode.borderLeft[2])).to.be.true;
expect(g.hasEdge(sgNode.borderRight[1], sgNode.borderRight[2])).to.be.true;
});
it('adds borders for nested subgraphs', function () {
g.setNode('sg1', { minRank: 1, maxRank: 1 });
g.setNode('sg2', { minRank: 1, maxRank: 1 });
g.setParent('sg2', 'sg1');
addBorderSegments(g);
var bl1 = g.node('sg1').borderLeft[1];
var br1 = g.node('sg1').borderRight[1];
expect(g.node(bl1)).eqls({
dummy: 'border',
borderType: 'borderLeft',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(bl1)).equals('sg1');
expect(g.node(br1)).eqls({
dummy: 'border',
borderType: 'borderRight',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(br1)).equals('sg1');
var bl2 = g.node('sg2').borderLeft[1];
var br2 = g.node('sg2').borderRight[1];
expect(g.node(bl2)).eqls({
dummy: 'border',
borderType: 'borderLeft',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(bl2)).equals('sg2');
expect(g.node(br2)).eqls({
dummy: 'border',
borderType: 'borderRight',
rank: 1,
width: 0,
height: 0,
});
expect(g.parent(br2)).equals('sg2');
});
});
tbo47-dagre-es-4b95ad0/src/dagre/coordinate-system.js 0000664 0000000 0000000 00000002676 15114061606 0022443 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { adjust, undo };
function adjust(g) {
var rankDir = g.graph().rankdir.toLowerCase();
if (rankDir === 'lr' || rankDir === 'rl') {
swapWidthHeight(g);
}
}
function undo(g) {
var rankDir = g.graph().rankdir.toLowerCase();
if (rankDir === 'bt' || rankDir === 'rl') {
reverseY(g);
}
if (rankDir === 'lr' || rankDir === 'rl') {
swapXY(g);
swapWidthHeight(g);
}
}
function swapWidthHeight(g) {
_.forEach(g.nodes(), function (v) {
swapWidthHeightOne(g.node(v));
});
_.forEach(g.edges(), function (e) {
swapWidthHeightOne(g.edge(e));
});
}
function swapWidthHeightOne(attrs) {
var w = attrs.width;
attrs.width = attrs.height;
attrs.height = w;
}
function reverseY(g) {
_.forEach(g.nodes(), function (v) {
reverseYOne(g.node(v));
});
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
_.forEach(edge.points, reverseYOne);
if (Object.prototype.hasOwnProperty.call(edge, 'y')) {
reverseYOne(edge);
}
});
}
function reverseYOne(attrs) {
attrs.y = -attrs.y;
}
function swapXY(g) {
_.forEach(g.nodes(), function (v) {
swapXYOne(g.node(v));
});
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
_.forEach(edge.points, swapXYOne);
if (Object.prototype.hasOwnProperty.call(edge, 'x')) {
swapXYOne(edge);
}
});
}
function swapXYOne(attrs) {
var x = attrs.x;
attrs.x = attrs.y;
attrs.y = x;
}
tbo47-dagre-es-4b95ad0/src/dagre/coordinate-system.test.js 0000664 0000000 0000000 00000004534 15114061606 0023414 0 ustar 00root root 0000000 0000000 import { Graph } from '../graphlib/index.js';
import * as coordinateSystem from './coordinate-system.js';
import { beforeEach, describe, expect, it } from 'vitest';
describe('coordinateSystem', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph();
});
describe('coordinateSystem.adjust', function () {
beforeEach(function () {
g.setNode('a', { width: 100, height: 200 });
});
it('does nothing to node dimensions with rankdir = TB', function () {
g.setGraph({ rankdir: 'TB' });
coordinateSystem.adjust(g);
expect(g.node('a')).eqls({ width: 100, height: 200 });
});
it('does nothing to node dimensions with rankdir = BT', function () {
g.setGraph({ rankdir: 'BT' });
coordinateSystem.adjust(g);
expect(g.node('a')).eqls({ width: 100, height: 200 });
});
it('swaps width and height for nodes with rankdir = LR', function () {
g.setGraph({ rankdir: 'LR' });
coordinateSystem.adjust(g);
expect(g.node('a')).eqls({ width: 200, height: 100 });
});
it('swaps width and height for nodes with rankdir = RL', function () {
g.setGraph({ rankdir: 'RL' });
coordinateSystem.adjust(g);
expect(g.node('a')).eqls({ width: 200, height: 100 });
});
});
describe('coordinateSystem.undo', function () {
beforeEach(function () {
g.setNode('a', { width: 100, height: 200, x: 20, y: 40 });
});
it('does nothing to points with rankdir = TB', function () {
g.setGraph({ rankdir: 'TB' });
coordinateSystem.undo(g);
expect(g.node('a')).eqls({ x: 20, y: 40, width: 100, height: 200 });
});
it('flips the y coordinate for points with rankdir = BT', function () {
g.setGraph({ rankdir: 'BT' });
coordinateSystem.undo(g);
expect(g.node('a')).eqls({ x: 20, y: -40, width: 100, height: 200 });
});
it('swaps dimensions and coordinates for points with rankdir = LR', function () {
g.setGraph({ rankdir: 'LR' });
coordinateSystem.undo(g);
expect(g.node('a')).eqls({ x: 40, y: 20, width: 200, height: 100 });
});
it('swaps dims and coords and flips x for points with rankdir = RL', function () {
g.setGraph({ rankdir: 'RL' });
coordinateSystem.undo(g);
expect(g.node('a')).eqls({ x: -40, y: 20, width: 200, height: 100 });
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/data/ 0000775 0000000 0000000 00000000000 15114061606 0017332 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre/data/list.js 0000664 0000000 0000000 00000002231 15114061606 0020641 0 ustar 00root root 0000000 0000000 /*
* Simple doubly linked list implementation derived from Cormen, et al.,
* "Introduction to Algorithms".
*/
export { List };
class List {
constructor() {
var sentinel = {};
sentinel._next = sentinel._prev = sentinel;
this._sentinel = sentinel;
}
dequeue() {
var sentinel = this._sentinel;
var entry = sentinel._prev;
if (entry !== sentinel) {
unlink(entry);
return entry;
}
}
enqueue(entry) {
var sentinel = this._sentinel;
if (entry._prev && entry._next) {
unlink(entry);
}
entry._next = sentinel._next;
sentinel._next._prev = entry;
sentinel._next = entry;
entry._prev = sentinel;
}
toString() {
var strs = [];
var sentinel = this._sentinel;
var curr = sentinel._prev;
while (curr !== sentinel) {
strs.push(JSON.stringify(curr, filterOutLinks));
curr = curr._prev;
}
return '[' + strs.join(', ') + ']';
}
}
function unlink(entry) {
entry._prev._next = entry._next;
entry._next._prev = entry._prev;
delete entry._next;
delete entry._prev;
}
function filterOutLinks(k, v) {
if (k !== '_next' && k !== '_prev') {
return v;
}
}
tbo47-dagre-es-4b95ad0/src/dagre/data/list.test.js 0000664 0000000 0000000 00000003053 15114061606 0021622 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { List } from './list.js';
describe('data.List', function () {
var list;
beforeEach(function () {
list = new List();
});
describe('dequeue', function () {
it('returns undefined with an empty list', function () {
expect(list.dequeue()).to.be.undefined;
});
it('unlinks and returns the first entry', function () {
var obj = {};
list.enqueue(obj);
expect(list.dequeue()).to.equal(obj);
});
it('unlinks and returns multiple entries in FIFO order', function () {
var obj1 = {};
var obj2 = {};
list.enqueue(obj1);
list.enqueue(obj2);
expect(list.dequeue()).to.equal(obj1);
expect(list.dequeue()).to.equal(obj2);
});
it('unlinks and relinks an entry if it is re-enqueued', function () {
var obj1 = {};
var obj2 = {};
list.enqueue(obj1);
list.enqueue(obj2);
list.enqueue(obj1);
expect(list.dequeue()).to.equal(obj2);
expect(list.dequeue()).to.equal(obj1);
});
it('unlinks and relinks an entry if it is enqueued on another list', function () {
var obj = {};
var list2 = new List();
list.enqueue(obj);
list2.enqueue(obj);
expect(list.dequeue()).to.be.undefined;
expect(list2.dequeue()).to.equal(obj);
});
it('can return a string representation', function () {
list.enqueue({ entry: 1 });
list.enqueue({ entry: 2 });
expect(list.toString()).to.equal('[{"entry":1}, {"entry":2}]');
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/debug.js 0000664 0000000 0000000 00000001375 15114061606 0020053 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
import * as util from './util.js';
export { debugOrdering };
/* istanbul ignore next */
function debugOrdering(g) {
var layerMatrix = util.buildLayerMatrix(g);
var h = new Graph({ compound: true, multigraph: true }).setGraph({});
_.forEach(g.nodes(), function (v) {
h.setNode(v, { label: v });
h.setParent(v, 'layer' + g.node(v).rank);
});
_.forEach(g.edges(), function (e) {
h.setEdge(e.v, e.w, {}, e.name);
});
_.forEach(layerMatrix, function (layer, i) {
var layerV = 'layer' + i;
h.setNode(layerV, { rank: 'same' });
_.reduce(layer, function (u, v) {
h.setEdge(u, v, { style: 'invis' });
return v;
});
});
return h;
}
tbo47-dagre-es-4b95ad0/src/dagre/greedy-fas.js 0000664 0000000 0000000 00000006525 15114061606 0021015 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
import { List } from './data/list.js';
/*
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
* arc set is a set of edges that can be removed to make a graph acyclic.
* The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
* effective heuristic for the feedback arc set problem." This implementation
* adjusts that from the paper to allow for weighted edges.
*/
export { greedyFAS };
var DEFAULT_WEIGHT_FN = _.constant(1);
function greedyFAS(g, weightFn) {
if (g.nodeCount() <= 1) {
return [];
}
var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
// Expand multi-edges
return _.flatten(
_.map(results, function (e) {
return g.outEdges(e.v, e.w);
}),
);
}
function doGreedyFAS(g, buckets, zeroIdx) {
var results = [];
var sources = buckets[buckets.length - 1];
var sinks = buckets[0];
var entry;
while (g.nodeCount()) {
while ((entry = sinks.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
while ((entry = sources.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
if (g.nodeCount()) {
for (var i = buckets.length - 2; i > 0; --i) {
entry = buckets[i].dequeue();
if (entry) {
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
break;
}
}
}
}
return results;
}
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
var results = collectPredecessors ? [] : undefined;
_.forEach(g.inEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var uEntry = g.node(edge.v);
if (collectPredecessors) {
results.push({ v: edge.v, w: edge.w });
}
uEntry.out -= weight;
assignBucket(buckets, zeroIdx, uEntry);
});
_.forEach(g.outEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var w = edge.w;
var wEntry = g.node(w);
wEntry['in'] -= weight;
assignBucket(buckets, zeroIdx, wEntry);
});
g.removeNode(entry.v);
return results;
}
function buildState(g, weightFn) {
var fasGraph = new Graph();
var maxIn = 0;
var maxOut = 0;
_.forEach(g.nodes(), function (v) {
fasGraph.setNode(v, { v: v, in: 0, out: 0 });
});
// Aggregate weights on nodes, but also sum the weights across multi-edges
// into a single edge for the fasGraph.
_.forEach(g.edges(), function (e) {
var prevWeight = fasGraph.edge(e.v, e.w) || 0;
var weight = weightFn(e);
var edgeWeight = prevWeight + weight;
fasGraph.setEdge(e.v, e.w, edgeWeight);
maxOut = Math.max(maxOut, (fasGraph.node(e.v).out += weight));
maxIn = Math.max(maxIn, (fasGraph.node(e.w)['in'] += weight));
});
var buckets = _.range(maxOut + maxIn + 3).map(function () {
return new List();
});
var zeroIdx = maxIn + 1;
_.forEach(fasGraph.nodes(), function (v) {
assignBucket(buckets, zeroIdx, fasGraph.node(v));
});
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
}
function assignBucket(buckets, zeroIdx, entry) {
if (!entry.out) {
buckets[0].enqueue(entry);
} else if (!entry['in']) {
buckets[buckets.length - 1].enqueue(entry);
} else {
buckets[entry.out - entry['in'] + zeroIdx].enqueue(entry);
}
}
tbo47-dagre-es-4b95ad0/src/dagre/greedy-fas.test.js 0000664 0000000 0000000 00000006402 15114061606 0021765 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../graphlib/index.js';
import { findCycles } from '../graphlib/alg/find-cycles.js';
import { greedyFAS } from './greedy-fas.js';
describe('greedyFAS', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph();
});
it('returns the empty set for empty graphs', function () {
expect(greedyFAS(g)).to.eql([]);
});
it('returns the empty set for single-node graphs', function () {
g.setNode('a');
expect(greedyFAS(g)).to.eql([]);
});
it('returns an empty set if the input graph is acyclic', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.setEdge('b', 'd');
g.setEdge('a', 'e');
expect(greedyFAS(g)).to.eql([]);
});
it('returns a single edge with a simple cycle', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('b', 'a');
checkFAS(g, greedyFAS(g));
});
it('returns a single edge in a 4-node cycle', function () {
var g = new Graph();
g.setEdge('n1', 'n2');
g.setPath(['n2', 'n3', 'n4', 'n5', 'n2']);
g.setEdge('n3', 'n5');
g.setEdge('n4', 'n2');
g.setEdge('n4', 'n6');
checkFAS(g, greedyFAS(g));
});
it('returns two edges for two 4-node cycles', function () {
var g = new Graph();
g.setEdge('n1', 'n2');
g.setPath(['n2', 'n3', 'n4', 'n5', 'n2']);
g.setEdge('n3', 'n5');
g.setEdge('n4', 'n2');
g.setEdge('n4', 'n6');
g.setPath(['n6', 'n7', 'n8', 'n9', 'n6']);
g.setEdge('n7', 'n9');
g.setEdge('n8', 'n6');
g.setEdge('n8', 'n10');
checkFAS(g, greedyFAS(g));
});
it('works with arbitrarily weighted edges', function () {
// Our algorithm should also work for graphs with multi-edges, a graph
// where more than one edge can be pointing in the same direction between
// the same pair of incident nodes. We try this by assigning weights to
// our edges representing the number of edges from one node to the other.
var g1 = new Graph();
g1.setEdge('n1', 'n2', 2);
g1.setEdge('n2', 'n1', 1);
expect(greedyFAS(g1, weightFn(g1))).to.eql([{ v: 'n2', w: 'n1' }]);
var g2 = new Graph();
g2.setEdge('n1', 'n2', 1);
g2.setEdge('n2', 'n1', 2);
expect(greedyFAS(g2, weightFn(g2))).to.eql([{ v: 'n1', w: 'n2' }]);
});
it('works for multigraphs', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', 5, 'foo');
g.setEdge('b', 'a', 2, 'bar');
g.setEdge('b', 'a', 2, 'baz');
expect(_.sortBy(greedyFAS(g, weightFn(g)), 'name')).to.eql([
{ v: 'b', w: 'a', name: 'bar' },
{ v: 'b', w: 'a', name: 'baz' },
]);
});
});
function checkFAS(g, fas) {
var n = g.nodeCount();
var m = g.edgeCount();
_.forEach(fas, function (edge) {
g.removeEdge(edge.v, edge.w);
});
expect(findCycles(g)).to.eql([]);
// The more direct m/2 - n/6 fails for the simple cycle A <-> B, where one
// edge must be reversed, but the performance bound implies that only 2/3rds
// of an edge can be reversed. I'm using floors to acount for this.
expect(fas.length).to.be.lte(Math.floor(m / 2) - Math.floor(n / 6));
}
function weightFn(g) {
return function (e) {
return g.edge(e);
};
}
tbo47-dagre-es-4b95ad0/src/dagre/index.js 0000664 0000000 0000000 00000000322 15114061606 0020063 0 ustar 00root root 0000000 0000000 import * as acyclic from './acyclic.js';
import { layout } from './layout.js';
import * as normalize from './normalize.js';
import { rank } from './rank/index.js';
export { acyclic, normalize, rank, layout };
tbo47-dagre-es-4b95ad0/src/dagre/layout.js 0000664 0000000 0000000 00000027547 15114061606 0020313 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
import { addBorderSegments } from './add-border-segments.js';
import * as coordinateSystem from './coordinate-system.js';
import * as acyclic from './acyclic.js';
import * as normalize from './normalize.js';
import { rank } from './rank/index.js';
import * as nestingGraph from './nesting-graph.js';
import { order } from './order/index.js';
import { parentDummyChains } from './parent-dummy-chains.js';
import { position } from './position/index.js';
import * as util from './util.js';
export { layout };
function layout(g, opts) {
var time = opts && opts.debugTiming ? util.time : util.notime;
time('layout', () => {
var layoutGraph = time(' buildLayoutGraph', () => buildLayoutGraph(g));
time(' runLayout', () => runLayout(layoutGraph, time));
time(' updateInputGraph', () => updateInputGraph(g, layoutGraph));
});
}
function runLayout(g, time) {
time(' makeSpaceForEdgeLabels', () => makeSpaceForEdgeLabels(g));
time(' removeSelfEdges', () => removeSelfEdges(g));
time(' acyclic', () => acyclic.run(g));
time(' nestingGraph.run', () => nestingGraph.run(g));
time(' rank', () => rank(util.asNonCompoundGraph(g)));
time(' injectEdgeLabelProxies', () => injectEdgeLabelProxies(g));
time(' removeEmptyRanks', () => util.removeEmptyRanks(g));
time(' nestingGraph.cleanup', () => nestingGraph.cleanup(g));
time(' normalizeRanks', () => util.normalizeRanks(g));
time(' assignRankMinMax', () => assignRankMinMax(g));
time(' removeEdgeLabelProxies', () => removeEdgeLabelProxies(g));
time(' normalize.run', () => normalize.run(g));
time(' parentDummyChains', () => parentDummyChains(g));
time(' addBorderSegments', () => addBorderSegments(g));
time(' order', () => order(g));
time(' insertSelfEdges', () => insertSelfEdges(g));
time(' adjustCoordinateSystem', () => coordinateSystem.adjust(g));
time(' position', () => position(g));
time(' positionSelfEdges', () => positionSelfEdges(g));
time(' removeBorderNodes', () => removeBorderNodes(g));
time(' normalize.undo', () => normalize.undo(g));
time(' fixupEdgeLabelCoords', () => fixupEdgeLabelCoords(g));
time(' undoCoordinateSystem', () => coordinateSystem.undo(g));
time(' translateGraph', () => translateGraph(g));
time(' assignNodeIntersects', () => assignNodeIntersects(g));
time(' reversePoints', () => reversePointsForReversedEdges(g));
time(' acyclic.undo', () => acyclic.undo(g));
}
/*
* Copies final layout information from the layout graph back to the input
* graph. This process only copies whitelisted attributes from the layout graph
* to the input graph, so it serves as a good place to determine what
* attributes can influence layout.
*/
function updateInputGraph(inputGraph, layoutGraph) {
_.forEach(inputGraph.nodes(), function (v) {
var inputLabel = inputGraph.node(v);
var layoutLabel = layoutGraph.node(v);
if (inputLabel) {
inputLabel.x = layoutLabel.x;
inputLabel.y = layoutLabel.y;
if (layoutGraph.children(v).length) {
inputLabel.width = layoutLabel.width;
inputLabel.height = layoutLabel.height;
}
}
});
_.forEach(inputGraph.edges(), function (e) {
var inputLabel = inputGraph.edge(e);
var layoutLabel = layoutGraph.edge(e);
inputLabel.points = layoutLabel.points;
if (Object.prototype.hasOwnProperty.call(layoutLabel, 'x')) {
inputLabel.x = layoutLabel.x;
inputLabel.y = layoutLabel.y;
}
});
inputGraph.graph().width = layoutGraph.graph().width;
inputGraph.graph().height = layoutGraph.graph().height;
}
var graphNumAttrs = ['nodesep', 'edgesep', 'ranksep', 'marginx', 'marginy'];
var graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' };
var graphAttrs = ['acyclicer', 'ranker', 'rankdir', 'align'];
var nodeNumAttrs = ['width', 'height'];
var nodeDefaults = { width: 0, height: 0 };
var edgeNumAttrs = ['minlen', 'weight', 'width', 'height', 'labeloffset'];
var edgeDefaults = {
minlen: 1,
weight: 1,
width: 0,
height: 0,
labeloffset: 10,
labelpos: 'r',
};
var edgeAttrs = ['labelpos'];
/*
* Constructs a new graph from the input graph, which can be used for layout.
* This process copies only whitelisted attributes from the input graph to the
* layout graph. Thus this function serves as a good place to determine what
* attributes can influence layout.
*/
function buildLayoutGraph(inputGraph) {
var g = new Graph({ multigraph: true, compound: true });
var graph = canonicalize(inputGraph.graph());
g.setGraph(
_.merge({}, graphDefaults, selectNumberAttrs(graph, graphNumAttrs), _.pick(graph, graphAttrs)),
);
_.forEach(inputGraph.nodes(), function (v) {
var node = canonicalize(inputGraph.node(v));
g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
g.setParent(v, inputGraph.parent(v));
});
_.forEach(inputGraph.edges(), function (e) {
var edge = canonicalize(inputGraph.edge(e));
g.setEdge(
e,
_.merge({}, edgeDefaults, selectNumberAttrs(edge, edgeNumAttrs), _.pick(edge, edgeAttrs)),
);
});
return g;
}
/*
* This idea comes from the Gansner paper: to account for edge labels in our
* layout we split each rank in half by doubling minlen and halving ranksep.
* Then we can place labels at these mid-points between nodes.
*
* We also add some minimal padding to the width to push the label for the edge
* away from the edge itself a bit.
*/
function makeSpaceForEdgeLabels(g) {
var graph = g.graph();
graph.ranksep /= 2;
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
edge.minlen *= 2;
if (edge.labelpos.toLowerCase() !== 'c') {
if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
edge.width += edge.labeloffset;
} else {
edge.height += edge.labeloffset;
}
}
});
}
/*
* Creates temporary dummy nodes that capture the rank in which each edge's
* label is going to, if it has one of non-zero width and height. We do this
* so that we can safely remove empty ranks while preserving balance for the
* label's position.
*/
function injectEdgeLabelProxies(g) {
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (edge.width && edge.height) {
var v = g.node(e.v);
var w = g.node(e.w);
var label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
util.addDummyNode(g, 'edge-proxy', label, '_ep');
}
});
}
function assignRankMinMax(g) {
var maxRank = 0;
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
if (node.borderTop) {
node.minRank = g.node(node.borderTop).rank;
node.maxRank = g.node(node.borderBottom).rank;
// @ts-expect-error
maxRank = _.max(maxRank, node.maxRank);
}
});
g.graph().maxRank = maxRank;
}
function removeEdgeLabelProxies(g) {
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
if (node.dummy === 'edge-proxy') {
g.edge(node.e).labelRank = node.rank;
g.removeNode(v);
}
});
}
function translateGraph(g) {
var minX = Number.POSITIVE_INFINITY;
var maxX = 0;
var minY = Number.POSITIVE_INFINITY;
var maxY = 0;
var graphLabel = g.graph();
var marginX = graphLabel.marginx || 0;
var marginY = graphLabel.marginy || 0;
function getExtremes(attrs) {
var x = attrs.x;
var y = attrs.y;
var w = attrs.width;
var h = attrs.height;
minX = Math.min(minX, x - w / 2);
maxX = Math.max(maxX, x + w / 2);
minY = Math.min(minY, y - h / 2);
maxY = Math.max(maxY, y + h / 2);
}
_.forEach(g.nodes(), function (v) {
getExtremes(g.node(v));
});
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (Object.prototype.hasOwnProperty.call(edge, 'x')) {
getExtremes(edge);
}
});
minX -= marginX;
minY -= marginY;
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
node.x -= minX;
node.y -= minY;
});
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
_.forEach(edge.points, function (p) {
p.x -= minX;
p.y -= minY;
});
if (Object.prototype.hasOwnProperty.call(edge, 'x')) {
edge.x -= minX;
}
if (Object.prototype.hasOwnProperty.call(edge, 'y')) {
edge.y -= minY;
}
});
graphLabel.width = maxX - minX + marginX;
graphLabel.height = maxY - minY + marginY;
}
function assignNodeIntersects(g) {
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
var nodeV = g.node(e.v);
var nodeW = g.node(e.w);
var p1, p2;
if (!edge.points) {
edge.points = [];
p1 = nodeW;
p2 = nodeV;
} else {
p1 = edge.points[0];
p2 = edge.points[edge.points.length - 1];
}
edge.points.unshift(util.intersectRect(nodeV, p1));
edge.points.push(util.intersectRect(nodeW, p2));
});
}
function fixupEdgeLabelCoords(g) {
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (Object.prototype.hasOwnProperty.call(edge, 'x')) {
if (edge.labelpos === 'l' || edge.labelpos === 'r') {
edge.width -= edge.labeloffset;
}
switch (edge.labelpos) {
case 'l':
edge.x -= edge.width / 2 + edge.labeloffset;
break;
case 'r':
edge.x += edge.width / 2 + edge.labeloffset;
break;
}
}
});
}
function reversePointsForReversedEdges(g) {
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (edge.reversed) {
edge.points.reverse();
}
});
}
function removeBorderNodes(g) {
_.forEach(g.nodes(), function (v) {
if (g.children(v).length) {
var node = g.node(v);
var t = g.node(node.borderTop);
var b = g.node(node.borderBottom);
var l = g.node(_.last(node.borderLeft));
var r = g.node(_.last(node.borderRight));
node.width = Math.abs(r.x - l.x);
node.height = Math.abs(b.y - t.y);
node.x = l.x + node.width / 2;
node.y = t.y + node.height / 2;
}
});
_.forEach(g.nodes(), function (v) {
if (g.node(v).dummy === 'border') {
g.removeNode(v);
}
});
}
function removeSelfEdges(g) {
_.forEach(g.edges(), function (e) {
if (e.v === e.w) {
var node = g.node(e.v);
if (!node.selfEdges) {
node.selfEdges = [];
}
node.selfEdges.push({ e: e, label: g.edge(e) });
g.removeEdge(e);
}
});
}
function insertSelfEdges(g) {
var layers = util.buildLayerMatrix(g);
_.forEach(layers, function (layer) {
var orderShift = 0;
_.forEach(layer, function (v, i) {
var node = g.node(v);
node.order = i + orderShift;
_.forEach(node.selfEdges, function (selfEdge) {
util.addDummyNode(
g,
'selfedge',
{
width: selfEdge.label.width,
height: selfEdge.label.height,
rank: node.rank,
order: i + ++orderShift,
e: selfEdge.e,
label: selfEdge.label,
},
'_se',
);
});
delete node.selfEdges;
});
});
}
function positionSelfEdges(g) {
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
if (node.dummy === 'selfedge') {
var selfNode = g.node(node.e.v);
var x = selfNode.x + selfNode.width / 2;
var y = selfNode.y;
var dx = node.x - x;
var dy = selfNode.height / 2;
g.setEdge(node.e, node.label);
g.removeNode(v);
node.label.points = [
{ x: x + (2 * dx) / 3, y: y - dy },
{ x: x + (5 * dx) / 6, y: y - dy },
{ x: x + dx, y: y },
{ x: x + (5 * dx) / 6, y: y + dy },
{ x: x + (2 * dx) / 3, y: y + dy },
];
node.label.x = node.x;
node.label.y = node.y;
}
});
}
function selectNumberAttrs(obj, attrs) {
return _.mapValues(_.pick(obj, attrs), Number);
}
function canonicalize(attrs) {
var newAttrs = {};
_.forEach(attrs, function (v, k) {
newAttrs[k.toLowerCase()] = v;
});
return newAttrs;
}
tbo47-dagre-es-4b95ad0/src/dagre/layout.test.js 0000664 0000000 0000000 00000024205 15114061606 0021255 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { layout } from './layout.js';
import { Graph } from '../graphlib/index.js';
describe('layout', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ multigraph: true, compound: true })
.setGraph({})
.setDefaultEdgeLabel(function () {
return {};
});
});
it('can layout a single node', function () {
g.setNode('a', { width: 50, height: 100 });
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 50 / 2, y: 100 / 2 },
});
expect(g.node('a').x).to.equal(50 / 2);
expect(g.node('a').y).to.equal(100 / 2);
});
it('can layout two nodes on the same rank', function () {
g.graph().nodesep = 200;
g.setNode('a', { width: 50, height: 100 });
g.setNode('b', { width: 75, height: 200 });
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 50 / 2, y: 200 / 2 },
b: { x: 50 + 200 + 75 / 2, y: 200 / 2 },
});
});
it('can layout two nodes connected by an edge', function () {
g.graph().ranksep = 300;
g.setNode('a', { width: 50, height: 100 });
g.setNode('b', { width: 75, height: 200 });
g.setEdge('a', 'b');
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 75 / 2, y: 100 / 2 },
b: { x: 75 / 2, y: 100 + 300 + 200 / 2 },
});
// We should not get x, y coordinates if the edge has no label
expect(g.edge('a', 'b')).to.not.have.property('x');
expect(g.edge('a', 'b')).to.not.have.property('y');
});
it('can layout an edge with a label', function () {
g.graph().ranksep = 300;
g.setNode('a', { width: 50, height: 100 });
g.setNode('b', { width: 75, height: 200 });
g.setEdge('a', 'b', { width: 60, height: 70, labelpos: 'c' });
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 75 / 2, y: 100 / 2 },
b: { x: 75 / 2, y: 100 + 150 + 70 + 150 + 200 / 2 },
});
expect(_.pick(g.edge('a', 'b'), ['x', 'y'])).eqls({ x: 75 / 2, y: 100 + 150 + 70 / 2 });
});
describe('can layout an edge with a long label, with rankdir =', function () {
_.forEach(['TB', 'BT', 'LR', 'RL'], function (rankdir) {
it(rankdir, function () {
g.graph().nodesep = g.graph().edgesep = 10;
g.graph().rankdir = rankdir;
_.forEach(['a', 'b', 'c', 'd'], function (v) {
g.setNode(v, { width: 10, height: 10 });
});
g.setEdge('a', 'c', { width: 2000, height: 10, labelpos: 'c' });
g.setEdge('b', 'd', { width: 1, height: 1 });
layout(g);
var p1, p2;
if (rankdir === 'TB' || rankdir === 'BT') {
p1 = g.edge('a', 'c');
p2 = g.edge('b', 'd');
} else {
p1 = g.node('a');
p2 = g.node('c');
}
expect(Math.abs(p1.x - p2.x)).gt(1000);
});
});
});
describe('can apply an offset, with rankdir =', function () {
_.forEach(['TB', 'BT', 'LR', 'RL'], function (rankdir) {
it(rankdir, function () {
g.graph().nodesep = g.graph().edgesep = 10;
g.graph().rankdir = rankdir;
_.forEach(['a', 'b', 'c', 'd'], function (v) {
g.setNode(v, { width: 10, height: 10 });
});
g.setEdge('a', 'b', { width: 10, height: 10, labelpos: 'l', labeloffset: 1000 });
g.setEdge('c', 'd', { width: 10, height: 10, labelpos: 'r', labeloffset: 1000 });
layout(g);
if (rankdir === 'TB' || rankdir === 'BT') {
expect(g.edge('a', 'b').x - g.edge('a', 'b').points[0].x).equals(-1000 - 10 / 2);
expect(g.edge('c', 'd').x - g.edge('c', 'd').points[0].x).equals(1000 + 10 / 2);
} else {
expect(g.edge('a', 'b').y - g.edge('a', 'b').points[0].y).equals(-1000 - 10 / 2);
expect(g.edge('c', 'd').y - g.edge('c', 'd').points[0].y).equals(1000 + 10 / 2);
}
});
});
});
it('can layout a long edge with a label', function () {
g.graph().ranksep = 300;
g.setNode('a', { width: 50, height: 100 });
g.setNode('b', { width: 75, height: 200 });
g.setEdge('a', 'b', { width: 60, height: 70, minlen: 2, labelpos: 'c' });
layout(g);
expect(g.edge('a', 'b').x).to.equal(75 / 2);
expect(g.edge('a', 'b').y).to.be.gt(g.node('a').y).to.be.lt(g.node('b').y);
});
it('can layout out a short cycle', function () {
g.graph().ranksep = 200;
g.setNode('a', { width: 100, height: 100 });
g.setNode('b', { width: 100, height: 100 });
g.setEdge('a', 'b', { weight: 2 });
g.setEdge('b', 'a');
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 100 / 2, y: 100 / 2 },
b: { x: 100 / 2, y: 100 + 200 + 100 / 2 },
});
// One arrow should point down, one up
expect(g.edge('a', 'b').points[1].y).gt(g.edge('a', 'b').points[0].y);
expect(g.edge('b', 'a').points[0].y).gt(g.edge('b', 'a').points[1].y);
});
it('adds rectangle intersects for edges', function () {
g.graph().ranksep = 200;
g.setNode('a', { width: 100, height: 100 });
g.setNode('b', { width: 100, height: 100 });
g.setEdge('a', 'b');
layout(g);
var points = g.edge('a', 'b').points;
expect(points).to.have.length(3);
expect(points).eqls([
{ x: 100 / 2, y: 100 }, // intersect with bottom of a
{ x: 100 / 2, y: 100 + 200 / 2 }, // point for edge label
{ x: 100 / 2, y: 100 + 200 }, // intersect with top of b
]);
});
it('adds rectangle intersects for edges spanning multiple ranks', function () {
g.graph().ranksep = 200;
g.setNode('a', { width: 100, height: 100 });
g.setNode('b', { width: 100, height: 100 });
g.setEdge('a', 'b', { minlen: 2 });
layout(g);
var points = g.edge('a', 'b').points;
expect(points).to.have.length(5);
expect(points).eqls([
{ x: 100 / 2, y: 100 }, // intersect with bottom of a
{ x: 100 / 2, y: 100 + 200 / 2 }, // bend #1
{ x: 100 / 2, y: 100 + 400 / 2 }, // point for edge label
{ x: 100 / 2, y: 100 + 600 / 2 }, // bend #2
{ x: 100 / 2, y: 100 + 800 / 2 }, // intersect with top of b
]);
});
describe('can layout a self loop', function () {
_.forEach(['TB', 'BT', 'LR', 'RL'], function (rankdir) {
it('in rankdir = ' + rankdir, function () {
g.graph().edgesep = 75;
g.graph().rankdir = rankdir;
g.setNode('a', { width: 100, height: 100 });
g.setEdge('a', 'a', { width: 50, height: 50 });
layout(g);
var nodeA = g.node('a');
var points = g.edge('a', 'a').points;
expect(points).to.have.length(7);
_.forEach(points, function (point) {
if (rankdir !== 'LR' && rankdir !== 'RL') {
expect(point.x).gt(nodeA.x);
expect(Math.abs(point.y - nodeA.y)).lte(nodeA.height / 2);
} else {
expect(point.y).gt(nodeA.y);
expect(Math.abs(point.x - nodeA.x)).lte(nodeA.width / 2);
}
});
});
});
});
it('can layout a graph with subgraphs', function () {
// To be expanded, this primarily ensures nothing blows up for the moment.
g.setNode('a', { width: 50, height: 50 });
g.setParent('a', 'sg1');
layout(g);
});
it('minimizes the height of subgraphs', function () {
_.forEach(['a', 'b', 'c', 'd', 'x', 'y'], function (v) {
g.setNode(v, { width: 50, height: 50 });
});
g.setPath(['a', 'b', 'c', 'd']);
g.setEdge('a', 'x', { weight: 100 });
g.setEdge('y', 'd', { weight: 100 });
g.setParent('x', 'sg');
g.setParent('y', 'sg');
// We did not set up an edge (x, y), and we set up high-weight edges from
// outside of the subgraph to nodes in the subgraph. This is to try to
// force nodes x and y to be on different ranks, which we want our ranker
// to avoid.
layout(g);
expect(g.node('x').y).to.equal(g.node('y').y);
});
it('can layout subgraphs with different rankdirs', function () {
g.setNode('a', { width: 50, height: 50 });
g.setNode('sg', {});
g.setParent('a', 'sg');
function check(rankdir) {
expect(g.node('sg').width, 'width ' + rankdir).gt(50);
expect(g.node('sg').height, 'height ' + rankdir).gt(50);
expect(g.node('sg').x, 'x ' + rankdir).gt(50 / 2);
expect(g.node('sg').y, 'y ' + rankdir).gt(50 / 2);
}
_.forEach(['tb', 'bt', 'lr', 'rl'], function (rankdir) {
g.graph().rankdir = rankdir;
layout(g);
check(rankdir);
});
});
it('adds dimensions to the graph', function () {
g.setNode('a', { width: 100, height: 50 });
layout(g);
expect(g.graph().width).equals(100);
expect(g.graph().height).equals(50);
});
describe('ensures all coordinates are in the bounding box for the graph', function () {
_.forEach(['TB', 'BT', 'LR', 'RL'], function (rankdir) {
describe(rankdir, function () {
beforeEach(function () {
g.graph().rankdir = rankdir;
});
it('node', function () {
g.setNode('a', { width: 100, height: 200 });
layout(g);
expect(g.node('a').x).equals(100 / 2);
expect(g.node('a').y).equals(200 / 2);
});
it('edge, labelpos = l', function () {
g.setNode('a', { width: 100, height: 100 });
g.setNode('b', { width: 100, height: 100 });
g.setEdge('a', 'b', {
width: 1000,
height: 2000,
labelpos: 'l',
labeloffset: 0,
});
layout(g);
if (rankdir === 'TB' || rankdir === 'BT') {
expect(g.edge('a', 'b').x).equals(1000 / 2);
} else {
expect(g.edge('a', 'b').y).equals(2000 / 2);
}
});
});
});
});
it('treats attributes with case-insensitivity', function () {
g.graph().nodeSep = 200; // note the capital S
g.setNode('a', { width: 50, height: 100 });
g.setNode('b', { width: 75, height: 200 });
layout(g);
expect(extractCoordinates(g)).to.eql({
a: { x: 50 / 2, y: 200 / 2 },
b: { x: 50 + 200 + 75 / 2, y: 200 / 2 },
});
});
});
function extractCoordinates(g) {
var nodes = g.nodes();
return _.zipObject(
nodes,
_.map(nodes, function (v) {
return _.pick(g.node(v), ['x', 'y']);
}),
);
}
tbo47-dagre-es-4b95ad0/src/dagre/nesting-graph.js 0000664 0000000 0000000 00000007117 15114061606 0021533 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import * as util from './util.js';
export { run, cleanup };
/*
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
* adds appropriate edges to ensure that all cluster nodes are placed between
* these boundries, and ensures that the graph is connected.
*
* In addition we ensure, through the use of the minlen property, that nodes
* and subgraph border nodes to not end up on the same rank.
*
* Preconditions:
*
* 1. Input graph is a DAG
* 2. Nodes in the input graph has a minlen attribute
*
* Postconditions:
*
* 1. Input graph is connected.
* 2. Dummy nodes are added for the tops and bottoms of subgraphs.
* 3. The minlen attribute for nodes is adjusted to ensure nodes do not
* get placed on the same rank as subgraph border nodes.
*
* The nesting graph idea comes from Sander, "Layout of Compound Directed
* Graphs."
*/
function run(g) {
var root = util.addDummyNode(g, 'root', {}, '_root');
var depths = treeDepths(g);
var height = _.max(_.values(depths)) - 1; // Note: depths is an Object not an array
var nodeSep = 2 * height + 1;
g.graph().nestingRoot = root;
// Multiply minlen by nodeSep to align nodes on non-border ranks.
_.forEach(g.edges(), function (e) {
g.edge(e).minlen *= nodeSep;
});
// Calculate a weight that is sufficient to keep subgraphs vertically compact
var weight = sumWeights(g) + 1;
// Create border nodes and link them up
_.forEach(g.children(), function (child) {
dfs(g, root, nodeSep, weight, height, depths, child);
});
// Save the multiplier for node layers for later removal of empty border
// layers.
g.graph().nodeRankFactor = nodeSep;
}
function dfs(g, root, nodeSep, weight, height, depths, v) {
var children = g.children(v);
if (!children.length) {
if (v !== root) {
g.setEdge(root, v, { weight: 0, minlen: nodeSep });
}
return;
}
var top = util.addBorderNode(g, '_bt');
var bottom = util.addBorderNode(g, '_bb');
var label = g.node(v);
g.setParent(top, v);
label.borderTop = top;
g.setParent(bottom, v);
label.borderBottom = bottom;
_.forEach(children, function (child) {
dfs(g, root, nodeSep, weight, height, depths, child);
var childNode = g.node(child);
var childTop = childNode.borderTop ? childNode.borderTop : child;
var childBottom = childNode.borderBottom ? childNode.borderBottom : child;
var thisWeight = childNode.borderTop ? weight : 2 * weight;
var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
g.setEdge(top, childTop, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true,
});
g.setEdge(childBottom, bottom, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true,
});
});
if (!g.parent(v)) {
g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
}
}
function treeDepths(g) {
var depths = {};
function dfs(v, depth) {
var children = g.children(v);
if (children && children.length) {
_.forEach(children, function (child) {
dfs(child, depth + 1);
});
}
depths[v] = depth;
}
_.forEach(g.children(), function (v) {
dfs(v, 1);
});
return depths;
}
function sumWeights(g) {
return _.reduce(
g.edges(),
function (acc, e) {
return acc + g.edge(e).weight;
},
0,
);
}
function cleanup(g) {
var graphLabel = g.graph();
g.removeNode(graphLabel.nestingRoot);
delete graphLabel.nestingRoot;
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (edge.nestingEdge) {
g.removeEdge(e);
}
});
}
tbo47-dagre-es-4b95ad0/src/dagre/nesting-graph.test.js 0000664 0000000 0000000 00000015565 15114061606 0022517 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../graphlib/index.js';
import { components } from '../graphlib/alg/components.js';
import * as nestingGraph from './nesting-graph.js';
describe('rank/nestingGraph', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ compound: true }).setGraph({}).setDefaultNodeLabel(function () {
return {};
});
});
describe('run', function () {
it('connects a disconnected graph', function () {
g.setNode('a');
g.setNode('b');
expect(components(g)).to.have.length(2);
nestingGraph.run(g);
expect(components(g)).to.have.length(1);
expect(g.hasNode('a'));
expect(g.hasNode('b'));
});
it('adds border nodes to the top and bottom of a subgraph', function () {
g.setParent('a', 'sg1');
nestingGraph.run(g);
var borderTop = g.node('sg1').borderTop;
var borderBottom = g.node('sg1').borderBottom;
expect(borderTop).to.exist;
expect(borderBottom).to.exist;
expect(g.parent(borderTop)).to.equal('sg1');
expect(g.parent(borderBottom)).to.equal('sg1');
expect(g.outEdges(borderTop, 'a')).to.have.length(1);
expect(g.edge(g.outEdges(borderTop, 'a')[0]).minlen).equals(1);
expect(g.outEdges('a', borderBottom)).to.have.length(1);
expect(g.edge(g.outEdges('a', borderBottom)[0]).minlen).equals(1);
expect(g.node(borderTop)).eqls({ width: 0, height: 0, dummy: 'border' });
expect(g.node(borderBottom)).eqls({ width: 0, height: 0, dummy: 'border' });
});
it('adds edges between borders of nested subgraphs', function () {
g.setParent('sg2', 'sg1');
g.setParent('a', 'sg2');
nestingGraph.run(g);
var sg1Top = g.node('sg1').borderTop;
var sg1Bottom = g.node('sg1').borderBottom;
var sg2Top = g.node('sg2').borderTop;
var sg2Bottom = g.node('sg2').borderBottom;
expect(sg1Top).to.exist;
expect(sg1Bottom).to.exist;
expect(sg2Top).to.exist;
expect(sg2Bottom).to.exist;
expect(g.outEdges(sg1Top, sg2Top)).to.have.length(1);
expect(g.edge(g.outEdges(sg1Top, sg2Top)[0]).minlen).equals(1);
expect(g.outEdges(sg2Bottom, sg1Bottom)).to.have.length(1);
expect(g.edge(g.outEdges(sg2Bottom, sg1Bottom)[0]).minlen).equals(1);
});
it('adds sufficient weight to border to node edges', function () {
// We want to keep subgraphs tight, so we should ensure that the weight for
// the edge between the top (and bottom) border nodes and nodes in the
// subgraph have weights exceeding anything in the graph.
g.setParent('x', 'sg');
g.setEdge('a', 'x', { weight: 100 });
g.setEdge('x', 'b', { weight: 200 });
nestingGraph.run(g);
var top = g.node('sg').borderTop;
var bot = g.node('sg').borderBottom;
expect(g.edge(top, 'x').weight).to.be.gt(300);
expect(g.edge('x', bot).weight).to.be.gt(300);
});
it('adds an edge from the root to the tops of top-level subgraphs', function () {
g.setParent('a', 'sg1');
nestingGraph.run(g);
var root = g.graph().nestingRoot;
var borderTop = g.node('sg1').borderTop;
expect(root).to.exist;
expect(borderTop).to.exist;
expect(g.outEdges(root, borderTop)).to.have.length(1);
expect(g.hasEdge(g.outEdges(root, borderTop)[0])).to.be.true;
});
it('adds an edge from root to each node with the correct minlen #1', function () {
g.setNode('a');
nestingGraph.run(g);
var root = g.graph().nestingRoot;
expect(root).to.exist;
expect(g.outEdges(root, 'a')).to.have.length(1);
expect(g.edge(g.outEdges(root, 'a')[0])).eqls({ weight: 0, minlen: 1 });
});
it('adds an edge from root to each node with the correct minlen #2', function () {
g.setParent('a', 'sg1');
nestingGraph.run(g);
var root = g.graph().nestingRoot;
expect(root).to.exist;
expect(g.outEdges(root, 'a')).to.have.length(1);
expect(g.edge(g.outEdges(root, 'a')[0])).eqls({ weight: 0, minlen: 3 });
});
it('adds an edge from root to each node with the correct minlen #3', function () {
g.setParent('sg2', 'sg1');
g.setParent('a', 'sg2');
nestingGraph.run(g);
var root = g.graph().nestingRoot;
expect(root).to.exist;
expect(g.outEdges(root, 'a')).to.have.length(1);
expect(g.edge(g.outEdges(root, 'a')[0])).eqls({ weight: 0, minlen: 5 });
});
it('does not add an edge from the root to itself', function () {
g.setNode('a');
nestingGraph.run(g);
var root = g.graph().nestingRoot;
expect(g.outEdges(root, root)).eqls([]);
});
it('expands inter-node edges to separate SG border and nodes #1', function () {
g.setEdge('a', 'b', { minlen: 1 });
nestingGraph.run(g);
expect(g.edge('a', 'b').minlen).equals(1);
});
it('expands inter-node edges to separate SG border and nodes #2', function () {
g.setParent('a', 'sg1');
g.setEdge('a', 'b', { minlen: 1 });
nestingGraph.run(g);
expect(g.edge('a', 'b').minlen).equals(3);
});
it('expands inter-node edges to separate SG border and nodes #3', function () {
g.setParent('sg2', 'sg1');
g.setParent('a', 'sg2');
g.setEdge('a', 'b', { minlen: 1 });
nestingGraph.run(g);
expect(g.edge('a', 'b').minlen).equals(5);
});
it('sets minlen correctly for nested SG boder to children', function () {
g.setParent('a', 'sg1');
g.setParent('sg2', 'sg1');
g.setParent('b', 'sg2');
nestingGraph.run(g);
// We expect the following layering:
//
// 0: root
// 1: empty (close sg2)
// 2: empty (close sg1)
// 3: open sg1
// 4: open sg2
// 5: a, b
// 6: close sg2
// 7: close sg1
var root = g.graph().nestingRoot;
var sg1Top = g.node('sg1').borderTop;
var sg1Bot = g.node('sg1').borderBottom;
var sg2Top = g.node('sg2').borderTop;
var sg2Bot = g.node('sg2').borderBottom;
expect(g.edge(root, sg1Top).minlen).equals(3);
expect(g.edge(sg1Top, sg2Top).minlen).equals(1);
expect(g.edge(sg1Top, 'a').minlen).equals(2);
expect(g.edge('a', sg1Bot).minlen).equals(2);
expect(g.edge(sg2Top, 'b').minlen).equals(1);
expect(g.edge('b', sg2Bot).minlen).equals(1);
expect(g.edge(sg2Bot, sg1Bot).minlen).equals(1);
});
});
describe('cleanup', function () {
it('removes nesting graph edges', function () {
g.setParent('a', 'sg1');
g.setEdge('a', 'b', { minlen: 1 });
nestingGraph.run(g);
nestingGraph.cleanup(g);
expect(g.successors('a')).eqls(['b']);
});
it('removes the root node', function () {
g.setParent('a', 'sg1');
nestingGraph.run(g);
nestingGraph.cleanup(g);
expect(g.nodeCount()).to.equal(4); // sg1 + sg1Top + sg1Bottom + "a"
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/normalize.js 0000664 0000000 0000000 00000005331 15114061606 0020761 0 ustar 00root root 0000000 0000000 /**
* TypeScript type imports:
*
* @import { Graph } from '../graphlib/graph.js';
*/
import * as _ from 'lodash-es';
import * as util from './util.js';
export { run, undo };
/*
* Breaks any long edges in the graph into short segments that span 1 layer
* each. This operation is undoable with the denormalize function.
*
* Pre-conditions:
*
* 1. The input graph is a DAG.
* 2. Each node in the graph has a "rank" property.
*
* Post-condition:
*
* 1. All edges in the graph have a length of 1.
* 2. Dummy nodes are added where edges have been split into segments.
* 3. The graph is augmented with a "dummyChains" attribute which contains
* the first dummy in each chain of dummy nodes produced.
*/
function run(g) {
g.graph().dummyChains = [];
_.forEach(g.edges(), function (edge) {
normalizeEdge(g, edge);
});
}
/**
* @param {Graph} g
*/
function normalizeEdge(g, e) {
var v = e.v;
var vRank = g.node(v).rank;
var w = e.w;
var wRank = g.node(w).rank;
var name = e.name;
var edgeLabel = g.edge(e);
var labelRank = edgeLabel.labelRank;
if (wRank === vRank + 1) return;
g.removeEdge(e);
/**
* @typedef {Object} Attrs
* @property {number} width
* @property {number} height
* @property {ReturnType} edgeLabel
* @property {any} edgeObj
* @property {ReturnType["rank"]} rank
* @property {string} [dummy]
* @property {ReturnType["labelpos"]} [labelpos]
*/
/** @type {Attrs | undefined} */
var attrs = undefined;
var dummy, i;
for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
edgeLabel.points = [];
attrs = {
width: 0,
height: 0,
edgeLabel: edgeLabel,
edgeObj: e,
rank: vRank,
};
dummy = util.addDummyNode(g, 'edge', attrs, '_d');
if (vRank === labelRank) {
attrs.width = edgeLabel.width;
attrs.height = edgeLabel.height;
attrs.dummy = 'edge-label';
attrs.labelpos = edgeLabel.labelpos;
}
g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
if (i === 0) {
g.graph().dummyChains.push(dummy);
}
v = dummy;
}
g.setEdge(v, w, { weight: edgeLabel.weight }, name);
}
function undo(g) {
_.forEach(g.graph().dummyChains, function (v) {
var node = g.node(v);
var origLabel = node.edgeLabel;
var w;
g.setEdge(node.edgeObj, origLabel);
while (node.dummy) {
w = g.successors(v)[0];
g.removeNode(v);
origLabel.points.push({ x: node.x, y: node.y });
if (node.dummy === 'edge-label') {
origLabel.x = node.x;
origLabel.y = node.y;
origLabel.width = node.width;
origLabel.height = node.height;
}
v = w;
node = g.node(v);
}
});
}
tbo47-dagre-es-4b95ad0/src/dagre/normalize.test.js 0000664 0000000 0000000 00000014414 15114061606 0021741 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import * as normalize from './normalize.js';
import { Graph } from '../graphlib/index.js';
describe('normalize', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ multigraph: true, compound: true }).setGraph({});
});
describe('run', function () {
it('does not change a short edge', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 1 });
g.setEdge('a', 'b', {});
normalize.run(g);
expect(_.map(g.edges(), incidentNodes)).to.eql([{ v: 'a', w: 'b' }]);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
});
it('splits a two layer edge into two segments', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', {});
normalize.run(g);
expect(g.successors('a')).to.have.length(1);
var successor = g.successors('a')[0];
expect(g.node(successor).dummy).to.equal('edge');
expect(g.node(successor).rank).to.equal(1);
expect(g.successors(successor)).to.eql(['b']);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(2);
expect(g.graph().dummyChains).to.have.length(1);
expect(g.graph().dummyChains[0]).to.equal(successor);
});
it('assigns width = 0, height = 0 to dummy nodes by default', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', { width: 10, height: 10 });
normalize.run(g);
expect(g.successors('a')).to.have.length(1);
var successor = g.successors('a')[0];
expect(g.node(successor).width).to.equal(0);
expect(g.node(successor).height).to.equal(0);
});
it('assigns width and height from the edge for the node on labelRank', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 4 });
g.setEdge('a', 'b', { width: 20, height: 10, labelRank: 2 });
normalize.run(g);
var labelV = g.successors(g.successors('a')[0])[0];
var labelNode = g.node(labelV);
expect(labelNode.width).to.equal(20);
expect(labelNode.height).to.equal(10);
});
it('preserves the weight for the edge', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', { weight: 2 });
normalize.run(g);
expect(g.successors('a')).to.have.length(1);
expect(g.edge('a', g.successors('a')[0]).weight).to.equal(2);
});
});
describe('undo', function () {
it('reverses the run operation', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', {});
normalize.run(g);
normalize.undo(g);
expect(_.map(g.edges(), incidentNodes)).to.eql([{ v: 'a', w: 'b' }]);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(2);
});
it('restores previous edge labels', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', { foo: 'bar' });
normalize.run(g);
normalize.undo(g);
expect(g.edge('a', 'b').foo).equals('bar');
});
it("collects assigned coordinates into the 'points' attribute", function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', {});
normalize.run(g);
var dummyLabel = g.node(g.neighbors('a')[0]);
dummyLabel.x = 5;
dummyLabel.y = 10;
normalize.undo(g);
expect(g.edge('a', 'b').points).eqls([{ x: 5, y: 10 }]);
});
it("merges assigned coordinates into the 'points' attribute", function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 4 });
g.setEdge('a', 'b', {});
normalize.run(g);
var aSucLabel = g.node(g.neighbors('a')[0]);
aSucLabel.x = 5;
aSucLabel.y = 10;
var midLabel = g.node(g.successors(g.successors('a')[0])[0]);
midLabel.x = 20;
midLabel.y = 25;
var bPredLabel = g.node(g.neighbors('b')[0]);
bPredLabel.x = 100;
bPredLabel.y = 200;
normalize.undo(g);
expect(g.edge('a', 'b').points).eqls([
{ x: 5, y: 10 },
{ x: 20, y: 25 },
{ x: 100, y: 200 },
]);
});
it('sets coords and dims for the label, if the edge has one', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', { width: 10, height: 20, labelRank: 1 });
normalize.run(g);
var labelNode = g.node(g.successors('a')[0]);
labelNode.x = 50;
labelNode.y = 60;
labelNode.width = 20;
labelNode.height = 10;
normalize.undo(g);
expect(_.pick(g.edge('a', 'b'), ['x', 'y', 'width', 'height'])).eqls({
x: 50,
y: 60,
width: 20,
height: 10,
});
});
it('sets coords and dims for the label, if the long edge has one', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 4 });
g.setEdge('a', 'b', { width: 10, height: 20, labelRank: 2 });
normalize.run(g);
var labelNode = g.node(g.successors(g.successors('a')[0])[0]);
labelNode.x = 50;
labelNode.y = 60;
labelNode.width = 20;
labelNode.height = 10;
normalize.undo(g);
expect(_.pick(g.edge('a', 'b'), ['x', 'y', 'width', 'height'])).eqls({
x: 50,
y: 60,
width: 20,
height: 10,
});
});
it('restores multi-edges', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', {}, 'bar');
g.setEdge('a', 'b', {}, 'foo');
normalize.run(g);
var outEdges = _.sortBy(g.outEdges('a'), 'name');
expect(outEdges).to.have.length(2);
var barDummy = g.node(outEdges[0].w);
barDummy.x = 5;
barDummy.y = 10;
var fooDummy = g.node(outEdges[1].w);
fooDummy.x = 15;
fooDummy.y = 20;
normalize.undo(g);
expect(g.hasEdge('a', 'b')).to.be.false;
expect(g.edge('a', 'b', 'bar').points).eqls([{ x: 5, y: 10 }]);
expect(g.edge('a', 'b', 'foo').points).eqls([{ x: 15, y: 20 }]);
});
});
});
function incidentNodes(edge) {
return { v: edge.v, w: edge.w };
}
tbo47-dagre-es-4b95ad0/src/dagre/order/ 0000775 0000000 0000000 00000000000 15114061606 0017534 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre/order/add-subgraph-constraints.js 0000664 0000000 0000000 00000002300 15114061606 0024773 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { addSubgraphConstraints };
function addSubgraphConstraints(g, cg, vs) {
var prev = {},
rootPrev;
_.forEach(vs, function (v) {
var child = g.parent(v),
parent,
prevChild;
while (child) {
parent = g.parent(child);
if (parent) {
prevChild = prev[parent];
prev[parent] = child;
} else {
prevChild = rootPrev;
rootPrev = child;
}
if (prevChild && prevChild !== child) {
cg.setEdge(prevChild, child);
return;
}
child = parent;
}
});
/*
function dfs(v) {
var children = v ? g.children(v) : g.children();
if (children.length) {
var min = Number.POSITIVE_INFINITY,
subgraphs = [];
_.each(children, function(child) {
var childMin = dfs(child);
if (g.children(child).length) {
subgraphs.push({ v: child, order: childMin });
}
min = Math.min(min, childMin);
});
_.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
cg.setEdge(prev.v, curr.v);
return curr;
});
return min;
}
return g.node(v).order;
}
dfs(undefined);
*/
}
tbo47-dagre-es-4b95ad0/src/dagre/order/add-subgraph-constraints.test.js 0000664 0000000 0000000 00000003474 15114061606 0025766 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { addSubgraphConstraints } from './add-subgraph-constraints.js';
describe('order/addSubgraphConstraints', function () {
/** @type {Graph} */
var g;
/** @type {Graph} */
var cg;
beforeEach(function () {
g = new Graph({ compound: true });
cg = new Graph();
});
it('does not change CG for a flat set of nodes', function () {
var vs = ['a', 'b', 'c', 'd'];
_.forEach(vs, function (v) {
g.setNode(v);
});
addSubgraphConstraints(g, cg, vs);
expect(cg.nodeCount()).equals(0);
expect(cg.edgeCount()).equals(0);
});
it("doesn't create a constraint for contiguous subgraph nodes", function () {
var vs = ['a', 'b', 'c'];
_.forEach(vs, function (v) {
g.setParent(v, 'sg');
});
addSubgraphConstraints(g, cg, vs);
expect(cg.nodeCount()).equals(0);
expect(cg.edgeCount()).equals(0);
});
it('adds a constraint when the parents for adjacent nodes are different', function () {
var vs = ['a', 'b'];
g.setParent('a', 'sg1');
g.setParent('b', 'sg2');
addSubgraphConstraints(g, cg, vs);
expect(cg.edges()).eqls([{ v: 'sg1', w: 'sg2' }]);
});
it('works for multiple levels', function () {
var vs = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
_.forEach(vs, function (v) {
g.setNode(v);
});
g.setParent('b', 'sg2');
g.setParent('sg2', 'sg1');
g.setParent('c', 'sg1');
g.setParent('d', 'sg3');
g.setParent('sg3', 'sg1');
g.setParent('f', 'sg4');
g.setParent('g', 'sg5');
g.setParent('sg5', 'sg4');
addSubgraphConstraints(g, cg, vs);
expect(_.sortBy(cg.edges(), 'v')).eqls([
{ v: 'sg1', w: 'sg4' },
{ v: 'sg2', w: 'sg3' },
]);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/barycenter.js 0000664 0000000 0000000 00000001233 15114061606 0022227 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { barycenter };
function barycenter(g, movable) {
return _.map(movable, function (v) {
var inV = g.inEdges(v);
if (!inV.length) {
return { v: v };
} else {
var result = _.reduce(
inV,
function (acc, e) {
var edge = g.edge(e),
nodeU = g.node(e.v);
return {
sum: acc.sum + edge.weight * nodeU.order,
weight: acc.weight + edge.weight,
};
},
{ sum: 0, weight: 0 },
);
return {
v: v,
barycenter: result.sum / result.weight,
weight: result.weight,
};
}
});
}
tbo47-dagre-es-4b95ad0/src/dagre/order/barycenter.test.js 0000664 0000000 0000000 00000004300 15114061606 0023203 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { barycenter } from './barycenter.js';
import { Graph } from '../../graphlib/graph.js';
describe('order/barycenter', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph()
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { weight: 1 };
});
});
it('assigns an undefined barycenter for a node with no predecessors', function () {
g.setNode('x', {});
var results = barycenter(g, ['x']);
expect(results).to.have.length(1);
expect(results[0]).to.eql({ v: 'x' });
});
it('assigns the position of the sole predecessors', function () {
g.setNode('a', { order: 2 });
g.setEdge('a', 'x');
var results = barycenter(g, ['x']);
expect(results).to.have.length(1);
expect(results[0]).eqls({ v: 'x', barycenter: 2, weight: 1 });
});
it('assigns the average of multiple predecessors', function () {
g.setNode('a', { order: 2 });
g.setNode('b', { order: 4 });
g.setEdge('a', 'x');
g.setEdge('b', 'x');
var results = barycenter(g, ['x']);
expect(results).to.have.length(1);
expect(results[0]).eqls({ v: 'x', barycenter: 3, weight: 2 });
});
it('takes into account the weight of edges', function () {
g.setNode('a', { order: 2 });
g.setNode('b', { order: 4 });
g.setEdge('a', 'x', { weight: 3 });
g.setEdge('b', 'x');
var results = barycenter(g, ['x']);
expect(results).to.have.length(1);
expect(results[0]).eqls({ v: 'x', barycenter: 2.5, weight: 4 });
});
it('calculates barycenters for all nodes in the movable layer', function () {
g.setNode('a', { order: 1 });
g.setNode('b', { order: 2 });
g.setNode('c', { order: 4 });
g.setEdge('a', 'x');
g.setEdge('b', 'x');
g.setNode('y');
g.setEdge('a', 'z', { weight: 2 });
g.setEdge('c', 'z');
var results = barycenter(g, ['x', 'y', 'z']);
expect(results).to.have.length(3);
expect(results[0]).eqls({ v: 'x', barycenter: 1.5, weight: 2 });
expect(results[1]).eqls({ v: 'y' });
expect(results[2]).eqls({ v: 'z', barycenter: 2, weight: 3 });
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/build-layer-graph.js 0000664 0000000 0000000 00000005105 15114061606 0023403 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
export { buildLayerGraph };
/*
* Constructs a graph that can be used to sort a layer of nodes. The graph will
* contain all base and subgraph nodes from the request layer in their original
* hierarchy and any edges that are incident on these nodes and are of the type
* requested by the "relationship" parameter.
*
* Nodes from the requested rank that do not have parents are assigned a root
* node in the output graph, which is set in the root graph attribute. This
* makes it easy to walk the hierarchy of movable nodes during ordering.
*
* Pre-conditions:
*
* 1. Input graph is a DAG
* 2. Base nodes in the input graph have a rank attribute
* 3. Subgraph nodes in the input graph has minRank and maxRank attributes
* 4. Edges have an assigned weight
*
* Post-conditions:
*
* 1. Output graph has all nodes in the movable rank with preserved
* hierarchy.
* 2. Root nodes in the movable layer are made children of the node
* indicated by the root attribute of the graph.
* 3. Non-movable nodes incident on movable nodes, selected by the
* relationship parameter, are included in the graph (without hierarchy).
* 4. Edges incident on movable nodes, selected by the relationship
* parameter, are added to the output graph.
* 5. The weights for copied edges are aggregated as need, since the output
* graph is not a multi-graph.
*/
function buildLayerGraph(g, rank, relationship) {
var root = createRootNode(g),
result = new Graph({ compound: true })
.setGraph({ root: root })
.setDefaultNodeLabel(function (v) {
return g.node(v);
});
_.forEach(g.nodes(), function (v) {
var node = g.node(v),
parent = g.parent(v);
if (node.rank === rank || (node.minRank <= rank && rank <= node.maxRank)) {
result.setNode(v);
result.setParent(v, parent || root);
// This assumes we have only short edges!
_.forEach(g[relationship](v), function (e) {
var u = e.v === v ? e.w : e.v,
edge = result.edge(u, v),
weight = !_.isUndefined(edge) ? edge.weight : 0;
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
});
if (Object.prototype.hasOwnProperty.call(node, 'minRank')) {
result.setNode(v, {
borderLeft: node.borderLeft[rank],
borderRight: node.borderRight[rank],
});
}
}
});
return result;
}
function createRootNode(g) {
var v;
while (g.hasNode((v = _.uniqueId('_root'))));
return v;
}
tbo47-dagre-es-4b95ad0/src/dagre/order/build-layer-graph.test.js 0000664 0000000 0000000 00000010427 15114061606 0024364 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { buildLayerGraph } from './build-layer-graph.js';
describe('order/buildLayerGraph', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ compound: true, multigraph: true });
});
it('places movable nodes with no parents under the root node', function () {
g.setNode('a', { rank: 1 });
g.setNode('b', { rank: 1 });
g.setNode('c', { rank: 2 });
g.setNode('d', { rank: 3 });
var lg;
lg = buildLayerGraph(g, 1, 'inEdges');
expect(lg.hasNode(lg.graph().root));
expect(lg.children()).eqls([lg.graph().root]);
expect(lg.children(lg.graph().root)).eqls(['a', 'b']);
});
it('copies flat nodes from the layer to the graph', function () {
g.setNode('a', { rank: 1 });
g.setNode('b', { rank: 1 });
g.setNode('c', { rank: 2 });
g.setNode('d', { rank: 3 });
expect(buildLayerGraph(g, 1, 'inEdges').nodes()).to.include('a');
expect(buildLayerGraph(g, 1, 'inEdges').nodes()).to.include('b');
expect(buildLayerGraph(g, 2, 'inEdges').nodes()).to.include('c');
expect(buildLayerGraph(g, 3, 'inEdges').nodes()).to.include('d');
});
it('uses the original node label for copied nodes', function () {
// This allows us to make updates to the original graph and have them
// be available automatically in the layer graph.
g.setNode('a', { foo: 1, rank: 1 });
g.setNode('b', { foo: 2, rank: 2 });
g.setEdge('a', 'b', { weight: 1 });
var lg = buildLayerGraph(g, 2, 'inEdges');
expect(lg.node('a').foo).equals(1);
g.node('a').foo = 'updated';
expect(lg.node('a').foo).equals('updated');
expect(lg.node('b').foo).equals(2);
g.node('b').foo = 'updated';
expect(lg.node('b').foo).equals('updated');
});
it('copies edges incident on rank nodes to the graph (inEdges)', function () {
g.setNode('a', { rank: 1 });
g.setNode('b', { rank: 1 });
g.setNode('c', { rank: 2 });
g.setNode('d', { rank: 3 });
g.setEdge('a', 'c', { weight: 2 });
g.setEdge('b', 'c', { weight: 3 });
g.setEdge('c', 'd', { weight: 4 });
expect(buildLayerGraph(g, 1, 'inEdges').edgeCount()).to.equal(0);
expect(buildLayerGraph(g, 2, 'inEdges').edgeCount()).to.equal(2);
expect(buildLayerGraph(g, 2, 'inEdges').edge('a', 'c')).eqls({ weight: 2 });
expect(buildLayerGraph(g, 2, 'inEdges').edge('b', 'c')).eqls({ weight: 3 });
expect(buildLayerGraph(g, 3, 'inEdges').edgeCount()).to.equal(1);
expect(buildLayerGraph(g, 3, 'inEdges').edge('c', 'd')).eqls({ weight: 4 });
});
it('copies edges incident on rank nodes to the graph (outEdges)', function () {
g.setNode('a', { rank: 1 });
g.setNode('b', { rank: 1 });
g.setNode('c', { rank: 2 });
g.setNode('d', { rank: 3 });
g.setEdge('a', 'c', { weight: 2 });
g.setEdge('b', 'c', { weight: 3 });
g.setEdge('c', 'd', { weight: 4 });
expect(buildLayerGraph(g, 1, 'outEdges').edgeCount()).to.equal(2);
expect(buildLayerGraph(g, 1, 'outEdges').edge('c', 'a')).eqls({ weight: 2 });
expect(buildLayerGraph(g, 1, 'outEdges').edge('c', 'b')).eqls({ weight: 3 });
expect(buildLayerGraph(g, 2, 'outEdges').edgeCount()).to.equal(1);
expect(buildLayerGraph(g, 2, 'outEdges').edge('d', 'c')).eqls({ weight: 4 });
expect(buildLayerGraph(g, 3, 'outEdges').edgeCount()).to.equal(0);
});
it('collapses multi-edges', function () {
g.setNode('a', { rank: 1 });
g.setNode('b', { rank: 2 });
g.setEdge('a', 'b', { weight: 2 });
g.setEdge('a', 'b', { weight: 3 }, 'multi');
expect(buildLayerGraph(g, 2, 'inEdges').edge('a', 'b')).eqls({ weight: 5 });
});
it('preserves hierarchy for the movable layer', function () {
g.setNode('a', { rank: 0 });
g.setNode('b', { rank: 0 });
g.setNode('c', { rank: 0 });
g.setNode('sg', {
minRank: 0,
maxRank: 0,
borderLeft: ['bl'],
borderRight: ['br'],
});
_.forEach(['a', 'b'], function (v) {
g.setParent(v, 'sg');
});
var lg = buildLayerGraph(g, 0, 'inEdges');
var root = lg.graph().root;
expect(_.sortBy(lg.children(root))).eqls(['c', 'sg']);
expect(lg.parent('a')).equals('sg');
expect(lg.parent('b')).equals('sg');
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/cross-count.js 0000664 0000000 0000000 00000004055 15114061606 0022355 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { crossCount };
/*
* A function that takes a layering (an array of layers, each with an array of
* ordererd nodes) and a graph and returns a weighted crossing count.
*
* Pre-conditions:
*
* 1. Input graph must be simple (not a multigraph), directed, and include
* only simple edges.
* 2. Edges in the input graph must have assigned weights.
*
* Post-conditions:
*
* 1. The graph and layering matrix are left unchanged.
*
* This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
*/
function crossCount(g, layering) {
var cc = 0;
for (var i = 1; i < layering.length; ++i) {
cc += twoLayerCrossCount(g, layering[i - 1], layering[i]);
}
return cc;
}
function twoLayerCrossCount(g, northLayer, southLayer) {
// Sort all of the edges between the north and south layers by their position
// in the north layer and then the south. Map these edges to the position of
// their head in the south layer.
var southPos = _.zipObject(
southLayer,
_.map(southLayer, function (v, i) {
return i;
}),
);
var southEntries = _.flatten(
_.map(northLayer, function (v) {
return _.sortBy(
_.map(g.outEdges(v), function (e) {
return { pos: southPos[e.w], weight: g.edge(e).weight };
}),
'pos',
);
}),
);
// Build the accumulator tree
var firstIndex = 1;
while (firstIndex < southLayer.length) firstIndex <<= 1;
var treeSize = 2 * firstIndex - 1;
firstIndex -= 1;
var tree = _.map(new Array(treeSize), function () {
return 0;
});
// Calculate the weighted crossings
var cc = 0;
_.forEach(
// @ts-expect-error
southEntries.forEach(function (entry) {
var index = entry.pos + firstIndex;
tree[index] += entry.weight;
var weightSum = 0;
while (index > 0) {
if (index % 2) {
weightSum += tree[index + 1];
}
index = (index - 1) >> 1;
tree[index] += entry.weight;
}
cc += entry.weight * weightSum;
}),
);
return cc;
}
tbo47-dagre-es-4b95ad0/src/dagre/order/cross-count.test.js 0000664 0000000 0000000 00000003531 15114061606 0023331 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { crossCount } from './cross-count.js';
describe('crossCount', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph().setDefaultEdgeLabel(function () {
return { weight: 1 };
});
});
it('returns 0 for an empty layering', function () {
expect(crossCount(g, [])).equals(0);
});
it('returns 0 for a layering with no crossings', function () {
g.setEdge('a1', 'b1');
g.setEdge('a2', 'b2');
expect(
crossCount(g, [
['a1', 'a2'],
['b1', 'b2'],
]),
).equals(0);
});
it('returns 1 for a layering with 1 crossing', function () {
g.setEdge('a1', 'b1');
g.setEdge('a2', 'b2');
expect(
crossCount(g, [
['a1', 'a2'],
['b2', 'b1'],
]),
).equals(1);
});
it('returns a weighted crossing count for a layering with 1 crossing', function () {
g.setEdge('a1', 'b1', { weight: 2 });
g.setEdge('a2', 'b2', { weight: 3 });
expect(
crossCount(g, [
['a1', 'a2'],
['b2', 'b1'],
]),
).equals(6);
});
it('calculates crossings across layers', function () {
g.setPath(['a1', 'b1', 'c1']);
g.setPath(['a2', 'b2', 'c2']);
expect(
crossCount(g, [
['a1', 'a2'],
['b2', 'b1'],
['c1', 'c2'],
]),
).equals(2);
});
it('works for graph #1', function () {
g.setPath(['a', 'b', 'c']);
g.setPath(['d', 'e', 'c']);
g.setPath(['a', 'f', 'i']);
g.setEdge('a', 'e');
expect(
crossCount(g, [
['a', 'd'],
['b', 'e', 'f'],
['c', 'i'],
]),
).equals(1);
expect(
crossCount(g, [
['d', 'a'],
['e', 'b', 'f'],
['c', 'i'],
]),
).equals(0);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/index.js 0000664 0000000 0000000 00000004203 15114061606 0021200 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
import * as util from '../util.js';
import { addSubgraphConstraints } from './add-subgraph-constraints.js';
import { buildLayerGraph } from './build-layer-graph.js';
import { crossCount } from './cross-count.js';
import { initOrder } from './init-order.js';
import { sortSubgraph } from './sort-subgraph.js';
export { order };
/*
* Applies heuristics to minimize edge crossings in the graph and sets the best
* order solution as an order attribute on each node.
*
* Pre-conditions:
*
* 1. Graph must be DAG
* 2. Graph nodes must be objects with a "rank" attribute
* 3. Graph edges must have the "weight" attribute
*
* Post-conditions:
*
* 1. Graph nodes will have an "order" attribute based on the results of the
* algorithm.
*/
function order(g) {
var maxRank = util.maxRank(g),
downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), 'inEdges'),
upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), 'outEdges');
var layering = initOrder(g);
assignOrder(g, layering);
var bestCC = Number.POSITIVE_INFINITY,
best;
for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
layering = util.buildLayerMatrix(g);
var cc = crossCount(g, layering);
if (cc < bestCC) {
lastBest = 0;
best = _.cloneDeep(layering);
bestCC = cc;
}
}
assignOrder(g, best);
}
function buildLayerGraphs(g, ranks, relationship) {
return _.map(ranks, function (rank) {
return buildLayerGraph(g, rank, relationship);
});
}
function sweepLayerGraphs(layerGraphs, biasRight) {
var cg = new Graph();
_.forEach(layerGraphs, function (lg) {
var root = lg.graph().root;
var sorted = sortSubgraph(lg, root, cg, biasRight);
_.forEach(sorted.vs, function (v, i) {
lg.node(v).order = i;
});
addSubgraphConstraints(lg, cg, sorted.vs);
});
}
function assignOrder(g, layering) {
_.forEach(layering, function (layer) {
_.forEach(layer, function (v, i) {
g.node(v).order = i;
});
});
}
tbo47-dagre-es-4b95ad0/src/dagre/order/index.test.js 0000664 0000000 0000000 00000003364 15114061606 0022165 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { order } from './index.js';
import { crossCount } from './cross-count.js';
import { buildLayerMatrix } from '../util.js';
describe('order', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph().setDefaultEdgeLabel({ weight: 1 });
});
it('does not add crossings to a tree structure', function () {
g.setNode('a', { rank: 1 });
_.forEach(['b', 'e'], function (v) {
g.setNode(v, { rank: 2 });
});
_.forEach(['c', 'd', 'f'], function (v) {
g.setNode(v, { rank: 3 });
});
g.setPath(['a', 'b', 'c']);
g.setEdge('b', 'd');
g.setPath(['a', 'e', 'f']);
order(g);
var layering = buildLayerMatrix(g);
expect(crossCount(g, layering)).to.equal(0);
});
it('can solve a simple graph', function () {
// This graph resulted in a single crossing for previous versions of dagre.
_.forEach(['a', 'd'], function (v) {
g.setNode(v, { rank: 1 });
});
_.forEach(['b', 'f', 'e'], function (v) {
g.setNode(v, { rank: 2 });
});
_.forEach(['c', 'g'], function (v) {
g.setNode(v, { rank: 3 });
});
order(g);
var layering = buildLayerMatrix(g);
expect(crossCount(g, layering)).to.equal(0);
});
it('can minimize crossings', function () {
g.setNode('a', { rank: 1 });
_.forEach(['b', 'e', 'g'], function (v) {
g.setNode(v, { rank: 2 });
});
_.forEach(['c', 'f', 'h'], function (v) {
g.setNode(v, { rank: 3 });
});
g.setNode('d', { rank: 4 });
order(g);
var layering = buildLayerMatrix(g);
expect(crossCount(g, layering)).to.be.lte(1);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/init-order.js 0000664 0000000 0000000 00000002061 15114061606 0022145 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
/*
* Assigns an initial order value for each node by performing a DFS search
* starting from nodes in the first rank. Nodes are assigned an order in their
* rank as they are first visited.
*
* This approach comes from Gansner, et al., "A Technique for Drawing Directed
* Graphs."
*
* Returns a layering matrix with an array per layer and each layer sorted by
* the order of its nodes.
*/
export function initOrder(g) {
var visited = {};
var simpleNodes = _.filter(g.nodes(), function (v) {
return !g.children(v).length;
});
var maxRank = _.max(
_.map(simpleNodes, function (v) {
return g.node(v).rank;
}),
);
var layers = _.map(_.range(maxRank + 1), function () {
return [];
});
function dfs(v) {
if (_.has(visited, v)) return;
visited[v] = true;
var node = g.node(v);
layers[node.rank].push(v);
_.forEach(g.successors(v), dfs);
}
var orderedVs = _.sortBy(simpleNodes, function (v) {
return g.node(v).rank;
});
_.forEach(orderedVs, dfs);
return layers;
}
tbo47-dagre-es-4b95ad0/src/dagre/order/init-order.test.js 0000664 0000000 0000000 00000002771 15114061606 0023133 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { initOrder } from './init-order.js';
describe('order/initOrder', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ compound: true }).setDefaultEdgeLabel(function () {
return { weight: 1 };
});
});
it('assigns non-overlapping orders for each rank in a tree', function () {
_.forEach({ a: 0, b: 1, c: 2, d: 2, e: 1 }, function (rank, v) {
g.setNode(v, { rank: rank });
});
g.setPath(['a', 'b', 'c']);
g.setEdge('b', 'd');
g.setEdge('a', 'e');
var layering = initOrder(g);
expect(layering[0]).to.eql(['a']);
expect(_.sortBy(layering[1])).to.eql(['b', 'e']);
expect(_.sortBy(layering[2])).to.eql(['c', 'd']);
});
it('assigns non-overlapping orders for each rank in a DAG', function () {
_.forEach({ a: 0, b: 1, c: 1, d: 2 }, function (rank, v) {
g.setNode(v, { rank: rank });
});
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
var layering = initOrder(g);
expect(layering[0]).to.eql(['a']);
expect(_.sortBy(layering[1])).to.eql(['b', 'c']);
expect(_.sortBy(layering[2])).to.eql(['d']);
});
it('does not assign an order to subgraph nodes', function () {
g.setNode('a', { rank: 0 });
g.setNode('sg1', {});
g.setParent('a', 'sg1');
var layering = initOrder(g);
expect(layering).to.eql([['a']]);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/resolve-conflicts.js 0000664 0000000 0000000 00000006540 15114061606 0023540 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { resolveConflicts };
/*
* Given a list of entries of the form {v, barycenter, weight} and a
* constraint graph this function will resolve any conflicts between the
* constraint graph and the barycenters for the entries. If the barycenters for
* an entry would violate a constraint in the constraint graph then we coalesce
* the nodes in the conflict into a new node that respects the contraint and
* aggregates barycenter and weight information.
*
* This implementation is based on the description in Forster, "A Fast and
* Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
* differs in some specific details.
*
* Pre-conditions:
*
* 1. Each entry has the form {v, barycenter, weight}, or if the node has
* no barycenter, then {v}.
*
* Returns:
*
* A new list of entries of the form {vs, i, barycenter, weight}. The list
* `vs` may either be a singleton or it may be an aggregation of nodes
* ordered such that they do not violate constraints from the constraint
* graph. The property `i` is the lowest original index of any of the
* elements in `vs`.
*/
function resolveConflicts(entries, cg) {
var mappedEntries = {};
_.forEach(entries, function (entry, i) {
var tmp = (mappedEntries[entry.v] = {
indegree: 0,
in: [],
out: [],
vs: [entry.v],
i: i,
});
if (!_.isUndefined(entry.barycenter)) {
// @ts-expect-error
tmp.barycenter = entry.barycenter;
// @ts-expect-error
tmp.weight = entry.weight;
}
});
_.forEach(cg.edges(), function (e) {
var entryV = mappedEntries[e.v];
var entryW = mappedEntries[e.w];
if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
entryW.indegree++;
entryV.out.push(mappedEntries[e.w]);
}
});
var sourceSet = _.filter(mappedEntries, function (entry) {
// @ts-expect-error
return !entry.indegree;
});
return doResolveConflicts(sourceSet);
}
function doResolveConflicts(sourceSet) {
var entries = [];
function handleIn(vEntry) {
return function (uEntry) {
if (uEntry.merged) {
return;
}
if (
_.isUndefined(uEntry.barycenter) ||
_.isUndefined(vEntry.barycenter) ||
uEntry.barycenter >= vEntry.barycenter
) {
mergeEntries(vEntry, uEntry);
}
};
}
function handleOut(vEntry) {
return function (wEntry) {
wEntry['in'].push(vEntry);
if (--wEntry.indegree === 0) {
sourceSet.push(wEntry);
}
};
}
while (sourceSet.length) {
var entry = sourceSet.pop();
entries.push(entry);
_.forEach(entry['in'].reverse(), handleIn(entry));
_.forEach(entry.out, handleOut(entry));
}
return _.map(
_.filter(entries, function (entry) {
return !entry.merged;
}),
function (entry) {
return _.pick(entry, ['vs', 'i', 'barycenter', 'weight']);
},
);
}
function mergeEntries(target, source) {
var sum = 0;
var weight = 0;
if (target.weight) {
sum += target.barycenter * target.weight;
weight += target.weight;
}
if (source.weight) {
sum += source.barycenter * source.weight;
weight += source.weight;
}
target.vs = source.vs.concat(target.vs);
target.barycenter = sum / weight;
target.weight = weight;
target.i = Math.min(source.i, target.i);
source.merged = true;
}
tbo47-dagre-es-4b95ad0/src/dagre/order/resolve-conflicts.test.js 0000664 0000000 0000000 00000011333 15114061606 0024512 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { resolveConflicts } from './resolve-conflicts.js';
describe('order/resolveConflicts', function () {
/** @type {Graph} */
var cg;
beforeEach(function () {
cg = new Graph();
});
it('returns back nodes unchanged when no constraints exist', function () {
var input = [
{ v: 'a', barycenter: 2, weight: 3 },
{ v: 'b', barycenter: 1, weight: 2 },
];
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a'], i: 0, barycenter: 2, weight: 3 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
]);
});
it('returns back nodes unchanged when no conflicts exist', function () {
var input = [
{ v: 'a', barycenter: 2, weight: 3 },
{ v: 'b', barycenter: 1, weight: 2 },
];
cg.setEdge('b', 'a');
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a'], i: 0, barycenter: 2, weight: 3 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
]);
});
it('coalesces nodes when there is a conflict', function () {
var input = [
{ v: 'a', barycenter: 2, weight: 3 },
{ v: 'b', barycenter: 1, weight: 2 },
];
cg.setEdge('a', 'b');
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a', 'b'], i: 0, barycenter: (3 * 2 + 2 * 1) / (3 + 2), weight: 3 + 2 },
]);
});
it('coalesces nodes when there is a conflict #2', function () {
var input = [
{ v: 'a', barycenter: 4, weight: 1 },
{ v: 'b', barycenter: 3, weight: 1 },
{ v: 'c', barycenter: 2, weight: 1 },
{ v: 'd', barycenter: 1, weight: 1 },
];
cg.setPath(['a', 'b', 'c', 'd']);
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a', 'b', 'c', 'd'], i: 0, barycenter: (4 + 3 + 2 + 1) / 4, weight: 4 },
]);
});
it('works with multiple constraints for the same target #1', function () {
var input = [
{ v: 'a', barycenter: 4, weight: 1 },
{ v: 'b', barycenter: 3, weight: 1 },
{ v: 'c', barycenter: 2, weight: 1 },
];
cg.setEdge('a', 'c');
cg.setEdge('b', 'c');
var results = resolveConflicts(input, cg);
expect(results).to.have.length(1);
expect(_.indexOf(results[0].vs, 'c')).to.be.gt(_.indexOf(results[0].vs, 'a'));
expect(_.indexOf(results[0].vs, 'c')).to.be.gt(_.indexOf(results[0].vs, 'b'));
expect(results[0].i).equals(0);
expect(results[0].barycenter).equals((4 + 3 + 2) / 3);
expect(results[0].weight).equals(3);
});
it('works with multiple constraints for the same target #2', function () {
var input = [
{ v: 'a', barycenter: 4, weight: 1 },
{ v: 'b', barycenter: 3, weight: 1 },
{ v: 'c', barycenter: 2, weight: 1 },
{ v: 'd', barycenter: 1, weight: 1 },
];
cg.setEdge('a', 'c');
cg.setEdge('a', 'd');
cg.setEdge('b', 'c');
cg.setEdge('c', 'd');
var results = resolveConflicts(input, cg);
expect(results).to.have.length(1);
expect(_.indexOf(results[0].vs, 'c')).to.be.gt(_.indexOf(results[0].vs, 'a'));
expect(_.indexOf(results[0].vs, 'c')).to.be.gt(_.indexOf(results[0].vs, 'b'));
expect(_.indexOf(results[0].vs, 'd')).to.be.gt(_.indexOf(results[0].vs, 'c'));
expect(results[0].i).equals(0);
expect(results[0].barycenter).equals((4 + 3 + 2 + 1) / 4);
expect(results[0].weight).equals(4);
});
it('does nothing to a node lacking both a barycenter and a constraint', function () {
var input = [{ v: 'a' }, { v: 'b', barycenter: 1, weight: 2 }];
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a'], i: 0 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
]);
});
it('treats a node w/o a barycenter as always violating constraints #1', function () {
var input = [{ v: 'a' }, { v: 'b', barycenter: 1, weight: 2 }];
cg.setEdge('a', 'b');
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a', 'b'], i: 0, barycenter: 1, weight: 2 },
]);
});
it('treats a node w/o a barycenter as always violating constraints #2', function () {
var input = [{ v: 'a' }, { v: 'b', barycenter: 1, weight: 2 }];
cg.setEdge('b', 'a');
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['b', 'a'], i: 0, barycenter: 1, weight: 2 },
]);
});
it('ignores edges not related to entries', function () {
var input = [
{ v: 'a', barycenter: 2, weight: 3 },
{ v: 'b', barycenter: 1, weight: 2 },
];
cg.setEdge('c', 'd');
expect(_.sortBy(resolveConflicts(input, cg), 'vs')).eqls([
{ vs: ['a'], i: 0, barycenter: 2, weight: 3 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
]);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/sort-subgraph.js 0000664 0000000 0000000 00000004176 15114061606 0022702 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { barycenter } from './barycenter.js';
import { resolveConflicts } from './resolve-conflicts.js';
import { sort } from './sort.js';
export { sortSubgraph };
function sortSubgraph(g, v, cg, biasRight) {
var movable = g.children(v);
var node = g.node(v);
var bl = node ? node.borderLeft : undefined;
var br = node ? node.borderRight : undefined;
var subgraphs = {};
if (bl) {
movable = _.filter(movable, function (w) {
return w !== bl && w !== br;
});
}
var barycenters = barycenter(g, movable);
_.forEach(barycenters, function (entry) {
if (g.children(entry.v).length) {
var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
subgraphs[entry.v] = subgraphResult;
if (Object.prototype.hasOwnProperty.call(subgraphResult, 'barycenter')) {
mergeBarycenters(entry, subgraphResult);
}
}
});
var entries = resolveConflicts(barycenters, cg);
expandSubgraphs(entries, subgraphs);
var result = sort(entries, biasRight);
if (bl) {
result.vs = _.flatten([bl, result.vs, br]);
if (g.predecessors(bl).length) {
var blPred = g.node(g.predecessors(bl)[0]),
brPred = g.node(g.predecessors(br)[0]);
if (!Object.prototype.hasOwnProperty.call(result, 'barycenter')) {
result.barycenter = 0;
result.weight = 0;
}
result.barycenter =
(result.barycenter * result.weight + blPred.order + brPred.order) / (result.weight + 2);
result.weight += 2;
}
}
return result;
}
function expandSubgraphs(entries, subgraphs) {
_.forEach(entries, function (entry) {
entry.vs = _.flatten(
entry.vs.map(function (v) {
if (subgraphs[v]) {
return subgraphs[v].vs;
}
return v;
}),
);
});
}
function mergeBarycenters(target, other) {
if (!_.isUndefined(target.barycenter)) {
target.barycenter =
(target.barycenter * target.weight + other.barycenter * other.weight) /
(target.weight + other.weight);
target.weight += other.weight;
} else {
target.barycenter = other.barycenter;
target.weight = other.weight;
}
}
tbo47-dagre-es-4b95ad0/src/dagre/order/sort-subgraph.test.js 0000664 0000000 0000000 00000010452 15114061606 0023652 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { sortSubgraph } from './sort-subgraph.js';
import { Graph } from '../../graphlib/graph.js';
describe('order/sortSubgraph', function () {
/** @type {Graph} */
var g;
/** @type {Graph} */
var cg;
beforeEach(function () {
g = new Graph({ compound: true })
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { weight: 1 };
});
_.forEach(_.range(5), function (v) {
g.setNode(v, { order: v });
});
cg = new Graph();
});
it('sorts a flat subgraph based on barycenter', function () {
g.setEdge(3, 'x');
g.setEdge(1, 'y', { weight: 2 });
g.setEdge(4, 'y');
_.forEach(['x', 'y'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['y', 'x']);
});
it('preserves the pos of a node (y) w/o neighbors in a flat subgraph', function () {
g.setEdge(3, 'x');
g.setNode('y');
g.setEdge(1, 'z', { weight: 2 });
g.setEdge(4, 'z');
_.forEach(['x', 'y', 'z'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['z', 'y', 'x']);
});
it('biases to the left without reverse bias', function () {
g.setEdge(1, 'x');
g.setEdge(1, 'y');
_.forEach(['x', 'y'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['x', 'y']);
});
it('biases to the right with reverse bias', function () {
g.setEdge(1, 'x');
g.setEdge(1, 'y');
_.forEach(['x', 'y'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg, true).vs).eqls(['y', 'x']);
});
it('aggregates stats about the subgraph', function () {
g.setEdge(3, 'x');
g.setEdge(1, 'y', { weight: 2 });
g.setEdge(4, 'y');
_.forEach(['x', 'y'], function (v) {
g.setParent(v, 'movable');
});
var results = sortSubgraph(g, 'movable', cg);
expect(results.barycenter).to.equal(2.25);
expect(results.weight).to.equal(4);
});
it('can sort a nested subgraph with no barycenter', function () {
g.setNodes(['a', 'b', 'c']);
g.setParent('a', 'y');
g.setParent('b', 'y');
g.setParent('c', 'y');
g.setEdge(0, 'x');
g.setEdge(1, 'z');
g.setEdge(2, 'y');
_.forEach(['x', 'y', 'z'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['x', 'z', 'a', 'b', 'c']);
});
it('can sort a nested subgraph with a barycenter', function () {
g.setNodes(['a', 'b', 'c']);
g.setParent('a', 'y');
g.setParent('b', 'y');
g.setParent('c', 'y');
g.setEdge(0, 'a', { weight: 3 });
g.setEdge(0, 'x');
g.setEdge(1, 'z');
g.setEdge(2, 'y');
_.forEach(['x', 'y', 'z'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['x', 'a', 'b', 'c', 'z']);
});
it('can sort a nested subgraph with no in-edges', function () {
g.setNodes(['a', 'b', 'c']);
g.setParent('a', 'y');
g.setParent('b', 'y');
g.setParent('c', 'y');
g.setEdge(0, 'a');
g.setEdge(1, 'b');
g.setEdge(0, 'x');
g.setEdge(1, 'z');
_.forEach(['x', 'y', 'z'], function (v) {
g.setParent(v, 'movable');
});
expect(sortSubgraph(g, 'movable', cg).vs).eqls(['x', 'a', 'b', 'c', 'z']);
});
it('sorts border nodes to the extremes of the subgraph', function () {
g.setEdge(0, 'x');
g.setEdge(1, 'y');
g.setEdge(2, 'z');
g.setNode('sg1', { borderLeft: 'bl', borderRight: 'br' });
_.forEach(['x', 'y', 'z', 'bl', 'br'], function (v) {
g.setParent(v, 'sg1');
});
expect(sortSubgraph(g, 'sg1', cg).vs).eqls(['bl', 'x', 'y', 'z', 'br']);
});
it('assigns a barycenter to a subgraph based on previous border nodes', function () {
g.setNode('bl1', { order: 0 });
g.setNode('br1', { order: 1 });
g.setEdge('bl1', 'bl2');
g.setEdge('br1', 'br2');
_.forEach(['bl2', 'br2'], function (v) {
g.setParent(v, 'sg');
});
g.setNode('sg', { borderLeft: 'bl2', borderRight: 'br2' });
expect(sortSubgraph(g, 'sg', cg)).eqls({
barycenter: 0.5,
weight: 2,
vs: ['bl2', 'br2'],
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/order/sort.js 0000664 0000000 0000000 00000002605 15114061606 0021064 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import * as util from '../util.js';
export { sort };
function sort(entries, biasRight) {
var parts = util.partition(entries, function (entry) {
return Object.prototype.hasOwnProperty.call(entry, 'barycenter');
});
var sortable = parts.lhs,
unsortable = _.sortBy(parts.rhs, function (entry) {
return -entry.i;
}),
vs = [],
sum = 0,
weight = 0,
vsIndex = 0;
sortable.sort(compareWithBias(!!biasRight));
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
_.forEach(sortable, function (entry) {
vsIndex += entry.vs.length;
vs.push(entry.vs);
sum += entry.barycenter * entry.weight;
weight += entry.weight;
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
});
var result = { vs: _.flatten(vs) };
if (weight) {
result.barycenter = sum / weight;
result.weight = weight;
}
return result;
}
function consumeUnsortable(vs, unsortable, index) {
var last;
while (unsortable.length && (last = _.last(unsortable)).i <= index) {
unsortable.pop();
vs.push(last.vs);
index++;
}
return index;
}
function compareWithBias(bias) {
return function (entryV, entryW) {
if (entryV.barycenter < entryW.barycenter) {
return -1;
} else if (entryV.barycenter > entryW.barycenter) {
return 1;
}
return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
};
}
tbo47-dagre-es-4b95ad0/src/dagre/order/sort.test.js 0000664 0000000 0000000 00000004443 15114061606 0022044 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { sort } from './sort.js';
describe('sort', function () {
it('sorts nodes by barycenter', function () {
var input = [
{ vs: ['a'], i: 0, barycenter: 2, weight: 3 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
];
expect(sort(input)).eqls({
vs: ['b', 'a'],
barycenter: (2 * 3 + 1 * 2) / (3 + 2),
weight: 3 + 2,
});
});
it('can sort super-nodes', function () {
var input = [
{ vs: ['a', 'c', 'd'], i: 0, barycenter: 2, weight: 3 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 2 },
];
expect(sort(input)).eqls({
vs: ['b', 'a', 'c', 'd'],
barycenter: (2 * 3 + 1 * 2) / (3 + 2),
weight: 3 + 2,
});
});
it('biases to the left by default', function () {
var input = [
{ vs: ['a'], i: 0, barycenter: 1, weight: 1 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 1 },
];
expect(sort(input)).eqls({
vs: ['a', 'b'],
barycenter: 1,
weight: 2,
});
});
it('biases to the right if biasRight = true', function () {
var input = [
{ vs: ['a'], i: 0, barycenter: 1, weight: 1 },
{ vs: ['b'], i: 1, barycenter: 1, weight: 1 },
];
expect(sort(input, true)).eqls({
vs: ['b', 'a'],
barycenter: 1,
weight: 2,
});
});
it('can sort nodes without a barycenter', function () {
var input = [
{ vs: ['a'], i: 0, barycenter: 2, weight: 1 },
{ vs: ['b'], i: 1, barycenter: 6, weight: 1 },
{ vs: ['c'], i: 2 },
{ vs: ['d'], i: 3, barycenter: 3, weight: 1 },
];
expect(sort(input)).eqls({
vs: ['a', 'd', 'c', 'b'],
barycenter: (2 + 6 + 3) / 3,
weight: 3,
});
});
it('can handle no barycenters for any nodes', function () {
var input = [
{ vs: ['a'], i: 0 },
{ vs: ['b'], i: 3 },
{ vs: ['c'], i: 2 },
{ vs: ['d'], i: 1 },
];
expect(sort(input)).eqls({ vs: ['a', 'd', 'c', 'b'] });
});
it('can handle a barycenter of 0', function () {
var input = [
{ vs: ['a'], i: 0, barycenter: 0, weight: 1 },
{ vs: ['b'], i: 3 },
{ vs: ['c'], i: 2 },
{ vs: ['d'], i: 1 },
];
expect(sort(input)).eqls({
vs: ['a', 'd', 'c', 'b'],
barycenter: 0,
weight: 1,
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/parent-dummy-chains.js 0000664 0000000 0000000 00000003726 15114061606 0022654 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { parentDummyChains };
function parentDummyChains(g) {
var postorderNums = postorder(g);
_.forEach(g.graph().dummyChains, function (v) {
var node = g.node(v);
var edgeObj = node.edgeObj;
var pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
var path = pathData.path;
var lca = pathData.lca;
var pathIdx = 0;
var pathV = path[pathIdx];
var ascending = true;
while (v !== edgeObj.w) {
node = g.node(v);
if (ascending) {
while ((pathV = path[pathIdx]) !== lca && g.node(pathV).maxRank < node.rank) {
pathIdx++;
}
if (pathV === lca) {
ascending = false;
}
}
if (!ascending) {
while (
pathIdx < path.length - 1 &&
g.node((pathV = path[pathIdx + 1])).minRank <= node.rank
) {
pathIdx++;
}
pathV = path[pathIdx];
}
g.setParent(v, pathV);
v = g.successors(v)[0];
}
});
}
// Find a path from v to w through the lowest common ancestor (LCA). Return the
// full path and the LCA.
function findPath(g, postorderNums, v, w) {
var vPath = [];
var wPath = [];
var low = Math.min(postorderNums[v].low, postorderNums[w].low);
var lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
var parent;
var lca;
// Traverse up from v to find the LCA
parent = v;
do {
parent = g.parent(parent);
vPath.push(parent);
} while (parent && (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
lca = parent;
// Traverse from w to LCA
parent = w;
while ((parent = g.parent(parent)) !== lca) {
wPath.push(parent);
}
return { path: vPath.concat(wPath.reverse()), lca: lca };
}
function postorder(g) {
var result = {};
var lim = 0;
function dfs(v) {
var low = lim;
_.forEach(g.children(v), dfs);
result[v] = { low: low, lim: lim++ };
}
_.forEach(g.children(), dfs);
return result;
}
tbo47-dagre-es-4b95ad0/src/dagre/parent-dummy-chains.test.js 0000664 0000000 0000000 00000011532 15114061606 0023624 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../graphlib/index.js';
import { parentDummyChains } from './parent-dummy-chains.js';
describe('parentDummyChains', function () {
var g;
beforeEach(function () {
g = new Graph({ compound: true }).setGraph({});
});
it('does not set a parent if both the tail and head have no parent', function () {
g.setNode('a');
g.setNode('b');
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' } });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).to.be.undefined;
});
it("uses the tail's parent for the first node if it is not the root", function () {
g.setParent('a', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 2 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 2 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg1');
});
it("uses the heads's parent for the first node if tail's is root", function () {
g.setParent('b', 'sg1');
g.setNode('sg1', { minRank: 1, maxRank: 3 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 1 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg1');
});
it('handles a long chain starting in a subgraph', function () {
g.setParent('a', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 2 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 2 });
g.setNode('d2', { rank: 3 });
g.setNode('d3', { rank: 4 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'd3', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg1');
expect(g.parent('d2')).to.be.undefined;
expect(g.parent('d3')).to.be.undefined;
});
it('handles a long chain ending in a subgraph', function () {
g.setParent('b', 'sg1');
g.setNode('sg1', { minRank: 3, maxRank: 5 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 1 });
g.setNode('d2', { rank: 2 });
g.setNode('d3', { rank: 3 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'd3', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).to.be.undefined;
expect(g.parent('d2')).to.be.undefined;
expect(g.parent('d3')).equals('sg1');
});
it('handles nested subgraphs', function () {
g.setParent('a', 'sg2');
g.setParent('sg2', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 4 });
g.setNode('sg2', { minRank: 1, maxRank: 3 });
g.setParent('b', 'sg4');
g.setParent('sg4', 'sg3');
g.setNode('sg3', { minRank: 6, maxRank: 10 });
g.setNode('sg4', { minRank: 7, maxRank: 9 });
for (var i = 0; i < 5; ++i) {
g.setNode('d' + (i + 1), { rank: i + 3 });
}
g.node('d1').edgeObj = { v: 'a', w: 'b' };
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'd3', 'd4', 'd5', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg2');
expect(g.parent('d2')).equals('sg1');
expect(g.parent('d3')).to.be.undefined;
expect(g.parent('d4')).equals('sg3');
expect(g.parent('d5')).equals('sg4');
});
it('handles overlapping rank ranges', function () {
g.setParent('a', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 3 });
g.setParent('b', 'sg2');
g.setNode('sg2', { minRank: 2, maxRank: 6 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 2 });
g.setNode('d2', { rank: 3 });
g.setNode('d3', { rank: 4 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'd3', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg1');
expect(g.parent('d2')).equals('sg1');
expect(g.parent('d3')).equals('sg2');
});
it('handles an LCA that is not the root of the graph #1', function () {
g.setParent('a', 'sg1');
g.setParent('sg2', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 6 });
g.setParent('b', 'sg2');
g.setNode('sg2', { minRank: 3, maxRank: 5 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 2 });
g.setNode('d2', { rank: 3 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg1');
expect(g.parent('d2')).equals('sg2');
});
it('handles an LCA that is not the root of the graph #2', function () {
g.setParent('a', 'sg2');
g.setParent('sg2', 'sg1');
g.setNode('sg1', { minRank: 0, maxRank: 6 });
g.setParent('b', 'sg1');
g.setNode('sg2', { minRank: 1, maxRank: 3 });
g.setNode('d1', { edgeObj: { v: 'a', w: 'b' }, rank: 3 });
g.setNode('d2', { rank: 4 });
g.graph().dummyChains = ['d1'];
g.setPath(['a', 'd1', 'd2', 'b']);
parentDummyChains(g);
expect(g.parent('d1')).equals('sg2');
expect(g.parent('d2')).equals('sg1');
});
});
tbo47-dagre-es-4b95ad0/src/dagre/position/ 0000775 0000000 0000000 00000000000 15114061606 0020265 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre/position/bk.js 0000664 0000000 0000000 00000031007 15114061606 0021220 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
import * as util from '../util.js';
/*
* This module provides coordinate assignment based on Brandes and Köpf, "Fast
* and Simple Horizontal Coordinate Assignment."
*/
export {
positionX,
findType1Conflicts,
findType2Conflicts,
addConflict,
hasConflict,
verticalAlignment,
horizontalCompaction,
alignCoordinates,
findSmallestWidthAlignment,
balance,
};
/*
* Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
* property. A type-1 conflict is one where a non-inner segment crosses an
* inner segment. An inner segment is an edge with both incident nodes marked
* with the "dummy" property.
*
* This algorithm scans layer by layer, starting with the second, for type-1
* conflicts between the current layer and the previous layer. For each layer
* it scans the nodes from left to right until it reaches one that is incident
* on an inner segment. It then scans predecessors to determine if they have
* edges that cross that inner segment. At the end a final scan is done for all
* nodes on the current rank to see if they cross the last visited inner
* segment.
*
* This algorithm (safely) assumes that a dummy node will only be incident on a
* single node in the layers being scanned.
*/
function findType1Conflicts(g, layering) {
/** @type {{[nodeId: string | number]: {[nodeId: string | number]: true}}} */
var conflicts = {};
function visitLayer(prevLayer, layer) {
var // last visited node in the previous layer that is incident on an inner
// segment.
k0 = 0,
// Tracks the last node in this layer scanned for crossings with a type-1
// segment.
scanPos = 0,
prevLayerLength = prevLayer.length,
lastNode = _.last(layer);
_.forEach(layer, function (v, i) {
var w = findOtherInnerSegmentNode(g, v),
k1 = w ? g.node(w).order : prevLayerLength;
if (w || v === lastNode) {
_.forEach(layer.slice(scanPos, i + 1), function (scanNode) {
_.forEach(g.predecessors(scanNode), function (u) {
var uLabel = g.node(u),
uPos = uLabel.order;
if ((uPos < k0 || k1 < uPos) && !(uLabel.dummy && g.node(scanNode).dummy)) {
addConflict(conflicts, u, scanNode);
}
});
});
// @ts-expect-error
scanPos = i + 1;
k0 = k1;
}
});
return layer;
}
_.reduce(layering, visitLayer);
return conflicts;
}
function findType2Conflicts(g, layering) {
/** @type {{[nodeId: string | number]: {[nodeId: string | number]: true}}} */
var conflicts = {};
function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
var v;
_.forEach(_.range(southPos, southEnd), function (i) {
v = south[i];
if (g.node(v).dummy) {
_.forEach(g.predecessors(v), function (u) {
var uNode = g.node(u);
if (uNode.dummy && (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
addConflict(conflicts, u, v);
}
});
}
});
}
function visitLayer(north, south) {
var prevNorthPos = -1,
nextNorthPos,
southPos = 0;
_.forEach(south, function (v, southLookahead) {
if (g.node(v).dummy === 'border') {
var predecessors = g.predecessors(v);
if (predecessors.length) {
nextNorthPos = g.node(predecessors[0]).order;
scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
// @ts-expect-error
southPos = southLookahead;
prevNorthPos = nextNorthPos;
}
}
scan(south, southPos, south.length, nextNorthPos, north.length);
});
return south;
}
_.reduce(layering, visitLayer);
return conflicts;
}
function findOtherInnerSegmentNode(g, v) {
if (g.node(v).dummy) {
return _.find(g.predecessors(v), function (u) {
return g.node(u).dummy;
});
}
}
/**
* Sets `conflicts[v][w] = true`, creating objects if needed.
*
* @param {{[nodeId: string | number]: {[nodeId: string | number]: true}}} conflicts - Object to set.
* @param {string | number} v - First Node ID
* @param {string | number} w - Second Node ID
*/
function addConflict(conflicts, v, w) {
if (v > w) {
var tmp = v;
v = w;
w = tmp;
}
if (!Object.prototype.hasOwnProperty.call(conflicts, v)) {
// can't use conflicts[v] = {} since it's unsafe if v = `__proto__`
Object.defineProperty(conflicts, v, {
enumerable: true,
configurable: true,
value: {},
writable: true,
});
}
var conflictsV = conflicts[v];
Object.defineProperty(conflictsV, w, {
enumerable: true,
configurable: true,
value: true,
writable: true,
});
}
function hasConflict(conflicts, v, w) {
if (v > w) {
var tmp = v;
v = w;
w = tmp;
}
return !!conflicts[v] && Object.prototype.hasOwnProperty.call(conflicts[v], w);
}
/*
* Try to align nodes into vertical "blocks" where possible. This algorithm
* attempts to align a node with one of its median neighbors. If the edge
* connecting a neighbor is a type-1 conflict then we ignore that possibility.
* If a previous node has already formed a block with a node after the node
* we're trying to form a block with, we also ignore that possibility - our
* blocks would be split in that scenario.
*/
function verticalAlignment(g, layering, conflicts, neighborFn) {
var root = {},
align = {},
pos = {};
// We cache the position here based on the layering because the graph and
// layering may be out of sync. The layering matrix is manipulated to
// generate different extreme alignments.
_.forEach(layering, function (layer) {
_.forEach(layer, function (v, order) {
root[v] = v;
align[v] = v;
pos[v] = order;
});
});
_.forEach(layering, function (layer) {
var prevIdx = -1;
_.forEach(layer, function (v) {
var ws = neighborFn(v);
if (ws.length) {
ws = _.sortBy(ws, function (w) {
return pos[w];
});
var mp = (ws.length - 1) / 2;
for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
var w = ws[i];
if (align[v] === v && prevIdx < pos[w] && !hasConflict(conflicts, v, w)) {
align[w] = v;
align[v] = root[v] = root[w];
prevIdx = pos[w];
}
}
}
});
});
return { root: root, align: align };
}
function horizontalCompaction(g, layering, root, align, reverseSep) {
// This portion of the algorithm differs from BK due to a number of problems.
// Instead of their algorithm we construct a new block graph and do two
// sweeps. The first sweep places blocks with the smallest possible
// coordinates. The second sweep removes unused space by moving blocks to the
// greatest coordinates without violating separation.
/** @type {Record} */
var xs = {},
blockG = buildBlockGraph(g, layering, root, reverseSep),
borderType = reverseSep ? 'borderLeft' : 'borderRight';
function iterate(setXsFunc, nextNodesFunc) {
var stack = blockG.nodes();
var elem = stack.pop();
var visited = {};
while (elem) {
if (visited[elem]) {
setXsFunc(elem);
} else {
visited[elem] = true;
stack.push(elem);
stack = stack.concat(nextNodesFunc(elem));
}
elem = stack.pop();
}
}
// First pass, assign smallest coordinates
function pass1(elem) {
xs[elem] = blockG.inEdges(elem).reduce(function (acc, e) {
return Math.max(acc, xs[e.v] + blockG.edge(e));
}, 0);
}
// Second pass, assign greatest coordinates
function pass2(elem) {
var min = blockG.outEdges(elem).reduce(function (acc, e) {
return Math.min(acc, xs[e.w] - blockG.edge(e));
}, Number.POSITIVE_INFINITY);
var node = g.node(elem);
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
xs[elem] = Math.max(xs[elem], min);
}
}
iterate(pass1, blockG.predecessors.bind(blockG));
iterate(pass2, blockG.successors.bind(blockG));
// Assign x coordinates to all nodes
_.forEach(align, function (v) {
xs[v] = xs[root[v]];
});
return xs;
}
function buildBlockGraph(g, layering, root, reverseSep) {
var blockGraph = new Graph(),
graphLabel = g.graph(),
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
_.forEach(layering, function (layer) {
var u;
_.forEach(layer, function (v) {
var vRoot = root[v];
blockGraph.setNode(vRoot);
if (u) {
var uRoot = root[u],
prevMax = blockGraph.edge(uRoot, vRoot);
blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
}
u = v;
});
});
return blockGraph;
}
/*
* Returns the alignment that has the smallest width of the given alignments.
*/
function findSmallestWidthAlignment(g, xss) {
return _.minBy(_.values(xss), function (xs) {
var max = Number.NEGATIVE_INFINITY;
var min = Number.POSITIVE_INFINITY;
_.forIn(xs, function (x, v) {
var halfWidth = width(g, v) / 2;
max = Math.max(x + halfWidth, max);
min = Math.min(x - halfWidth, min);
});
return max - min;
});
}
/*
* Align the coordinates of each of the layout alignments such that
* left-biased alignments have their minimum coordinate at the same point as
* the minimum coordinate of the smallest width alignment and right-biased
* alignments have their maximum coordinate at the same point as the maximum
* coordinate of the smallest width alignment.
*/
function alignCoordinates(xss, alignTo) {
var alignToVals = _.values(alignTo),
alignToMin = _.min(alignToVals),
alignToMax = _.max(alignToVals);
_.forEach(['u', 'd'], function (vert) {
_.forEach(['l', 'r'], function (horiz) {
var alignment = vert + horiz,
xs = xss[alignment],
delta;
if (xs === alignTo) return;
var xsVals = _.values(xs);
delta = horiz === 'l' ? alignToMin - _.min(xsVals) : alignToMax - _.max(xsVals);
if (delta) {
xss[alignment] = _.mapValues(xs, function (x) {
return x + delta;
});
}
});
});
}
function balance(xss, align) {
return _.mapValues(xss.ul, function (ignore, v) {
if (align) {
return xss[align.toLowerCase()][v];
} else {
var xs = _.sortBy(_.map(xss, v));
return (xs[1] + xs[2]) / 2;
}
});
}
function positionX(g) {
var layering = util.buildLayerMatrix(g);
var conflicts = _.merge(findType1Conflicts(g, layering), findType2Conflicts(g, layering));
var xss = {};
var adjustedLayering;
_.forEach(['u', 'd'], function (vert) {
adjustedLayering = vert === 'u' ? layering : _.values(layering).reverse();
_.forEach(['l', 'r'], function (horiz) {
if (horiz === 'r') {
adjustedLayering = _.map(adjustedLayering, function (inner) {
return _.values(inner).reverse();
});
}
var neighborFn = (vert === 'u' ? g.predecessors : g.successors).bind(g);
var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
var xs = horizontalCompaction(g, adjustedLayering, align.root, align.align, horiz === 'r');
if (horiz === 'r') {
xs = _.mapValues(xs, function (x) {
return -x;
});
}
xss[vert + horiz] = xs;
});
});
var smallestWidth = findSmallestWidthAlignment(g, xss);
alignCoordinates(xss, smallestWidth);
return balance(xss, g.graph().align);
}
function sep(nodeSep, edgeSep, reverseSep) {
return function (g, v, w) {
var vLabel = g.node(v);
var wLabel = g.node(w);
var sum = 0;
var delta;
sum += vLabel.width / 2;
if (Object.prototype.hasOwnProperty.call(vLabel, 'labelpos')) {
switch (vLabel.labelpos.toLowerCase()) {
case 'l':
delta = -vLabel.width / 2;
break;
case 'r':
delta = vLabel.width / 2;
break;
}
}
if (delta) {
sum += reverseSep ? delta : -delta;
}
delta = 0;
sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
sum += wLabel.width / 2;
if (Object.prototype.hasOwnProperty.call(wLabel, 'labelpos')) {
switch (wLabel.labelpos.toLowerCase()) {
case 'l':
delta = wLabel.width / 2;
break;
case 'r':
delta = -wLabel.width / 2;
break;
}
}
if (delta) {
sum += reverseSep ? delta : -delta;
}
delta = 0;
return sum;
};
}
function width(g, v) {
return g.node(v).width;
}
tbo47-dagre-es-4b95ad0/src/dagre/position/bk.test.js 0000664 0000000 0000000 00000055636 15114061606 0022214 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { buildLayerMatrix } from '../util.js';
import {
findType1Conflicts,
findType2Conflicts,
addConflict,
hasConflict,
verticalAlignment,
horizontalCompaction,
alignCoordinates,
balance,
findSmallestWidthAlignment,
positionX,
} from './bk.js';
import { Graph } from '../../graphlib/graph.js';
describe('position/bk', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph().setGraph({});
});
describe('findType1Conflicts', function () {
var layering;
beforeEach(function () {
g.setDefaultEdgeLabel(function () {
return {};
})
.setNode('a', { rank: 0, order: 0 })
.setNode('b', { rank: 0, order: 1 })
.setNode('c', { rank: 1, order: 0 })
.setNode('d', { rank: 1, order: 1 })
// Set up crossing
.setEdge('a', 'd')
.setEdge('b', 'c');
layering = buildLayerMatrix(g);
});
it('does not mark edges that have no conflict', function () {
g.removeEdge('a', 'd');
g.removeEdge('b', 'c');
g.setEdge('a', 'c');
g.setEdge('b', 'd');
var conflicts = findType1Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'c')).to.be.false;
expect(hasConflict(conflicts, 'b', 'd')).to.be.false;
});
it('does not mark type-0 conflicts (no dummies)', function () {
var conflicts = findType1Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'd')).to.be.false;
expect(hasConflict(conflicts, 'b', 'c')).to.be.false;
});
_.forEach(['a', 'b', 'c', 'd'], function (v) {
it('does not mark type-0 conflicts (' + v + ' is dummy)', function () {
g.node(v).dummy = true;
var conflicts = findType1Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'd')).to.be.false;
expect(hasConflict(conflicts, 'b', 'c')).to.be.false;
});
});
_.forEach(['a', 'b', 'c', 'd'], function (v) {
it('does mark type-1 conflicts (' + v + ' is non-dummy)', function () {
_.forEach(['a', 'b', 'c', 'd'], function (w) {
if (v !== w) {
g.node(w).dummy = true;
}
});
var conflicts = findType1Conflicts(g, layering);
if (v === 'a' || v === 'd') {
expect(hasConflict(conflicts, 'a', 'd')).to.be.true;
expect(hasConflict(conflicts, 'b', 'c')).to.be.false;
} else {
expect(hasConflict(conflicts, 'a', 'd')).to.be.false;
expect(hasConflict(conflicts, 'b', 'c')).to.be.true;
}
});
});
it('does not mark type-2 conflicts (all dummies)', function () {
_.forEach(['a', 'b', 'c', 'd'], function (v) {
g.node(v).dummy = true;
});
var conflicts = findType1Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'd')).to.be.false;
expect(hasConflict(conflicts, 'b', 'c')).to.be.false;
findType1Conflicts(g, layering);
});
});
describe('findType2Conflicts', function () {
var layering;
beforeEach(function () {
g.setDefaultEdgeLabel(function () {
return {};
})
.setNode('a', { rank: 0, order: 0 })
.setNode('b', { rank: 0, order: 1 })
.setNode('c', { rank: 1, order: 0 })
.setNode('d', { rank: 1, order: 1 })
// Set up crossing
.setEdge('a', 'd')
.setEdge('b', 'c');
layering = buildLayerMatrix(g);
});
it('marks type-2 conflicts favoring border segments #1', function () {
_.forEach(['a', 'd'], function (v) {
g.node(v).dummy = true;
});
_.forEach(['b', 'c'], function (v) {
g.node(v).dummy = 'border';
});
var conflicts = findType2Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'd')).to.be.true;
expect(hasConflict(conflicts, 'b', 'c')).to.be.false;
findType1Conflicts(g, layering);
});
it('marks type-2 conflicts favoring border segments #2', function () {
_.forEach(['b', 'c'], function (v) {
g.node(v).dummy = true;
});
_.forEach(['a', 'd'], function (v) {
g.node(v).dummy = 'border';
});
var conflicts = findType2Conflicts(g, layering);
expect(hasConflict(conflicts, 'a', 'd')).to.be.false;
expect(hasConflict(conflicts, 'b', 'c')).to.be.true;
findType1Conflicts(g, layering);
});
});
describe('hasConflict', function () {
it('can test for a type-1 conflict regardless of edge orientation', function () {
/** @type {Parameters[0]} */
var conflicts = {};
addConflict(conflicts, 'b', 'a');
expect(hasConflict(conflicts, 'a', 'b')).to.be.true;
expect(hasConflict(conflicts, 'b', 'a')).to.be.true;
});
it('works for multiple conflicts with the same node', function () {
/** @type {Parameters[0]} */
var conflicts = {};
addConflict(conflicts, 'a', 'b');
addConflict(conflicts, 'a', 'c');
expect(hasConflict(conflicts, 'a', 'b')).to.be.true;
expect(hasConflict(conflicts, 'a', 'c')).to.be.true;
});
it('works for nodes named __proto__', function () {
/** @type {Parameters[0]} */
var conflicts = {};
addConflict(conflicts, '__proto__', 'myAdminKey');
expect(hasConflict(conflicts, '__proto__', 'myAdminKey')).to.be.true;
expect({}).not.to.have.property('myAdminKey');
});
});
describe('verticalAlignment', function () {
it('Aligns with itself if the node has no adjacencies', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 1, order: 0 });
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'b' },
align: { a: 'a', b: 'b' },
});
});
it('Aligns with its sole adjacency', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 1, order: 0 });
g.setEdge('a', 'b');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'a' },
align: { a: 'b', b: 'a' },
});
});
it('aligns with its left median when possible', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 1, order: 0 });
g.setEdge('a', 'c');
g.setEdge('b', 'c');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'b', c: 'a' },
align: { a: 'c', b: 'b', c: 'a' },
});
});
it('aligns correctly even regardless of node name / insertion order', function () {
// This test ensures that we're actually properly sorting nodes by
// position when searching for candidates. Many of these tests previously
// passed because the node insertion order matched the order of the nodes
// in the layering.
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 1, order: 0 });
g.setNode('z', { rank: 0, order: 0 });
g.setEdge('z', 'c');
g.setEdge('b', 'c');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { z: 'z', b: 'b', c: 'z' },
align: { z: 'c', b: 'b', c: 'z' },
});
});
it('aligns with its right median when left is unavailable', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 1, order: 0 });
g.setEdge('a', 'c');
g.setEdge('b', 'c');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
addConflict(conflicts, 'a', 'c');
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'b', c: 'b' },
align: { a: 'a', b: 'c', c: 'b' },
});
});
it('aligns with neither median if both are unavailable', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 1, order: 0 });
g.setNode('d', { rank: 1, order: 1 });
g.setEdge('a', 'd');
g.setEdge('b', 'c');
g.setEdge('b', 'd');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
// c will align with b, so d will not be able to align with a, because
// (a,d) and (c,b) cross.
expect(result).to.eql({
root: { a: 'a', b: 'b', c: 'b', d: 'd' },
align: { a: 'a', b: 'c', c: 'b', d: 'd' },
});
});
it('aligns with the single median for an odd number of adjacencies', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 0, order: 2 });
g.setNode('d', { rank: 1, order: 0 });
g.setEdge('a', 'd');
g.setEdge('b', 'd');
g.setEdge('c', 'd');
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'b', c: 'c', d: 'b' },
align: { a: 'a', b: 'd', c: 'c', d: 'b' },
});
});
it('aligns blocks across multiple layers', function () {
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 1, order: 0 });
g.setNode('c', { rank: 1, order: 1 });
g.setNode('d', { rank: 2, order: 0 });
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
var layering = buildLayerMatrix(g);
/** @type {Parameters[0]} */
var conflicts = {};
var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
expect(result).to.eql({
root: { a: 'a', b: 'a', c: 'c', d: 'a' },
align: { a: 'b', b: 'd', c: 'c', d: 'a' },
});
});
});
describe('horizonalCompaction', function () {
it('places the center of a single node graph at origin (0,0)', function () {
var root = { a: 'a' };
var align = { a: 'a' };
g.setNode('a', { rank: 0, order: 0 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
});
it('separates adjacent nodes by specified node separation', function () {
var root = { a: 'a', b: 'b' };
var align = { a: 'a', b: 'b' };
g.graph().nodesep = 100;
g.setNode('a', { rank: 0, order: 0, width: 100 });
g.setNode('b', { rank: 0, order: 1, width: 200 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(100 / 2 + 100 + 200 / 2);
});
it('separates adjacent edges by specified node separation', function () {
var root = { a: 'a', b: 'b' };
var align = { a: 'a', b: 'b' };
g.graph().edgesep = 20;
g.setNode('a', { rank: 0, order: 0, width: 100, dummy: true });
g.setNode('b', { rank: 0, order: 1, width: 200, dummy: true });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(100 / 2 + 20 + 200 / 2);
});
it('aligns the centers of nodes in the same block', function () {
var root = { a: 'a', b: 'a' };
var align = { a: 'b', b: 'a' };
g.setNode('a', { rank: 0, order: 0, width: 100 });
g.setNode('b', { rank: 1, order: 0, width: 200 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(0);
});
it('separates blocks with the appropriate separation', function () {
var root = { a: 'a', b: 'a', c: 'c' };
var align = { a: 'b', b: 'a', c: 'c' };
g.graph().nodesep = 75;
g.setNode('a', { rank: 0, order: 0, width: 100 });
g.setNode('b', { rank: 1, order: 1, width: 200 });
g.setNode('c', { rank: 1, order: 0, width: 50 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(50 / 2 + 75 + 200 / 2);
expect(xs.b).to.equal(50 / 2 + 75 + 200 / 2);
expect(xs.c).to.equal(0);
});
it('separates classes with the appropriate separation', function () {
var root = { a: 'a', b: 'b', c: 'c', d: 'b' };
var align = { a: 'a', b: 'd', c: 'c', d: 'b' };
g.graph().nodesep = 75;
g.setNode('a', { rank: 0, order: 0, width: 100 });
g.setNode('b', { rank: 0, order: 1, width: 200 });
g.setNode('c', { rank: 1, order: 0, width: 50 });
g.setNode('d', { rank: 1, order: 1, width: 80 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(100 / 2 + 75 + 200 / 2);
expect(xs.c).to.equal(100 / 2 + 75 + 200 / 2 - 80 / 2 - 75 - 50 / 2);
expect(xs.d).to.equal(100 / 2 + 75 + 200 / 2);
});
it('shifts classes by max sep from the adjacent block #1', function () {
var root = { a: 'a', b: 'b', c: 'a', d: 'b' };
var align = { a: 'c', b: 'd', c: 'a', d: 'b' };
g.graph().nodesep = 75;
g.setNode('a', { rank: 0, order: 0, width: 50 });
g.setNode('b', { rank: 0, order: 1, width: 150 });
g.setNode('c', { rank: 1, order: 0, width: 60 });
g.setNode('d', { rank: 1, order: 1, width: 70 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(50 / 2 + 75 + 150 / 2);
expect(xs.c).to.equal(0);
expect(xs.d).to.equal(50 / 2 + 75 + 150 / 2);
});
it('shifts classes by max sep from the adjacent block #2', function () {
var root = { a: 'a', b: 'b', c: 'a', d: 'b' };
var align = { a: 'c', b: 'd', c: 'a', d: 'b' };
g.graph().nodesep = 75;
g.setNode('a', { rank: 0, order: 0, width: 50 });
g.setNode('b', { rank: 0, order: 1, width: 70 });
g.setNode('c', { rank: 1, order: 0, width: 60 });
g.setNode('d', { rank: 1, order: 1, width: 150 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(60 / 2 + 75 + 150 / 2);
expect(xs.c).to.equal(0);
expect(xs.d).to.equal(60 / 2 + 75 + 150 / 2);
});
it('cascades class shift', function () {
var root = { a: 'a', b: 'b', c: 'c', d: 'd', e: 'b', f: 'f', g: 'd' };
var align = { a: 'a', b: 'e', c: 'c', d: 'g', e: 'b', f: 'f', g: 'd' };
g.graph().nodesep = 75;
g.setNode('a', { rank: 0, order: 0, width: 50 });
g.setNode('b', { rank: 0, order: 1, width: 50 });
g.setNode('c', { rank: 1, order: 0, width: 50 });
g.setNode('d', { rank: 1, order: 1, width: 50 });
g.setNode('e', { rank: 1, order: 2, width: 50 });
g.setNode('f', { rank: 2, order: 0, width: 50 });
g.setNode('g', { rank: 2, order: 1, width: 50 });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
// Use f as 0, everything is relative to it
expect(xs.a).to.equal(xs.b - 50 / 2 - 75 - 50 / 2);
expect(xs.b).to.equal(xs.e);
expect(xs.c).to.equal(xs.f);
expect(xs.d).to.equal(xs.c + 50 / 2 + 75 + 50 / 2);
expect(xs.e).to.equal(xs.d + 50 / 2 + 75 + 50 / 2);
expect(xs.g).to.equal(xs.f + 50 / 2 + 75 + 50 / 2);
});
it('handles labelpos = l', function () {
var root = { a: 'a', b: 'b', c: 'c' };
var align = { a: 'a', b: 'b', c: 'c' };
g.graph().edgesep = 50;
g.setNode('a', { rank: 0, order: 0, width: 100, dummy: 'edge' });
g.setNode('b', {
rank: 0,
order: 1,
width: 200,
dummy: 'edge-label',
labelpos: 'l',
});
g.setNode('c', { rank: 0, order: 2, width: 300, dummy: 'edge' });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 200);
expect(xs.c).to.equal(xs.b + 0 + 50 + 300 / 2);
});
it('handles labelpos = c', function () {
var root = { a: 'a', b: 'b', c: 'c' };
var align = { a: 'a', b: 'b', c: 'c' };
g.graph().edgesep = 50;
g.setNode('a', { rank: 0, order: 0, width: 100, dummy: 'edge' });
g.setNode('b', {
rank: 0,
order: 1,
width: 200,
dummy: 'edge-label',
labelpos: 'c',
});
g.setNode('c', { rank: 0, order: 2, width: 300, dummy: 'edge' });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 200 / 2);
expect(xs.c).to.equal(xs.b + 200 / 2 + 50 + 300 / 2);
});
it('handles labelpos = r', function () {
var root = { a: 'a', b: 'b', c: 'c' };
var align = { a: 'a', b: 'b', c: 'c' };
g.graph().edgesep = 50;
g.setNode('a', { rank: 0, order: 0, width: 100, dummy: 'edge' });
g.setNode('b', {
rank: 0,
order: 1,
width: 200,
dummy: 'edge-label',
labelpos: 'r',
});
g.setNode('c', { rank: 0, order: 2, width: 300, dummy: 'edge' });
var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
expect(xs.a).to.equal(0);
expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 0);
expect(xs.c).to.equal(xs.b + 200 + 50 + 300 / 2);
});
});
describe('alignCoordinates', function () {
it('aligns a single node', function () {
var xss = {
ul: { a: 50 },
ur: { a: 100 },
dl: { a: 50 },
dr: { a: 200 },
};
alignCoordinates(xss, xss.ul);
expect(xss.ul).to.eql({ a: 50 });
expect(xss.ur).to.eql({ a: 50 });
expect(xss.dl).to.eql({ a: 50 });
expect(xss.dr).to.eql({ a: 50 });
});
it('aligns multiple nodes', function () {
var xss = {
ul: { a: 50, b: 1000 },
ur: { a: 100, b: 900 },
dl: { a: 150, b: 800 },
dr: { a: 200, b: 700 },
};
alignCoordinates(xss, xss.ul);
expect(xss.ul).to.eql({ a: 50, b: 1000 });
expect(xss.ur).to.eql({ a: 200, b: 1000 });
expect(xss.dl).to.eql({ a: 50, b: 700 });
expect(xss.dr).to.eql({ a: 500, b: 1000 });
});
});
describe('findSmallestWidthAlignment', function () {
it('finds the alignment with the smallest width', function () {
g.setNode('a', { width: 50 });
g.setNode('b', { width: 50 });
var xss = {
ul: { a: 0, b: 1000 },
ur: { a: -5, b: 1000 },
dl: { a: 5, b: 2000 },
dr: { a: 0, b: 200 },
};
expect(findSmallestWidthAlignment(g, xss)).to.eql(xss.dr);
});
it('takes node width into account', function () {
g.setNode('a', { width: 50 });
g.setNode('b', { width: 50 });
g.setNode('c', { width: 200 });
var xss = {
ul: { a: 0, b: 100, c: 75 },
ur: { a: 0, b: 100, c: 80 },
dl: { a: 0, b: 100, c: 85 },
dr: { a: 0, b: 100, c: 90 },
};
expect(findSmallestWidthAlignment(g, xss)).to.eql(xss.ul);
});
});
describe('balance', function () {
it('aligns a single node to the shared median value', function () {
var xss = {
ul: { a: 0 },
ur: { a: 100 },
dl: { a: 100 },
dr: { a: 200 },
};
expect(balance(xss)).to.eql({ a: 100 });
});
it('aligns a single node to the average of different median values', function () {
var xss = {
ul: { a: 0 },
ur: { a: 75 },
dl: { a: 125 },
dr: { a: 200 },
};
expect(balance(xss)).to.eql({ a: 100 });
});
it('balances multiple nodes', function () {
var xss = {
ul: { a: 0, b: 50 },
ur: { a: 75, b: 0 },
dl: { a: 125, b: 60 },
dr: { a: 200, b: 75 },
};
expect(balance(xss)).to.eql({ a: 100, b: 55 });
});
});
describe('positionX', function () {
it('positions a single node at origin', function () {
g.setNode('a', { rank: 0, order: 0, width: 100 });
expect(positionX(g)).to.eql({ a: 0 });
});
it('positions a single node block at origin', function () {
g.setNode('a', { rank: 0, order: 0, width: 100 });
g.setNode('b', { rank: 1, order: 0, width: 100 });
g.setEdge('a', 'b');
expect(positionX(g)).to.eql({ a: 0, b: 0 });
});
it('positions a single node block at origin even when their sizes differ', function () {
g.setNode('a', { rank: 0, order: 0, width: 40 });
g.setNode('b', { rank: 1, order: 0, width: 500 });
g.setNode('c', { rank: 2, order: 0, width: 20 });
g.setPath(['a', 'b', 'c']);
expect(positionX(g)).to.eql({ a: 0, b: 0, c: 0 });
});
it('centers a node if it is a predecessor of two same sized nodes', function () {
g.graph().nodesep = 10;
g.setNode('a', { rank: 0, order: 0, width: 20 });
g.setNode('b', { rank: 1, order: 0, width: 50 });
g.setNode('c', { rank: 1, order: 1, width: 50 });
g.setEdge('a', 'b');
g.setEdge('a', 'c');
var pos = positionX(g);
var a = pos.a;
expect(pos).to.eql({ a: a, b: a - (25 + 5), c: a + (25 + 5) });
});
it('shifts blocks on both sides of aligned block', function () {
g.graph().nodesep = 10;
g.setNode('a', { rank: 0, order: 0, width: 50 });
g.setNode('b', { rank: 0, order: 1, width: 60 });
g.setNode('c', { rank: 1, order: 0, width: 70 });
g.setNode('d', { rank: 1, order: 1, width: 80 });
g.setEdge('b', 'c');
var pos = positionX(g);
var b = pos.b;
var c = b;
expect(pos).to.eql({
a: b - 60 / 2 - 10 - 50 / 2,
b: b,
c: c,
d: c + 70 / 2 + 10 + 80 / 2,
});
});
it('aligns inner segments', function () {
g.graph().nodesep = 10;
g.setNode('a', { rank: 0, order: 0, width: 50, dummy: true });
g.setNode('b', { rank: 0, order: 1, width: 60 });
g.setNode('c', { rank: 1, order: 0, width: 70 });
g.setNode('d', { rank: 1, order: 1, width: 80, dummy: true });
g.setEdge('b', 'c');
g.setEdge('a', 'd');
var pos = positionX(g);
var a = pos.a;
var d = a;
expect(pos).to.eql({
a: a,
b: a + 50 / 2 + 10 + 60 / 2,
c: d - 70 / 2 - 10 - 80 / 2,
d: d,
});
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/position/index.js 0000664 0000000 0000000 00000001243 15114061606 0021732 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import * as util from '../util.js';
import { positionX } from './bk.js';
export { position };
function position(g) {
g = util.asNonCompoundGraph(g);
positionY(g);
_.forOwn(positionX(g), function (x, v) {
g.node(v).x = x;
});
}
function positionY(g) {
var layering = util.buildLayerMatrix(g);
var rankSep = g.graph().ranksep;
var prevY = 0;
_.forEach(layering, function (layer) {
var maxHeight = _.max(
_.map(layer, function (v) {
return g.node(v).height;
}),
);
_.forEach(layer, function (v) {
g.node(v).y = prevY + maxHeight / 2;
});
prevY += maxHeight + rankSep;
});
}
tbo47-dagre-es-4b95ad0/src/dagre/position/index.test.js 0000664 0000000 0000000 00000003453 15114061606 0022715 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { position } from './index.js';
import { Graph } from '../../graphlib/index.js';
describe('position', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ compound: true }).setGraph({
ranksep: 50,
nodesep: 50,
edgesep: 10,
});
});
it('respects ranksep', function () {
g.graph().ranksep = 1000;
g.setNode('a', { width: 50, height: 100, rank: 0, order: 0 });
g.setNode('b', { width: 50, height: 80, rank: 1, order: 0 });
g.setEdge('a', 'b');
position(g);
expect(g.node('b').y).to.equal(100 + 1000 + 80 / 2);
});
it('use the largest height in each rank with ranksep', function () {
g.graph().ranksep = 1000;
g.setNode('a', { width: 50, height: 100, rank: 0, order: 0 });
g.setNode('b', { width: 50, height: 80, rank: 0, order: 1 });
g.setNode('c', { width: 50, height: 90, rank: 1, order: 0 });
g.setEdge('a', 'c');
position(g);
expect(g.node('a').y).to.equal(100 / 2);
expect(g.node('b').y).to.equal(100 / 2); // Note we used 100 and not 80 here
expect(g.node('c').y).to.equal(100 + 1000 + 90 / 2);
});
it('respects nodesep', function () {
g.graph().nodesep = 1000;
g.setNode('a', { width: 50, height: 100, rank: 0, order: 0 });
g.setNode('b', { width: 70, height: 80, rank: 0, order: 1 });
position(g);
expect(g.node('b').x).to.equal(g.node('a').x + 50 / 2 + 1000 + 70 / 2);
});
it('should not try to position the subgraph node itself', function () {
g.setNode('a', { width: 50, height: 50, rank: 0, order: 0 });
g.setNode('sg1', {});
g.setParent('a', 'sg1');
position(g);
expect(g.node('sg1')).to.not.have.property('x');
expect(g.node('sg1')).to.not.have.property('y');
});
});
tbo47-dagre-es-4b95ad0/src/dagre/rank/ 0000775 0000000 0000000 00000000000 15114061606 0017354 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/dagre/rank/feasible-tree.js 0000664 0000000 0000000 00000004235 15114061606 0022425 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
import { slack } from './util.js';
export { feasibleTree };
/*
* Constructs a spanning tree with tight edges and adjusted the input node's
* ranks to achieve this. A tight edge is one that is has a length that matches
* its "minlen" attribute.
*
* The basic structure for this function is derived from Gansner, et al., "A
* Technique for Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a DAG.
* 2. Graph must be connected.
* 3. Graph must have at least one node.
* 5. Graph nodes must have been previously assigned a "rank" property that
* respects the "minlen" property of incident edges.
* 6. Graph edges must have a "minlen" property.
*
* Post-conditions:
*
* - Graph nodes will have their rank adjusted to ensure that all edges are
* tight.
*
* Returns a tree (undirected graph) that is constructed using only "tight"
* edges.
*/
function feasibleTree(g) {
var t = new Graph({ directed: false });
// Choose arbitrary node from which to start our tree
var start = g.nodes()[0];
var size = g.nodeCount();
t.setNode(start, {});
var edge, delta;
while (tightTree(t, g) < size) {
edge = findMinSlackEdge(t, g);
delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
shiftRanks(t, g, delta);
}
return t;
}
/*
* Finds a maximal tree of tight edges and returns the number of nodes in the
* tree.
*/
function tightTree(t, g) {
function dfs(v) {
_.forEach(g.nodeEdges(v), function (e) {
var edgeV = e.v,
w = v === edgeV ? e.w : edgeV;
if (!t.hasNode(w) && !slack(g, e)) {
t.setNode(w, {});
t.setEdge(v, w, {});
dfs(w);
}
});
}
_.forEach(t.nodes(), dfs);
return t.nodeCount();
}
/*
* Finds the edge with the smallest slack that is incident on tree and returns
* it.
*/
function findMinSlackEdge(t, g) {
return _.minBy(g.edges(), function (e) {
if (t.hasNode(e.v) !== t.hasNode(e.w)) {
return slack(g, e);
}
});
}
function shiftRanks(t, g, delta) {
_.forEach(t.nodes(), function (v) {
g.node(v).rank += delta;
});
}
tbo47-dagre-es-4b95ad0/src/dagre/rank/feasible-tree.test.js 0000664 0000000 0000000 00000003600 15114061606 0023376 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { feasibleTree } from './feasible-tree.js';
describe('feasibleTree', function () {
it('creates a tree for a trivial input graph', function () {
var g = new Graph()
.setNode('a', { rank: 0 })
.setNode('b', { rank: 1 })
.setEdge('a', 'b', { minlen: 1 });
var tree = feasibleTree(g);
expect(g.node('b').rank).to.equal(g.node('a').rank + 1);
expect(tree.neighbors('a')).to.eql(['b']);
});
it('correctly shortens slack by pulling a node up', function () {
var g = new Graph()
.setNode('a', { rank: 0 })
.setNode('b', { rank: 1 })
.setNode('c', { rank: 2 })
.setNode('d', { rank: 2 })
.setPath(['a', 'b', 'c'], { minlen: 1 })
.setEdge('a', 'd', { minlen: 1 });
var tree = feasibleTree(g);
expect(g.node('b').rank).to.eql(g.node('a').rank + 1);
expect(g.node('c').rank).to.eql(g.node('b').rank + 1);
expect(g.node('d').rank).to.eql(g.node('a').rank + 1);
expect(_.sortBy(tree.neighbors('a'))).to.eql(['b', 'd']);
expect(_.sortBy(tree.neighbors('b'))).to.eql(['a', 'c']);
expect(tree.neighbors('c')).to.eql(['b']);
expect(tree.neighbors('d')).to.eql(['a']);
});
it('correctly shortens slack by pulling a node down', function () {
var g = new Graph()
.setNode('a', { rank: 2 })
.setNode('b', { rank: 0 })
.setNode('c', { rank: 2 })
.setEdge('b', 'a', { minlen: 1 })
.setEdge('b', 'c', { minlen: 1 });
var tree = feasibleTree(g);
expect(g.node('a').rank).to.eql(g.node('b').rank + 1);
expect(g.node('c').rank).to.eql(g.node('b').rank + 1);
expect(_.sortBy(tree.neighbors('a'))).to.eql(['b']);
expect(_.sortBy(tree.neighbors('b'))).to.eql(['a', 'c']);
expect(_.sortBy(tree.neighbors('c'))).to.eql(['b']);
});
});
tbo47-dagre-es-4b95ad0/src/dagre/rank/index.js 0000664 0000000 0000000 00000002433 15114061606 0021023 0 ustar 00root root 0000000 0000000 import { feasibleTree } from './feasible-tree.js';
import { networkSimplex } from './network-simplex.js';
import { longestPath } from './util.js';
export { rank };
/*
* Assigns a rank to each node in the input graph that respects the "minlen"
* constraint specified on edges between nodes.
*
* This basic structure is derived from Gansner, et al., "A Technique for
* Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a connected DAG
* 2. Graph nodes must be objects
* 3. Graph edges must have "weight" and "minlen" attributes
*
* Post-conditions:
*
* 1. Graph nodes will have a "rank" attribute based on the results of the
* algorithm. Ranks can start at any index (including negative), we'll
* fix them up later.
*/
function rank(g) {
switch (g.graph().ranker) {
case 'network-simplex':
networkSimplexRanker(g);
break;
case 'tight-tree':
tightTreeRanker(g);
break;
case 'longest-path':
longestPathRanker(g);
break;
default:
networkSimplexRanker(g);
}
}
// A fast and simple ranker, but results are far from optimal.
var longestPathRanker = longestPath;
function tightTreeRanker(g) {
longestPath(g);
feasibleTree(g);
}
function networkSimplexRanker(g) {
networkSimplex(g);
}
tbo47-dagre-es-4b95ad0/src/dagre/rank/index.test.js 0000664 0000000 0000000 00000002414 15114061606 0022000 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { rank } from './index.js';
import { Graph } from '../../graphlib/graph.js';
describe('rank', function () {
var RANKERS = ['longest-path', 'tight-tree', 'network-simplex', 'unknown-should-still-work'];
var g;
beforeEach(function () {
g = new Graph()
.setGraph({})
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { minlen: 1, weight: 1 };
})
.setPath(['a', 'b', 'c', 'd', 'h'])
.setPath(['a', 'e', 'g', 'h'])
.setPath(['a', 'f', 'g']);
});
_.forEach(RANKERS, function (ranker) {
describe(ranker, function () {
it('respects the minlen attribute', function () {
g.graph().ranker = ranker;
rank(g);
_.forEach(g.edges(), function (e) {
var vRank = g.node(e.v).rank;
var wRank = g.node(e.w).rank;
expect(wRank - vRank).to.be.gte(g.edge(e).minlen);
});
});
it('can rank a single node graph', function () {
var g = new Graph().setGraph({}).setNode('a', {});
g.graph().ranker = ranker;
rank(g);
expect(g.node('a').rank).to.equal(0);
});
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/rank/network-simplex.js 0000664 0000000 0000000 00000015014 15114061606 0023063 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import * as alg from '../../graphlib/alg/index.js';
import { simplify } from '../util.js';
import { feasibleTree } from './feasible-tree.js';
import { longestPath, slack } from './util.js';
export { networkSimplex };
// Expose some internals for testing purposes
networkSimplex.initLowLimValues = initLowLimValues;
networkSimplex.initCutValues = initCutValues;
networkSimplex.calcCutValue = calcCutValue;
networkSimplex.leaveEdge = leaveEdge;
networkSimplex.enterEdge = enterEdge;
networkSimplex.exchangeEdges = exchangeEdges;
/*
* The network simplex algorithm assigns ranks to each node in the input graph
* and iteratively improves the ranking to reduce the length of edges.
*
* Preconditions:
*
* 1. The input graph must be a DAG.
* 2. All nodes in the graph must have an object value.
* 3. All edges in the graph must have "minlen" and "weight" attributes.
*
* Postconditions:
*
* 1. All nodes in the graph will have an assigned "rank" attribute that has
* been optimized by the network simplex algorithm. Ranks start at 0.
*
*
* A rough sketch of the algorithm is as follows:
*
* 1. Assign initial ranks to each node. We use the longest path algorithm,
* which assigns ranks to the lowest position possible. In general this
* leads to very wide bottom ranks and unnecessarily long edges.
* 2. Construct a feasible tight tree. A tight tree is one such that all
* edges in the tree have no slack (difference between length of edge
* and minlen for the edge). This by itself greatly improves the assigned
* rankings by shorting edges.
* 3. Iteratively find edges that have negative cut values. Generally a
* negative cut value indicates that the edge could be removed and a new
* tree edge could be added to produce a more compact graph.
*
* Much of the algorithms here are derived from Gansner, et al., "A Technique
* for Drawing Directed Graphs." The structure of the file roughly follows the
* structure of the overall algorithm.
*/
function networkSimplex(g) {
g = simplify(g);
longestPath(g);
var t = feasibleTree(g);
initLowLimValues(t);
initCutValues(t, g);
var e, f;
while ((e = leaveEdge(t))) {
f = enterEdge(t, g, e);
exchangeEdges(t, g, e, f);
}
}
/*
* Initializes cut values for all edges in the tree.
*/
function initCutValues(t, g) {
var vs = alg.postorder(t, t.nodes());
vs = vs.slice(0, vs.length - 1);
_.forEach(vs, function (v) {
assignCutValue(t, g, v);
});
}
function assignCutValue(t, g, child) {
var childLab = t.node(child);
var parent = childLab.parent;
t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
}
/*
* Given the tight tree, its graph, and a child in the graph calculate and
* return the cut value for the edge between the child and its parent.
*/
function calcCutValue(t, g, child) {
var childLab = t.node(child);
var parent = childLab.parent;
// True if the child is on the tail end of the edge in the directed graph
var childIsTail = true;
// The graph's view of the tree edge we're inspecting
var graphEdge = g.edge(child, parent);
// The accumulated cut value for the edge between this node and its parent
var cutValue = 0;
if (!graphEdge) {
childIsTail = false;
graphEdge = g.edge(parent, child);
}
cutValue = graphEdge.weight;
_.forEach(g.nodeEdges(child), function (e) {
var isOutEdge = e.v === child,
other = isOutEdge ? e.w : e.v;
if (other !== parent) {
var pointsToHead = isOutEdge === childIsTail,
otherWeight = g.edge(e).weight;
cutValue += pointsToHead ? otherWeight : -otherWeight;
if (isTreeEdge(t, child, other)) {
var otherCutValue = t.edge(child, other).cutvalue;
cutValue += pointsToHead ? -otherCutValue : otherCutValue;
}
}
});
return cutValue;
}
function initLowLimValues(tree, root) {
if (arguments.length < 2) {
root = tree.nodes()[0];
}
dfsAssignLowLim(tree, {}, 1, root);
}
function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
var low = nextLim;
var label = tree.node(v);
visited[v] = true;
_.forEach(tree.neighbors(v), function (w) {
if (!Object.prototype.hasOwnProperty.call(visited, w)) {
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
}
});
label.low = low;
label.lim = nextLim++;
if (parent) {
label.parent = parent;
} else {
// TODO should be able to remove this when we incrementally update low lim
delete label.parent;
}
return nextLim;
}
function leaveEdge(tree) {
return _.find(tree.edges(), function (e) {
return tree.edge(e).cutvalue < 0;
});
}
function enterEdge(t, g, edge) {
var v = edge.v;
var w = edge.w;
// For the rest of this function we assume that v is the tail and w is the
// head, so if we don't have this edge in the graph we should flip it to
// match the correct orientation.
if (!g.hasEdge(v, w)) {
v = edge.w;
w = edge.v;
}
var vLabel = t.node(v);
var wLabel = t.node(w);
var tailLabel = vLabel;
var flip = false;
// If the root is in the tail of the edge then we need to flip the logic that
// checks for the head and tail nodes in the candidates function below.
if (vLabel.lim > wLabel.lim) {
tailLabel = wLabel;
flip = true;
}
var candidates = _.filter(g.edges(), function (edge) {
return (
flip === isDescendant(t, t.node(edge.v), tailLabel) &&
flip !== isDescendant(t, t.node(edge.w), tailLabel)
);
});
return _.minBy(candidates, function (edge) {
return slack(g, edge);
});
}
function exchangeEdges(t, g, e, f) {
var v = e.v;
var w = e.w;
t.removeEdge(v, w);
t.setEdge(f.v, f.w, {});
initLowLimValues(t);
initCutValues(t, g);
updateRanks(t, g);
}
function updateRanks(t, g) {
var root = _.find(t.nodes(), function (v) {
return !g.node(v).parent;
});
var vs = alg.preorder(t, root);
vs = vs.slice(1);
_.forEach(vs, function (v) {
var parent = t.node(v).parent,
edge = g.edge(v, parent),
flipped = false;
if (!edge) {
edge = g.edge(parent, v);
flipped = true;
}
g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
});
}
/*
* Returns true if the edge is in the tree.
*/
function isTreeEdge(tree, u, v) {
return tree.hasEdge(u, v);
}
/*
* Returns true if the specified node is descendant of the root node per the
* assigned low and lim attributes in the tree.
*/
function isDescendant(tree, vLabel, rootLabel) {
return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
}
tbo47-dagre-es-4b95ad0/src/dagre/rank/network-simplex.test.js 0000664 0000000 0000000 00000036504 15114061606 0024050 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { networkSimplex } from './network-simplex.js';
import { longestPath } from './util.js';
var initLowLimValues = networkSimplex.initLowLimValues;
var initCutValues = networkSimplex.initCutValues;
var calcCutValue = networkSimplex.calcCutValue;
var leaveEdge = networkSimplex.leaveEdge;
var enterEdge = networkSimplex.enterEdge;
var exchangeEdges = networkSimplex.exchangeEdges;
import { normalizeRanks } from '../util.js';
describe('network simplex', function () {
/** @type {Graph} */
var g;
/** @type {Graph} */
var t;
/** @type {Graph} */
var gansnerGraph;
/** @type {Graph} */
var gansnerTree;
beforeEach(function () {
g = new Graph({ multigraph: true })
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { minlen: 1, weight: 1 };
});
t = new Graph({ directed: false })
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return {};
});
gansnerGraph = new Graph()
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { minlen: 1, weight: 1 };
})
.setPath(['a', 'b', 'c', 'd', 'h'])
.setPath(['a', 'e', 'g', 'h'])
.setPath(['a', 'f', 'g']);
gansnerTree = new Graph({ directed: false })
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return {};
})
.setPath(['a', 'b', 'c', 'd', 'h', 'g', 'e'])
.setEdge('g', 'f');
});
it('can assign a rank to a single node', function () {
g.setNode('a');
ns(g);
expect(g.node('a').rank).to.equal(0);
});
it('can assign a rank to a 2-node connected graph', function () {
g.setEdge('a', 'b');
ns(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
});
it('can assign ranks for a diamond', function () {
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
ns(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
expect(g.node('c').rank).to.equal(1);
expect(g.node('d').rank).to.equal(2);
});
it('uses the minlen attribute on the edge', function () {
g.setPath(['a', 'b', 'd']);
g.setEdge('a', 'c');
g.setEdge('c', 'd', { minlen: 2 });
ns(g);
expect(g.node('a').rank).to.equal(0);
// longest path biases towards the lowest rank it can assign. Since the
// graph has no optimization opportunities we can assume that the longest
// path ranking is used.
expect(g.node('b').rank).to.equal(2);
expect(g.node('c').rank).to.equal(1);
expect(g.node('d').rank).to.equal(3);
});
it('can rank the gansner graph', function () {
g = gansnerGraph;
ns(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
expect(g.node('c').rank).to.equal(2);
expect(g.node('d').rank).to.equal(3);
expect(g.node('h').rank).to.equal(4);
expect(g.node('e').rank).to.equal(1);
expect(g.node('f').rank).to.equal(1);
expect(g.node('g').rank).to.equal(2);
});
it('can handle multi-edges', function () {
g.setPath(['a', 'b', 'c', 'd']);
g.setEdge('a', 'e', { weight: 2, minlen: 1 });
g.setEdge('e', 'd');
g.setEdge('b', 'c', { weight: 1, minlen: 2 }, 'multi');
ns(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
// b -> c has minlen = 1 and minlen = 2, so it should be 2 ranks apart.
expect(g.node('c').rank).to.equal(3);
expect(g.node('d').rank).to.equal(4);
expect(g.node('e').rank).to.equal(1);
});
describe('leaveEdge', function () {
it('returns undefined if there is no edge with a negative cutvalue', function () {
var tree = new Graph({ directed: false });
tree.setEdge('a', 'b', { cutvalue: 1 });
tree.setEdge('b', 'c', { cutvalue: 1 });
expect(leaveEdge(tree)).to.be.undefined;
});
it('returns an edge if one is found with a negative cutvalue', function () {
var tree = new Graph({ directed: false });
tree.setEdge('a', 'b', { cutvalue: 1 });
tree.setEdge('b', 'c', { cutvalue: -1 });
expect(leaveEdge(tree)).to.eql({ v: 'b', w: 'c' });
});
});
describe('enterEdge', function () {
it('finds an edge from the head to tail component', function () {
g.setNode('a', { rank: 0 })
.setNode('b', { rank: 2 })
.setNode('c', { rank: 3 })
.setPath(['a', 'b', 'c'])
.setEdge('a', 'c');
t.setPath(['b', 'c', 'a']);
initLowLimValues(t, 'c');
var f = enterEdge(t, g, { v: 'b', w: 'c' });
expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: 'a', w: 'b' }));
});
it('works when the root of the tree is in the tail component', function () {
g.setNode('a', { rank: 0 })
.setNode('b', { rank: 2 })
.setNode('c', { rank: 3 })
.setPath(['a', 'b', 'c'])
.setEdge('a', 'c');
t.setPath(['b', 'c', 'a']);
initLowLimValues(t, 'b');
var f = enterEdge(t, g, { v: 'b', w: 'c' });
expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: 'a', w: 'b' }));
});
it('finds the edge with the least slack', function () {
g.setNode('a', { rank: 0 })
.setNode('b', { rank: 1 })
.setNode('c', { rank: 3 })
.setNode('d', { rank: 4 })
.setEdge('a', 'd')
.setPath(['a', 'c', 'd'])
.setEdge('b', 'c');
t.setPath(['c', 'd', 'a', 'b']);
initLowLimValues(t, 'a');
var f = enterEdge(t, g, { v: 'c', w: 'd' });
expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: 'b', w: 'c' }));
});
it('finds an appropriate edge for gansner graph #1', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t, 'a');
var f = enterEdge(t, g, { v: 'g', w: 'h' });
expect(undirectedEdge(f).v).to.equal('a');
expect(['e', 'f']).to.include(undirectedEdge(f).w);
});
it('finds an appropriate edge for gansner graph #2', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t, 'e');
var f = enterEdge(t, g, { v: 'g', w: 'h' });
expect(undirectedEdge(f).v).to.equal('a');
expect(['e', 'f']).to.include(undirectedEdge(f).w);
});
it('finds an appropriate edge for gansner graph #3', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t, 'a');
var f = enterEdge(t, g, { v: 'h', w: 'g' });
expect(undirectedEdge(f).v).to.equal('a');
expect(['e', 'f']).to.include(undirectedEdge(f).w);
});
it('finds an appropriate edge for gansner graph #4', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t, 'e');
var f = enterEdge(t, g, { v: 'h', w: 'g' });
expect(undirectedEdge(f).v).to.equal('a');
expect(['e', 'f']).to.include(undirectedEdge(f).w);
});
});
describe('initLowLimValues', function () {
it('assigns low, lim, and parent for each node in a tree', function () {
var g = new Graph()
.setDefaultNodeLabel(function () {
return {};
})
.setNodes(['a', 'b', 'c', 'd', 'e'])
.setPath(['a', 'b', 'a', 'c', 'd', 'c', 'e']);
initLowLimValues(g, 'a');
var a = g.node('a');
var b = g.node('b');
var c = g.node('c');
var d = g.node('d');
var e = g.node('e');
expect(
_.sortBy(
_.map(g.nodes(), function (v) {
return g.node(v).lim;
}),
),
).to.eql(_.range(1, 6));
expect(a).to.eql({ low: 1, lim: 5 });
expect(b.parent).to.equal('a');
expect(b.lim).to.be.lt(a.lim);
expect(c.parent).to.equal('a');
expect(c.lim).to.be.lt(a.lim);
expect(c.lim).to.not.equal(b.lim);
expect(d.parent).to.equal('c');
expect(d.lim).to.be.lt(c.lim);
expect(e.parent).to.equal('c');
expect(e.lim).to.be.lt(c.lim);
expect(e.lim).to.not.equal(d.lim);
});
});
describe('exchangeEdges', function () {
it('exchanges edges and updates cut values and low/lim numbers', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t);
exchangeEdges(t, g, { v: 'g', w: 'h' }, { v: 'a', w: 'e' });
// check new cut values
expect(t.edge('a', 'b').cutvalue).to.equal(2);
expect(t.edge('b', 'c').cutvalue).to.equal(2);
expect(t.edge('c', 'd').cutvalue).to.equal(2);
expect(t.edge('d', 'h').cutvalue).to.equal(2);
expect(t.edge('a', 'e').cutvalue).to.equal(1);
expect(t.edge('e', 'g').cutvalue).to.equal(1);
expect(t.edge('g', 'f').cutvalue).to.equal(0);
// ensure lim numbers look right
var lims = _.sortBy(
_.map(t.nodes(), function (v) {
return t.node(v).lim;
}),
);
expect(lims).to.eql(_.range(1, 9));
});
it('updates ranks', function () {
g = gansnerGraph;
t = gansnerTree;
longestPath(g);
initLowLimValues(t);
exchangeEdges(t, g, { v: 'g', w: 'h' }, { v: 'a', w: 'e' });
normalizeRanks(g);
// check new ranks
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
expect(g.node('c').rank).to.equal(2);
expect(g.node('d').rank).to.equal(3);
expect(g.node('e').rank).to.equal(1);
expect(g.node('f').rank).to.equal(1);
expect(g.node('g').rank).to.equal(2);
expect(g.node('h').rank).to.equal(4);
});
});
// Note: we use p for parent, c for child, gc_x for grandchild nodes, and o for
// other nodes in the tree for these tests.
describe('calcCutValue', function () {
it('works for a 2-node tree with c -> p', function () {
g.setPath(['c', 'p']);
t.setPath(['p', 'c']);
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(1);
});
it('works for a 2-node tree with c <- p', function () {
g.setPath(['p', 'c']);
t.setPath(['p', 'c']);
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(1);
});
it('works for 3-node tree with gc -> c -> p', function () {
g.setPath(['gc', 'c', 'p']);
t.setEdge('gc', 'c', { cutvalue: 3 }).setEdge('p', 'c');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(3);
});
it('works for 3-node tree with gc -> c <- p', function () {
g.setEdge('p', 'c').setEdge('gc', 'c');
t.setEdge('gc', 'c', { cutvalue: 3 }).setEdge('p', 'c');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-1);
});
it('works for 3-node tree with gc <- c -> p', function () {
g.setEdge('c', 'p').setEdge('c', 'gc');
t.setEdge('gc', 'c', { cutvalue: 3 }).setEdge('p', 'c');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-1);
});
it('works for 3-node tree with gc <- c <- p', function () {
g.setPath(['p', 'c', 'gc']);
t.setEdge('gc', 'c', { cutvalue: 3 }).setEdge('p', 'c');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(3);
});
it('works for 4-node tree with gc -> c -> p -> o, with o -> c', function () {
g.setEdge('o', 'c', { weight: 7 }).setPath(['gc', 'c', 'p', 'o']);
t.setEdge('gc', 'c', { cutvalue: 3 }).setPath(['c', 'p', 'o']);
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-4);
});
it('works for 4-node tree with gc -> c -> p -> o, with o <- c', function () {
g.setEdge('c', 'o', { weight: 7 }).setPath(['gc', 'c', 'p', 'o']);
t.setEdge('gc', 'c', { cutvalue: 3 }).setPath(['c', 'p', 'o']);
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(10);
});
it('works for 4-node tree with o -> gc -> c -> p, with o -> c', function () {
g.setEdge('o', 'c', { weight: 7 }).setPath(['o', 'gc', 'c', 'p']);
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-4);
});
it('works for 4-node tree with o -> gc -> c -> p, with o <- c', function () {
g.setEdge('c', 'o', { weight: 7 }).setPath(['o', 'gc', 'c', 'p']);
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(10);
});
it('works for 4-node tree with gc -> c <- p -> o, with o -> c', function () {
g.setEdge('gc', 'c').setEdge('p', 'c').setEdge('p', 'o').setEdge('o', 'c', { weight: 7 });
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(6);
});
it('works for 4-node tree with gc -> c <- p -> o, with o <- c', function () {
g.setEdge('gc', 'c').setEdge('p', 'c').setEdge('p', 'o').setEdge('c', 'o', { weight: 7 });
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-8);
});
it('works for 4-node tree with o -> gc -> c <- p, with o -> c', function () {
g.setEdge('o', 'c', { weight: 7 }).setPath(['o', 'gc', 'c']).setEdge('p', 'c');
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(6);
});
it('works for 4-node tree with o -> gc -> c <- p, with o <- c', function () {
g.setEdge('c', 'o', { weight: 7 }).setPath(['o', 'gc', 'c']).setEdge('p', 'c');
t.setEdge('o', 'gc').setEdge('gc', 'c', { cutvalue: 3 }).setEdge('c', 'p');
initLowLimValues(t, 'p');
expect(calcCutValue(t, g, 'c')).to.equal(-8);
});
});
describe('initCutValues', function () {
it('works for gansnerGraph', function () {
initLowLimValues(gansnerTree);
initCutValues(gansnerTree, gansnerGraph);
expect(gansnerTree.edge('a', 'b').cutvalue).to.equal(3);
expect(gansnerTree.edge('b', 'c').cutvalue).to.equal(3);
expect(gansnerTree.edge('c', 'd').cutvalue).to.equal(3);
expect(gansnerTree.edge('d', 'h').cutvalue).to.equal(3);
expect(gansnerTree.edge('g', 'h').cutvalue).to.equal(-1);
expect(gansnerTree.edge('e', 'g').cutvalue).to.equal(0);
expect(gansnerTree.edge('f', 'g').cutvalue).to.equal(0);
});
it('works for updated gansnerGraph', function () {
gansnerTree.removeEdge('g', 'h');
gansnerTree.setEdge('a', 'e');
initLowLimValues(gansnerTree);
initCutValues(gansnerTree, gansnerGraph);
expect(gansnerTree.edge('a', 'b').cutvalue).to.equal(2);
expect(gansnerTree.edge('b', 'c').cutvalue).to.equal(2);
expect(gansnerTree.edge('c', 'd').cutvalue).to.equal(2);
expect(gansnerTree.edge('d', 'h').cutvalue).to.equal(2);
expect(gansnerTree.edge('a', 'e').cutvalue).to.equal(1);
expect(gansnerTree.edge('e', 'g').cutvalue).to.equal(1);
expect(gansnerTree.edge('f', 'g').cutvalue).to.equal(0);
});
});
});
function ns(g) {
networkSimplex(g);
normalizeRanks(g);
}
function undirectedEdge(e) {
return e.v < e.w ? { v: e.v, w: e.w } : { v: e.w, w: e.v };
}
tbo47-dagre-es-4b95ad0/src/dagre/rank/util.js 0000664 0000000 0000000 00000003371 15114061606 0020673 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
export { longestPath, slack };
/*
* Initializes ranks for the input graph using the longest path algorithm. This
* algorithm scales well and is fast in practice, it yields rather poor
* solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
* ranks wide and leaving edges longer than necessary. However, due to its
* speed, this algorithm is good for getting an initial ranking that can be fed
* into other algorithms.
*
* This algorithm does not normalize layers because it will be used by other
* algorithms in most cases. If using this algorithm directly, be sure to
* run normalize at the end.
*
* Pre-conditions:
*
* 1. Input graph is a DAG.
* 2. Input graph node labels can be assigned properties.
*
* Post-conditions:
*
* 1. Each node will be assign an (unnormalized) "rank" property.
*/
function longestPath(g) {
var visited = {};
function dfs(v) {
var label = g.node(v);
if (Object.prototype.hasOwnProperty.call(visited, v)) {
return label.rank;
}
visited[v] = true;
var rank = _.min(
_.map(g.outEdges(v), function (e) {
return dfs(e.w) - g.edge(e).minlen;
}),
);
if (
rank === Number.POSITIVE_INFINITY || // return value of _.map([]) for Lodash 3
rank === undefined || // return value of _.map([]) for Lodash 4
rank === null
) {
// return value of _.map([null])
rank = 0;
}
return (label.rank = rank);
}
_.forEach(g.sources(), dfs);
}
/*
* Returns the amount of slack for the given edge. The slack is defined as the
* difference between the length of the edge and its minimum length.
*/
function slack(g, e) {
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
}
tbo47-dagre-es-4b95ad0/src/dagre/rank/util.test.js 0000664 0000000 0000000 00000003753 15114061606 0021655 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../../graphlib/graph.js';
import { normalizeRanks } from '../util.js';
import { longestPath } from './util.js';
describe('rank/util', function () {
describe('longestPath', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph()
.setDefaultNodeLabel(function () {
return {};
})
.setDefaultEdgeLabel(function () {
return { minlen: 1 };
});
});
it('can assign a rank to a single node graph', function () {
g.setNode('a');
longestPath(g);
normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
});
it('can assign ranks to unconnected nodes', function () {
g.setNode('a');
g.setNode('b');
longestPath(g);
normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(0);
});
it('can assign ranks to connected nodes', function () {
g.setEdge('a', 'b');
longestPath(g);
normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
});
it('can assign ranks for a diamond', function () {
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
longestPath(g);
normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
expect(g.node('c').rank).to.equal(1);
expect(g.node('d').rank).to.equal(2);
});
it('uses the minlen attribute on the edge', function () {
g.setPath(['a', 'b', 'd']);
g.setEdge('a', 'c');
g.setEdge('c', 'd', { minlen: 2 });
longestPath(g);
normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
// longest path biases towards the lowest rank it can assign
expect(g.node('b').rank).to.equal(2);
expect(g.node('c').rank).to.equal(1);
expect(g.node('d').rank).to.equal(3);
});
});
});
tbo47-dagre-es-4b95ad0/src/dagre/util.js 0000664 0000000 0000000 00000013016 15114061606 0017735 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
export {
addDummyNode,
simplify,
asNonCompoundGraph,
successorWeights,
predecessorWeights,
intersectRect,
buildLayerMatrix,
normalizeRanks,
removeEmptyRanks,
addBorderNode,
maxRank,
partition,
time,
notime,
};
/*
* Adds a dummy node to the graph and return v.
*/
function addDummyNode(g, type, attrs, name) {
var v;
do {
v = _.uniqueId(name);
} while (g.hasNode(v));
attrs.dummy = type;
g.setNode(v, attrs);
return v;
}
/*
* Returns a new graph with only simple edges. Handles aggregation of data
* associated with multi-edges.
*/
function simplify(g) {
var simplified = new Graph().setGraph(g.graph());
_.forEach(g.nodes(), function (v) {
simplified.setNode(v, g.node(v));
});
_.forEach(g.edges(), function (e) {
var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 };
var label = g.edge(e);
simplified.setEdge(e.v, e.w, {
weight: simpleLabel.weight + label.weight,
minlen: Math.max(simpleLabel.minlen, label.minlen),
});
});
return simplified;
}
function asNonCompoundGraph(g) {
var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
_.forEach(g.nodes(), function (v) {
if (!g.children(v).length) {
simplified.setNode(v, g.node(v));
}
});
_.forEach(g.edges(), function (e) {
simplified.setEdge(e, g.edge(e));
});
return simplified;
}
function successorWeights(g) {
var weightMap = _.map(g.nodes(), function (v) {
var sucs = {};
_.forEach(g.outEdges(v), function (e) {
sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
});
return sucs;
});
return _.zipObject(g.nodes(), weightMap);
}
function predecessorWeights(g) {
var weightMap = _.map(g.nodes(), function (v) {
var preds = {};
_.forEach(g.inEdges(v), function (e) {
preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
});
return preds;
});
return _.zipObject(g.nodes(), weightMap);
}
/*
* Finds where a line starting at point ({x, y}) would intersect a rectangle
* ({x, y, width, height}) if it were pointing at the rectangle's center.
*/
function intersectRect(rect, point) {
var x = rect.x;
var y = rect.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = rect.width / 2;
var h = rect.height / 2;
if (!dx && !dy) {
throw new Error('Not possible to find intersection inside of the rectangle');
}
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = (h * dx) / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = (w * dy) / dx;
}
return { x: x + sx, y: y + sy };
}
/*
* Given a DAG with each node assigned "rank" and "order" properties, this
* function will produce a matrix with the ids of each node.
*/
function buildLayerMatrix(g) {
var layering = _.map(_.range(maxRank(g) + 1), function () {
return [];
});
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
var rank = node.rank;
if (!_.isUndefined(rank)) {
layering[rank][node.order] = v;
}
});
return layering;
}
/*
* Adjusts the ranks for all nodes in the graph such that all nodes v have
* rank(v) >= 0 and at least one node w has rank(w) = 0.
*/
function normalizeRanks(g) {
var min = _.min(
_.map(g.nodes(), function (v) {
return g.node(v).rank;
}),
);
_.forEach(g.nodes(), function (v) {
var node = g.node(v);
if (_.has(node, 'rank')) {
node.rank -= min;
}
});
}
function removeEmptyRanks(g) {
// Ranks may not start at 0, so we need to offset them
var offset = _.min(
_.map(g.nodes(), function (v) {
return g.node(v).rank;
}),
);
var layers = [];
_.forEach(g.nodes(), function (v) {
var rank = g.node(v).rank - offset;
if (!layers[rank]) {
layers[rank] = [];
}
layers[rank].push(v);
});
var delta = 0;
var nodeRankFactor = g.graph().nodeRankFactor;
_.forEach(layers, function (vs, i) {
if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
--delta;
} else if (delta) {
_.forEach(vs, function (v) {
g.node(v).rank += delta;
});
}
});
}
function addBorderNode(g, prefix, rank, order) {
var node = {
width: 0,
height: 0,
};
if (arguments.length >= 4) {
node.rank = rank;
node.order = order;
}
return addDummyNode(g, 'border', node, prefix);
}
function maxRank(g) {
return _.max(
_.map(g.nodes(), function (v) {
var rank = g.node(v).rank;
if (!_.isUndefined(rank)) {
return rank;
}
}),
);
}
/*
* Partition a collection into two groups: `lhs` and `rhs`. If the supplied
* function returns true for an entry it goes into `lhs`. Otherwise it goes
* into `rhs.
*/
function partition(collection, fn) {
var result = { lhs: [], rhs: [] };
_.forEach(collection, function (value) {
if (fn(value)) {
result.lhs.push(value);
} else {
result.rhs.push(value);
}
});
return result;
}
/*
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
* time it takes to execute the function.
*/
function time(name, fn) {
var start = _.now();
try {
return fn();
} finally {
console.log(name + ' time: ' + (_.now() - start) + 'ms');
}
}
function notime(name, fn) {
return fn();
}
tbo47-dagre-es-4b95ad0/src/dagre/util.test.js 0000664 0000000 0000000 00000017564 15114061606 0020727 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { Graph } from '../graphlib/index.js';
import * as util from './util.js';
describe('util', function () {
describe('simplify', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph({ multigraph: true });
});
it('copies without change a graph with no multi-edges', function () {
g.setEdge('a', 'b', { weight: 1, minlen: 1 });
var g2 = util.simplify(g);
expect(g2.edge('a', 'b')).eql({ weight: 1, minlen: 1 });
expect(g2.edgeCount()).equals(1);
});
it('collapses multi-edges', function () {
g.setEdge('a', 'b', { weight: 1, minlen: 1 });
g.setEdge('a', 'b', { weight: 2, minlen: 2 }, 'multi');
var g2 = util.simplify(g);
expect(g2.isMultigraph()).to.be.false;
expect(g2.edge('a', 'b')).eql({ weight: 3, minlen: 2 });
expect(g2.edgeCount()).equals(1);
});
it('copies the graph object', function () {
g.setGraph({ foo: 'bar' });
var g2 = util.simplify(g);
expect(g2.graph()).eqls({ foo: 'bar' });
});
});
describe('asNonCompoundGraph', function () {
var g;
beforeEach(function () {
g = new Graph({ compound: true, multigraph: true });
});
it('copies all nodes', function () {
g.setNode('a', { foo: 'bar' });
g.setNode('b');
var g2 = util.asNonCompoundGraph(g);
expect(g2.node('a')).to.eql({ foo: 'bar' });
expect(g2.hasNode('b')).to.be.true;
});
it('copies all edges', function () {
g.setEdge('a', 'b', { foo: 'bar' });
g.setEdge('a', 'b', { foo: 'baz' }, 'multi');
var g2 = util.asNonCompoundGraph(g);
expect(g2.edge('a', 'b')).eqls({ foo: 'bar' });
expect(g2.edge('a', 'b', 'multi')).eqls({ foo: 'baz' });
});
it('does not copy compound nodes', function () {
g.setParent('a', 'sg1');
var g2 = util.asNonCompoundGraph(g);
expect(g2.parent(g)).to.be.undefined;
expect(g2.isCompound()).to.be.false;
});
it('copies the graph object', function () {
g.setGraph({ foo: 'bar' });
var g2 = util.asNonCompoundGraph(g);
expect(g2.graph()).eqls({ foo: 'bar' });
});
});
describe('successorWeights', function () {
it('maps a node to its successors with associated weights', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', { weight: 2 });
g.setEdge('b', 'c', { weight: 1 });
g.setEdge('b', 'c', { weight: 2 }, 'multi');
g.setEdge('b', 'd', { weight: 1 }, 'multi');
expect(util.successorWeights(g).a).to.eql({ b: 2 });
expect(util.successorWeights(g).b).to.eql({ c: 3, d: 1 });
expect(util.successorWeights(g).c).to.eql({});
expect(util.successorWeights(g).d).to.eql({});
});
});
describe('predecessorWeights', function () {
it('maps a node to its predecessors with associated weights', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', { weight: 2 });
g.setEdge('b', 'c', { weight: 1 });
g.setEdge('b', 'c', { weight: 2 }, 'multi');
g.setEdge('b', 'd', { weight: 1 }, 'multi');
expect(util.predecessorWeights(g).a).to.eql({});
expect(util.predecessorWeights(g).b).to.eql({ a: 2 });
expect(util.predecessorWeights(g).c).to.eql({ b: 3 });
expect(util.predecessorWeights(g).d).to.eql({ b: 1 });
});
});
describe('intersectRect', function () {
function expectIntersects(rect, point) {
var cross = util.intersectRect(rect, point);
if (cross.x !== point.x) {
var m = (cross.y - point.y) / (cross.x - point.x);
expect(cross.y - rect.y).equals(m * (cross.x - rect.x));
}
}
function expectTouchesBorder(rect, point) {
var cross = util.intersectRect(rect, point);
if (Math.abs(rect.x - cross.x) !== rect.width / 2) {
expect(Math.abs(rect.y - cross.y)).equals(rect.height / 2);
}
}
it("creates a slope that will intersect the rectangle's center", function () {
var rect = { x: 0, y: 0, width: 1, height: 1 };
expectIntersects(rect, { x: 2, y: 6 });
expectIntersects(rect, { x: 2, y: -6 });
expectIntersects(rect, { x: 6, y: 2 });
expectIntersects(rect, { x: -6, y: 2 });
expectIntersects(rect, { x: 5, y: 0 });
expectIntersects(rect, { x: 0, y: 5 });
});
it('touches the border of the rectangle', function () {
var rect = { x: 0, y: 0, width: 1, height: 1 };
expectTouchesBorder(rect, { x: 2, y: 6 });
expectTouchesBorder(rect, { x: 2, y: -6 });
expectTouchesBorder(rect, { x: 6, y: 2 });
expectTouchesBorder(rect, { x: -6, y: 2 });
expectTouchesBorder(rect, { x: 5, y: 0 });
expectTouchesBorder(rect, { x: 0, y: 5 });
});
it('throws an error if the point is at the center of the rectangle', function () {
var rect = { x: 0, y: 0, width: 1, height: 1 };
expect(function () {
util.intersectRect(rect, { x: 0, y: 0 });
}).to.throw();
});
});
describe('buildLayerMatrix', function () {
it('creates a matrix based on rank and order of nodes in the graph', function () {
var g = new Graph();
g.setNode('a', { rank: 0, order: 0 });
g.setNode('b', { rank: 0, order: 1 });
g.setNode('c', { rank: 1, order: 0 });
g.setNode('d', { rank: 1, order: 1 });
g.setNode('e', { rank: 2, order: 0 });
expect(util.buildLayerMatrix(g)).to.eql([['a', 'b'], ['c', 'd'], ['e']]);
});
});
describe('time', function () {
var consoleLog;
beforeEach(function () {
consoleLog = console.log;
});
afterEach(function () {
console.log = consoleLog;
});
it('logs timing information', function () {
var capture = [];
console.log = function () {
capture.push(_.toArray(arguments)[0]);
};
util.time('foo', function () {});
expect(capture.length).to.equal(1);
expect(capture[0]).to.match(/^foo time: .*ms/);
});
it('returns the value from the evaluated function', function () {
console.log = function () {};
expect(util.time('foo', _.constant('bar'))).to.equal('bar');
});
});
describe('normalizeRanks', function () {
it('adjust ranks such that all are >= 0, and at least one is 0', function () {
var g = new Graph()
.setNode('a', { rank: 3 })
.setNode('b', { rank: 2 })
.setNode('c', { rank: 4 });
util.normalizeRanks(g);
expect(g.node('a').rank).to.equal(1);
expect(g.node('b').rank).to.equal(0);
expect(g.node('c').rank).to.equal(2);
});
it('works for negative ranks', function () {
var g = new Graph().setNode('a', { rank: -3 }).setNode('b', { rank: -2 });
util.normalizeRanks(g);
expect(g.node('a').rank).to.equal(0);
expect(g.node('b').rank).to.equal(1);
});
it('does not assign a rank to subgraphs', function () {
var g = new Graph({ compound: true })
.setNode('a', { rank: 0 })
.setNode('sg', {})
.setParent('a', 'sg');
util.normalizeRanks(g);
expect(g.node('sg')).to.not.have.property('rank');
expect(g.node('a').rank).to.equal(0);
});
});
describe('removeEmptyRanks', function () {
it('Removes border ranks without any nodes', function () {
var g = new Graph()
.setGraph({ nodeRankFactor: 4 })
.setNode('a', { rank: 0 })
.setNode('b', { rank: 4 });
util.removeEmptyRanks(g);
expect(g.node('a').rank).equals(0);
expect(g.node('b').rank).equals(1);
});
it('Does not remove non-border ranks', function () {
var g = new Graph()
.setGraph({ nodeRankFactor: 4 })
.setNode('a', { rank: 0 })
.setNode('b', { rank: 8 });
util.removeEmptyRanks(g);
expect(g.node('a').rank).equals(0);
expect(g.node('b').rank).equals(2);
});
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/ 0000775 0000000 0000000 00000000000 15114061606 0017127 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/graphlib/alg/ 0000775 0000000 0000000 00000000000 15114061606 0017672 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/graphlib/alg/components.js 0000664 0000000 0000000 00000002605 15114061606 0022420 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
/**
* @import { Graph, NodeID } from '../graph.js';
*/
export { components };
/**
* Finds all [connected components][] in a graph and returns an array of these
* components. Each component is itself an array that contains the ids of nodes
* in the component.
*
* [connected components]: http://en.wikipedia.org/wiki/Connected_component_(graph_theory)
*
* @example
*
* 
*
* ```js
* graphlib.alg.components(g);
* // => [ [ 'A', 'B', 'C', 'D' ],
* // [ 'E', 'F', 'G' ],
* // [ 'H', 'I' ] ]
* ```
*
* @param {Graph} g - The graph to find components in.
* @returns {NodeID[][]} An array of components, each of which is an array of node IDs.
*
* @remarks This function takes `O(|V|)` time.
*/
function components(g) {
/**
* @type {Record}
*/
var visited = {};
/**
* @type {NodeID[][]}
*/
var cmpts = [];
/**
* @type {NodeID[]}
*/
var cmpt;
/**
* @param {NodeID} v - The node to visit.
*/
function dfs(v) {
if (Object.prototype.hasOwnProperty.call(visited, v)) return;
visited[v] = true;
cmpt.push(v);
_.each(g.successors(v), dfs);
_.each(g.predecessors(v), dfs);
}
_.each(g.nodes(), function (v) {
cmpt = [];
dfs(v);
if (cmpt.length) {
cmpts.push(cmpt);
}
});
return cmpts;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/components.test.js 0000664 0000000 0000000 00000002344 15114061606 0023376 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { components } from './components.js';
describe('alg.components', function () {
it('returns an empty list for an empty graph', function () {
expect(components(new Graph({ directed: false }))).to.be.empty;
});
it('returns singleton lists for unconnected nodes', function () {
var g = new Graph({ directed: false });
g.setNode('a');
g.setNode('b');
var result = components(g).sort((a, b) => a[0].localeCompare(b[0]));
expect(result).to.eql([['a'], ['b']]);
});
it('returns a list of nodes in a component', function () {
var g = new Graph({ directed: false });
g.setEdge('a', 'b');
g.setEdge('b', 'c');
var result = components(g).map((xs) => xs.sort());
expect(result).to.eql([['a', 'b', 'c']]);
});
it('returns nodes connected by a neighbor relationship in a digraph', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c', 'a']);
g.setEdge('d', 'c');
g.setEdge('e', 'f');
var result = components(g)
.map((xs) => xs.sort())
.sort((a, b) => a[0].localeCompare(b[0]));
expect(result).to.eql([
['a', 'b', 'c', 'd'],
['e', 'f'],
]);
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/alg/dfs.js 0000664 0000000 0000000 00000003563 15114061606 0021013 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
/**
* @import { Graph, NodeID } from '../graph.js';
*/
export { dfs };
/**
* A helper that preforms a pre- or post-order traversal on the input graph
* and returns the nodes in the order they were visited. If the graph is
* undirected then this algorithm will navigate using neighbors. If the graph
* is directed then this algorithm will navigate using successors.
*
* @param {Graph} g - Input graph.
* @param {NodeID[] | NodeID} vs - Starting node or array of nodes.
* @param {'post' | 'pre'} order - The order to use. Must be one of "pre" or "post".
* @returns {NodeID[]} The nodes in the order they were visited.
*/
function dfs(g, vs, order) {
if (!_.isArray(vs)) {
vs = [vs];
}
/** @type {Parameters[4]} */
var navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g);
/** @type {Parameters[5]} */
var acc = [];
/** @type {Parameters[3]} */
var visited = {};
_.each(vs, function (v) {
if (!g.hasNode(v)) {
throw new Error('Graph does not have node: ' + v);
}
doDfs(g, v, order === 'post', visited, navigation, acc);
});
return acc;
}
/**
* @param {Graph} g - Input graph.
* @param {NodeID} v - The node to visit.
* @param {boolean} postorder - Whether to do postorder traversal.
* @param {Record} visited - Visited nodes.
* @param {(node: NodeID) => (NodeID[] | undefined)} navigation - Function to get
* neighbors/successors.
* @param {NodeID[]} acc - Accumulator for visited nodes.
*/
function doDfs(g, v, postorder, visited, navigation, acc) {
if (!Object.prototype.hasOwnProperty.call(visited, v)) {
visited[v] = true;
if (!postorder) {
acc.push(v);
}
_.each(navigation(v), function (w) {
doDfs(g, w, postorder, visited, navigation, acc);
});
if (postorder) {
acc.push(v);
}
}
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/dijkstra-all.js 0000664 0000000 0000000 00000004521 15114061606 0022613 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { dijkstra } from './dijkstra.js';
/**
* @import { EdgeObj, Graph, NodeID } from '../graph.js';
*/
export { dijkstraAll };
/**
* This function finds the shortest path from each node to every other
* reachable node in the graph. It is similar to
* {@link dijkstra}, but instead of returning a single-source
* array, it returns a mapping of of `source -> alg.dijksta(g, source,
* weightFn, edgeFn)`.
*
* @remarks This function takes `O(|V| * (|E| + |V|) * log |V|)` time.
*
* @example
*
* 
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.dijkstraAll(g, function(e) { return g.edge(e); });
*
* // => { A:
* // { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } },
* // B:
* // { A: { distance: Infinity },
* // B: { distance: 0 },
* // C: { distance: Infinity },
* // D: { distance: Infinity },
* // E: { distance: 6, predecessor: 'B' },
* // F: { distance: Infinity } },
* // C: { ... },
* // D: { ... },
* // E: { ... },
* // F: { ... } }
* ```
*
* @param {Graph} g - Input graph.
* @param {(e: EdgeObj) => number} [weightFunc] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFunc] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal. By default this function uses the {@link Graph.outEdges}.
* @returns {Record>} a mapping of of
* `source -> alg.dijksta(g, source, weightFn, edgeFn)`.
* @throws {Error} If any of the traversed edges has a negative edge weight.
*/
function dijkstraAll(g, weightFunc, edgeFunc) {
return _.transform(
g.nodes(),
/**
* @param {Record>} acc
* @param {NodeID} v
*/
function (acc, v) {
acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
},
{},
);
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/dijkstra-all.test.js 0000664 0000000 0000000 00000001515 15114061606 0023571 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { dijkstraAll } from './dijkstra-all.js';
import { allShortestPathsTests } from '../../../test/graphlib/alg/all-shortest-paths.js';
describe('alg.dijkstraAll', function () {
allShortestPathsTests(dijkstraAll);
it('throws an Error if it encounters a negative edge weight', function () {
var g = new Graph();
g.setEdge('a', 'b', 1);
g.setEdge('a', 'c', -2);
g.setEdge('b', 'd', 3);
g.setEdge('c', 'd', 3);
expect(function () {
dijkstraAll(g, weight(g));
}).to.throw();
});
});
/**
* @param {Graph} g - The graph to generate a weight function for.
* @returns {Parameters[1]} A weight function for the graph `g`.
*/
function weight(g) {
return function (e) {
return g.edge(e);
};
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/dijkstra.js 0000664 0000000 0000000 00000010330 15114061606 0022040 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { PriorityQueue } from '../data/priority-queue.js';
/**
* @import { EdgeObj, Graph, NodeID } from '../graph.js';
*/
export { dijkstra };
var DEFAULT_WEIGHT_FUNC = _.constant(1);
/**
* @typedef {Object} PathEntry
* @property {number} distance The sum of the weights from `source` to `v`
* along the shortest path or `Number.POSITIVE_INFINITY` if there is no path
* from `source`.
* @property {NodeID} [predecessor] Can be used to walk the individual
* elements of the path from `source` to `v` in reverse order.
*/
/**
* This function is an implementation of [Dijkstra's algorithm][] which finds
* the shortest path from `source` to all other nodes in `g`. This
* function returns
*
* [Dijkstra's algorithm]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
*
* @example
*
* 
*
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.dijkstra(g, "A", weight);
* // => { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } }
* ```
*
* @remarks It takes `O((|E| + |V|) * log |V|)` time.
*
* @param {Graph} g - Input graph.
* @param {NodeID | number} source - The source node id. Converted to a string.
* @param {(e: EdgeObj) => number} [weightFn] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFn] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal.
* By default this function uses the {@link Graph.outEdges} function on the
* supplied graph.
* @returns {Record} a map of `v -> { distance, predecessor }`.
* @throws {Error} If any of the traversed edges has a negative edge weight.
*/
function dijkstra(g, source, weightFn, edgeFn) {
return runDijkstra(
g,
String(source),
weightFn || DEFAULT_WEIGHT_FUNC,
edgeFn ||
function (v) {
return g.outEdges(v);
},
);
}
/**
* @param {Graph} g - Input graph.
* @param {NodeID} source - The source node id.
* @param {(e: EdgeObj) => number} weightFn - Required weight function.
* @param {(v: NodeID) => EdgeObj[]} edgeFn - Required edge function.
*/
function runDijkstra(g, source, weightFn, edgeFn) {
/** @type {Record} */
var results = {};
var pq = new PriorityQueue();
/** @type {NodeID} */
var v;
/** @type {PathEntry} */
var vEntry;
/** @param {EdgeObj} edge */
var updateNeighbors = function (edge) {
var w = edge.v !== v ? edge.v : edge.w;
var wEntry = results[w];
var weight = weightFn(edge);
var distance = vEntry.distance + weight;
if (weight < 0) {
throw new Error(
'dijkstra does not allow negative edge weights. ' +
'Bad edge: ' +
edge +
' Weight: ' +
weight,
);
}
if (distance < wEntry.distance) {
wEntry.distance = distance;
wEntry.predecessor = v;
pq.decrease(w, distance);
}
};
g.nodes().forEach(function (v) {
var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
results[v] = { distance: distance };
pq.add(v, distance);
});
while (pq.size() > 0) {
v = pq.removeMin();
vEntry = results[v];
if (vEntry.distance === Number.POSITIVE_INFINITY) {
break;
}
edgeFn(v).forEach(updateNeighbors);
}
return results;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/dijkstra.test.js 0000664 0000000 0000000 00000005326 15114061606 0023027 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { dijkstra } from './dijkstra.js';
describe('alg.dijkstra', function () {
it('assigns distance 0 for the source node', function () {
var g = new Graph();
g.setNode('source');
expect(dijkstra(g, 'source')).to.eql({ source: { distance: 0 } });
});
it('returns Number.POSITIVE_INFINITY for unconnected nodes', function () {
var g = new Graph();
g.setNode('a');
g.setNode('b');
expect(dijkstra(g, 'a')).to.eql({
a: { distance: 0 },
b: { distance: Number.POSITIVE_INFINITY },
});
});
it('returns the distance and path from the source node to other nodes', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c']);
g.setEdge('b', 'd');
expect(dijkstra(g, 'a')).to.eql({
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: 2, predecessor: 'b' },
d: { distance: 2, predecessor: 'b' },
});
});
it('works for undirected graphs', function () {
var g = new Graph({ directed: false });
g.setPath(['a', 'b', 'c']);
g.setEdge('b', 'd');
expect(dijkstra(g, 'a')).to.eql({
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: 2, predecessor: 'b' },
d: { distance: 2, predecessor: 'b' },
});
});
it('uses an optionally supplied weight function', function () {
var g = new Graph();
g.setEdge('a', 'b', 1);
g.setEdge('a', 'c', 2);
g.setEdge('b', 'd', 3);
g.setEdge('c', 'd', 3);
expect(dijkstra(g, 'a', weightFn(g))).to.eql({
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: 2, predecessor: 'a' },
d: { distance: 4, predecessor: 'b' },
});
});
it('uses an optionally supplied edge function', function () {
var g = new Graph();
g.setPath(['a', 'c', 'd']);
g.setEdge('b', 'c');
expect(
dijkstra(g, 'd', undefined, function (e) {
return g.inEdges(e);
}),
).to.eql({
a: { distance: 2, predecessor: 'c' },
b: { distance: 2, predecessor: 'c' },
c: { distance: 1, predecessor: 'd' },
d: { distance: 0 },
});
});
it('throws an Error if it encounters a negative edge weight', function () {
var g = new Graph();
g.setEdge('a', 'b', 1);
g.setEdge('a', 'c', -2);
g.setEdge('b', 'd', 3);
g.setEdge('c', 'd', 3);
expect(function () {
dijkstra(g, 'a', weightFn(g));
}).to.throw();
});
});
/**
* @param {Graph} g - The graph to generate a weight function for.
* @returns {Parameters[2]} A weight function for the graph `g`.
*/
function weightFn(g) {
return function (e) {
return g.edge(e);
};
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/find-cycles.js 0000664 0000000 0000000 00000002501 15114061606 0022426 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { tarjan } from './tarjan.js';
/**
* @import { Graph, NodeID } from '../graph.js';
*/
export { findCycles };
/**
* Given a Graph, `g`, this function returns all nodes that
* are part of a cycle. As there may be more than one cycle in a graph this
* function return an array of these cycles, where each cycle is itself
* represented by an array of ids for each node involved in that cycle.
*
* @remarks
*
* {@link isAcyclic} is more efficient if you only need to
* determine whether a graph has a cycle or not.
*
* @example
*
* ```js
* var g = new graphlib.Graph();
* g.setNode(1);
* g.setNode(2);
* g.setNode(3);
* g.setEdge(1, 2);
* g.setEdge(2, 3);
*
* graphlib.alg.findCycles(g);
* // => []
*
* g.setEdge(3, 1);
* graphlib.alg.findCycles(g);
* // => [ [ '3', '2', '1' ] ]
*
* g.setNode(4);
* g.setNode(5);
* g.setEdge(4, 5);
* g.setEdge(5, 4);
* graphlib.alg.findCycles(g);
* // => [ [ '3', '2', '1' ], [ '5', '4' ] ]
* ```
*
* @param {Graph} g - The graph to analyze.
* @returns {NodeID[][]} An array of cycles. Each cycle is itself an array
* that contains the ids of all nodes in the cycle.
*/
function findCycles(g) {
return _.filter(tarjan(g), function (cmpt) {
return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]));
});
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/find-cycles.test.js 0000664 0000000 0000000 00000003155 15114061606 0023412 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { findCycles } from './find-cycles.js';
/**
* @import { NodeID } from '../graph.js';
*/
describe('alg.findCycles', function () {
it('returns an empty array for an empty graph', function () {
expect(findCycles(new Graph())).to.eql([]);
});
it('returns an empty array if the graph has no cycles', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c']);
expect(findCycles(g)).to.eql([]);
});
it('returns a single entry for a cycle of 1 node', function () {
var g = new Graph();
g.setPath(['a', 'a']);
expect(sort(findCycles(g))).to.eql([['a']]);
});
it('returns a single entry for a cycle of 2 nodes', function () {
var g = new Graph();
g.setPath(['a', 'b', 'a']);
expect(sort(findCycles(g))).to.eql([['a', 'b']]);
});
it('returns a single entry for a triangle', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c', 'a']);
expect(sort(findCycles(g))).to.eql([['a', 'b', 'c']]);
});
it('returns multiple entries for multiple cycles', function () {
var g = new Graph();
g.setPath(['a', 'b', 'a']);
g.setPath(['c', 'd', 'e', 'c']);
g.setPath(['f', 'g', 'g']);
g.setNode('h');
expect(sort(findCycles(g))).to.eql([['a', 'b'], ['c', 'd', 'e'], ['g']]);
});
});
/**
* A helper that sorts components and their contents
*
* @param {NodeID[][]} cmpts - The components to sort.
* @returns {NodeID[][]} The sorted components.
*/
function sort(cmpts) {
return cmpts.map((cmpt) => cmpt.sort()).sort((a, b) => a[0].localeCompare(b[0]));
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/floyd-warshall.js 0000664 0000000 0000000 00000007020 15114061606 0023157 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
/**
* @import { Graph, EdgeObj, NodeID } from '../graph.js';
* @import { PathEntry } from './dijkstra.js';
*/
export { floydWarshall };
var DEFAULT_WEIGHT_FUNC = _.constant(1);
/**
* This function is an implementation of the [Floyd-Warshall algorithm][],
* which finds the shortest path from each node to every other reachable node
* in the graph. It is similar to {@link dijkstraAll}, but
* it handles negative edge weights and is more efficient for some types of
* graphs.
*
* [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm
*
* @remarks This algorithm takes `O(|V|^3)` time.
*
* @example
*
* 
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.floydWarshall(g, function(e) { return g.edge(e); });
*
* // => { A:
* // { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } },
* // B:
* // { A: { distance: Infinity },
* // B: { distance: 0 },
* // C: { distance: Infinity },
* // D: { distance: Infinity },
* // E: { distance: 6, predecessor: 'B' },
* // F: { distance: Infinity } },
* // C: { ... },
* // D: { ... },
* // E: { ... },
* // F: { ... } }
* ```
*
* @param {Graph} g - The graph to analyze.
* @param {(e: EdgeObj) => number} [weightFn] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFn] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal.
* By default this function uses the {@link Graph.outEdges} function on the
* supplied graph.
* @returns {Record>} a map of
* `source -> { target -> { distance, predecessor }`.
*/
function floydWarshall(g, weightFn, edgeFn) {
return runFloydWarshall(
g,
weightFn || DEFAULT_WEIGHT_FUNC,
edgeFn ||
function (v) {
return g.outEdges(v);
},
);
}
/**
* @param {Graph} g - Input graph.
* @param {(e: EdgeObj) => number} weightFn - Required weight function.
* @param {(v: NodeID) => EdgeObj[]} edgeFn - Required edge function.
*/
function runFloydWarshall(g, weightFn, edgeFn) {
/** @type {Record>} */
var results = {};
var nodes = g.nodes();
nodes.forEach(function (v) {
results[v] = {};
results[v][v] = { distance: 0 };
nodes.forEach(function (w) {
if (v !== w) {
results[v][w] = { distance: Number.POSITIVE_INFINITY };
}
});
edgeFn(v).forEach(function (edge) {
var w = edge.v === v ? edge.w : edge.v;
var d = weightFn(edge);
results[v][w] = { distance: d, predecessor: v };
});
});
nodes.forEach(function (k) {
var rowK = results[k];
nodes.forEach(function (i) {
var rowI = results[i];
nodes.forEach(function (j) {
var ik = rowI[k];
var kj = rowK[j];
var ij = rowI[j];
var altDistance = ik.distance + kj.distance;
if (altDistance < ij.distance) {
ij.distance = altDistance;
ij.predecessor = kj.predecessor;
}
});
});
});
return results;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/floyd-warshall.test.js 0000664 0000000 0000000 00000003666 15114061606 0024151 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { floydWarshall } from './floyd-warshall.js';
import { allShortestPathsTests } from '../../../test/graphlib/alg/all-shortest-paths.js';
describe('alg.floydWarshall', function () {
allShortestPathsTests(floydWarshall);
it('handles negative weights', function () {
var g = new Graph();
g.setEdge('a', 'b', 1);
g.setEdge('a', 'c', -2);
g.setEdge('b', 'd', 3);
g.setEdge('c', 'd', 3);
expect(floydWarshall(g, weightFn(g))).to.eql({
a: {
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: -2, predecessor: 'a' },
d: { distance: 1, predecessor: 'c' },
},
b: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: 0 },
c: { distance: Number.POSITIVE_INFINITY },
d: { distance: 3, predecessor: 'b' },
},
c: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: Number.POSITIVE_INFINITY },
c: { distance: 0 },
d: { distance: 3, predecessor: 'c' },
},
d: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: Number.POSITIVE_INFINITY },
c: { distance: Number.POSITIVE_INFINITY },
d: { distance: 0 },
},
});
});
it('does include negative weight self edges', function () {
var g = new Graph();
g.setEdge('a', 'a', -1);
// In the case of a negative cycle the distance is not well-defined beyond
// having a negative value along the diagonal.
expect(floydWarshall(g, weightFn(g))).to.eql({
a: {
a: { distance: -2, predecessor: 'a' },
},
});
});
});
/**
* @param {Graph} g - The graph to generate a weight function for.
* @returns {Parameters[1]} A weight function for the graph `g`.
*/
function weightFn(g) {
return function (edge) {
return g.edge(edge);
};
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/index.js 0000664 0000000 0000000 00000001170 15114061606 0021336 0 ustar 00root root 0000000 0000000 import { components } from './components.js';
import { dijkstra } from './dijkstra.js';
import { dijkstraAll } from './dijkstra-all.js';
import { findCycles } from './find-cycles.js';
import { floydWarshall } from './floyd-warshall.js';
import { isAcyclic } from './is-acyclic.js';
import { postorder } from './postorder.js';
import { preorder } from './preorder.js';
import { prim } from './prim.js';
import { tarjan } from './tarjan.js';
import { topsort } from './topsort.js';
export {
components,
dijkstra,
dijkstraAll,
findCycles,
floydWarshall,
isAcyclic,
postorder,
preorder,
prim,
tarjan,
topsort,
};
tbo47-dagre-es-4b95ad0/src/graphlib/alg/is-acyclic.js 0000664 0000000 0000000 00000001722 15114061606 0022252 0 ustar 00root root 0000000 0000000 import { topsort, CycleException } from './topsort.js';
/**
* @import { Graph } from '../graph.js';
*/
export { isAcyclic };
/**
* Given a Graph, `g`, this function returns `true` if the
* graph has no cycles and returns `false` if it does.
*
* @remarks
* This algorithm returns
* as soon as it detects the first cycle. You can use
* {@link ../findCycles} to get the actual list of cycles in the
* graph.
*
* @example
*
* ```js
* var g = new graphlib.Graph();
* g.setNode(1);
* g.setNode(2);
* g.setNode(3);
* g.setEdge(1, 2);
* g.setEdge(2, 3);
*
* graphlib.alg.isAcyclic(g);
* // => true
*
* g.setEdge(3, 1);
* graphlib.alg.isAcyclic(g);
* // => false
* ```
*
* @param {Graph} g - The graph to analyze.
* @returns {boolean} `true` if the graph is acyclic, `false` otherwise.
*/
function isAcyclic(g) {
try {
topsort(g);
} catch (e) {
if (e instanceof CycleException) {
return false;
}
throw e;
}
return true;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/is-acyclic.test.js 0000664 0000000 0000000 00000001464 15114061606 0023233 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { isAcyclic } from './is-acyclic.js';
describe('alg.isAcyclic', function () {
it('returns true if the graph has no cycles', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c']);
expect(isAcyclic(g)).to.be.true;
});
it('returns false if the graph has at least one cycle', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c', 'a']);
expect(isAcyclic(g)).to.be.false;
});
it('returns false if the graph has a cycle of 1 node', function () {
var g = new Graph();
g.setPath(['a', 'a']);
expect(isAcyclic(g)).to.be.false;
});
it('rethrows non-CycleException errors', function () {
expect(function () {
isAcyclic(undefined);
}).to.throw();
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/alg/postorder.js 0000664 0000000 0000000 00000001576 15114061606 0022262 0 ustar 00root root 0000000 0000000 import { dfs } from './dfs.js';
export { postorder };
/**
* This function performs a [postorder traversal][] of the graph `g` starting
* at the nodes `vs`. For each node visited, `v`, the function `callback(v)`
* is called.
*
* [postorder traversal]: https://en.wikipedia.org/wiki/Tree_traversal#Depth-first
*
* @example
*
* 
*
* ```js
* graphlib.alg.postorder(g, "A");
* // => One of:
* // [ "B", "D", "E", C", "A" ]
* // [ "B", "E", "D", C", "A" ]
* // [ "D", "E", "C", B", "A" ]
* // [ "E", "D", "C", B", "A" ]
* ```
*
* @param {Parameters[0]} g - The graph to traverse.
* @param {Parameters[1]} vs - Nodes to start the traversal from.
* @returns {ReturnType} The nodes in the order they were visited.
*/
function postorder(g, vs) {
return dfs(g, vs, 'post');
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/postorder.test.js 0000664 0000000 0000000 00000004100 15114061606 0023222 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { postorder } from './postorder.js';
describe('alg.postorder', function () {
it('returns the root for a singleton graph', function () {
var g = new Graph();
g.setNode('a');
expect(postorder(g, 'a')).to.eql(['a']);
});
it('visits each node in the graph once', function () {
var g = new Graph();
g.setPath(['a', 'b', 'd', 'e']);
g.setPath(['a', 'c', 'd', 'e']);
var nodes = postorder(g, 'a');
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
});
it('works for a tree', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setPath(['a', 'c', 'd']);
g.setEdge('c', 'e');
var nodes = postorder(g, 'a');
expect(nodes.indexOf('b')).to.be.lt(nodes.indexOf('a'));
expect(nodes.indexOf('c')).to.be.lt(nodes.indexOf('a'));
expect(nodes.indexOf('d')).to.be.lt(nodes.indexOf('c'));
expect(nodes.indexOf('e')).to.be.lt(nodes.indexOf('c'));
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
});
it('works for an array of roots', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('c', 'd');
g.setNode('e');
g.setNode('f');
var nodes = postorder(g, ['a', 'b', 'c', 'e']);
expect(nodes.indexOf('b')).to.be.lt(nodes.indexOf('a'));
expect(nodes.indexOf('d')).to.be.lt(nodes.indexOf('c'));
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
});
it('works for multiple connected roots', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('a', 'c');
g.setEdge('d', 'c');
var nodes = postorder(g, ['a', 'd']);
expect(nodes.indexOf('b')).to.be.lt(nodes.indexOf('a'));
expect(nodes.indexOf('c')).to.be.lt(nodes.indexOf('a'));
expect(nodes.indexOf('c')).to.be.lt(nodes.indexOf('d'));
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd']);
});
it('fails if root is not in the graph', function () {
var g = new Graph();
g.setNode('a');
expect(function () {
postorder(g, 'b');
}).to.throw();
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/alg/preorder.js 0000664 0000000 0000000 00000002364 15114061606 0022057 0 ustar 00root root 0000000 0000000 import { dfs } from './dfs.js';
export { preorder };
/**
* This function performs a [preorder traversal][] of the graph `g` starting
* at the nodes `vs`. For each node visited, `v`, the function `callback(v)`
* is called.
*
* [preorder traversal]: https://en.wikipedia.org/wiki/Tree_traversal#Depth-first
*
* @example
*
* 
*
*
* ```js
* graphlib.alg.preorder(g, "A");
* // => One of:
* // [ "A", "B", "C", "D", "E" ]
* // [ "A", "B", "C", "E", "D" ]
* // [ "A", "C", "D", "E", "B" ]
* // [ "A", "C", "E", "D", "B" ]
* ```
*
* @param {Parameters[0]} g - The graph to traverse.
* @param {Parameters[1]} vs - Nodes to start the traversal from.
* @returns {ReturnType} The nodes in the order they were visited.
*/
function preorder(g, vs) {
return dfs(g, vs, 'pre');
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/preorder.test.js 0000664 0000000 0000000 00000003166 15114061606 0023036 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { preorder } from './preorder.js';
describe('alg.preorder', function () {
it('returns the root for a singleton graph', function () {
var g = new Graph();
g.setNode('a');
expect(preorder(g, 'a')).to.eql(['a']);
});
it('visits each node in the graph once', function () {
var g = new Graph();
g.setPath(['a', 'b', 'd', 'e']);
g.setPath(['a', 'c', 'd', 'e']);
var nodes = preorder(g, 'a');
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
});
it('works for a tree', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setPath(['a', 'c', 'd']);
g.setEdge('c', 'e');
var nodes = preorder(g, 'a');
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
expect(nodes.indexOf('b')).to.be.gt(nodes.indexOf('a'));
expect(nodes.indexOf('c')).to.be.gt(nodes.indexOf('a'));
expect(nodes.indexOf('d')).to.be.gt(nodes.indexOf('c'));
expect(nodes.indexOf('e')).to.be.gt(nodes.indexOf('c'));
});
it('works for an array of roots', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('c', 'd');
g.setNode('e');
g.setNode('f');
var nodes = preorder(g, ['a', 'c', 'e']);
expect(nodes.sort()).to.eql(['a', 'b', 'c', 'd', 'e']);
expect(nodes.indexOf('b')).to.be.gt(nodes.indexOf('a'));
expect(nodes.indexOf('d')).to.be.gt(nodes.indexOf('c'));
});
it('fails if root is not in the graph', function () {
var g = new Graph();
g.setNode('a');
expect(function () {
preorder(g, 'b');
}).to.throw();
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/alg/prim.js 0000664 0000000 0000000 00000006023 15114061606 0021200 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { PriorityQueue } from '../data/priority-queue.js';
import { Graph } from '../graph.js';
/**
* @import { EdgeObj, NodeID } from '../graph.js';
*/
export { prim };
/**
* [Prim's algorithm][] takes a connected undirected graph and generates a
* [minimum spanning tree][]. This function returns the minimum spanning
* tree as an undirected graph. This algorithm is derived from the description
* in "Introduction to Algorithms", Third Edition, Cormen, et al., Pg 634.
*
* [Prim's algorithm]: https://en.wikipedia.org/wiki/Prim's_algorithm
* [minimum spanning tree]: https://en.wikipedia.org/wiki/Minimum_spanning_tree
*
* @remarks This function takes `O(|E| log |V|)` time.
*
* @example
*
* 
*
*
* ```js
* function weight(e) { return g(e); }
* graphlib.alg.prim(g, weight);
* ```
*
* Returns a tree (represented as a Graph) of the following form:
*
* 
*
*
* @param {Graph} g - The input undirected connected graph.
* @param {(e: EdgeObj) => number} weightFunc - Function that returns
* the weight for edge `e`.
* @returns {Graph} The minimum spanning tree
* as an undirected graph.
* @throws {Error} If the input graph is not connected.
*/
function prim(g, weightFunc) {
var result = new Graph();
/** @type {Record} */
var parents = {};
var pq = new PriorityQueue();
/** @type {NodeID} */
var v;
/**
* @param {EdgeObj} edge - Edge to examine for possible inclusion in the
* minimum spanning tree.
*/
function updateNeighbors(edge) {
var w = edge.v === v ? edge.w : edge.v;
var pri = pq.priority(w);
if (pri !== undefined) {
var edgeWeight = weightFunc(edge);
if (edgeWeight < pri) {
parents[w] = v;
pq.decrease(w, edgeWeight);
}
}
}
if (g.nodeCount() === 0) {
return result;
}
_.each(g.nodes(), function (v) {
pq.add(v, Number.POSITIVE_INFINITY);
result.setNode(v);
});
// Start from an arbitrary node
pq.decrease(g.nodes()[0], 0);
var init = false;
while (pq.size() > 0) {
v = pq.removeMin();
if (Object.prototype.hasOwnProperty.call(parents, v)) {
result.setEdge(v, parents[v]);
} else if (init) {
throw new Error('Input graph is not connected: ' + g);
} else {
init = true;
}
g.nodeEdges(v).forEach(updateNeighbors);
}
return result;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/prim.test.js 0000664 0000000 0000000 00000003500 15114061606 0022153 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { prim } from './prim.js';
describe('alg.prim', function () {
it('returns an empty graph for an empty input', function () {
var source = new Graph();
var g = prim(source, weightFn(source));
expect(g.nodeCount()).to.equal(0);
expect(g.edgeCount()).to.equal(0);
});
it('returns a single node graph for a graph with a single node', function () {
var source = new Graph();
source.setNode('a');
var g = prim(source, weightFn(source));
expect(g.nodes()).to.eql(['a']);
expect(g.edgeCount()).to.equal(0);
});
it('returns a deterministic result given an optimal solution', function () {
var source = new Graph();
source.setEdge('a', 'b', 1);
source.setEdge('b', 'c', 2);
source.setEdge('b', 'd', 3);
// This edge should not be in the min spanning tree
source.setEdge('c', 'd', 20);
// This edge should not be in the min spanning tree
source.setEdge('c', 'e', 60);
source.setEdge('d', 'e', 1);
var g = prim(source, weightFn(source));
expect(g.neighbors('a').sort()).to.eql(['b']);
expect(g.neighbors('b').sort()).to.eql(['a', 'c', 'd']);
expect(g.neighbors('c').sort()).to.eql(['b']);
expect(g.neighbors('d').sort()).to.eql(['b', 'e']);
expect(g.neighbors('e').sort()).to.eql(['d']);
});
it('throws an Error for unconnected graphs', function () {
var source = new Graph();
source.setNode('a');
source.setNode('b');
expect(function () {
prim(source, weightFn(source));
}).to.throw();
});
});
/**
* @param {Graph} g - The graph to generate a weight function for.
* @returns {Parameters[1]} A weight function for the graph `g`.
*/
function weightFn(g) {
return function (edge) {
return g.edge(edge);
};
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/tarjan.js 0000664 0000000 0000000 00000005141 15114061606 0021510 0 ustar 00root root 0000000 0000000 /**
* @import { Graph, NodeID } from '../graph.js';
*/
export { tarjan };
/**
* This function is an implementation of [Tarjan's algorithm][] which finds
* all [strongly connected components][] in the directed graph `g`. Each
* strongly connected component is composed of nodes that can reach all other
* nodes in the component via directed edges. A strongly connected component
* can consist of a single node if that node cannot both reach and be reached
* by any other specific node in the graph. Components of more than one node
* are guaranteed to have at least one cycle.
*
* [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
* [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component
*
* @example
*
* 
*
*
* ```js
* graphlib.alg.tarjan(g);
* // => [ [ 'F', 'G' ],
* // [ 'H', 'D', 'C' ],
* // [ 'E', 'B', 'A' ] ]
* ```
*
* @param {Graph} g - The directed graph to analyze.
* @returns {NodeID[][]} an array of components. Each component is itself an
* array that contains the ids of all nodes in the component.
*/
function tarjan(g) {
var index = 0;
/** @type {NodeID[]} */
var stack = [];
/**
* @type {Record}
*/
var visited = {};
/** @type {NodeID[][]} */
var results = [];
/**
* @param {NodeID} v - Node to recursively visit
*/
function dfs(v) {
var entry = (visited[v] = {
onStack: true,
lowlink: index,
index: index++,
});
stack.push(v);
g.successors(v).forEach(function (w) {
if (!Object.prototype.hasOwnProperty.call(visited, w)) {
dfs(w);
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
} else if (visited[w].onStack) {
entry.lowlink = Math.min(entry.lowlink, visited[w].index);
}
});
if (entry.lowlink === entry.index) {
/** @type {NodeID[]} */
var cmpt = [];
/** @type {NodeID} */
var w;
do {
w = stack.pop();
visited[w].onStack = false;
cmpt.push(w);
} while (v !== w);
results.push(cmpt);
}
}
g.nodes().forEach(function (v) {
if (!Object.prototype.hasOwnProperty.call(visited, v)) {
dfs(v);
}
});
return results;
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/tarjan.test.js 0000664 0000000 0000000 00000002676 15114061606 0022500 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { tarjan } from './tarjan.js';
/**
* @import { NodeID } from '../graph.js';
*/
describe('alg.tarjan', function () {
it('returns an empty array for an empty graph', function () {
expect(tarjan(new Graph())).to.eql([]);
});
it('returns singletons for nodes not in a strongly connected component', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c']);
g.setEdge('d', 'c');
expect(sort(tarjan(g))).to.eql([['a'], ['b'], ['c'], ['d']]);
});
it('returns a single component for a cycle of 1 edge', function () {
var g = new Graph();
g.setPath(['a', 'b', 'a']);
expect(sort(tarjan(g))).to.eql([['a', 'b']]);
});
it('returns a single component for a triangle', function () {
var g = new Graph();
g.setPath(['a', 'b', 'c', 'a']);
expect(sort(tarjan(g))).to.eql([['a', 'b', 'c']]);
});
it('can find multiple components', function () {
var g = new Graph();
g.setPath(['a', 'b', 'a']);
g.setPath(['c', 'd', 'e', 'c']);
g.setNode('f');
expect(sort(tarjan(g))).to.eql([['a', 'b'], ['c', 'd', 'e'], ['f']]);
});
});
/**
* A helper that sorts components and their contents
*
* @param {NodeID[][]} cmpts - The components to sort.
* @returns {NodeID[][]} The sorted components.
*/
function sort(cmpts) {
return cmpts.map((cmpt) => cmpt.sort()).sort((a, b) => a[0].localeCompare(b[0]));
}
tbo47-dagre-es-4b95ad0/src/graphlib/alg/topsort.js 0000664 0000000 0000000 00000003153 15114061606 0021744 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
/**
* @import { Graph, NodeID } from '../graph.js';
*/
export { topsort, CycleException };
topsort.CycleException = CycleException;
/**
* An implementation of [topological sorting](https://en.wikipedia.org/wiki/Topological_sorting).
*
* @remarks Takes `O(|V| + |E|)` time.
*
* @example
*
* 
*
* ```js
* graphlib.alg.topsort(g)
* // [ '1', '2', '3', '4' ] or [ '1', '3', '2', '4' ]
* ```
*
* @param {Graph} g - The graph to sort.
* @returns {NodeID[]} an array of nodes
* such that for each edge `u -> v`, `u` appears before `v` in the array.
* @throws {CycleException} If the graph has a cycle so that it is impossible
* to generate a topological sort.
*/
function topsort(g) {
/** @type {Record} */
var visited = {};
/** @type {Record} */
var stack = {};
/** @type {NodeID[]} */
var results = [];
/**
* @param {NodeID} node - Node to recursively visit.
*/
function visit(node) {
if (Object.prototype.hasOwnProperty.call(stack, node)) {
throw new CycleException();
}
if (!Object.prototype.hasOwnProperty.call(visited, node)) {
stack[node] = true;
visited[node] = true;
_.each(g.predecessors(node), visit);
delete stack[node];
results.push(node);
}
}
_.each(g.sinks(), visit);
if (_.size(visited) !== g.nodeCount()) {
throw new CycleException();
}
return results;
}
/**
* @class
*/
function CycleException() {}
CycleException.prototype = new Error(); // must be an instance of Error to pass testing
tbo47-dagre-es-4b95ad0/src/graphlib/alg/topsort.test.js 0000664 0000000 0000000 00000003052 15114061606 0022720 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../graph.js';
import { topsort } from './topsort.js';
describe('alg.topsort', function () {
it('returns an empty array for an empty graph', function () {
expect(topsort(new Graph())).to.be.empty;
});
it('sorts nodes such that earlier nodes have directed edges to later nodes', function () {
var g = new Graph();
g.setPath(['b', 'c', 'a']);
expect(topsort(g)).to.eql(['b', 'c', 'a']);
});
it('works for a diamond', function () {
var g = new Graph();
g.setPath(['a', 'b', 'd']);
g.setPath(['a', 'c', 'd']);
var result = topsort(g);
expect(result.indexOf('a')).to.equal(0);
expect(result.indexOf('b')).to.be.lt(result.indexOf('d'));
expect(result.indexOf('c')).to.be.lt(result.indexOf('d'));
expect(result.indexOf('d')).to.equal(3);
});
it('throws CycleException if there is a cycle #1', function () {
var g = new Graph();
g.setPath(['b', 'c', 'a', 'b']);
expect(function () {
topsort(g);
}).to.throw(topsort.CycleException);
});
it('throws CycleException if there is a cycle #2', function () {
var g = new Graph();
g.setPath(['b', 'c', 'a', 'b']);
g.setEdge('b', 'd');
expect(function () {
topsort(g);
}).to.throw(topsort.CycleException);
});
it('throws CycleException if there is a cycle #3', function () {
var g = new Graph();
g.setPath(['b', 'c', 'a', 'b']);
g.setNode('d');
expect(function () {
topsort(g);
}).to.throw(topsort.CycleException);
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/data/ 0000775 0000000 0000000 00000000000 15114061606 0020040 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/src/graphlib/data/priority-queue.js 0000664 0000000 0000000 00000011336 15114061606 0023405 0 ustar 00root root 0000000 0000000 export { PriorityQueue };
/**
* A min-priority queue data structure. This algorithm is derived from Cormen,
* et al., "Introduction to Algorithms". The basic idea of a min-priority
* queue is that you can efficiently (in O(1) time) get the smallest key in
* the queue. Adding and removing elements takes O(log n) time. A key can
* have its priority decreased in O(log n) time.
*/
class PriorityQueue {
constructor() {
/**
* @private
* @type {Array<{key: string, priority: number}>}
*/
this._arr = [];
/**
* @private
* @type {Record}
*/
this._keyIndices = {};
}
/**
* @returns {number} the number of elements in the queue.
* @remarks Takes `O(1)` time.
*/
size() {
return this._arr.length;
}
/**
* @returns {string[]} the keys that are in the queue.
* @remarks Takes `O(n)` time.
*/
keys() {
return this._arr.map(function (x) {
return x.key;
});
}
/**
* @param {Object} key - The key to check for presence in the queue.
* @returns {boolean} `true` if **key** is in the queue and `false` if not.
*/
has(key) {
return Object.prototype.hasOwnProperty.call(this._keyIndices, key);
}
/**
* @param {Object} key - The key to get the priority for.
* @returns {number | undefined} the priority for **key**.
* If **key** is not present in the queue then this function returns `undefined`.
* @remarks Takes `O(1)` time.
*/
priority(key) {
var index = this._keyIndices[key];
if (index !== undefined) {
return this._arr[index].priority;
}
}
/**
* @returns {string} the key for the minimum element in this queue.
* @throws {Error} if the queue is empty.
* @remarks Takes `O(1)` time.
*/
min() {
if (this.size() === 0) {
throw new Error('Queue underflow');
}
return this._arr[0].key;
}
/**
* Inserts a new key into the priority queue.
*
* @remarks Takes `O(n)` time.
*
* @param {Object} key the key to add. This will be coerced to a `string`.
* @param {Number} priority the initial priority for the key
* @returns {boolean} `true` if the key was added and `false` if it was already
* present in the queue.
*/
add(key, priority) {
var keyIndices = this._keyIndices;
key = String(key);
if (!Object.prototype.hasOwnProperty.call(keyIndices, key)) {
var arr = this._arr;
var index = arr.length;
keyIndices[key] = index;
arr.push({ key: key, priority: priority });
this._decrease(index);
return true;
}
return false;
}
/**
* Removes and returns the smallest key in the queue.
* @returns {string} the key with the smallest priority
* @remarks Takes `O(log n)` time.
*/
removeMin() {
this._swap(0, this._arr.length - 1);
var min = this._arr.pop();
delete this._keyIndices[min.key];
this._heapify(0);
return min.key;
}
/**
* Decreases the priority for **key** to **priority**.
*
* @param {Object} key the key for which to raise priority
* @param {Number} priority the new priority for the key
* @throws {Error} if the new priority is greater than the previous priority.
*/
decrease(key, priority) {
var index = this._keyIndices[key];
if (priority > this._arr[index].priority) {
throw new Error(
'New priority is greater than current priority. ' +
'Key: ' +
key +
' Old: ' +
this._arr[index].priority +
' New: ' +
priority,
);
}
this._arr[index].priority = priority;
this._decrease(index);
}
/**
* @param {number} i - Lower index.
* @private
*/
_heapify(i) {
var arr = this._arr;
var l = 2 * i;
var r = l + 1;
var largest = i;
if (l < arr.length) {
largest = arr[l].priority < arr[largest].priority ? l : largest;
if (r < arr.length) {
largest = arr[r].priority < arr[largest].priority ? r : largest;
}
if (largest !== i) {
this._swap(i, largest);
this._heapify(largest);
}
}
}
/**
* @param {number} index - Index to decrease.
* @private
*/
_decrease(index) {
var arr = this._arr;
var priority = arr[index].priority;
var parent;
while (index !== 0) {
parent = index >> 1;
if (arr[parent].priority < priority) {
break;
}
this._swap(index, parent);
index = parent;
}
}
/**
* @param {number} i - First index
* @param {number} j - Second index
* @private
*/
_swap(i, j) {
var arr = this._arr;
var keyIndices = this._keyIndices;
var origArrI = arr[i];
var origArrJ = arr[j];
arr[i] = origArrJ;
arr[j] = origArrI;
keyIndices[origArrJ.key] = i;
keyIndices[origArrI.key] = j;
}
}
tbo47-dagre-es-4b95ad0/src/graphlib/data/priority-queue.test.js 0000664 0000000 0000000 00000007132 15114061606 0024362 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { PriorityQueue } from './priority-queue.js';
describe('data.PriorityQueue', function () {
/** @type {PriorityQueue} */
var pq;
beforeEach(function () {
pq = new PriorityQueue();
});
describe('size', function () {
it('returns 0 for an empty queue', function () {
expect(pq.size()).to.equal(0);
});
it('returns the number of elements in the queue', function () {
pq.add('a', 1);
expect(pq.size()).to.equal(1);
pq.add('b', 2);
expect(pq.size()).to.equal(2);
});
});
describe('keys', function () {
it('returns all of the keys in the queue', function () {
pq.add('a', 1);
pq.add(1, 2);
pq.add(false, 3);
pq.add(undefined, 4);
pq.add(null, 5);
expect(pq.keys().sort()).to.eql(['a', '1', 'false', 'undefined', 'null'].sort());
});
});
describe('has', function () {
it('returns true if the key is in the queue', function () {
pq.add('a', 1);
expect(pq.has('a')).to.be.true;
});
it('returns false if the key is not in the queue', function () {
expect(pq.has('a')).to.be.false;
});
});
describe('priority', function () {
it('returns the current priority for the key', function () {
pq.add('a', 1);
pq.add('b', 2);
expect(pq.priority('a')).to.equal(1);
expect(pq.priority('b')).to.equal(2);
});
it('returns undefined if the key is not in the queue', function () {
expect(pq.priority('foo')).to.be.undefined;
});
});
describe('min', function () {
it('throws an error if there is no element in the queue', function () {
expect(function () {
pq.min();
}).to.throw();
});
it('returns the smallest element', function () {
pq.add('b', 2);
pq.add('a', 1);
expect(pq.min()).to.equal('a');
});
it('does not remove the minimum element from the queue', function () {
pq.add('b', 2);
pq.add('a', 1);
pq.min();
expect(pq.size()).to.equal(2);
});
});
describe('add', function () {
it('adds the key to the queue', function () {
pq.add('a', 1);
expect(pq.keys()).to.eql(['a']);
});
it('returns true if the key was added', function () {
expect(pq.add('a', 1)).to.be.true;
});
it('returns false if the key already exists in the queue', function () {
pq.add('a', 1);
expect(pq.add('a', 1)).to.be.false;
});
});
describe('removeMin', function () {
it('removes the minimum element from the queue', function () {
pq.add('b', 2);
pq.add('a', 1);
pq.add('c', 3);
pq.add('e', 5);
pq.add('d', 4);
expect(pq.removeMin()).to.equal('a');
expect(pq.removeMin()).to.equal('b');
expect(pq.removeMin()).to.equal('c');
expect(pq.removeMin()).to.equal('d');
expect(pq.removeMin()).to.equal('e');
});
it('throws an error if there is no element in the queue', function () {
expect(function () {
pq.removeMin();
}).to.throw();
});
});
describe('decrease', function () {
it('decreases the priority of a key', function () {
pq.add('a', 1);
pq.decrease('a', -1);
expect(pq.priority('a')).to.equal(-1);
});
it('raises an error if the key is not in the queue', function () {
expect(function () {
pq.decrease('a', -1);
}).to.throw();
});
it('raises an error if the new priority is greater than current', function () {
pq.add('a', 1);
expect(function () {
pq.decrease('a', 2);
}).to.throw();
});
});
});
tbo47-dagre-es-4b95ad0/src/graphlib/graph.js 0000664 0000000 0000000 00000103317 15114061606 0020573 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
var DEFAULT_EDGE_NAME = '\x00';
var GRAPH_NODE = '\x00';
var EDGE_KEY_DELIM = '\x01';
/**
* @typedef {string} NodeID ID of a node.
*/
/**
* @typedef {`${string}${typeof EDGE_KEY_DELIM}${string}${typeof EDGE_KEY_DELIM}${string}`} EdgeID ID of an edge.
* @internal - All public APIs use {@link EdgeObj} instead to refer to edges.
*/
/**
* @typedef {object} EdgeObj
* @property {NodeID} v the id of the source or tail node of an edge
* @property {NodeID} w the id of the target or head node of an edge
* @property {string | number} [name] Name of the edge. Needed to uniquely identify
* multiple edges between the same pair of nodes in a multigraph.
*/
/**
* @template {unknown} T
* @typedef {T[] | Record} Collection
* Lodash object that can be iterated over with `_.each`.
*
* Beware, objects with `.length` are treated as arrays, see
* https://lodash.com/docs/4.17.15#forEach
*/
// Implementation notes:
//
// * Node id query functions should return string ids for the nodes
// * Edge id query functions should return an "edgeObj", edge object, that is
// composed of enough information to uniquely identify an edge: {v, w, name}.
// * Internally we use an "edgeId", a stringified form of the edgeObj, to
// reference edges. This is because we need a performant way to look these
// edges up and, object properties, which have string keys, are the closest
// we're going to get to a performant hashtable in JavaScript.
// Implementation notes:
//
// * Node id query functions should return string ids for the nodes
// * Edge id query functions should return an "edgeObj", edge object, that is
// composed of enough information to uniquely identify an edge: {v, w, name}.
// * Internally we use an "edgeId", a stringified form of the edgeObj, to
// reference edges. This is because we need a performant way to look these
// edges up and, object properties, which have string keys, are the closest
// we're going to get to a performant hashtable in JavaScript.
/**
* @typedef {object} GraphOptions
* @property {boolean | undefined} [directed] - set to `true` to get a
* directed graph and `false` to get an undirected graph.
* An undirected graph does not treat the order of nodes in an edge as
* significant.
* In other words, `g.edge("a", "b") === g.edge("b", "a")` for
* an undirected graph.
* Default: `true`
* @property {boolean | undefined} [multigraph] - set to `true` to allow a
* graph to have multiple edges between the same pair of nodes.
* Default: `false`.
* @property {boolean | undefined} [compound] - set to `true` to allow a
* graph to have compound nodes - nodes which can be the parent of other
* nodes.
* Default: `false`.
*/
/**
* Graphlib has a single graph type: {@link Graph}. To create a new instance:
*
* ```js
* var g = new Graph();
* ```
*
* By default this will create a directed graph that does not allow multi-edges
* or compound nodes.
* The following options can be used when constructing a new graph:
*
* * {@link GraphOptions#directed}: set to `true` to get a directed graph and `false` to get an
* undirected graph.
* An undirected graph does not treat the order of nodes in an edge as
* significant. In other words,
* `g.edge("a", "b") === g.edge("b", "a")` for an undirected graph.
* Default: `true`.
* * {@link GraphOptions#multigraph}: set to `true` to allow a graph to have multiple edges
* between the same pair of nodes. Default: `false`.
* * {@link GraphOptions#compound}: set to `true` to allow a graph to have compound nodes -
* nodes which can be the parent of other nodes. Default: `false`.
*
* To set the options, pass in an options object to the `Graph` constructor.
* For example, to create a directed compound multigraph:
*
* ```js
* var g = new Graph({ directed: true, compound: true, multigraph: true });
* ```
*
* ### Node and Edge Representation
*
* In graphlib, a node is represented by a user-supplied String id.
* All node related functions use this String id as a way to uniquely identify
* the node. Here is an example of interacting with nodes:
*
* ```js
* var g = new Graph();
* g.setNode("my-id", "my-label");
* g.node("my-id"); // returns "my-label"
* ```
*
* Edges in graphlib are identified by the nodes they connect. For example:
*
* ```js
* var g = new Graph();
* g.setEdge("source", "target", "my-label");
* g.edge("source", "target"); // returns "my-label"
* ```
*
* However, we need a way to uniquely identify an edge in a single object for
* various edge queries (e.g. {@link Graph#outEdges}).
* We use {@link EdgeObj}s for this purpose.
* They consist of the following properties:
*
* * {@link EdgeObj#v}: the id of the source or tail node of an edge
* * {@link EdgeObj#w}: the id of the target or head node of an edge
* * {@link EdgeObj#name} (optional): the name that uniquely identifies a multiedge.
*
* Any edge function that takes an edge id will also work with an {@link EdgeObj}. For example:
*
* ```js
* var g = new Graph();
* g.setEdge("source", "target", "my-label");
* g.edge({ v: "source", w: "target" }); // returns "my-label"
* ```
*
* ### Multigraphs
*
* A [multigraph](https://en.wikipedia.org/wiki/Multigraph) is a graph that can
* have more than one edge between the same pair of nodes.
* By default graphlib graphs are not multigraphs, but a multigraph can be
* constructed by setting the {@link GraphOptions#multigraph} property to true:
*
* ```js
* var g = new Graph({ multigraph: true });
* ```
*
* With multiple edges between two nodes we need some way to uniquely identify
* each edge. We call this the {@link EdgeObj#name} property.
* Here's an example of creating a couple of edges between the same nodes:
*
* ```js
* var g = new Graph({ multigraph: true });
* g.setEdge("a", "b", "edge1-label", "edge1");
* g.setEdge("a", "b", "edge2-label", "edge2");
* g.edge("a", "b", "edge1"); // returns "edge1-label"
* g.edge("a", "b", "edge2"); // returns "edge2-label"
* g.edges(); // returns [{ v: "a", w: "b", name: "edge1" },
* // { v: "a", w: "b", name: "edge2" }]
* ```
*
* A multigraph still allows an edge with no name to be created:
*
* ```js
* var g = new Graph({ multigraph: true });
* g.setEdge("a", "b", "my-label");
* g.edge({ v: "a", w: "b" }); // returns "my-label"
* ```
*
* ### Compound Graphs
*
* A compound graph is one where a node can be the parent of other nodes.
* The child nodes form a "subgraph".
* Here's an example of constructing and interacting with a compound graph:
*
* ```js
* var g = new Graph({ compound: true });
* g.setParent("a", "parent");
* g.setParent("b", "parent");
* g.parent("a"); // returns "parent"
* g.parent("b"); // returns "parent"
* g.parent("parent"); // returns undefined
* ```
*
* ### Default Labels
*
* When a node or edge is created without a label, a default label can be assigned.
* See {@link setDefaultNodeLabel} and {@link setDefaultEdgeLabel}.
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* Even though this is a "label", this could be any type that the user requires
* (and may need to be an object for some layout/ranking algorithms in dagre).
* @template [EdgeLabel=any] - Label of an edge.
* Even though this is a "label", this could be any type that the user requires,
* (and may need to be a object for ranking in dagre).
*/
export class Graph {
/**
* @param {GraphOptions} [opts] - Graph options.
*/
constructor(opts = {}) {
/**
* @type {boolean}
* @private
*/
this._isDirected = Object.prototype.hasOwnProperty.call(opts, 'directed')
? opts.directed
: true;
/**
* @type {boolean}
* @private
*/
this._isMultigraph = Object.prototype.hasOwnProperty.call(opts, 'multigraph')
? opts.multigraph
: false;
/**
* @type {boolean}
* @private
*/
this._isCompound = Object.prototype.hasOwnProperty.call(opts, 'compound')
? opts.compound
: false;
/**
* @type {GraphLabel | undefined}
* Label for the graph itself
*/
this._label = undefined;
/**
* Default label to be set when creating a new node.
*
* @private
* @type {(v: NodeID | number) => NodeLabel}
*/
this._defaultNodeLabelFn = _.constant(undefined);
/**
* Default label to be set when creating a new edge
*
* @private
* @type {(v: NodeID, w: NodeID, name: string | undefined) => EdgeLabel}
*/
this._defaultEdgeLabelFn = _.constant(undefined);
/**
* @type {Record}
* @private
*
* v -> label
*/
this._nodes = {};
if (this._isCompound) {
/**
* @type {Record}
* @private
* v -> parent
*/
this._parent = {};
/**
* @type {Record>}
* @private
* v -> children
*/
this._children = {};
this._children[GRAPH_NODE] = {};
}
/**
* @type {Record>}
* @private
* v -> edgeObj
*/
this._in = {};
/**
* @type {Record>}
* @private
* u -> v -> Number
*/
this._preds = {};
/**
* @type {Record>}
* @private
* v -> edgeObj
*/
this._out = {};
/**
* @type {Record>}
* @private
* v -> w -> Number
*/
this._sucs = {};
/**
* @type {Record}
* @private
* e -> edgeObj
*/
this._edgeObjs = {};
/**
* @type {Record}
* @private
* e -> label
*/
this._edgeLabels = {};
}
/* === Graph functions ========= */
/**
*
* @returns {boolean} `true` if the graph is [directed](https://en.wikipedia.org/wiki/Directed_graph).
* A directed graph treats the order of nodes in an edge as significant whereas an
* [undirected](https://en.wikipedia.org/wiki/Graph_(mathematics)#Undirected_graph)
* graph does not.
* This example demonstrates the difference:
*
* @example
*
* ```js
* var directed = new Graph({ directed: true });
* directed.setEdge("a", "b", "my-label");
* directed.edge("a", "b"); // returns "my-label"
* directed.edge("b", "a"); // returns undefined
*
* var undirected = new Graph({ directed: false });
* undirected.setEdge("a", "b", "my-label");
* undirected.edge("a", "b"); // returns "my-label"
* undirected.edge("b", "a"); // returns "my-label"
* ```
*/
isDirected() {
return this._isDirected;
}
/**
* @returns {boolean} `true` if the graph is a multigraph.
*/
isMultigraph() {
return this._isMultigraph;
}
/**
* @returns {boolean} `true` if the graph is compound.
*/
isCompound() {
return this._isCompound;
}
/**
* Sets the label for the graph to `label`.
*
* @param {GraphLabel} label - Label for the graph.
* @returns {this}
*/
setGraph(label) {
this._label = label;
return this;
}
/**
* @returns {GraphLabel | undefined} the currently assigned label for the graph.
* If no label has been assigned, returns `undefined`.
*
* @example
*
* ```js
* var g = new Graph();
* g.graph(); // returns undefined
* g.setGraph("graph-label");
* g.graph(); // returns "graph-label"
* ```
*/
graph() {
return this._label;
}
/* === Node functions ========== */
/**
* Sets a new default value that is assigned to nodes that are created without
* a label.
*
* @param {typeof this._defaultNodeLabelFn | NodeLabel} newDefault - If a function,
* it is called with the id of the node being created.
* Otherwise, it is assigned as the label directly.
* @returns {this}
*/
setDefaultNodeLabel(newDefault) {
if (!_.isFunction(newDefault)) {
newDefault = _.constant(newDefault);
}
this._defaultNodeLabelFn = newDefault;
return this;
}
/**
* @returns {number} the number of nodes in the graph.
*/
nodeCount() {
return this._nodeCount;
}
/**
* @returns {NodeID[]} the ids of the nodes in the graph.
*
* @remarks
* Use {@link node()} to get the label for each node.
* Takes `O(|V|)` time.
*/
nodes() {
return _.keys(this._nodes);
}
/**
* @returns {NodeID[]} those nodes in the graph that have no in-edges.
* @remarks Takes `O(|V|)` time.
*/
sources() {
var self = this;
return _.filter(this.nodes(), function (v) {
return _.isEmpty(self._in[v]);
});
}
/**
* @returns {NodeID[]} those nodes in the graph that have no out-edges.
* @remarks Takes `O(|V|)` time.
*/
sinks() {
var self = this;
return _.filter(this.nodes(), function (v) {
return _.isEmpty(self._out[v]);
});
}
/**
* Invokes setNode method for each node in `vs` list.
*
* @param {Collection} vs - List of node IDs to create/set.
* @param {NodeLabel} [value] - If set, update all nodes with this value.
* @returns {this}
* @remarks Complexity: O(|names|).
*/
setNodes(vs, value) {
var args = arguments;
var self = this;
_.each(vs, function (v) {
if (args.length > 1) {
self.setNode(v, value);
} else {
self.setNode(v);
}
});
return this;
}
/**
* Creates or updates the value for the node `v` in the graph.
*
* @param {NodeID | number} v - ID of the node to create/set.
* @param {NodeLabel} [value] - If supplied, it is set as the value for the node.
* If not supplied and the node was created by this call then
* {@link setDefaultNodeLabel} will be used to set the node's value.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
setNode(v, value) {
if (Object.prototype.hasOwnProperty.call(this._nodes, v)) {
if (arguments.length > 1) {
this._nodes[v] = value;
}
return this;
}
this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
if (this._isCompound) {
this._parent[v] = GRAPH_NODE;
this._children[v] = {};
this._children[GRAPH_NODE][v] = true;
}
this._in[v] = {};
this._preds[v] = {};
this._out[v] = {};
this._sucs[v] = {};
++this._nodeCount;
return this;
}
/**
* Gets the label of node with specified name.
*
* @param {NodeID | number} v - Node ID.
* @returns {NodeLabel | undefined} the label assigned to the node with the id `v`
* if it is in the graph.
* Otherwise returns `undefined`.
* @remarks Takes `O(1)` time.
*/
node(v) {
return this._nodes[v];
}
/**
* Detects whether graph has a node with specified name or not.
*
* @param {NodeID | number} v - Node ID.
* @returns {boolean} Returns `true` the graph has a node with the id.
* @remarks Takes `O(1)` time.
*/
hasNode(v) {
return Object.prototype.hasOwnProperty.call(this._nodes, v);
}
/**
* Remove the node with the id `v` in the graph or do nothing if the node is
* not in the graph.
*
* If the node was removed this function also removes any incident edges.
*
* @param {NodeID | number} v - Node ID to remove.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(|E|)` time.
*/
removeNode(v) {
if (Object.prototype.hasOwnProperty.call(this._nodes, v)) {
var removeEdge = (e) => this.removeEdge(this._edgeObjs[e]);
delete this._nodes[v];
if (this._isCompound) {
this._removeFromParentsChildList(v);
delete this._parent[v];
_.each(this.children(v), (child) => {
this.setParent(child);
});
delete this._children[v];
}
_.each(_.keys(this._in[v]), removeEdge);
delete this._in[v];
delete this._preds[v];
_.each(_.keys(this._out[v]), removeEdge);
delete this._out[v];
delete this._sucs[v];
--this._nodeCount;
}
return this;
}
/**
* Sets the parent for `v` to `parent` if it is defined or removes the parent
* for `v` if `parent` is undefined.
*
* @param {NodeID | number} v - Node ID to set the parent for.
* @param {NodeID | number} [parent] - Parent node ID. If not defined, removes the parent.
* @returns {this} the graph, allowing this to be chained with other functions.
* @throws if the graph is not compound.
* @throws if setting the parent would create a cycle.
* @remarks Takes `O(1)` time.
*/
setParent(v, parent) {
if (!this._isCompound) {
throw new Error('Cannot set parent in a non-compound graph');
}
if (_.isUndefined(parent)) {
parent = GRAPH_NODE;
} else {
// Coerce parent to string
parent += '';
for (var ancestor = parent; !_.isUndefined(ancestor); ancestor = this.parent(ancestor)) {
if (ancestor === v) {
throw new Error('Setting ' + parent + ' as parent of ' + v + ' would create a cycle');
}
}
this.setNode(parent);
}
this.setNode(v);
this._removeFromParentsChildList(v);
// @ts-expect-error -- We coerced parent to a string above
this._parent[v] = parent;
this._children[parent][v] = true;
return this;
}
/**
* @private
* @param {NodeID | number} v - Node ID.
*/
_removeFromParentsChildList(v) {
delete this._children[this._parent[v]][v];
}
/**
* Get parent node for node `v`.
*
* @param {NodeID | number} v - Node ID.
* @returns {NodeID | undefined} the node that is a parent of node `v`
* or `undefined` if node `v` does not have a parent or is not a member of
* the graph.
* Always returns `undefined` for graphs that are not compound.
* @remarks Takes `O(1)` time.
*/
parent(v) {
if (this._isCompound) {
var parent = this._parent[v];
if (parent !== GRAPH_NODE) {
return parent;
}
}
}
/**
* Gets list of direct children of node v.
*
* @param {NodeID | number} [v] - Node ID. If not specified, gets nodes
* with no parent (top-level nodes).
* @returns {NodeID[] | undefined} all nodes that are children of node `v` or
* `undefined` if node `v` is not in the graph.
* Always returns `[]` for graphs that are not compound.
* @remarks Takes `O(|V|)` time.
*/
children(v) {
if (_.isUndefined(v)) {
v = GRAPH_NODE;
}
if (this._isCompound) {
var children = this._children[v];
if (children) {
return _.keys(children);
}
} else if (v === GRAPH_NODE) {
return this.nodes();
} else if (this.hasNode(v)) {
return [];
}
}
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are predecessors of the
* specified node or `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link neighbors} instead.
* Takes `O(|V|)` time.
*/
predecessors(v) {
var predsV = this._preds[v];
if (predsV) {
return _.keys(predsV);
}
}
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are successors of the
* specified node or `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link neighbors} instead.
* Takes `O(|V|)` time.
*/
successors(v) {
var sucsV = this._sucs[v];
if (sucsV) {
return _.keys(sucsV);
}
}
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are predecessors or
* successors of the specified node
* or `undefined` if node `v` is not in the graph.
* @remarks Takes `O(|V|)` time.
*/
neighbors(v) {
var preds = this.predecessors(v);
if (preds) {
return _.union(preds, this.successors(v));
}
}
/**
* @param {NodeID | number} v - Node ID.
* @returns {boolean} True if the node is a leaf (has no successors), false otherwise.
*/
isLeaf(v) {
var neighbors;
if (this.isDirected()) {
neighbors = this.successors(v);
} else {
neighbors = this.neighbors(v);
}
return neighbors.length === 0;
}
/**
* Creates new graph with nodes filtered via `filter`.
* Edges incident to rejected node
* are also removed.
*
* In case of compound graph, if parent is rejected by `filter`,
* than all its children are rejected too.
* @param {(v: NodeID) => boolean} filter - Function that returns `true` for nodes to keep.
* @returns {Graph} A new graph containing only the nodes for which `filter` returns `true`.
* @remarks Average-case complexity: O(|E|+|V|).
*/
filterNodes(filter) {
/**
* @type {Graph}
*/
// @ts-expect-error
var copy = new this.constructor({
directed: this._isDirected,
multigraph: this._isMultigraph,
compound: this._isCompound,
});
copy.setGraph(this.graph());
var self = this;
_.each(this._nodes, function (value, v) {
if (filter(v)) {
copy.setNode(v, value);
}
});
_.each(this._edgeObjs, function (e) {
if (copy.hasNode(e.v) && copy.hasNode(e.w)) {
copy.setEdge(e, self.edge(e));
}
});
var parents = {};
function findParent(v) {
var parent = self.parent(v);
if (parent === undefined || copy.hasNode(parent)) {
parents[v] = parent;
return parent;
} else if (parent in parents) {
return parents[parent];
} else {
return findParent(parent);
}
}
if (this._isCompound) {
_.each(copy.nodes(), function (v) {
copy.setParent(v, findParent(v));
});
}
return copy;
}
/* === Edge functions ========== */
/**
* Sets a new default value that is assigned to edges that are created without
* a label.
*
* @param {typeof this._defaultEdgeLabelFn | EdgeLabel} newDefault - If a function,
* it is called with the parameters `(v, w, name)`.
* Otherwise, it is assigned as the label directly.
* @returns {this}
*/
setDefaultEdgeLabel(newDefault) {
if (!_.isFunction(newDefault)) {
newDefault = _.constant(newDefault);
}
this._defaultEdgeLabelFn = newDefault;
return this;
}
/**
* @returns {number} the number of edges in the graph.
* @remarks Complexity: O(1).
*/
edgeCount() {
return this._edgeCount;
}
/**
* Gets edges of the graph.
*
* @returns {EdgeObj[]} the {@link EdgeObj} for each edge in the graph.
*
* @remarks
* In case of compound graph subgraphs are not considered.
* Use {@link edge()} to get the label for each edge.
* Takes `O(|E|)` time.
*/
edges() {
return _.values(this._edgeObjs);
}
/**
* Establish an edges path over the nodes in nodes list.
*
* If some edge is already exists, it will update its label, otherwise it will
* create an edge between pair of nodes with label provided or default label
* if no label provided.
*
* @param {Collection} vs - List of node IDs to create edges between.
* @param {EdgeLabel} [value] - If set, update all edges with this value.
* @returns {this}
* @remarks Complexity: O(|nodes|).
*/
setPath(vs, value) {
var self = this;
var args = arguments;
_.reduce(vs, function (v, w) {
if (args.length > 1) {
self.setEdge(v, w, value);
} else {
self.setEdge(v, w);
}
return w;
});
return this;
}
/**
* Creates or updates the label for the edge (`v`, `w`) with the optionally
* supplied `name`.
*
* @overload
* @param {EdgeObj} arg0 - Edge object.
* @param {EdgeLabel} [value] - If supplied, it is set as the label for the edge.
* If not supplied and the edge was created by this call then
* {@link setDefaultEdgeLabel} will be used to assign the edge's label.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
/**
* Creates or updates the label for the edge (`v`, `w`) with the optionally
* supplied `name`.
*
* @overload
* @param {NodeID | number} v - Source node ID. Number values will be coerced to strings.
* @param {NodeID | number} w - Target node ID. Number values will be coerced to strings.
* @param {EdgeLabel} [value] - If supplied, it is set as the label for the edge.
* If not supplied and the edge was created by this call then
* {@link setDefaultEdgeLabel} will be used to assign the edge's label.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
setEdge() {
var v, w, name, value;
var valueSpecified = false;
var arg0 = arguments[0];
if (typeof arg0 === 'object' && arg0 !== null && 'v' in arg0) {
v = arg0.v;
w = arg0.w;
name = arg0.name;
if (arguments.length === 2) {
value = arguments[1];
valueSpecified = true;
}
} else {
v = arg0;
w = arguments[1];
name = arguments[3];
if (arguments.length > 2) {
value = arguments[2];
valueSpecified = true;
}
}
v = '' + v;
w = '' + w;
if (!_.isUndefined(name)) {
name = '' + name;
}
var e = edgeArgsToId(this._isDirected, v, w, name);
if (Object.prototype.hasOwnProperty.call(this._edgeLabels, e)) {
if (valueSpecified) {
this._edgeLabels[e] = value;
}
return this;
}
if (!_.isUndefined(name) && !this._isMultigraph) {
throw new Error('Cannot set a named edge when isMultigraph = false');
}
// It didn't exist, so we need to create it.
// First ensure the nodes exist.
this.setNode(v);
this.setNode(w);
this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
// Ensure we add undirected edges in a consistent way.
v = edgeObj.v;
w = edgeObj.w;
Object.freeze(edgeObj);
this._edgeObjs[e] = edgeObj;
incrementOrInitEntry(this._preds[w], v);
incrementOrInitEntry(this._sucs[v], w);
this._in[w][e] = edgeObj;
this._out[v][e] = edgeObj;
this._edgeCount++;
return this;
}
/**
* Gets the label for the specified edge.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {EdgeLabel | undefined} the label for the edge (`v`, `w`) if the
* graph has an edge between `v` and `w` with the optional `name`.
* Returned `undefined` if there is no such edge in the graph.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
/**
* Gets the label for the specified edge.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {EdgeLabel | undefined} the label for the edge (`v`, `w`) if the
* graph has an edge between `v` and `w` with the optional `name`.
* Returned `undefined` if there is no such edge in the graph.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
edge(v, w, name) {
var e =
arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name);
return this._edgeLabels[e];
}
/**
* Detects whether the graph contains specified edge or not.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {boolean} `true` if the graph has an edge between `v` and `w`
* with the optional `name`.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
/**
* Detects whether the graph contains specified edge or not.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {boolean} `true` if the graph has an edge between `v` and `w`
* with the optional `name`.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
hasEdge(v, w, name) {
var e =
arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name);
return Object.prototype.hasOwnProperty.call(this._edgeLabels, e);
}
/**
* Removes the edge (`v`, `w`) if the graph has an edge between `v` and `w`
* with the optional `name`. If not this function does nothing.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {this}
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
/**
* Removes the edge (`v`, `w`) if the graph has an edge between `v` and `w`
* with the optional `name`. If not this function does nothing.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {this}
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
removeEdge(v, w, name) {
var e =
arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name);
var edge = this._edgeObjs[e];
if (edge) {
v = edge.v;
w = edge.w;
delete this._edgeLabels[e];
delete this._edgeObjs[e];
decrementOrRemoveEntry(this._preds[w], v);
decrementOrRemoveEntry(this._sucs[v], w);
delete this._in[w][e];
delete this._out[v][e];
this._edgeCount--;
}
return this;
}
/**
* @param {NodeID | number} v - Target node ID.
* @param {NodeID | number} [u] - Optionally filters edges down to just those
* coming from node `u`.
* @returns {EdgeObj[] | undefined} all edges that point to the node `v`.
* Returns `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link nodeEdges} instead.
* Takes `O(|E|)` time.
*/
inEdges(v, u) {
var inV = this._in[v];
if (inV) {
var edges = _.values(inV);
if (!u) {
return edges;
}
return _.filter(edges, function (edge) {
return edge.v === u;
});
}
}
/**
* @param {NodeID | number} v - Target node ID.
* @param {NodeID | number} [w] - Optionally filters edges down to just those
* that point to `w`.
* @returns {EdgeObj[] | undefined} all edges that point to the node `v`.
* Returns `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link nodeEdges} instead.
* Takes `O(|E|)` time.
*/
outEdges(v, w) {
var outV = this._out[v];
if (outV) {
var edges = _.values(outV);
if (!w) {
return edges;
}
return _.filter(edges, function (edge) {
return edge.w === w;
});
}
}
/**
* @param {NodeID | number} v - Target Node ID.
* @param {NodeID | number} [w] - If set, filters those edges down to just
* those between nodes `v` and `w` regardless of direction
* @returns {EdgeObj[] | undefined} all edges to or from node `v` regardless
* of direction. Returns `undefined` if node `v` is not in the graph.
* @remarks Takes `O(|E|)` time.
*/
nodeEdges(v, w) {
var inEdges = this.inEdges(v, w);
if (inEdges) {
return inEdges.concat(this.outEdges(v, w));
}
}
}
/* Number of nodes in the graph. Should only be changed by the implementation. */
Graph.prototype._nodeCount = 0;
/* Number of edges in the graph. Should only be changed by the implementation. */
Graph.prototype._edgeCount = 0;
/**
* @param {Record} map - Object mapping node IDs to counts.
* @param {NodeID | number} k - Node ID.
*/
function incrementOrInitEntry(map, k) {
if (map[k]) {
map[k]++;
} else {
map[k] = 1;
}
}
/**
* @param {Record} map - Object mapping node IDs to counts.
* @param {NodeID | number} k - Node ID.
*/
function decrementOrRemoveEntry(map, k) {
if (!--map[k]) {
delete map[k];
}
}
/**
* @param {boolean} isDirected - If `false`, sorts v and w to ensure a consistent ID.
* @param {EdgeObj['v'] | number} v_ - Source node ID.
* @param {EdgeObj['w'] | number} w_ - Target node ID.
* @param {EdgeObj['name']} [name] - Edge name (for multiple edges between the same nodes).
* @returns {EdgeID} Unique ID for the edge.
*/
function edgeArgsToId(isDirected, v_, w_, name) {
var v = '' + v_;
var w = '' + w_;
if (!isDirected && v > w) {
var tmp = v;
v = w;
w = tmp;
}
return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM + (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
}
/**
* @param {boolean} isDirected - If `false`, sorts v and w to ensure a consistent ID.
* @param {EdgeObj['v'] | number} v_ - Source node ID.
* @param {EdgeObj['w'] | number} w_ - Target node ID.
* @param {EdgeObj['name']} [name] - Edge name (for multiple edges between the same nodes).
* @returns {EdgeObj}
*/
function edgeArgsToObj(isDirected, v_, w_, name) {
var v = '' + v_;
var w = '' + w_;
if (!isDirected && v > w) {
var tmp = v;
v = w;
w = tmp;
}
var edgeObj = { v: v, w: w };
if (name) {
edgeObj.name = name;
}
return edgeObj;
}
/**
* @param {boolean} isDirected - If `false`, sorts v and w to ensure a consistent ID.
* @param {EdgeObj} edgeObj - Edge object.
* @returns {EdgeID} Unique ID for the edge.
*/
function edgeObjToId(isDirected, edgeObj) {
return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
}
tbo47-dagre-es-4b95ad0/src/graphlib/graph.test.js 0000664 0000000 0000000 00000077541 15114061606 0021562 0 ustar 00root root 0000000 0000000 import { beforeEach, describe, expect, it } from 'vitest';
import { Graph } from './graph.js';
describe('Graph', function () {
/** @type {Graph} */
var g;
beforeEach(function () {
g = new Graph();
});
describe('initial state', function () {
it('has no nodes', function () {
expect(g.nodeCount()).to.equal(0);
});
it('has no edges', function () {
expect(g.edgeCount()).to.equal(0);
});
it('has no attributes', function () {
expect(g.graph()).to.be.undefined;
});
it('defaults to a simple directed graph', function () {
expect(g.isDirected()).to.be.true;
expect(g.isCompound()).to.be.false;
expect(g.isMultigraph()).to.be.false;
});
it('can be set to undirected', function () {
var g = new Graph({ directed: false });
expect(g.isDirected()).to.be.false;
expect(g.isCompound()).to.be.false;
expect(g.isMultigraph()).to.be.false;
});
it('can be set to a compound graph', function () {
var g = new Graph({ compound: true });
expect(g.isDirected()).to.be.true;
expect(g.isCompound()).to.be.true;
expect(g.isMultigraph()).to.be.false;
});
it('can be set to a mulitgraph', function () {
var g = new Graph({ multigraph: true });
expect(g.isDirected()).to.be.true;
expect(g.isCompound()).to.be.false;
expect(g.isMultigraph()).to.be.true;
});
});
describe('setGraph', function () {
it('can be used to get and set properties for the graph', function () {
g.setGraph('foo');
expect(g.graph()).to.equal('foo');
});
it('is chainable', function () {
expect(g.setGraph('foo')).to.equal(g);
});
});
describe('nodes', function () {
it('is empty if there are no nodes in the graph', function () {
expect(g.nodes()).to.eql([]);
});
it('returns the ids of nodes in the graph', function () {
g.setNode('a');
g.setNode('b');
expect(g.nodes().sort()).to.eql(['a', 'b']);
});
});
describe('sources', function () {
it('returns nodes in the graph that have no in-edges', function () {
g.setPath(['a', 'b', 'c']);
g.setNode('d');
expect(g.sources().sort()).to.eql(['a', 'd']);
});
});
describe('sinks', function () {
it('returns nodes in the graph that have no out-edges', function () {
g.setPath(['a', 'b', 'c']);
g.setNode('d');
expect(g.sinks().sort()).to.eql(['c', 'd']);
});
});
describe('filterNodes', function () {
it('returns an identical graph when the filter selects everything', function () {
g.setGraph('graph label');
g.setNode('a', 123);
g.setPath(['a', 'b', 'c']);
g.setEdge('a', 'c', 456);
var g2 = g.filterNodes(function () {
return true;
});
expect(g2.nodes().sort()).eqls(['a', 'b', 'c']);
expect(g2.successors('a').sort()).eqls(['b', 'c']);
expect(g2.successors('b').sort()).eqls(['c']);
expect(g2.node('a')).eqls(123);
expect(g2.edge('a', 'c')).eqls(456);
expect(g2.graph()).eqls('graph label');
});
it('returns an empty graph when the filter selects nothing', function () {
g.setPath(['a', 'b', 'c']);
var g2 = g.filterNodes(function () {
return false;
});
expect(g2.nodes()).eqls([]);
expect(g2.edges()).eqls([]);
});
it('only includes nodes for which the filter returns true', function () {
g.setNodes(['a', 'b']);
var g2 = g.filterNodes(function (v) {
return v === 'a';
});
expect(g2.nodes()).eqls(['a']);
});
it('removes edges that are connected to removed nodes', function () {
g.setEdge('a', 'b');
var g2 = g.filterNodes(function (v) {
return v === 'a';
});
expect(g2.nodes().sort()).eqls(['a']);
expect(g2.edges()).eqls([]);
});
it('preserves the directed option', function () {
g = new Graph({ directed: true });
expect(
g
.filterNodes(function () {
return true;
})
.isDirected(),
).to.be.true;
g = new Graph({ directed: false });
expect(
g
.filterNodes(function () {
return true;
})
.isDirected(),
).to.be.false;
});
it('preserves the multigraph option', function () {
g = new Graph({ multigraph: true });
expect(
g
.filterNodes(function () {
return true;
})
.isMultigraph(),
).to.be.true;
g = new Graph({ multigraph: false });
expect(
g
.filterNodes(function () {
return true;
})
.isMultigraph(),
).to.be.false;
});
it('preserves the compound option', function () {
g = new Graph({ compound: true });
expect(
g
.filterNodes(function () {
return true;
})
.isCompound(),
).to.be.true;
g = new Graph({ compound: false });
expect(
g
.filterNodes(function () {
return true;
})
.isCompound(),
).to.be.false;
});
it('includes subgraphs', function () {
g = new Graph({ compound: true });
g.setParent('a', 'parent');
var g2 = g.filterNodes(function () {
return true;
});
expect(g2.parent('a')).eqls('parent');
});
it('includes multi-level subgraphs', function () {
g = new Graph({ compound: true });
g.setParent('a', 'parent');
g.setParent('parent', 'root');
var g2 = g.filterNodes(function () {
return true;
});
expect(g2.parent('a')).eqls('parent');
expect(g2.parent('parent')).eqls('root');
});
it('promotes a node to a higher subgraph if its parent is not included', function () {
g = new Graph({ compound: true });
g.setParent('a', 'parent');
g.setParent('parent', 'root');
var g2 = g.filterNodes(function (v) {
return v !== 'parent';
});
expect(g2.parent('a')).eqls('root');
});
});
describe('setNodes', function () {
it('creates multiple nodes', function () {
g.setNodes(['a', 'b', 'c']);
expect(g.hasNode('a')).to.be.true;
expect(g.hasNode('b')).to.be.true;
expect(g.hasNode('c')).to.be.true;
});
it('can set a value for all of the nodes', function () {
g.setNodes(['a', 'b', 'c'], 'foo');
expect(g.node('a')).to.equal('foo');
expect(g.node('b')).to.equal('foo');
expect(g.node('c')).to.equal('foo');
});
it('is chainable', function () {
expect(g.setNodes(['a', 'b', 'c'])).to.equal(g);
});
});
describe('setNode', function () {
it("creates the node if it isn't part of the graph", function () {
g.setNode('a');
expect(g.hasNode('a')).to.be.true;
expect(g.node('a')).to.be.undefined;
expect(g.nodeCount()).to.equal(1);
});
it('can set a value for the node', function () {
g.setNode('a', 'foo');
expect(g.node('a')).to.equal('foo');
});
it("does not change the node's value with a 1-arg invocation", function () {
g.setNode('a', 'foo');
g.setNode('a');
expect(g.node('a')).to.equal('foo');
});
it("can remove the node's value by passing undefined", function () {
g.setNode('a', undefined);
expect(g.node('a')).to.be.undefined;
});
it('is idempotent', function () {
g.setNode('a', 'foo');
g.setNode('a', 'foo');
expect(g.node('a')).to.equal('foo');
expect(g.nodeCount()).to.equal(1);
});
it('uses the stringified form of the id', function () {
g.setNode(1);
expect(g.hasNode(1)).to.be.true;
expect(g.hasNode('1')).to.be.true;
expect(g.nodes()).eqls(['1']);
});
it('is chainable', function () {
expect(g.setNode('a')).to.equal(g);
});
});
describe('setNodeDefaults', function () {
it('sets a default label for new nodes', function () {
g.setDefaultNodeLabel('foo');
g.setNode('a');
expect(g.node('a')).to.equal('foo');
});
it('does not change existing nodes', function () {
g.setNode('a');
g.setDefaultNodeLabel('foo');
expect(g.node('a')).to.be.undefined;
});
it('is not used if an explicit value is set', function () {
g.setDefaultNodeLabel('foo');
g.setNode('a', 'bar');
expect(g.node('a')).to.equal('bar');
});
it('can take a function', function () {
g.setDefaultNodeLabel(function () {
return 'foo';
});
g.setNode('a');
expect(g.node('a')).to.equal('foo');
});
it("can take a function that takes the node's name", function () {
g.setDefaultNodeLabel(function (v) {
return v + '-foo';
});
g.setNode('a');
expect(g.node('a')).to.equal('a-foo');
});
it('is chainable', function () {
expect(g.setDefaultNodeLabel('foo')).to.equal(g);
});
});
describe('node', function () {
it("returns undefined if the node isn't part of the graph", function () {
expect(g.node('a')).to.be.undefined;
});
it('returns the value of the node if it is part of the graph', function () {
g.setNode('a', 'foo');
expect(g.node('a')).to.equal('foo');
});
});
describe('removeNode', function () {
it('does nothing if the node is not in the graph', function () {
expect(g.nodeCount()).to.equal(0);
g.removeNode('a');
expect(g.hasNode('a')).to.be.false;
expect(g.nodeCount()).to.equal(0);
});
it('removes the node if it is in the graph', function () {
g.setNode('a');
g.removeNode('a');
expect(g.hasNode('a')).to.be.false;
expect(g.nodeCount()).to.equal(0);
});
it('is idempotent', function () {
g.setNode('a');
g.removeNode('a');
g.removeNode('a');
expect(g.hasNode('a')).to.be.false;
expect(g.nodeCount()).to.equal(0);
});
it('removes edges incident on the node', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.removeNode('b');
expect(g.edgeCount()).to.equal(0);
});
it('removes parent / child relationships for the node', function () {
var g = new Graph({ compound: true });
g.setParent('c', 'b');
g.setParent('b', 'a');
g.removeNode('b');
expect(g.parent('b')).to.be.undefined;
expect(g.children('b')).to.be.undefined;
expect(g.children('a')).to.not.include('b');
expect(g.parent('c')).to.be.undefined;
});
it('is chainable', function () {
expect(g.removeNode('a')).to.equal(g);
});
});
describe('setParent', function () {
beforeEach(function () {
g = new Graph({ compound: true });
});
it('throws if the graph is not compound', function () {
expect(function () {
new Graph().setParent('a', 'parent');
}).to.throw();
});
it('creates the parent if it does not exist', function () {
g.setNode('a');
g.setParent('a', 'parent');
expect(g.hasNode('parent')).to.be.true;
expect(g.parent('a')).to.equal('parent');
});
it('creates the child if it does not exist', function () {
g.setNode('parent');
g.setParent('a', 'parent');
expect(g.hasNode('a')).to.be.true;
expect(g.parent('a')).to.equal('parent');
});
it('has the parent as undefined if it has never been invoked', function () {
g.setNode('a');
expect(g.parent('a')).to.be.undefined;
});
it('moves the node from the previous parent', function () {
g.setParent('a', 'parent');
g.setParent('a', 'parent2');
expect(g.parent('a')).to.equal('parent2');
expect(g.children('parent')).to.eql([]);
expect(g.children('parent2')).to.eql(['a']);
});
it('removes the parent if the parent is undefined', function () {
g.setParent('a', 'parent');
g.setParent('a', undefined);
expect(g.parent('a')).to.be.undefined;
expect(g.children().sort()).to.eql(['a', 'parent']);
});
it('removes the parent if no parent was specified', function () {
g.setParent('a', 'parent');
g.setParent('a');
expect(g.parent('a')).to.be.undefined;
expect(g.children().sort()).to.eql(['a', 'parent']);
});
it('is idempotent to remove a parent', function () {
g.setParent('a', 'parent');
g.setParent('a');
g.setParent('a');
expect(g.parent('a')).to.be.undefined;
expect(g.children().sort()).to.eql(['a', 'parent']);
});
it('uses the stringified form of the id', function () {
g.setParent(2, 1);
g.setParent(3, 2);
expect(g.parent(2)).equals('1');
expect(g.parent('2')).equals('1');
expect(g.parent(3)).equals('2');
});
it('preserves the tree invariant', function () {
g.setParent('c', 'b');
g.setParent('b', 'a');
expect(function () {
g.setParent('a', 'c');
}).to.throw();
});
it('is chainable', function () {
expect(g.setParent('a', 'parent')).to.equal(g);
});
});
describe('parent', function () {
beforeEach(function () {
g = new Graph({ compound: true });
});
it('returns undefined if the graph is not compound', function () {
expect(new Graph({ compound: false }).parent('a')).to.be.undefined;
});
it('returns undefined if the node is not in the graph', function () {
expect(g.parent('a')).to.be.undefined;
});
it('defaults to undefined for new nodes', function () {
g.setNode('a');
expect(g.parent('a')).to.be.undefined;
});
it('returns the current parent assignment', function () {
g.setNode('a');
g.setNode('parent');
g.setParent('a', 'parent');
expect(g.parent('a')).to.equal('parent');
});
});
describe('children', function () {
beforeEach(function () {
g = new Graph({ compound: true });
});
it('returns undefined if the node is not in the graph', function () {
expect(g.children('a')).to.be.undefined;
});
it('defaults to en empty list for new nodes', function () {
g.setNode('a');
expect(g.children('a')).to.eql([]);
});
it('returns undefined for a non-compound graph without the node', function () {
var g = new Graph();
expect(g.children('a')).to.be.undefined;
});
it('returns an empty list for a non-compound graph with the node', function () {
var g = new Graph();
g.setNode('a');
expect(g.children('a')).eqls([]);
});
it('returns all nodes for the root of a non-compound graph', function () {
var g = new Graph();
g.setNode('a');
g.setNode('b');
expect(g.children().sort()).eqls(['a', 'b']);
});
it('returns children for the node', function () {
g.setParent('a', 'parent');
g.setParent('b', 'parent');
expect(g.children('parent').sort()).to.eql(['a', 'b']);
});
it('returns all nodes without a parent when the parent is not set', function () {
g.setNode('a');
g.setNode('b');
g.setNode('c');
g.setNode('parent');
g.setParent('a', 'parent');
expect(g.children().sort()).to.eql(['b', 'c', 'parent']);
expect(g.children(undefined).sort()).to.eql(['b', 'c', 'parent']);
});
});
describe('predecessors', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.predecessors('a')).to.be.undefined;
});
it('returns the predecessors of a node', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.setEdge('a', 'a');
expect(g.predecessors('a').sort()).to.eql(['a']);
expect(g.predecessors('b').sort()).to.eql(['a']);
expect(g.predecessors('c').sort()).to.eql(['b']);
});
});
describe('successors', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.successors('a')).to.be.undefined;
});
it('returns the successors of a node', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.setEdge('a', 'a');
expect(g.successors('a').sort()).to.eql(['a', 'b']);
expect(g.successors('b').sort()).to.eql(['c']);
expect(g.successors('c').sort()).to.eql([]);
});
});
describe('neighbors', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.neighbors('a')).to.be.undefined;
});
it('returns the neighbors of a node', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
g.setEdge('a', 'a');
expect(g.neighbors('a').sort()).to.eql(['a', 'b']);
expect(g.neighbors('b').sort()).to.eql(['a', 'c']);
expect(g.neighbors('c').sort()).to.eql(['b']);
});
});
describe('isLeaf', function () {
it('returns false for connected node in undirected graph', function () {
g = new Graph({ directed: false });
g.setNode('a');
g.setNode('b');
g.setEdge('a', 'b');
expect(g.isLeaf('b')).to.be.false;
});
it('returns true for an unconnected node in undirected graph', function () {
g = new Graph({ directed: false });
g.setNode('a');
expect(g.isLeaf('a')).to.be.true;
});
it('returns true for unconnected node in directed graph', function () {
g.setNode('a');
expect(g.isLeaf('a')).to.be.true;
});
it('returns false for predecessor node in directed graph', function () {
g.setNode('a');
g.setNode('b');
g.setEdge('a', 'b');
expect(g.isLeaf('a')).to.be.false;
});
it('returns true for successor node in directed graph', function () {
g.setNode('a');
g.setNode('b');
g.setEdge('a', 'b');
expect(g.isLeaf('b')).to.be.true;
});
});
describe('edges', function () {
it('is empty if there are no edges in the graph', function () {
expect(g.edges()).to.eql([]);
});
it('returns the keys for edges in the graph', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(g.edges().sort(sortEdges)).to.eql([
{ v: 'a', w: 'b' },
{ v: 'b', w: 'c' },
]);
});
});
describe('setPath', function () {
it('creates a path of mutiple edges', function () {
g.setPath(['a', 'b', 'c']);
expect(g.hasEdge('a', 'b')).to.be.true;
expect(g.hasEdge('b', 'c')).to.be.true;
});
it('can set a value for all of the edges', function () {
g.setPath(['a', 'b', 'c'], 'foo');
expect(g.edge('a', 'b')).to.equal('foo');
expect(g.edge('b', 'c')).to.equal('foo');
});
it('is chainable', function () {
expect(g.setPath(['a', 'b', 'c'])).to.equal(g);
});
});
describe('setEdge', function () {
it("creates the edge if it isn't part of the graph", function () {
g.setNode('a');
g.setNode('b');
g.setEdge('a', 'b');
expect(g.edge('a', 'b')).to.be.undefined;
expect(g.hasEdge('a', 'b')).to.be.true;
expect(g.hasEdge({ v: 'a', w: 'b' })).to.be.true;
expect(g.edgeCount()).to.equal(1);
});
it('creates the nodes for the edge if they are not part of the graph', function () {
g.setEdge('a', 'b');
expect(g.hasNode('a')).to.be.true;
expect(g.hasNode('b')).to.be.true;
expect(g.nodeCount()).to.equal(2);
});
it("creates a multi-edge if if it isn't part of the graph", function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', undefined, 'name');
expect(g.hasEdge('a', 'b')).to.be.false;
expect(g.hasEdge('a', 'b', 'name')).to.be.true;
});
it('throws if a multi-edge is used with a non-multigraph', function () {
expect(function () {
g.setEdge('a', 'b', undefined, 'name');
}).to.throw();
});
it('changes the value for an edge if it is already in the graph', function () {
g.setEdge('a', 'b', 'foo');
g.setEdge('a', 'b', 'bar');
expect(g.edge('a', 'b')).to.equal('bar');
});
it('deletes the value for the edge if the value arg is undefined', function () {
g.setEdge('a', 'b', 'foo');
g.setEdge('a', 'b', undefined);
expect(g.edge('a', 'b')).to.be.undefined;
expect(g.hasEdge('a', 'b')).to.be.true;
});
it('changes the value for a multi-edge if it is already in the graph', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', 'value', 'name');
g.setEdge('a', 'b', undefined, 'name');
expect(g.edge('a', 'b', 'name')).to.be.undefined;
expect(g.hasEdge('a', 'b', 'name')).to.be.true;
});
it('can take an edge object as the first parameter', function () {
g.setEdge({ v: 'a', w: 'b' }, 'value');
expect(g.edge('a', 'b')).to.equal('value');
});
it('can take an multi-edge object as the first parameter', function () {
var g = new Graph({ multigraph: true });
g.setEdge({ v: 'a', w: 'b', name: 'name' }, 'value');
expect(g.edge('a', 'b', 'name')).to.equal('value');
});
it('uses the stringified form of the id #1', function () {
g.setEdge(1, 2, 'foo');
expect(g.edges()).eqls([{ v: '1', w: '2' }]);
expect(g.edge('1', '2')).to.equal('foo');
expect(g.edge(1, 2)).to.equal('foo');
});
it('uses the stringified form of the id #2', function () {
g = new Graph({ multigraph: true });
g.setEdge(1, 2, 'foo', undefined);
expect(g.edges()).eqls([{ v: '1', w: '2' }]);
expect(g.edge('1', '2')).to.equal('foo');
expect(g.edge(1, 2)).to.equal('foo');
});
it('uses the stringified form of the id with a name', function () {
g = new Graph({ multigraph: true });
g.setEdge(1, 2, 'foo', 3);
expect(g.edge('1', '2', '3')).to.equal('foo');
expect(g.edge(1, 2, 3)).to.equal('foo');
expect(g.edges()).eqls([{ v: '1', w: '2', name: '3' }]);
});
it('treats edges in opposite directions as distinct in a digraph', function () {
g.setEdge('a', 'b');
expect(g.hasEdge('a', 'b')).to.be.true;
expect(g.hasEdge('b', 'a')).to.be.false;
});
it('handles undirected graph edges', function () {
var g = new Graph({ directed: false });
g.setEdge('a', 'b', 'foo');
expect(g.edge('a', 'b')).to.equal('foo');
expect(g.edge('b', 'a')).to.equal('foo');
});
it('handles undirected edges where id has different order than Stringified id', function () {
var g = new Graph({ directed: false });
g.setEdge(9, 10, 'foo');
expect(g.hasEdge('9', '10')).to.be.true;
expect(g.hasEdge(9, 10)).to.be.true;
expect(g.hasEdge('10', '9')).to.be.true;
expect(g.hasEdge(10, 9)).to.be.true;
expect(g.edge('9', '10')).eqls('foo');
expect(g.edge(9, 10)).eqls('foo');
});
it('is chainable', function () {
expect(g.setEdge('a', 'b')).to.equal(g);
});
});
describe('setDefaultEdgeLabel', function () {
it('sets a default label for new edges', function () {
g.setDefaultEdgeLabel('foo');
g.setEdge('a', 'b');
expect(g.edge('a', 'b')).to.equal('foo');
});
it('does not change existing edges', function () {
g.setEdge('a', 'b');
g.setDefaultEdgeLabel('foo');
expect(g.edge('a', 'b')).to.be.undefined;
});
it('is not used if an explicit value is set', function () {
g.setDefaultEdgeLabel('foo');
g.setEdge('a', 'b', 'bar');
expect(g.edge('a', 'b')).to.equal('bar');
});
it('can take a function', function () {
g.setDefaultEdgeLabel(function () {
return 'foo';
});
g.setEdge('a', 'b');
expect(g.edge('a', 'b')).to.equal('foo');
});
it("can take a function that takes the edge's endpoints and name", function () {
var g = new Graph({ multigraph: true });
g.setDefaultEdgeLabel(function (v, w, name) {
return v + '-' + w + '-' + name + '-foo';
});
g.setEdge({ v: 'a', w: 'b', name: 'name' });
expect(g.edge('a', 'b', 'name')).to.equal('a-b-name-foo');
});
it('does not set a default value for a multi-edge that already exists', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', 'old', 'name');
g.setDefaultEdgeLabel(function () {
return 'should not set this';
});
g.setEdge({ v: 'a', w: 'b', name: 'name' });
expect(g.edge('a', 'b', 'name')).to.equal('old');
});
it('is chainable', function () {
expect(g.setDefaultEdgeLabel('foo')).to.equal(g);
});
});
describe('edge', function () {
it("returns undefined if the edge isn't part of the graph", function () {
expect(g.edge('a', 'b')).to.be.undefined;
expect(g.edge({ v: 'a', w: 'b' })).to.be.undefined;
expect(g.edge('a', 'b', 'foo')).to.be.undefined;
});
it('returns the value of the edge if it is part of the graph', function () {
g.setEdge('a', 'b', { foo: 'bar' });
expect(g.edge('a', 'b')).to.eql({ foo: 'bar' });
expect(g.edge({ v: 'a', w: 'b' })).to.eql({ foo: 'bar' });
expect(g.edge('b', 'a')).to.be.undefined;
});
it('returns the value of a multi-edge if it is part of the graph', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b', { bar: 'baz' }, 'foo');
expect(g.edge('a', 'b', 'foo')).to.eql({ bar: 'baz' });
expect(g.edge('a', 'b')).to.be.undefined;
});
it('returns an edge in either direction in an undirected graph', function () {
var g = new Graph({ directed: false });
g.setEdge('a', 'b', { foo: 'bar' });
expect(g.edge('a', 'b')).to.eql({ foo: 'bar' });
expect(g.edge('b', 'a')).to.eql({ foo: 'bar' });
});
});
describe('removeEdge', function () {
it('has no effect if the edge is not in the graph', function () {
g.removeEdge('a', 'b');
expect(g.hasEdge('a', 'b')).to.be.false;
expect(g.edgeCount()).to.equal(0);
});
it('can remove an edge by edgeObj', function () {
var g = new Graph({ multigraph: true });
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
g.removeEdge({ v: 'a', w: 'b', name: 'foo' });
expect(g.hasEdge('a', 'b', 'foo')).to.be.false;
expect(g.edgeCount()).to.equal(0);
});
it('can remove an edge by separate ids', function () {
var g = new Graph({ multigraph: true });
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
g.removeEdge('a', 'b', 'foo');
expect(g.hasEdge('a', 'b', 'foo')).to.be.false;
expect(g.edgeCount()).to.equal(0);
});
it('correctly removes neighbors', function () {
g.setEdge('a', 'b');
g.removeEdge('a', 'b');
expect(g.successors('a')).to.eql([]);
expect(g.neighbors('a')).to.eql([]);
expect(g.predecessors('b')).to.eql([]);
expect(g.neighbors('b')).to.eql([]);
});
it('correctly decrements neighbor counts', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
g.removeEdge('a', 'b');
expect(g.hasEdge('a', 'b', 'foo'));
expect(g.successors('a')).to.eql(['b']);
expect(g.neighbors('a')).to.eql(['b']);
expect(g.predecessors('b')).to.eql(['a']);
expect(g.neighbors('b')).to.eql(['a']);
});
it('works with undirected graphs', function () {
var g = new Graph({ directed: false });
g.setEdge('h', 'g');
g.removeEdge('g', 'h');
expect(g.neighbors('g')).to.eql([]);
expect(g.neighbors('h')).to.eql([]);
});
it('is chainable', function () {
g.setEdge('a', 'b');
expect(g.removeEdge('a', 'b')).to.equal(g);
});
});
describe('inEdges', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.inEdges('a')).to.be.undefined;
});
it('returns the edges that point at the specified node', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(g.inEdges('a')).to.eql([]);
expect(g.inEdges('b')).to.eql([{ v: 'a', w: 'b' }]);
expect(g.inEdges('c')).to.eql([{ v: 'b', w: 'c' }]);
});
it('works for multigraphs', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge('a', 'b', undefined, 'bar');
g.setEdge('a', 'b', undefined, 'foo');
expect(g.inEdges('a')).to.eql([]);
expect(g.inEdges('b').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'bar' },
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
});
it('can return only edges from a specified node', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge('a', 'b', undefined, 'foo');
g.setEdge('a', 'c');
g.setEdge('b', 'c');
g.setEdge('z', 'a');
g.setEdge('z', 'b');
expect(g.inEdges('a', 'b')).to.eql([]);
expect(g.inEdges('b', 'a').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
});
});
describe('outEdges', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.outEdges('a')).to.be.undefined;
});
it('returns all edges that this node points at', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(g.outEdges('a')).to.eql([{ v: 'a', w: 'b' }]);
expect(g.outEdges('b')).to.eql([{ v: 'b', w: 'c' }]);
expect(g.outEdges('c')).to.eql([]);
});
it('works for multigraphs', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge('a', 'b', undefined, 'bar');
g.setEdge('a', 'b', undefined, 'foo');
expect(g.outEdges('a').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'bar' },
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
expect(g.outEdges('b')).to.eql([]);
});
it('can return only edges to a specified node', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge('a', 'b', undefined, 'foo');
g.setEdge('a', 'c');
g.setEdge('b', 'c');
g.setEdge('z', 'a');
g.setEdge('z', 'b');
expect(g.outEdges('a', 'b').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
expect(g.outEdges('b', 'a')).to.eql([]);
});
});
describe('nodeEdges', function () {
it('returns undefined for a node that is not in the graph', function () {
expect(g.nodeEdges('a')).to.be.undefined;
});
it('returns all edges that this node points at', function () {
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(g.nodeEdges('a')).to.eql([{ v: 'a', w: 'b' }]);
expect(g.nodeEdges('b').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b' },
{ v: 'b', w: 'c' },
]);
expect(g.nodeEdges('c')).to.eql([{ v: 'b', w: 'c' }]);
});
it('works for multigraphs', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge({ v: 'a', w: 'b', name: 'bar' });
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
expect(g.nodeEdges('a').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'bar' },
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
expect(g.nodeEdges('b').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'bar' },
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
});
it('can return only edges between specific nodes', function () {
var g = new Graph({ multigraph: true });
g.setEdge('a', 'b');
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
g.setEdge('a', 'c');
g.setEdge('b', 'c');
g.setEdge('z', 'a');
g.setEdge('z', 'b');
expect(g.nodeEdges('a', 'b').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
expect(g.nodeEdges('b', 'a').sort(sortEdges)).to.eql([
{ v: 'a', w: 'b', name: 'foo' },
{ v: 'a', w: 'b' },
]);
});
});
});
function sortEdges(a, b) {
if (a.name) {
return a.name.localeCompare(b.name);
}
const order = a.v.localeCompare(b.v);
if (order != 0) {
return order;
}
return a.w.localeCompare(b.w);
}
tbo47-dagre-es-4b95ad0/src/graphlib/index.js 0000664 0000000 0000000 00000000207 15114061606 0020573 0 ustar 00root root 0000000 0000000 // Includes only the "core" of graphlib
import { Graph } from './graph.js';
const version = '2.1.9-pre';
export { Graph, version };
tbo47-dagre-es-4b95ad0/src/graphlib/json.js 0000664 0000000 0000000 00000011001 15114061606 0020427 0 ustar 00root root 0000000 0000000 import * as _ from 'lodash-es';
import { Graph } from './graph.js';
/**
* @import { NodeID, EdgeObj, GraphOptions } from './graph.js';
*/
export { write, read };
/**
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
*
* @typedef {object} GraphJSON
* @property {Required} options - The options used to create the graph.
* @property {Array<{ v: NodeID; value?: NodeLabel; parent?: NodeID }>} nodes - The nodes in the graph.
* @property {Array} edges - The edges in the graph.
* @property {GraphLabel} [value] - The graph's value, if any.
*/
/**
* Creates a JSON representation of the graph that can be serialized to a
* string with
* [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
* The graph can later be restored using {@link read}.
*
* @example
*
* ```js
* var g = new graphlib.Graph();
* g.setNode("a", { label: "node a" });
* g.setNode("b", { label: "node b" });
* g.setEdge("a", "b", { label: "edge a->b" });
* graphlib.json.write(g);
* // Returns the object:
* //
* // {
* // "options": {
* // "directed": true,
* // "multigraph": false,
* // "compound": false
* // },
* // "nodes": [
* // { "v": "a", "value": { "label": "node a" } },
* // { "v": "b", "value": { "label": "node b" } }
* // ],
* // "edges": [
* // { "v": "a", "w": "b", "value": { "label": "edge a->b" } }
* // ]
* // }
* ```
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
* @param {Graph} g - The graph to serialize.
* @returns {GraphJSON} The JSON representation of the graph.
*/
function write(g) {
/** @type {GraphJSON} */
var json = {
options: {
directed: g.isDirected(),
multigraph: g.isMultigraph(),
compound: g.isCompound(),
},
nodes: writeNodes(g),
edges: writeEdges(g),
};
if (!_.isUndefined(g.graph())) {
json.value = _.clone(g.graph());
}
return json;
}
/**
* @template NodeLabel - Label of a node.
*
* @param {Graph} g - The graph to serialize.
* @returns {Array<{ v: NodeID; value?: NodeLabel; parent?: NodeID }>} The nodes in the graph.
*/
function writeNodes(g) {
return _.map(g.nodes(), function (v) {
var nodeValue = g.node(v);
var parent = g.parent(v);
/** @type {{ v: NodeID; value?: NodeLabel; parent?: NodeID }} */
var node = { v: v };
if (!_.isUndefined(nodeValue)) {
node.value = nodeValue;
}
if (!_.isUndefined(parent)) {
node.parent = parent;
}
return node;
});
}
/**
* @template EdgeLabel - Label of a node.
*
* @param {Graph} g - The graph to serialize.
* @returns {Array} The edges in the graph.
*/
function writeEdges(g) {
return _.map(g.edges(), function (e) {
var edgeValue = g.edge(e);
/** @type {EdgeObj & { value?: EdgeLabel }} */
var edge = { v: e.v, w: e.w };
if (!_.isUndefined(e.name)) {
edge.name = e.name;
}
if (!_.isUndefined(edgeValue)) {
edge.value = edgeValue;
}
return edge;
});
}
/**
* Takes JSON as input and returns the graph representation.
*
* @example
*
* For example, if we have serialized the graph in {@link write}
* to a string named `str`, we can restore it to a graph as follows:
*
* ```js
* var g2 = graphlib.json.read(JSON.parse(str));
* // or, in order to copy the graph
* var g3 = graphlib.json.read(graphlib.json.write(g))
*
* g2.nodes();
* // ['a', 'b']
* g2.edges()
* // [ { v: 'a', w: 'b' } ]
* ```
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
* @param {GraphJSON} json - The JSON representation of the graph.
* @returns {Graph} The restored graph.
*/
function read(json) {
var g = new Graph(json.options).setGraph(json.value);
_.each(json.nodes, function (entry) {
g.setNode(entry.v, entry.value);
if (entry.parent) {
g.setParent(entry.v, entry.parent);
}
});
_.each(json.edges, function (entry) {
g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
});
return g;
}
tbo47-dagre-es-4b95ad0/src/graphlib/json.test.js 0000664 0000000 0000000 00000005404 15114061606 0021417 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from './graph.js';
import { read, write } from './json.js';
describe('json', function () {
it('preserves the graph options', function () {
expect(rw(new Graph({ directed: true })).isDirected()).to.be.true;
expect(rw(new Graph({ directed: false })).isDirected()).to.be.false;
expect(rw(new Graph({ multigraph: true })).isMultigraph()).to.be.true;
expect(rw(new Graph({ multigraph: false })).isMultigraph()).to.be.false;
expect(rw(new Graph({ compound: true })).isCompound()).to.be.true;
expect(rw(new Graph({ compound: false })).isCompound()).to.be.false;
});
it('preserves the graph value, if any', function () {
expect(rw(new Graph().setGraph(1)).graph()).equals(1);
expect(rw(new Graph().setGraph({ foo: 'bar' })).graph()).eqls({ foo: 'bar' });
expect(rw(new Graph()).graph()).to.be.undefined;
});
it('preserves nodes', function () {
expect(rw(new Graph().setNode('a')).hasNode('a')).to.be.true;
expect(rw(new Graph().setNode('a')).node('a')).to.be.undefined;
expect(rw(new Graph().setNode('a', 1)).node('a')).equals(1);
expect(rw(new Graph().setNode('a', { foo: 'bar' })).node('a')).eqls({ foo: 'bar' });
});
it('preserves simple edges', function () {
expect(rw(new Graph().setEdge('a', 'b')).hasEdge('a', 'b')).to.be.true;
expect(rw(new Graph().setEdge('a', 'b')).edge('a', 'b')).to.be.undefined;
expect(rw(new Graph().setEdge('a', 'b', 1)).edge('a', 'b')).equals(1);
expect(rw(new Graph().setEdge('a', 'b', { foo: 'bar' })).edge('a', 'b')).eqls({ foo: 'bar' });
});
it('preserves multi-edges', function () {
var g = new Graph({ multigraph: true });
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
expect(rw(g).hasEdge('a', 'b', 'foo')).to.be.true;
g.setEdge({ v: 'a', w: 'b', name: 'foo' });
expect(rw(g).edge('a', 'b', 'foo')).to.be.undefined;
g.setEdge({ v: 'a', w: 'b', name: 'foo' }, 1);
expect(rw(g).edge('a', 'b', 'foo')).equals(1);
g.setEdge({ v: 'a', w: 'b', name: 'foo' }, { foo: 'bar' });
expect(rw(g).edge('a', 'b', 'foo')).eqls({ foo: 'bar' });
});
it('preserves parent / child relationships', function () {
expect(rw(new Graph({ compound: true }).setNode('a')).parent('a')).to.be.undefined;
expect(rw(new Graph({ compound: true }).setParent('a', 'parent')).parent('a')).to.equal(
'parent',
);
});
});
/**
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
* @param {Graph} g - The graph to serialize and deserialize.
* @returns {Graph} Copy of g after write and read.
*/
function rw(g) {
return read(write(g));
}
tbo47-dagre-es-4b95ad0/src/index.js 0000664 0000000 0000000 00000000306 15114061606 0017003 0 ustar 00root root 0000000 0000000 import { render } from './dagre-js/render.js';
import * as graphlib from './graphlib/index.js';
import * as intersect from './dagre-js/intersect/index.js';
export { graphlib, intersect, render };
tbo47-dagre-es-4b95ad0/test/ 0000775 0000000 0000000 00000000000 15114061606 0015527 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/test/graphlib/ 0000775 0000000 0000000 00000000000 15114061606 0017317 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/test/graphlib/alg/ 0000775 0000000 0000000 00000000000 15114061606 0020062 5 ustar 00root root 0000000 0000000 tbo47-dagre-es-4b95ad0/test/graphlib/alg/all-shortest-paths.js 0000664 0000000 0000000 00000007616 15114061606 0024170 0 ustar 00root root 0000000 0000000 import { describe, expect, it } from 'vitest';
import { Graph } from '../../../src/graphlib/graph.js';
/**
* @import { floydWarshall } from '../../../src/graphlib/alg/index.js';
*/
/**
* @param {typeof floydWarshall} sp - The all-shortest-paths function to test.
*/
export function allShortestPathsTests(sp) {
describe('allShortestPaths', function () {
it('returns 0 for the node itself', function () {
var g = new Graph();
g.setNode('a');
expect(sp(g)).to.eql({ a: { a: { distance: 0 } } });
});
it('returns the distance and path from all nodes to other nodes', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(sp(g)).to.eql({
a: {
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: 2, predecessor: 'b' },
},
b: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: 0 },
c: { distance: 1, predecessor: 'b' },
},
c: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: Number.POSITIVE_INFINITY },
c: { distance: 0 },
},
});
});
it('uses an optionally supplied weight function', function () {
var g = new Graph();
g.setEdge('a', 'b', 2);
g.setEdge('b', 'c', 3);
expect(sp(g, weightFn(g))).to.eql({
a: {
a: { distance: 0 },
b: { distance: 2, predecessor: 'a' },
c: { distance: 5, predecessor: 'b' },
},
b: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: 0 },
c: { distance: 3, predecessor: 'b' },
},
c: {
a: { distance: Number.POSITIVE_INFINITY },
b: { distance: Number.POSITIVE_INFINITY },
c: { distance: 0 },
},
});
});
it('uses an optionally supplied incident function', function () {
var g = new Graph();
g.setEdge('a', 'b');
g.setEdge('b', 'c');
expect(
sp(g, undefined, function (v) {
return g.inEdges(v);
}),
).to.eql({
a: {
a: { distance: 0 },
b: { distance: Number.POSITIVE_INFINITY },
c: { distance: Number.POSITIVE_INFINITY },
},
b: {
a: { distance: 1, predecessor: 'b' },
b: { distance: 0 },
c: { distance: Number.POSITIVE_INFINITY },
},
c: {
a: { distance: 2, predecessor: 'b' },
b: { distance: 1, predecessor: 'c' },
c: { distance: 0 },
},
});
});
it('works with undirected graphs', function () {
var g = new Graph({ directed: false });
g.setEdge('a', 'b', 1);
g.setEdge('b', 'c', 2);
g.setEdge('c', 'a', 4);
g.setEdge('b', 'd', 6);
expect(sp(g, weightFn(g), g.nodeEdges.bind(g))).to.eql({
a: {
a: { distance: 0 },
b: { distance: 1, predecessor: 'a' },
c: { distance: 3, predecessor: 'b' },
d: { distance: 7, predecessor: 'b' },
},
b: {
a: { distance: 1, predecessor: 'b' },
b: { distance: 0 },
c: { distance: 2, predecessor: 'b' },
d: { distance: 6, predecessor: 'b' },
},
c: {
a: { distance: 3, predecessor: 'b' },
b: { distance: 2, predecessor: 'c' },
c: { distance: 0 },
d: { distance: 8, predecessor: 'b' },
},
d: {
a: { distance: 7, predecessor: 'b' },
b: { distance: 6, predecessor: 'd' },
c: { distance: 8, predecessor: 'b' },
d: { distance: 0 },
},
});
});
});
}
/**
* @param {Graph} g - The graph to generate a weight function for.
* @returns {Parameters[1]} A weight function for the graph `g`.
*/
function weightFn(g) {
return function (e) {
return g.edge(e);
};
}
tbo47-dagre-es-4b95ad0/tsconfig.build.json 0000664 0000000 0000000 00000000260 15114061606 0020353 0 ustar 00root root 0000000 0000000 {
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"noEmit": false
},
"exclude": ["src/**/*.test.js"]
}
tbo47-dagre-es-4b95ad0/tsconfig.json 0000664 0000000 0000000 00000000305 15114061606 0017255 0 ustar 00root root 0000000 0000000 {
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"lib": ["dom", "dom.iterable", "es2020"],
"skipLibCheck": true,
"module": "node16"
},
"include": ["src/**/*.js"]
}
tbo47-dagre-es-4b95ad0/vite.config.js 0000664 0000000 0000000 00000000230 15114061606 0017314 0 ustar 00root root 0000000 0000000 export default {
test: {
// we can't do `import {it} from "vitest"` due to https://github.com/vitejs/vite/issues/11552
globals: true,
},
};