├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── examples ├── dashboard.ts ├── get-started.ts ├── multi-series.ts └── single.ts ├── package-lock.json ├── package.json ├── src ├── axis.ts ├── enum.ts ├── index.ts ├── label.ts ├── multi-plot.ts ├── plot.ts └── utils.ts ├── tsconfig.json └── tsconfig.lib.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /lib 6 | /tmp 7 | /out 8 | /docs 9 | /out-tsc 10 | # Only exists if Bazel was run 11 | /bazel-out 12 | .angular 13 | 14 | # dependencies 15 | /node_modules 16 | 17 | # profiling files 18 | chrome-profiler-events*.json 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | .history/* 36 | 37 | # misc 38 | /.sass-cache 39 | /connect.lock 40 | /coverage 41 | /libpeerconnection.log 42 | npm-debug.log 43 | yarn-error.log 44 | testem.log 45 | /typings 46 | 47 | # System Files 48 | .DS_Store 49 | Thumbs.db 50 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | examples/ 3 | node_modules/ 4 | src/ 5 | 6 | .gitignore 7 | tsconfig.json 8 | tsconfig.lib.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Alexander 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # text-graph.js 2 | 3 |

4 | animation 5 |

6 | 7 | `text-graph.js` is a compact and easy-to-use JavaScript/TypeScript library. It lets you create charts in the terminal and browser console. You can make line charts and build a dashboard with multiple charts, all without any extarnal dependencies. It has features for different axis and data scaling methods. Plus, it supports adding colors to your charts. 8 | 9 | [![npm version](https://badge.fury.io/js/text-graph.js.svg)](https://badge.fury.io/js/text-graph.js) 10 | 11 | ## Features 12 | 13 | - Create line charts 14 | - Drawing multiple series on one plot 15 | - Creating dashboards with multiple charts 16 | - Colors for chart elements 17 | - Built-in axis scale functions (i.e. log) 18 | - Built-in different data overflow handling functions (i.e. linear scale, clapm, etc) 19 | - Built-in different data compression functions (i.e. mean, max, etc) 20 | 21 | ## Installation 22 | 23 | ```shell 24 | npm install text-graph.js 25 | ``` 26 | 27 | ### Run from source 28 | 29 | ```shell 30 | # clone repo 31 | git clone https://github.com/DrA1ex/text-graph.js.git 32 | cd ./text-graph.js 33 | 34 | # install dependencies 35 | npm install 36 | 37 | # Run example 38 | npx tsx ./examples/dashboard.ts 39 | ``` 40 | 41 | ## Get Started 42 | 43 | ```javascript 44 | // Importing the Plot class 45 | import {Plot} from 'text-graph.js'; 46 | 47 | // Creating a new instance of the Plot class with a width of 80 characters and height of 20 characters 48 | const plot = new Plot(80, 20); 49 | 50 | // Adding a new series to the plot and storing its ID 51 | const id = plot.addSeries(); 52 | 53 | // Defining a function that takes a number "x" as input and calculates a mathematical expression 54 | const fn = (x) => Math.pow(Math.sin(x), 3) + Math.pow(Math.cos(x), 3) - 1.5 * Math.sin(x) * Math.cos(x); 55 | 56 | // Iterating over a range of values from -2 to just below 2, incrementing by 0.05 at each step 57 | for (let x = -2; x < 2; x += 0.05) { 58 | // Adding an entry to the series with the given ID, calculated using the function "fn" 59 | plot.addSeriesEntry(id, fn(x)); 60 | } 61 | 62 | // Printing the chart output to the console 63 | console.log(plot.paint()); 64 | ``` 65 | 66 | Source code: [link](/examples/get-started.ts) 67 | 68 | ## Usage 69 | 70 | To use `text-graph.js`, follow these steps: 71 | 72 | 1. Import the necessary classes and enums: 73 | 74 | ```javascript 75 | import { 76 | Plot, LabelPositionFlags, PlotAxisScale, PlotSeriesAggregationFn, PlotSeriesOverflow, Color, BackgroundColor 77 | } from 'text-graph.js'; 78 | ``` 79 | 80 | 2. Define the plot options: 81 | 82 | ```javascript 83 | const plotOptions = { 84 | showAxis: true, 85 | title: 'Chart Title', 86 | horizontalBoundary: 1, 87 | verticalBoundary: 2, 88 | titlePosition: LabelPositionFlags.top, 89 | titleForeground: Color.blue, 90 | titleBackground: BackgroundColor.black, 91 | axisLabelsFraction: 4, 92 | axisScale: PlotAxisScale.linear, 93 | aggregation: PlotSeriesAggregationFn.mean, 94 | zoom: false, 95 | } 96 | ``` 97 | 98 | 3. Create a plot instance: 99 | 100 | ```javascript 101 | const width = 60; 102 | const height = 20; 103 | const plot = new Plot(width, height, plotOptions); 104 | ``` 105 | 106 | 4. Define the series configurations: 107 | 108 | ```javascript 109 | const plotSeriesConfig1 = { 110 | color: Color.cyan, 111 | overflow: PlotSeriesOverflow.logScale 112 | }; 113 | 114 | const plotSeriesConfig2 = { 115 | color: Color.magenta, 116 | overflow: PlotSeriesOverflow.clamp 117 | }; 118 | ``` 119 | 120 | 5. Add plot series to the plot: 121 | 122 | ```javascript 123 | const seriesId1 = plot.addSeries(plotSeriesConfig1); 124 | const seriesId2 = plot.addSeries(plotSeriesConfig2); 125 | ``` 126 | 127 | 6. Option 1: Iterate over your data and update the plot: 128 | 129 | ```javascript 130 | const data1 = [1, 2, 3]; 131 | for (const value of data1) { 132 | plot.addSeriesEntry(seriesId1, value); 133 | } 134 | 135 | const data2 = [0, -1, -2]; 136 | for (const value of data2) { 137 | plot.addSeriesEntry(seriesId2, value); 138 | } 139 | ``` 140 | 141 | 6. Option 2: Populate all data to the plot: 142 | ```javascript 143 | plot.addSeriesRange(seriesId1, [1, 2, 3]); 144 | plot.addSeriesRange(seriesId2, [0, -1, -2]); 145 | ``` 146 | 147 | 7. Display the plot: 148 | ```javascript 149 | const chartData = plot.paint(); 150 | console.log(chartData); 151 | ``` 152 | 153 | ## Examples 154 | 155 | ### Single Series Chart 156 | 157 | 158 | 159 | Source code: [link](/examples/single.ts) 160 | 161 | ### Multi-line Series Chart 162 | 163 | 164 | 165 | Source code: [link](/examples/multi-series.ts) 166 | 167 | ### Dashboard 168 | 169 | 170 | 171 | Source code: [link](/examples/dashboard.ts) 172 | 173 | ### Neural network training dashboard 174 | 175 | 176 | 177 | Project: [link](https://github.com/DrA1ex/mind-net.js) 178 | 179 | ### Snippets 180 | 181 | #### Fast plot drawing 182 | 183 | ```javascript 184 | const data = new Array(200); 185 | for (let i = 0; i < data.length; i++) { 186 | data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30 187 | } 188 | 189 | console.log(Plot.plot(data)); 190 | ``` 191 | 192 | 193 | 194 | #### Axis scale 195 | 196 | ```javascript 197 | const data = new Array(300); 198 | for (let i = 0; i < data.length; i++) { 199 | data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30 200 | } 201 | 202 | console.log(Plot.plot(data, {axisScale: PlotAxisScale.log})); 203 | ``` 204 | 205 | 206 | 207 | #### Series data zoom 208 | 209 | ```javascript 210 | const data = [1, 2, 3] 211 | console.log(Plot.plot(data, {zoom: true})); 212 | ``` 213 | 214 | 215 | 216 | 217 | #### Series scale on overflow 218 | 219 | ```javascript 220 | const data = new Array(300); 221 | for (let i = 0; i < data.length; i++) { 222 | data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30 223 | } 224 | 225 | console.log(Plot.plot(data, {}, {overflow: PlotSeriesOverflow.logScale})); 226 | ``` 227 | 228 | 229 | 230 | #### Series color 231 | 232 | ```javascript 233 | const data = new Array(300); 234 | for (let i = 0; i < data.length; i++) { 235 | data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30 236 | } 237 | 238 | console.log(Plot.plot(data, {}, {color: Color.green})); 239 | ``` 240 | 241 | 242 | 243 | #### Different height 244 | 245 | ```javascript 246 | const data = new Array(200); 247 | for (let i = 0; i < data.length; i++) { 248 | data[i] = Math.sin(0.3 * i) * Math.cos(0.6 * i) - Math.sin(i * Math.PI / 50) * Math.abs(i - 100) / 30 249 | } 250 | 251 | console.log(Plot.plot(data, {height: 5})); 252 | ``` 253 | 254 | 255 | 256 | 257 | ## License 258 | 259 | `text-graph.js` is released under the [BSD-3-Clause License](/LICENSE). 260 | -------------------------------------------------------------------------------- /examples/dashboard.ts: -------------------------------------------------------------------------------- 1 | import {Color, BackgroundColor, MultiPlotChart, PlotAxisScale, PlotSeriesAggregationFn, PlotSeriesOverflow} from "../src"; 2 | 3 | const chart = new MultiPlotChart({ 4 | title: "Dashboard chart", 5 | titleBoundary: 2, 6 | titleSpacing: 8, 7 | titleForeground: Color.blue, 8 | titleBackground: BackgroundColor.black, 9 | }); 10 | 11 | chart.addPlot({xOffset: 0, yOffset: 0, width: 40, height: 31}, { 12 | title: "overflow: skip", 13 | }); 14 | 15 | chart.addPlot({xOffset: 42, yOffset: 0, width: 60, height: 15}, { 16 | title: "overflow: logScale (agg: max)", 17 | axisScale: PlotAxisScale.log, 18 | }); 19 | 20 | chart.addPlot({xOffset: 42, yOffset: 16, width: 60, height: 15}, { 21 | title: "overflow: linearScale (agg: mean)", 22 | axisScale: PlotAxisScale.logInverted, 23 | aggregation: PlotSeriesAggregationFn.mean 24 | }); 25 | 26 | chart.addPlotSeries(0, {color: Color.red, overflow: PlotSeriesOverflow.clamp}); 27 | chart.addPlotSeries(1, {color: Color.blue, overflow: PlotSeriesOverflow.linearScale}); 28 | chart.addPlotSeries(2, {color: Color.yellow}); 29 | 30 | let delay = 66; // Delay in milliseconds 31 | 32 | for (let i = 0; i < 2000; i++) { 33 | setTimeout(() => { 34 | chart.addSeriesEntry(0, 0, Math.cos(i * Math.PI / 15)); 35 | chart.addSeriesEntry(1, 0, Math.sin(i * Math.PI / 30) * 100 + 2); 36 | chart.addSeriesEntry(2, 0, Math.cos(i * Math.PI / 30) * 100 + 2); 37 | 38 | const chartData = chart.paint(); 39 | console.clear(); 40 | console.log(chartData); 41 | }, delay * i); 42 | } -------------------------------------------------------------------------------- /examples/get-started.ts: -------------------------------------------------------------------------------- 1 | // Importing the Plot class 2 | import {Plot} from "../src"; 3 | 4 | // Creating a new instance of the Plot class with a width of 80 characters and height of 20 characters 5 | const plot = new Plot(80, 20); 6 | 7 | // Adding a new series to the plot and storing its ID 8 | const id = plot.addSeries(); 9 | 10 | // Defining a function that takes a number "x" as input and calculates a mathematical expression 11 | const fn = (x: number) => Math.pow(Math.sin(x), 3) + Math.pow(Math.cos(x), 3) - 1.5 * Math.sin(x) * Math.cos(x); 12 | 13 | // Iterating over a range of values from -2 to just below 2, incrementing by 0.05 at each step 14 | for (let x = -2; x < 2; x += 0.05) { 15 | // Adding an entry to the series with the given ID, calculated using the function "fn" 16 | plot.addSeriesEntry(id, fn(x)); 17 | } 18 | 19 | // Printing the chart output to the console 20 | console.log(plot.paint()); -------------------------------------------------------------------------------- /examples/multi-series.ts: -------------------------------------------------------------------------------- 1 | import {Plot, Color, PlotAxisScale, PlotSeriesAggregationFn, PlotSeriesOverflow, LabelPositionFlags} from "../src"; 2 | 3 | const plotOptions = { 4 | showAxis: true, // Show vertical axis 5 | title: "Multi-Series Demo", // Title of the chart 6 | titlePosition: LabelPositionFlags.top, // Position of the title 7 | axisScale: PlotAxisScale.linear, // Scale of the axis 8 | aggregation: PlotSeriesAggregationFn.mean, // Aggregation type for data points 9 | }; 10 | 11 | const plot = new Plot(80, 20, plotOptions); 12 | 13 | const scale = PlotSeriesOverflow.linearScale // Overflow behavior of the series 14 | const seriesConfig1 = { 15 | color: Color.red, // Color of the first series 16 | overflow: scale 17 | }; 18 | 19 | const seriesConfig2 = { 20 | color: Color.green, // Color of the second series 21 | overflow: scale 22 | }; 23 | 24 | const seriesConfig3 = { 25 | color: Color.cyan, // Color of the third series 26 | overflow: scale 27 | }; 28 | 29 | const seriesId1 = plot.addSeries(seriesConfig1); 30 | const seriesId2 = plot.addSeries(seriesConfig2); 31 | const seriesId3 = plot.addSeries(seriesConfig3); 32 | 33 | const fn1 = (x: number) => Math.sin(x) * Math.exp(-0.1 * x); 34 | const fn2 = (x: number) => 0.8 * Math.sin(x) + 0.6 * Math.sin(2 * x) + 0.4 * Math.sin(3 * x); 35 | const fn3 = (x: number) => Math.sin(x) * Math.cos(2 * x) + Math.cos(x) * Math.sin(2 * x); 36 | 37 | const delay = 66; 38 | 39 | async function draw() { 40 | for (let x = -2; x <= 2; x += 0.03) { 41 | plot.addSeriesEntry(seriesId1, fn1(x)); 42 | plot.addSeriesEntry(seriesId2, fn2(x)); 43 | plot.addSeriesEntry(seriesId3, fn3(x)); 44 | 45 | const chartData = plot.paint(); 46 | console.clear(); 47 | console.log(chartData); 48 | 49 | await _delay(delay); 50 | } 51 | } 52 | 53 | // Start animated drawing 54 | draw(); 55 | 56 | // Auxiliary function to avoid setTimeout in loop 57 | function _delay(d: number) { return new Promise(resolve => setTimeout(resolve, d))} -------------------------------------------------------------------------------- /examples/single.ts: -------------------------------------------------------------------------------- 1 | import {Plot, Color, PlotAxisScale, PlotSeriesAggregationFn, PlotSeriesOverflow, LabelPositionFlags} from "../src"; 2 | 3 | // Define the plot options 4 | const plotOptions = { 5 | showAxis: true, 6 | horizontalBoundary: 0, 7 | verticalBoundary: 1, 8 | title: 'Sample Line Chart', 9 | titlePosition: LabelPositionFlags.top, 10 | axisScale: PlotAxisScale.linear, 11 | aggregation: PlotSeriesAggregationFn.skip, 12 | }; 13 | 14 | // Add a plot to the chart 15 | const plot = new Plot(80, 20, plotOptions); 16 | 17 | // Define the series configuration 18 | const seriesConfig = { 19 | color: Color.yellow, 20 | overflow: PlotSeriesOverflow.linearScale, 21 | }; 22 | 23 | // Add new plot series 24 | const seriesId = plot.addSeries(seriesConfig); 25 | 26 | // Define function 27 | const fn = (x: number) => -Math.pow(x, 2) + plot.width * x; 28 | 29 | // Add data entries to the series 30 | for (let i = 0; i <= plot.width; i++) { 31 | plot.addSeriesEntry(seriesId, fn(i)); 32 | } 33 | 34 | // Generate and print the chart data 35 | const chartData = plot.paint(); 36 | console.log(chartData); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "text-graph.js", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "text-graph.js", 8 | "license": "BSD 3-Clause", 9 | "devDependencies": { 10 | "esbuild": "^0.19.3", 11 | "ts-loader": "^9.4.4", 12 | "tsx": "^3.12.7", 13 | "typescript": "^5.1.6" 14 | }, 15 | "version": "1.1.2" 16 | }, 17 | "node_modules/@esbuild-kit/cjs-loader": { 18 | "version": "2.4.2", 19 | "resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz", 20 | "integrity": "sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==", 21 | "dev": true, 22 | "dependencies": { 23 | "@esbuild-kit/core-utils": "^3.0.0", 24 | "get-tsconfig": "^4.4.0" 25 | } 26 | }, 27 | "node_modules/@esbuild-kit/core-utils": { 28 | "version": "3.1.0", 29 | "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", 30 | "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", 31 | "dev": true, 32 | "dependencies": { 33 | "esbuild": "~0.17.6", 34 | "source-map-support": "^0.5.21" 35 | } 36 | }, 37 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { 38 | "version": "0.17.19", 39 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 40 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 41 | "cpu": [ 42 | "arm" 43 | ], 44 | "dev": true, 45 | "optional": true, 46 | "os": [ 47 | "android" 48 | ], 49 | "engines": { 50 | "node": ">=12" 51 | } 52 | }, 53 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { 54 | "version": "0.17.19", 55 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 56 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 57 | "cpu": [ 58 | "arm64" 59 | ], 60 | "dev": true, 61 | "optional": true, 62 | "os": [ 63 | "android" 64 | ], 65 | "engines": { 66 | "node": ">=12" 67 | } 68 | }, 69 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { 70 | "version": "0.17.19", 71 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 72 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 73 | "cpu": [ 74 | "x64" 75 | ], 76 | "dev": true, 77 | "optional": true, 78 | "os": [ 79 | "android" 80 | ], 81 | "engines": { 82 | "node": ">=12" 83 | } 84 | }, 85 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { 86 | "version": "0.17.19", 87 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 88 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 89 | "cpu": [ 90 | "arm64" 91 | ], 92 | "dev": true, 93 | "optional": true, 94 | "os": [ 95 | "darwin" 96 | ], 97 | "engines": { 98 | "node": ">=12" 99 | } 100 | }, 101 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { 102 | "version": "0.17.19", 103 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 104 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 105 | "cpu": [ 106 | "x64" 107 | ], 108 | "dev": true, 109 | "optional": true, 110 | "os": [ 111 | "darwin" 112 | ], 113 | "engines": { 114 | "node": ">=12" 115 | } 116 | }, 117 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { 118 | "version": "0.17.19", 119 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 120 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 121 | "cpu": [ 122 | "arm64" 123 | ], 124 | "dev": true, 125 | "optional": true, 126 | "os": [ 127 | "freebsd" 128 | ], 129 | "engines": { 130 | "node": ">=12" 131 | } 132 | }, 133 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { 134 | "version": "0.17.19", 135 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 136 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 137 | "cpu": [ 138 | "x64" 139 | ], 140 | "dev": true, 141 | "optional": true, 142 | "os": [ 143 | "freebsd" 144 | ], 145 | "engines": { 146 | "node": ">=12" 147 | } 148 | }, 149 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { 150 | "version": "0.17.19", 151 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 152 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 153 | "cpu": [ 154 | "arm" 155 | ], 156 | "dev": true, 157 | "optional": true, 158 | "os": [ 159 | "linux" 160 | ], 161 | "engines": { 162 | "node": ">=12" 163 | } 164 | }, 165 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { 166 | "version": "0.17.19", 167 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 168 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 169 | "cpu": [ 170 | "arm64" 171 | ], 172 | "dev": true, 173 | "optional": true, 174 | "os": [ 175 | "linux" 176 | ], 177 | "engines": { 178 | "node": ">=12" 179 | } 180 | }, 181 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { 182 | "version": "0.17.19", 183 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 184 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 185 | "cpu": [ 186 | "ia32" 187 | ], 188 | "dev": true, 189 | "optional": true, 190 | "os": [ 191 | "linux" 192 | ], 193 | "engines": { 194 | "node": ">=12" 195 | } 196 | }, 197 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { 198 | "version": "0.17.19", 199 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 200 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 201 | "cpu": [ 202 | "loong64" 203 | ], 204 | "dev": true, 205 | "optional": true, 206 | "os": [ 207 | "linux" 208 | ], 209 | "engines": { 210 | "node": ">=12" 211 | } 212 | }, 213 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { 214 | "version": "0.17.19", 215 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 216 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 217 | "cpu": [ 218 | "mips64el" 219 | ], 220 | "dev": true, 221 | "optional": true, 222 | "os": [ 223 | "linux" 224 | ], 225 | "engines": { 226 | "node": ">=12" 227 | } 228 | }, 229 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { 230 | "version": "0.17.19", 231 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 232 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 233 | "cpu": [ 234 | "ppc64" 235 | ], 236 | "dev": true, 237 | "optional": true, 238 | "os": [ 239 | "linux" 240 | ], 241 | "engines": { 242 | "node": ">=12" 243 | } 244 | }, 245 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { 246 | "version": "0.17.19", 247 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 248 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 249 | "cpu": [ 250 | "riscv64" 251 | ], 252 | "dev": true, 253 | "optional": true, 254 | "os": [ 255 | "linux" 256 | ], 257 | "engines": { 258 | "node": ">=12" 259 | } 260 | }, 261 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { 262 | "version": "0.17.19", 263 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 264 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 265 | "cpu": [ 266 | "s390x" 267 | ], 268 | "dev": true, 269 | "optional": true, 270 | "os": [ 271 | "linux" 272 | ], 273 | "engines": { 274 | "node": ">=12" 275 | } 276 | }, 277 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { 278 | "version": "0.17.19", 279 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 280 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 281 | "cpu": [ 282 | "x64" 283 | ], 284 | "dev": true, 285 | "optional": true, 286 | "os": [ 287 | "linux" 288 | ], 289 | "engines": { 290 | "node": ">=12" 291 | } 292 | }, 293 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { 294 | "version": "0.17.19", 295 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 296 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 297 | "cpu": [ 298 | "x64" 299 | ], 300 | "dev": true, 301 | "optional": true, 302 | "os": [ 303 | "netbsd" 304 | ], 305 | "engines": { 306 | "node": ">=12" 307 | } 308 | }, 309 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { 310 | "version": "0.17.19", 311 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 312 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 313 | "cpu": [ 314 | "x64" 315 | ], 316 | "dev": true, 317 | "optional": true, 318 | "os": [ 319 | "openbsd" 320 | ], 321 | "engines": { 322 | "node": ">=12" 323 | } 324 | }, 325 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { 326 | "version": "0.17.19", 327 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 328 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 329 | "cpu": [ 330 | "x64" 331 | ], 332 | "dev": true, 333 | "optional": true, 334 | "os": [ 335 | "sunos" 336 | ], 337 | "engines": { 338 | "node": ">=12" 339 | } 340 | }, 341 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { 342 | "version": "0.17.19", 343 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 344 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 345 | "cpu": [ 346 | "arm64" 347 | ], 348 | "dev": true, 349 | "optional": true, 350 | "os": [ 351 | "win32" 352 | ], 353 | "engines": { 354 | "node": ">=12" 355 | } 356 | }, 357 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { 358 | "version": "0.17.19", 359 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 360 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 361 | "cpu": [ 362 | "ia32" 363 | ], 364 | "dev": true, 365 | "optional": true, 366 | "os": [ 367 | "win32" 368 | ], 369 | "engines": { 370 | "node": ">=12" 371 | } 372 | }, 373 | "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { 374 | "version": "0.17.19", 375 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 376 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 377 | "cpu": [ 378 | "x64" 379 | ], 380 | "dev": true, 381 | "optional": true, 382 | "os": [ 383 | "win32" 384 | ], 385 | "engines": { 386 | "node": ">=12" 387 | } 388 | }, 389 | "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { 390 | "version": "0.17.19", 391 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 392 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 393 | "dev": true, 394 | "hasInstallScript": true, 395 | "bin": { 396 | "esbuild": "bin/esbuild" 397 | }, 398 | "engines": { 399 | "node": ">=12" 400 | }, 401 | "optionalDependencies": { 402 | "@esbuild/android-arm": "0.17.19", 403 | "@esbuild/android-arm64": "0.17.19", 404 | "@esbuild/android-x64": "0.17.19", 405 | "@esbuild/darwin-arm64": "0.17.19", 406 | "@esbuild/darwin-x64": "0.17.19", 407 | "@esbuild/freebsd-arm64": "0.17.19", 408 | "@esbuild/freebsd-x64": "0.17.19", 409 | "@esbuild/linux-arm": "0.17.19", 410 | "@esbuild/linux-arm64": "0.17.19", 411 | "@esbuild/linux-ia32": "0.17.19", 412 | "@esbuild/linux-loong64": "0.17.19", 413 | "@esbuild/linux-mips64el": "0.17.19", 414 | "@esbuild/linux-ppc64": "0.17.19", 415 | "@esbuild/linux-riscv64": "0.17.19", 416 | "@esbuild/linux-s390x": "0.17.19", 417 | "@esbuild/linux-x64": "0.17.19", 418 | "@esbuild/netbsd-x64": "0.17.19", 419 | "@esbuild/openbsd-x64": "0.17.19", 420 | "@esbuild/sunos-x64": "0.17.19", 421 | "@esbuild/win32-arm64": "0.17.19", 422 | "@esbuild/win32-ia32": "0.17.19", 423 | "@esbuild/win32-x64": "0.17.19" 424 | } 425 | }, 426 | "node_modules/@esbuild-kit/esm-loader": { 427 | "version": "2.5.5", 428 | "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", 429 | "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", 430 | "dev": true, 431 | "dependencies": { 432 | "@esbuild-kit/core-utils": "^3.0.0", 433 | "get-tsconfig": "^4.4.0" 434 | } 435 | }, 436 | "node_modules/@esbuild/android-arm": { 437 | "version": "0.19.3", 438 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz", 439 | "integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==", 440 | "cpu": [ 441 | "arm" 442 | ], 443 | "dev": true, 444 | "optional": true, 445 | "os": [ 446 | "android" 447 | ], 448 | "engines": { 449 | "node": ">=12" 450 | } 451 | }, 452 | "node_modules/@esbuild/android-arm64": { 453 | "version": "0.19.3", 454 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz", 455 | "integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==", 456 | "cpu": [ 457 | "arm64" 458 | ], 459 | "dev": true, 460 | "optional": true, 461 | "os": [ 462 | "android" 463 | ], 464 | "engines": { 465 | "node": ">=12" 466 | } 467 | }, 468 | "node_modules/@esbuild/android-x64": { 469 | "version": "0.19.3", 470 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz", 471 | "integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==", 472 | "cpu": [ 473 | "x64" 474 | ], 475 | "dev": true, 476 | "optional": true, 477 | "os": [ 478 | "android" 479 | ], 480 | "engines": { 481 | "node": ">=12" 482 | } 483 | }, 484 | "node_modules/@esbuild/darwin-arm64": { 485 | "version": "0.19.3", 486 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz", 487 | "integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==", 488 | "cpu": [ 489 | "arm64" 490 | ], 491 | "dev": true, 492 | "optional": true, 493 | "os": [ 494 | "darwin" 495 | ], 496 | "engines": { 497 | "node": ">=12" 498 | } 499 | }, 500 | "node_modules/@esbuild/darwin-x64": { 501 | "version": "0.19.3", 502 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz", 503 | "integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==", 504 | "cpu": [ 505 | "x64" 506 | ], 507 | "dev": true, 508 | "optional": true, 509 | "os": [ 510 | "darwin" 511 | ], 512 | "engines": { 513 | "node": ">=12" 514 | } 515 | }, 516 | "node_modules/@esbuild/freebsd-arm64": { 517 | "version": "0.19.3", 518 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz", 519 | "integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==", 520 | "cpu": [ 521 | "arm64" 522 | ], 523 | "dev": true, 524 | "optional": true, 525 | "os": [ 526 | "freebsd" 527 | ], 528 | "engines": { 529 | "node": ">=12" 530 | } 531 | }, 532 | "node_modules/@esbuild/freebsd-x64": { 533 | "version": "0.19.3", 534 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz", 535 | "integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==", 536 | "cpu": [ 537 | "x64" 538 | ], 539 | "dev": true, 540 | "optional": true, 541 | "os": [ 542 | "freebsd" 543 | ], 544 | "engines": { 545 | "node": ">=12" 546 | } 547 | }, 548 | "node_modules/@esbuild/linux-arm": { 549 | "version": "0.19.3", 550 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz", 551 | "integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==", 552 | "cpu": [ 553 | "arm" 554 | ], 555 | "dev": true, 556 | "optional": true, 557 | "os": [ 558 | "linux" 559 | ], 560 | "engines": { 561 | "node": ">=12" 562 | } 563 | }, 564 | "node_modules/@esbuild/linux-arm64": { 565 | "version": "0.19.3", 566 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz", 567 | "integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==", 568 | "cpu": [ 569 | "arm64" 570 | ], 571 | "dev": true, 572 | "optional": true, 573 | "os": [ 574 | "linux" 575 | ], 576 | "engines": { 577 | "node": ">=12" 578 | } 579 | }, 580 | "node_modules/@esbuild/linux-ia32": { 581 | "version": "0.19.3", 582 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz", 583 | "integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==", 584 | "cpu": [ 585 | "ia32" 586 | ], 587 | "dev": true, 588 | "optional": true, 589 | "os": [ 590 | "linux" 591 | ], 592 | "engines": { 593 | "node": ">=12" 594 | } 595 | }, 596 | "node_modules/@esbuild/linux-loong64": { 597 | "version": "0.19.3", 598 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz", 599 | "integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==", 600 | "cpu": [ 601 | "loong64" 602 | ], 603 | "dev": true, 604 | "optional": true, 605 | "os": [ 606 | "linux" 607 | ], 608 | "engines": { 609 | "node": ">=12" 610 | } 611 | }, 612 | "node_modules/@esbuild/linux-mips64el": { 613 | "version": "0.19.3", 614 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz", 615 | "integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==", 616 | "cpu": [ 617 | "mips64el" 618 | ], 619 | "dev": true, 620 | "optional": true, 621 | "os": [ 622 | "linux" 623 | ], 624 | "engines": { 625 | "node": ">=12" 626 | } 627 | }, 628 | "node_modules/@esbuild/linux-ppc64": { 629 | "version": "0.19.3", 630 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz", 631 | "integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==", 632 | "cpu": [ 633 | "ppc64" 634 | ], 635 | "dev": true, 636 | "optional": true, 637 | "os": [ 638 | "linux" 639 | ], 640 | "engines": { 641 | "node": ">=12" 642 | } 643 | }, 644 | "node_modules/@esbuild/linux-riscv64": { 645 | "version": "0.19.3", 646 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz", 647 | "integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==", 648 | "cpu": [ 649 | "riscv64" 650 | ], 651 | "dev": true, 652 | "optional": true, 653 | "os": [ 654 | "linux" 655 | ], 656 | "engines": { 657 | "node": ">=12" 658 | } 659 | }, 660 | "node_modules/@esbuild/linux-s390x": { 661 | "version": "0.19.3", 662 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz", 663 | "integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==", 664 | "cpu": [ 665 | "s390x" 666 | ], 667 | "dev": true, 668 | "optional": true, 669 | "os": [ 670 | "linux" 671 | ], 672 | "engines": { 673 | "node": ">=12" 674 | } 675 | }, 676 | "node_modules/@esbuild/linux-x64": { 677 | "version": "0.19.3", 678 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz", 679 | "integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==", 680 | "cpu": [ 681 | "x64" 682 | ], 683 | "dev": true, 684 | "optional": true, 685 | "os": [ 686 | "linux" 687 | ], 688 | "engines": { 689 | "node": ">=12" 690 | } 691 | }, 692 | "node_modules/@esbuild/netbsd-x64": { 693 | "version": "0.19.3", 694 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz", 695 | "integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==", 696 | "cpu": [ 697 | "x64" 698 | ], 699 | "dev": true, 700 | "optional": true, 701 | "os": [ 702 | "netbsd" 703 | ], 704 | "engines": { 705 | "node": ">=12" 706 | } 707 | }, 708 | "node_modules/@esbuild/openbsd-x64": { 709 | "version": "0.19.3", 710 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz", 711 | "integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==", 712 | "cpu": [ 713 | "x64" 714 | ], 715 | "dev": true, 716 | "optional": true, 717 | "os": [ 718 | "openbsd" 719 | ], 720 | "engines": { 721 | "node": ">=12" 722 | } 723 | }, 724 | "node_modules/@esbuild/sunos-x64": { 725 | "version": "0.19.3", 726 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz", 727 | "integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==", 728 | "cpu": [ 729 | "x64" 730 | ], 731 | "dev": true, 732 | "optional": true, 733 | "os": [ 734 | "sunos" 735 | ], 736 | "engines": { 737 | "node": ">=12" 738 | } 739 | }, 740 | "node_modules/@esbuild/win32-arm64": { 741 | "version": "0.19.3", 742 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz", 743 | "integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==", 744 | "cpu": [ 745 | "arm64" 746 | ], 747 | "dev": true, 748 | "optional": true, 749 | "os": [ 750 | "win32" 751 | ], 752 | "engines": { 753 | "node": ">=12" 754 | } 755 | }, 756 | "node_modules/@esbuild/win32-ia32": { 757 | "version": "0.19.3", 758 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz", 759 | "integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==", 760 | "cpu": [ 761 | "ia32" 762 | ], 763 | "dev": true, 764 | "optional": true, 765 | "os": [ 766 | "win32" 767 | ], 768 | "engines": { 769 | "node": ">=12" 770 | } 771 | }, 772 | "node_modules/@esbuild/win32-x64": { 773 | "version": "0.19.3", 774 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz", 775 | "integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==", 776 | "cpu": [ 777 | "x64" 778 | ], 779 | "dev": true, 780 | "optional": true, 781 | "os": [ 782 | "win32" 783 | ], 784 | "engines": { 785 | "node": ">=12" 786 | } 787 | }, 788 | "node_modules/@jridgewell/gen-mapping": { 789 | "version": "0.3.3", 790 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 791 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 792 | "dev": true, 793 | "peer": true, 794 | "dependencies": { 795 | "@jridgewell/set-array": "^1.0.1", 796 | "@jridgewell/sourcemap-codec": "^1.4.10", 797 | "@jridgewell/trace-mapping": "^0.3.9" 798 | }, 799 | "engines": { 800 | "node": ">=6.0.0" 801 | } 802 | }, 803 | "node_modules/@jridgewell/resolve-uri": { 804 | "version": "3.1.1", 805 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 806 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 807 | "dev": true, 808 | "peer": true, 809 | "engines": { 810 | "node": ">=6.0.0" 811 | } 812 | }, 813 | "node_modules/@jridgewell/set-array": { 814 | "version": "1.1.2", 815 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 816 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 817 | "dev": true, 818 | "peer": true, 819 | "engines": { 820 | "node": ">=6.0.0" 821 | } 822 | }, 823 | "node_modules/@jridgewell/source-map": { 824 | "version": "0.3.5", 825 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", 826 | "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", 827 | "dev": true, 828 | "peer": true, 829 | "dependencies": { 830 | "@jridgewell/gen-mapping": "^0.3.0", 831 | "@jridgewell/trace-mapping": "^0.3.9" 832 | } 833 | }, 834 | "node_modules/@jridgewell/sourcemap-codec": { 835 | "version": "1.4.15", 836 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 837 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 838 | "dev": true, 839 | "peer": true 840 | }, 841 | "node_modules/@jridgewell/trace-mapping": { 842 | "version": "0.3.19", 843 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 844 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 845 | "dev": true, 846 | "peer": true, 847 | "dependencies": { 848 | "@jridgewell/resolve-uri": "^3.1.0", 849 | "@jridgewell/sourcemap-codec": "^1.4.14" 850 | } 851 | }, 852 | "node_modules/@types/eslint": { 853 | "version": "8.44.2", 854 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", 855 | "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", 856 | "dev": true, 857 | "peer": true, 858 | "dependencies": { 859 | "@types/estree": "*", 860 | "@types/json-schema": "*" 861 | } 862 | }, 863 | "node_modules/@types/eslint-scope": { 864 | "version": "3.7.4", 865 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", 866 | "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", 867 | "dev": true, 868 | "peer": true, 869 | "dependencies": { 870 | "@types/eslint": "*", 871 | "@types/estree": "*" 872 | } 873 | }, 874 | "node_modules/@types/estree": { 875 | "version": "1.0.1", 876 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", 877 | "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", 878 | "dev": true, 879 | "peer": true 880 | }, 881 | "node_modules/@types/json-schema": { 882 | "version": "7.0.12", 883 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", 884 | "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", 885 | "dev": true, 886 | "peer": true 887 | }, 888 | "node_modules/@types/node": { 889 | "version": "20.4.9", 890 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.9.tgz", 891 | "integrity": "sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ==", 892 | "dev": true, 893 | "peer": true 894 | }, 895 | "node_modules/@webassemblyjs/ast": { 896 | "version": "1.11.6", 897 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", 898 | "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", 899 | "dev": true, 900 | "peer": true, 901 | "dependencies": { 902 | "@webassemblyjs/helper-numbers": "1.11.6", 903 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6" 904 | } 905 | }, 906 | "node_modules/@webassemblyjs/floating-point-hex-parser": { 907 | "version": "1.11.6", 908 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", 909 | "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", 910 | "dev": true, 911 | "peer": true 912 | }, 913 | "node_modules/@webassemblyjs/helper-api-error": { 914 | "version": "1.11.6", 915 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", 916 | "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", 917 | "dev": true, 918 | "peer": true 919 | }, 920 | "node_modules/@webassemblyjs/helper-buffer": { 921 | "version": "1.11.6", 922 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", 923 | "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", 924 | "dev": true, 925 | "peer": true 926 | }, 927 | "node_modules/@webassemblyjs/helper-numbers": { 928 | "version": "1.11.6", 929 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", 930 | "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", 931 | "dev": true, 932 | "peer": true, 933 | "dependencies": { 934 | "@webassemblyjs/floating-point-hex-parser": "1.11.6", 935 | "@webassemblyjs/helper-api-error": "1.11.6", 936 | "@xtuc/long": "4.2.2" 937 | } 938 | }, 939 | "node_modules/@webassemblyjs/helper-wasm-bytecode": { 940 | "version": "1.11.6", 941 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", 942 | "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", 943 | "dev": true, 944 | "peer": true 945 | }, 946 | "node_modules/@webassemblyjs/helper-wasm-section": { 947 | "version": "1.11.6", 948 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", 949 | "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", 950 | "dev": true, 951 | "peer": true, 952 | "dependencies": { 953 | "@webassemblyjs/ast": "1.11.6", 954 | "@webassemblyjs/helper-buffer": "1.11.6", 955 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6", 956 | "@webassemblyjs/wasm-gen": "1.11.6" 957 | } 958 | }, 959 | "node_modules/@webassemblyjs/ieee754": { 960 | "version": "1.11.6", 961 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", 962 | "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", 963 | "dev": true, 964 | "peer": true, 965 | "dependencies": { 966 | "@xtuc/ieee754": "^1.2.0" 967 | } 968 | }, 969 | "node_modules/@webassemblyjs/leb128": { 970 | "version": "1.11.6", 971 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", 972 | "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", 973 | "dev": true, 974 | "peer": true, 975 | "dependencies": { 976 | "@xtuc/long": "4.2.2" 977 | } 978 | }, 979 | "node_modules/@webassemblyjs/utf8": { 980 | "version": "1.11.6", 981 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", 982 | "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", 983 | "dev": true, 984 | "peer": true 985 | }, 986 | "node_modules/@webassemblyjs/wasm-edit": { 987 | "version": "1.11.6", 988 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", 989 | "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", 990 | "dev": true, 991 | "peer": true, 992 | "dependencies": { 993 | "@webassemblyjs/ast": "1.11.6", 994 | "@webassemblyjs/helper-buffer": "1.11.6", 995 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6", 996 | "@webassemblyjs/helper-wasm-section": "1.11.6", 997 | "@webassemblyjs/wasm-gen": "1.11.6", 998 | "@webassemblyjs/wasm-opt": "1.11.6", 999 | "@webassemblyjs/wasm-parser": "1.11.6", 1000 | "@webassemblyjs/wast-printer": "1.11.6" 1001 | } 1002 | }, 1003 | "node_modules/@webassemblyjs/wasm-gen": { 1004 | "version": "1.11.6", 1005 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", 1006 | "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", 1007 | "dev": true, 1008 | "peer": true, 1009 | "dependencies": { 1010 | "@webassemblyjs/ast": "1.11.6", 1011 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6", 1012 | "@webassemblyjs/ieee754": "1.11.6", 1013 | "@webassemblyjs/leb128": "1.11.6", 1014 | "@webassemblyjs/utf8": "1.11.6" 1015 | } 1016 | }, 1017 | "node_modules/@webassemblyjs/wasm-opt": { 1018 | "version": "1.11.6", 1019 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", 1020 | "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", 1021 | "dev": true, 1022 | "peer": true, 1023 | "dependencies": { 1024 | "@webassemblyjs/ast": "1.11.6", 1025 | "@webassemblyjs/helper-buffer": "1.11.6", 1026 | "@webassemblyjs/wasm-gen": "1.11.6", 1027 | "@webassemblyjs/wasm-parser": "1.11.6" 1028 | } 1029 | }, 1030 | "node_modules/@webassemblyjs/wasm-parser": { 1031 | "version": "1.11.6", 1032 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", 1033 | "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", 1034 | "dev": true, 1035 | "peer": true, 1036 | "dependencies": { 1037 | "@webassemblyjs/ast": "1.11.6", 1038 | "@webassemblyjs/helper-api-error": "1.11.6", 1039 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6", 1040 | "@webassemblyjs/ieee754": "1.11.6", 1041 | "@webassemblyjs/leb128": "1.11.6", 1042 | "@webassemblyjs/utf8": "1.11.6" 1043 | } 1044 | }, 1045 | "node_modules/@webassemblyjs/wast-printer": { 1046 | "version": "1.11.6", 1047 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", 1048 | "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", 1049 | "dev": true, 1050 | "peer": true, 1051 | "dependencies": { 1052 | "@webassemblyjs/ast": "1.11.6", 1053 | "@xtuc/long": "4.2.2" 1054 | } 1055 | }, 1056 | "node_modules/@xtuc/ieee754": { 1057 | "version": "1.2.0", 1058 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", 1059 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", 1060 | "dev": true, 1061 | "peer": true 1062 | }, 1063 | "node_modules/@xtuc/long": { 1064 | "version": "4.2.2", 1065 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", 1066 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", 1067 | "dev": true, 1068 | "peer": true 1069 | }, 1070 | "node_modules/acorn": { 1071 | "version": "8.10.0", 1072 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 1073 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 1074 | "dev": true, 1075 | "peer": true, 1076 | "bin": { 1077 | "acorn": "bin/acorn" 1078 | }, 1079 | "engines": { 1080 | "node": ">=0.4.0" 1081 | } 1082 | }, 1083 | "node_modules/acorn-import-assertions": { 1084 | "version": "1.9.0", 1085 | "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", 1086 | "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", 1087 | "dev": true, 1088 | "peer": true, 1089 | "peerDependencies": { 1090 | "acorn": "^8" 1091 | } 1092 | }, 1093 | "node_modules/ajv": { 1094 | "version": "6.12.6", 1095 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1096 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1097 | "dev": true, 1098 | "peer": true, 1099 | "dependencies": { 1100 | "fast-deep-equal": "^3.1.1", 1101 | "fast-json-stable-stringify": "^2.0.0", 1102 | "json-schema-traverse": "^0.4.1", 1103 | "uri-js": "^4.2.2" 1104 | }, 1105 | "funding": { 1106 | "type": "github", 1107 | "url": "https://github.com/sponsors/epoberezkin" 1108 | } 1109 | }, 1110 | "node_modules/ajv-keywords": { 1111 | "version": "3.5.2", 1112 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", 1113 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", 1114 | "dev": true, 1115 | "peer": true, 1116 | "peerDependencies": { 1117 | "ajv": "^6.9.1" 1118 | } 1119 | }, 1120 | "node_modules/ansi-styles": { 1121 | "version": "4.3.0", 1122 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1123 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1124 | "dev": true, 1125 | "dependencies": { 1126 | "color-convert": "^2.0.1" 1127 | }, 1128 | "engines": { 1129 | "node": ">=8" 1130 | }, 1131 | "funding": { 1132 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1133 | } 1134 | }, 1135 | "node_modules/braces": { 1136 | "version": "3.0.2", 1137 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1138 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1139 | "dev": true, 1140 | "dependencies": { 1141 | "fill-range": "^7.0.1" 1142 | }, 1143 | "engines": { 1144 | "node": ">=8" 1145 | } 1146 | }, 1147 | "node_modules/browserslist": { 1148 | "version": "4.21.10", 1149 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", 1150 | "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", 1151 | "dev": true, 1152 | "funding": [ 1153 | { 1154 | "type": "opencollective", 1155 | "url": "https://opencollective.com/browserslist" 1156 | }, 1157 | { 1158 | "type": "tidelift", 1159 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1160 | }, 1161 | { 1162 | "type": "github", 1163 | "url": "https://github.com/sponsors/ai" 1164 | } 1165 | ], 1166 | "peer": true, 1167 | "dependencies": { 1168 | "caniuse-lite": "^1.0.30001517", 1169 | "electron-to-chromium": "^1.4.477", 1170 | "node-releases": "^2.0.13", 1171 | "update-browserslist-db": "^1.0.11" 1172 | }, 1173 | "bin": { 1174 | "browserslist": "cli.js" 1175 | }, 1176 | "engines": { 1177 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1178 | } 1179 | }, 1180 | "node_modules/buffer-from": { 1181 | "version": "1.1.2", 1182 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1183 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1184 | "dev": true 1185 | }, 1186 | "node_modules/caniuse-lite": { 1187 | "version": "1.0.30001519", 1188 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", 1189 | "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", 1190 | "dev": true, 1191 | "funding": [ 1192 | { 1193 | "type": "opencollective", 1194 | "url": "https://opencollective.com/browserslist" 1195 | }, 1196 | { 1197 | "type": "tidelift", 1198 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 1199 | }, 1200 | { 1201 | "type": "github", 1202 | "url": "https://github.com/sponsors/ai" 1203 | } 1204 | ], 1205 | "peer": true 1206 | }, 1207 | "node_modules/chalk": { 1208 | "version": "4.1.2", 1209 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1210 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1211 | "dev": true, 1212 | "dependencies": { 1213 | "ansi-styles": "^4.1.0", 1214 | "supports-color": "^7.1.0" 1215 | }, 1216 | "engines": { 1217 | "node": ">=10" 1218 | }, 1219 | "funding": { 1220 | "url": "https://github.com/chalk/chalk?sponsor=1" 1221 | } 1222 | }, 1223 | "node_modules/chrome-trace-event": { 1224 | "version": "1.0.3", 1225 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", 1226 | "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", 1227 | "dev": true, 1228 | "peer": true, 1229 | "engines": { 1230 | "node": ">=6.0" 1231 | } 1232 | }, 1233 | "node_modules/color-convert": { 1234 | "version": "2.0.1", 1235 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1236 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1237 | "dev": true, 1238 | "dependencies": { 1239 | "color-name": "~1.1.4" 1240 | }, 1241 | "engines": { 1242 | "node": ">=7.0.0" 1243 | } 1244 | }, 1245 | "node_modules/color-name": { 1246 | "version": "1.1.4", 1247 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1248 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1249 | "dev": true 1250 | }, 1251 | "node_modules/commander": { 1252 | "version": "2.20.3", 1253 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1254 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1255 | "dev": true, 1256 | "peer": true 1257 | }, 1258 | "node_modules/electron-to-chromium": { 1259 | "version": "1.4.490", 1260 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz", 1261 | "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", 1262 | "dev": true, 1263 | "peer": true 1264 | }, 1265 | "node_modules/enhanced-resolve": { 1266 | "version": "5.15.0", 1267 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", 1268 | "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", 1269 | "dev": true, 1270 | "dependencies": { 1271 | "graceful-fs": "^4.2.4", 1272 | "tapable": "^2.2.0" 1273 | }, 1274 | "engines": { 1275 | "node": ">=10.13.0" 1276 | } 1277 | }, 1278 | "node_modules/es-module-lexer": { 1279 | "version": "1.3.0", 1280 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", 1281 | "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", 1282 | "dev": true, 1283 | "peer": true 1284 | }, 1285 | "node_modules/esbuild": { 1286 | "version": "0.19.3", 1287 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", 1288 | "integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==", 1289 | "dev": true, 1290 | "hasInstallScript": true, 1291 | "bin": { 1292 | "esbuild": "bin/esbuild" 1293 | }, 1294 | "engines": { 1295 | "node": ">=12" 1296 | }, 1297 | "optionalDependencies": { 1298 | "@esbuild/android-arm": "0.19.3", 1299 | "@esbuild/android-arm64": "0.19.3", 1300 | "@esbuild/android-x64": "0.19.3", 1301 | "@esbuild/darwin-arm64": "0.19.3", 1302 | "@esbuild/darwin-x64": "0.19.3", 1303 | "@esbuild/freebsd-arm64": "0.19.3", 1304 | "@esbuild/freebsd-x64": "0.19.3", 1305 | "@esbuild/linux-arm": "0.19.3", 1306 | "@esbuild/linux-arm64": "0.19.3", 1307 | "@esbuild/linux-ia32": "0.19.3", 1308 | "@esbuild/linux-loong64": "0.19.3", 1309 | "@esbuild/linux-mips64el": "0.19.3", 1310 | "@esbuild/linux-ppc64": "0.19.3", 1311 | "@esbuild/linux-riscv64": "0.19.3", 1312 | "@esbuild/linux-s390x": "0.19.3", 1313 | "@esbuild/linux-x64": "0.19.3", 1314 | "@esbuild/netbsd-x64": "0.19.3", 1315 | "@esbuild/openbsd-x64": "0.19.3", 1316 | "@esbuild/sunos-x64": "0.19.3", 1317 | "@esbuild/win32-arm64": "0.19.3", 1318 | "@esbuild/win32-ia32": "0.19.3", 1319 | "@esbuild/win32-x64": "0.19.3" 1320 | } 1321 | }, 1322 | "node_modules/escalade": { 1323 | "version": "3.1.1", 1324 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1325 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1326 | "dev": true, 1327 | "peer": true, 1328 | "engines": { 1329 | "node": ">=6" 1330 | } 1331 | }, 1332 | "node_modules/eslint-scope": { 1333 | "version": "5.1.1", 1334 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 1335 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 1336 | "dev": true, 1337 | "peer": true, 1338 | "dependencies": { 1339 | "esrecurse": "^4.3.0", 1340 | "estraverse": "^4.1.1" 1341 | }, 1342 | "engines": { 1343 | "node": ">=8.0.0" 1344 | } 1345 | }, 1346 | "node_modules/esrecurse": { 1347 | "version": "4.3.0", 1348 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1349 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1350 | "dev": true, 1351 | "peer": true, 1352 | "dependencies": { 1353 | "estraverse": "^5.2.0" 1354 | }, 1355 | "engines": { 1356 | "node": ">=4.0" 1357 | } 1358 | }, 1359 | "node_modules/esrecurse/node_modules/estraverse": { 1360 | "version": "5.3.0", 1361 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1362 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1363 | "dev": true, 1364 | "peer": true, 1365 | "engines": { 1366 | "node": ">=4.0" 1367 | } 1368 | }, 1369 | "node_modules/estraverse": { 1370 | "version": "4.3.0", 1371 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 1372 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 1373 | "dev": true, 1374 | "peer": true, 1375 | "engines": { 1376 | "node": ">=4.0" 1377 | } 1378 | }, 1379 | "node_modules/events": { 1380 | "version": "3.3.0", 1381 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 1382 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 1383 | "dev": true, 1384 | "peer": true, 1385 | "engines": { 1386 | "node": ">=0.8.x" 1387 | } 1388 | }, 1389 | "node_modules/fast-deep-equal": { 1390 | "version": "3.1.3", 1391 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1392 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1393 | "dev": true, 1394 | "peer": true 1395 | }, 1396 | "node_modules/fast-json-stable-stringify": { 1397 | "version": "2.1.0", 1398 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1399 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1400 | "dev": true, 1401 | "peer": true 1402 | }, 1403 | "node_modules/fill-range": { 1404 | "version": "7.0.1", 1405 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1406 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1407 | "dev": true, 1408 | "dependencies": { 1409 | "to-regex-range": "^5.0.1" 1410 | }, 1411 | "engines": { 1412 | "node": ">=8" 1413 | } 1414 | }, 1415 | "node_modules/fsevents": { 1416 | "version": "2.3.2", 1417 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1418 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1419 | "dev": true, 1420 | "hasInstallScript": true, 1421 | "optional": true, 1422 | "os": [ 1423 | "darwin" 1424 | ], 1425 | "engines": { 1426 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1427 | } 1428 | }, 1429 | "node_modules/get-tsconfig": { 1430 | "version": "4.7.0", 1431 | "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.0.tgz", 1432 | "integrity": "sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==", 1433 | "dev": true, 1434 | "dependencies": { 1435 | "resolve-pkg-maps": "^1.0.0" 1436 | }, 1437 | "funding": { 1438 | "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 1439 | } 1440 | }, 1441 | "node_modules/glob-to-regexp": { 1442 | "version": "0.4.1", 1443 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 1444 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 1445 | "dev": true, 1446 | "peer": true 1447 | }, 1448 | "node_modules/graceful-fs": { 1449 | "version": "4.2.11", 1450 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1451 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1452 | "dev": true 1453 | }, 1454 | "node_modules/has-flag": { 1455 | "version": "4.0.0", 1456 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1457 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1458 | "dev": true, 1459 | "engines": { 1460 | "node": ">=8" 1461 | } 1462 | }, 1463 | "node_modules/is-number": { 1464 | "version": "7.0.0", 1465 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1466 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1467 | "dev": true, 1468 | "engines": { 1469 | "node": ">=0.12.0" 1470 | } 1471 | }, 1472 | "node_modules/jest-worker": { 1473 | "version": "27.5.1", 1474 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", 1475 | "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", 1476 | "dev": true, 1477 | "peer": true, 1478 | "dependencies": { 1479 | "@types/node": "*", 1480 | "merge-stream": "^2.0.0", 1481 | "supports-color": "^8.0.0" 1482 | }, 1483 | "engines": { 1484 | "node": ">= 10.13.0" 1485 | } 1486 | }, 1487 | "node_modules/jest-worker/node_modules/supports-color": { 1488 | "version": "8.1.1", 1489 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1490 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1491 | "dev": true, 1492 | "peer": true, 1493 | "dependencies": { 1494 | "has-flag": "^4.0.0" 1495 | }, 1496 | "engines": { 1497 | "node": ">=10" 1498 | }, 1499 | "funding": { 1500 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1501 | } 1502 | }, 1503 | "node_modules/json-parse-even-better-errors": { 1504 | "version": "2.3.1", 1505 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 1506 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 1507 | "dev": true, 1508 | "peer": true 1509 | }, 1510 | "node_modules/json-schema-traverse": { 1511 | "version": "0.4.1", 1512 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1513 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1514 | "dev": true, 1515 | "peer": true 1516 | }, 1517 | "node_modules/loader-runner": { 1518 | "version": "4.3.0", 1519 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", 1520 | "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", 1521 | "dev": true, 1522 | "peer": true, 1523 | "engines": { 1524 | "node": ">=6.11.5" 1525 | } 1526 | }, 1527 | "node_modules/lru-cache": { 1528 | "version": "6.0.0", 1529 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1530 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1531 | "dev": true, 1532 | "dependencies": { 1533 | "yallist": "^4.0.0" 1534 | }, 1535 | "engines": { 1536 | "node": ">=10" 1537 | } 1538 | }, 1539 | "node_modules/merge-stream": { 1540 | "version": "2.0.0", 1541 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 1542 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 1543 | "dev": true, 1544 | "peer": true 1545 | }, 1546 | "node_modules/micromatch": { 1547 | "version": "4.0.5", 1548 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1549 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1550 | "dev": true, 1551 | "dependencies": { 1552 | "braces": "^3.0.2", 1553 | "picomatch": "^2.3.1" 1554 | }, 1555 | "engines": { 1556 | "node": ">=8.6" 1557 | } 1558 | }, 1559 | "node_modules/mime-db": { 1560 | "version": "1.52.0", 1561 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1562 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1563 | "dev": true, 1564 | "peer": true, 1565 | "engines": { 1566 | "node": ">= 0.6" 1567 | } 1568 | }, 1569 | "node_modules/mime-types": { 1570 | "version": "2.1.35", 1571 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1572 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1573 | "dev": true, 1574 | "peer": true, 1575 | "dependencies": { 1576 | "mime-db": "1.52.0" 1577 | }, 1578 | "engines": { 1579 | "node": ">= 0.6" 1580 | } 1581 | }, 1582 | "node_modules/neo-async": { 1583 | "version": "2.6.2", 1584 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 1585 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 1586 | "dev": true, 1587 | "peer": true 1588 | }, 1589 | "node_modules/node-releases": { 1590 | "version": "2.0.13", 1591 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", 1592 | "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", 1593 | "dev": true, 1594 | "peer": true 1595 | }, 1596 | "node_modules/picocolors": { 1597 | "version": "1.0.0", 1598 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1599 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1600 | "dev": true, 1601 | "peer": true 1602 | }, 1603 | "node_modules/picomatch": { 1604 | "version": "2.3.1", 1605 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1606 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1607 | "dev": true, 1608 | "engines": { 1609 | "node": ">=8.6" 1610 | }, 1611 | "funding": { 1612 | "url": "https://github.com/sponsors/jonschlinkert" 1613 | } 1614 | }, 1615 | "node_modules/punycode": { 1616 | "version": "2.3.0", 1617 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", 1618 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", 1619 | "dev": true, 1620 | "peer": true, 1621 | "engines": { 1622 | "node": ">=6" 1623 | } 1624 | }, 1625 | "node_modules/randombytes": { 1626 | "version": "2.1.0", 1627 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1628 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1629 | "dev": true, 1630 | "peer": true, 1631 | "dependencies": { 1632 | "safe-buffer": "^5.1.0" 1633 | } 1634 | }, 1635 | "node_modules/resolve-pkg-maps": { 1636 | "version": "1.0.0", 1637 | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 1638 | "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 1639 | "dev": true, 1640 | "funding": { 1641 | "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 1642 | } 1643 | }, 1644 | "node_modules/safe-buffer": { 1645 | "version": "5.2.1", 1646 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1647 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1648 | "dev": true, 1649 | "funding": [ 1650 | { 1651 | "type": "github", 1652 | "url": "https://github.com/sponsors/feross" 1653 | }, 1654 | { 1655 | "type": "patreon", 1656 | "url": "https://www.patreon.com/feross" 1657 | }, 1658 | { 1659 | "type": "consulting", 1660 | "url": "https://feross.org/support" 1661 | } 1662 | ], 1663 | "peer": true 1664 | }, 1665 | "node_modules/schema-utils": { 1666 | "version": "3.3.0", 1667 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", 1668 | "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", 1669 | "dev": true, 1670 | "peer": true, 1671 | "dependencies": { 1672 | "@types/json-schema": "^7.0.8", 1673 | "ajv": "^6.12.5", 1674 | "ajv-keywords": "^3.5.2" 1675 | }, 1676 | "engines": { 1677 | "node": ">= 10.13.0" 1678 | }, 1679 | "funding": { 1680 | "type": "opencollective", 1681 | "url": "https://opencollective.com/webpack" 1682 | } 1683 | }, 1684 | "node_modules/semver": { 1685 | "version": "7.5.4", 1686 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 1687 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 1688 | "dev": true, 1689 | "dependencies": { 1690 | "lru-cache": "^6.0.0" 1691 | }, 1692 | "bin": { 1693 | "semver": "bin/semver.js" 1694 | }, 1695 | "engines": { 1696 | "node": ">=10" 1697 | } 1698 | }, 1699 | "node_modules/serialize-javascript": { 1700 | "version": "6.0.1", 1701 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", 1702 | "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", 1703 | "dev": true, 1704 | "peer": true, 1705 | "dependencies": { 1706 | "randombytes": "^2.1.0" 1707 | } 1708 | }, 1709 | "node_modules/source-map": { 1710 | "version": "0.6.1", 1711 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1712 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1713 | "dev": true, 1714 | "engines": { 1715 | "node": ">=0.10.0" 1716 | } 1717 | }, 1718 | "node_modules/source-map-support": { 1719 | "version": "0.5.21", 1720 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1721 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1722 | "dev": true, 1723 | "dependencies": { 1724 | "buffer-from": "^1.0.0", 1725 | "source-map": "^0.6.0" 1726 | } 1727 | }, 1728 | "node_modules/supports-color": { 1729 | "version": "7.2.0", 1730 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1731 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1732 | "dev": true, 1733 | "dependencies": { 1734 | "has-flag": "^4.0.0" 1735 | }, 1736 | "engines": { 1737 | "node": ">=8" 1738 | } 1739 | }, 1740 | "node_modules/tapable": { 1741 | "version": "2.2.1", 1742 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", 1743 | "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", 1744 | "dev": true, 1745 | "engines": { 1746 | "node": ">=6" 1747 | } 1748 | }, 1749 | "node_modules/terser": { 1750 | "version": "5.19.2", 1751 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", 1752 | "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", 1753 | "dev": true, 1754 | "peer": true, 1755 | "dependencies": { 1756 | "@jridgewell/source-map": "^0.3.3", 1757 | "acorn": "^8.8.2", 1758 | "commander": "^2.20.0", 1759 | "source-map-support": "~0.5.20" 1760 | }, 1761 | "bin": { 1762 | "terser": "bin/terser" 1763 | }, 1764 | "engines": { 1765 | "node": ">=10" 1766 | } 1767 | }, 1768 | "node_modules/terser-webpack-plugin": { 1769 | "version": "5.3.9", 1770 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", 1771 | "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", 1772 | "dev": true, 1773 | "peer": true, 1774 | "dependencies": { 1775 | "@jridgewell/trace-mapping": "^0.3.17", 1776 | "jest-worker": "^27.4.5", 1777 | "schema-utils": "^3.1.1", 1778 | "serialize-javascript": "^6.0.1", 1779 | "terser": "^5.16.8" 1780 | }, 1781 | "engines": { 1782 | "node": ">= 10.13.0" 1783 | }, 1784 | "funding": { 1785 | "type": "opencollective", 1786 | "url": "https://opencollective.com/webpack" 1787 | }, 1788 | "peerDependencies": { 1789 | "webpack": "^5.1.0" 1790 | }, 1791 | "peerDependenciesMeta": { 1792 | "@swc/core": { 1793 | "optional": true 1794 | }, 1795 | "esbuild": { 1796 | "optional": true 1797 | }, 1798 | "uglify-js": { 1799 | "optional": true 1800 | } 1801 | } 1802 | }, 1803 | "node_modules/to-regex-range": { 1804 | "version": "5.0.1", 1805 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1806 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1807 | "dev": true, 1808 | "dependencies": { 1809 | "is-number": "^7.0.0" 1810 | }, 1811 | "engines": { 1812 | "node": ">=8.0" 1813 | } 1814 | }, 1815 | "node_modules/ts-loader": { 1816 | "version": "9.4.4", 1817 | "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", 1818 | "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", 1819 | "dev": true, 1820 | "dependencies": { 1821 | "chalk": "^4.1.0", 1822 | "enhanced-resolve": "^5.0.0", 1823 | "micromatch": "^4.0.0", 1824 | "semver": "^7.3.4" 1825 | }, 1826 | "engines": { 1827 | "node": ">=12.0.0" 1828 | }, 1829 | "peerDependencies": { 1830 | "typescript": "*", 1831 | "webpack": "^5.0.0" 1832 | } 1833 | }, 1834 | "node_modules/tsx": { 1835 | "version": "3.12.7", 1836 | "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz", 1837 | "integrity": "sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==", 1838 | "dev": true, 1839 | "dependencies": { 1840 | "@esbuild-kit/cjs-loader": "^2.4.2", 1841 | "@esbuild-kit/core-utils": "^3.0.0", 1842 | "@esbuild-kit/esm-loader": "^2.5.5" 1843 | }, 1844 | "bin": { 1845 | "tsx": "dist/cli.js" 1846 | }, 1847 | "optionalDependencies": { 1848 | "fsevents": "~2.3.2" 1849 | } 1850 | }, 1851 | "node_modules/typescript": { 1852 | "version": "5.1.6", 1853 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", 1854 | "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", 1855 | "dev": true, 1856 | "bin": { 1857 | "tsc": "bin/tsc", 1858 | "tsserver": "bin/tsserver" 1859 | }, 1860 | "engines": { 1861 | "node": ">=14.17" 1862 | } 1863 | }, 1864 | "node_modules/update-browserslist-db": { 1865 | "version": "1.0.11", 1866 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", 1867 | "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", 1868 | "dev": true, 1869 | "funding": [ 1870 | { 1871 | "type": "opencollective", 1872 | "url": "https://opencollective.com/browserslist" 1873 | }, 1874 | { 1875 | "type": "tidelift", 1876 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1877 | }, 1878 | { 1879 | "type": "github", 1880 | "url": "https://github.com/sponsors/ai" 1881 | } 1882 | ], 1883 | "peer": true, 1884 | "dependencies": { 1885 | "escalade": "^3.1.1", 1886 | "picocolors": "^1.0.0" 1887 | }, 1888 | "bin": { 1889 | "update-browserslist-db": "cli.js" 1890 | }, 1891 | "peerDependencies": { 1892 | "browserslist": ">= 4.21.0" 1893 | } 1894 | }, 1895 | "node_modules/uri-js": { 1896 | "version": "4.4.1", 1897 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1898 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1899 | "dev": true, 1900 | "peer": true, 1901 | "dependencies": { 1902 | "punycode": "^2.1.0" 1903 | } 1904 | }, 1905 | "node_modules/watchpack": { 1906 | "version": "2.4.0", 1907 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", 1908 | "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", 1909 | "dev": true, 1910 | "peer": true, 1911 | "dependencies": { 1912 | "glob-to-regexp": "^0.4.1", 1913 | "graceful-fs": "^4.1.2" 1914 | }, 1915 | "engines": { 1916 | "node": ">=10.13.0" 1917 | } 1918 | }, 1919 | "node_modules/webpack": { 1920 | "version": "5.88.2", 1921 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", 1922 | "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", 1923 | "dev": true, 1924 | "peer": true, 1925 | "dependencies": { 1926 | "@types/eslint-scope": "^3.7.3", 1927 | "@types/estree": "^1.0.0", 1928 | "@webassemblyjs/ast": "^1.11.5", 1929 | "@webassemblyjs/wasm-edit": "^1.11.5", 1930 | "@webassemblyjs/wasm-parser": "^1.11.5", 1931 | "acorn": "^8.7.1", 1932 | "acorn-import-assertions": "^1.9.0", 1933 | "browserslist": "^4.14.5", 1934 | "chrome-trace-event": "^1.0.2", 1935 | "enhanced-resolve": "^5.15.0", 1936 | "es-module-lexer": "^1.2.1", 1937 | "eslint-scope": "5.1.1", 1938 | "events": "^3.2.0", 1939 | "glob-to-regexp": "^0.4.1", 1940 | "graceful-fs": "^4.2.9", 1941 | "json-parse-even-better-errors": "^2.3.1", 1942 | "loader-runner": "^4.2.0", 1943 | "mime-types": "^2.1.27", 1944 | "neo-async": "^2.6.2", 1945 | "schema-utils": "^3.2.0", 1946 | "tapable": "^2.1.1", 1947 | "terser-webpack-plugin": "^5.3.7", 1948 | "watchpack": "^2.4.0", 1949 | "webpack-sources": "^3.2.3" 1950 | }, 1951 | "bin": { 1952 | "webpack": "bin/webpack.js" 1953 | }, 1954 | "engines": { 1955 | "node": ">=10.13.0" 1956 | }, 1957 | "funding": { 1958 | "type": "opencollective", 1959 | "url": "https://opencollective.com/webpack" 1960 | }, 1961 | "peerDependenciesMeta": { 1962 | "webpack-cli": { 1963 | "optional": true 1964 | } 1965 | } 1966 | }, 1967 | "node_modules/webpack-sources": { 1968 | "version": "3.2.3", 1969 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", 1970 | "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", 1971 | "dev": true, 1972 | "peer": true, 1973 | "engines": { 1974 | "node": ">=10.13.0" 1975 | } 1976 | }, 1977 | "node_modules/yallist": { 1978 | "version": "4.0.0", 1979 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1980 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1981 | "dev": true 1982 | } 1983 | }, 1984 | "version": "1.1.2" 1985 | } 1986 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "text-graph.js", 3 | "version": "1.1.2", 4 | "author": "DrA1ex", 5 | "description": "A versatile JavaScript library for creating ASCII charts in the terminal and browser console", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/DrA1ex/text-graph.js.git" 9 | }, 10 | "homepage": "https://github.com/DrA1ex/text-graph.js", 11 | "keywords": [ 12 | "ascii-chart", 13 | "terminal-chart", 14 | "console-chart", 15 | "browser-chart", 16 | "chart-library", 17 | "multi-series-chart", 18 | "chart-dashboard", 19 | "text-graph", 20 | "data-visualization", 21 | "javascript-graph", 22 | "ascii-visualization", 23 | "dashboard-library", 24 | "text-based-chart", 25 | "text-based-visualization" 26 | ], 27 | "license": "BSD-3-Clause", 28 | "scripts": { 29 | "bundle_esm": "esbuild src/index.ts --bundle --format=esm --outdir=./lib --out-extension:.js=.mjs", 30 | "bundle_cjs": "esbuild src/index.ts --bundle --format=cjs --outdir=./lib --out-extension:.js=.js", 31 | "build": "rm -rf ./lib/ && tsc --project tsconfig.lib.json && npm run bundle_esm && npm run bundle_cjs" 32 | }, 33 | "devDependencies": { 34 | "esbuild": "^0.19.3", 35 | "ts-loader": "^9.4.4", 36 | "tsx": "^3.12.7", 37 | "typescript": "^5.1.6" 38 | }, 39 | "main": "./lib/index.js", 40 | "module": "./lib/index.mjs", 41 | "types": "./lib/index.d.ts", 42 | "exports": { 43 | ".": { 44 | "require": "./lib/index.js", 45 | "import": "./lib/index.mjs", 46 | "types": "./lib/index.d.ts" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/axis.ts: -------------------------------------------------------------------------------- 1 | import {PlotAxisScale} from "./enum"; 2 | import * as Utils from "./utils"; 3 | 4 | export class Axis { 5 | readonly labels: number[]; 6 | 7 | constructor(public min: number, 8 | public max: number, 9 | public readonly size: number, 10 | public readonly scale: PlotAxisScale, 11 | ) { 12 | if (min > max) throw new Error("Incorrect range: min should be less or equals to max") 13 | if (this.size <= 1) throw new Error("Size should be >= 2"); 14 | 15 | switch (this.scale) { 16 | case PlotAxisScale.log: 17 | this.labels = Array.from(Utils.logDistribution(this.min, this.max, this.size)); 18 | break; 19 | 20 | case PlotAxisScale.logInverted: 21 | this.labels = Array.from(Utils.invertedLogDistribution(this.min, this.max, this.size)); 22 | break; 23 | 24 | default: 25 | this.labels = Array.from(Utils.linearDistribution(this.min, this.max, this.size)); 26 | } 27 | } 28 | 29 | getPosition(value: number) { 30 | const index = Utils.findClosestIndexSorted(this.labels, value); 31 | return this.size - 1 - index; 32 | } 33 | } -------------------------------------------------------------------------------- /src/enum.ts: -------------------------------------------------------------------------------- 1 | import * as Utils from "./utils" 2 | 3 | export enum LabelPositionFlags { 4 | top = 1 << 1, 5 | bottom = 1 << 2, 6 | left = 1 << 5, 7 | right = 1 << 6, 8 | 9 | top_left = top | left, 10 | top_right = top | right, 11 | bottom_left = bottom | left, 12 | bottom_right = bottom | right, 13 | } 14 | 15 | export enum Color { 16 | red = "\x1b[31m", 17 | green = "\x1b[32m", 18 | yellow = "\x1b[33m", 19 | blue = "\x1b[34m", 20 | magenta = "\x1b[35m", 21 | cyan = "\x1b[36m", 22 | lightgray = "\x1b[37m", 23 | default = "\x1b[39m", 24 | 25 | white = "\x1b[97m", 26 | black = "\x1b[30m", 27 | reset = "\x1b[0m", 28 | } 29 | 30 | export enum BackgroundColor { 31 | black = "\x1b[40m", 32 | red = "\x1b[41m", 33 | green = "\x1b[42m", 34 | yellow = "\x1b[43m", 35 | blue = "\x1b[44m", 36 | magenta = "\x1b[45m", 37 | cyan = "\x1b[46m", 38 | lightgray = "\x1b[47m", 39 | default = "\x1b[49m", 40 | } 41 | 42 | export enum PlotSeriesOverflow { 43 | linearScale, 44 | logScale, 45 | clamp, 46 | } 47 | 48 | export enum PlotAxisScale { 49 | linear, 50 | log, 51 | logInverted 52 | } 53 | 54 | export const PlotSeriesAggregationFn = { 55 | mean: Utils.aggregateAverage, 56 | min: Utils.aggregateMin, 57 | max: Utils.aggregateMax, 58 | skip: Utils.aggregateSkip, 59 | } as const; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import {Plot} from "./plot"; 2 | import {MultiPlotChart} from "./multi-plot"; 3 | 4 | export default { 5 | Plot, 6 | MultiPlotChart 7 | } 8 | 9 | export {Plot, MultiPlotChart} 10 | export { 11 | Color, BackgroundColor, PlotAxisScale, PlotSeriesOverflow, LabelPositionFlags, PlotSeriesAggregationFn 12 | } from "./enum" -------------------------------------------------------------------------------- /src/label.ts: -------------------------------------------------------------------------------- 1 | import {BackgroundColor, Color, LabelPositionFlags} from "./enum"; 2 | 3 | export const LabelDefaults = { 4 | align: LabelPositionFlags.top, 5 | foregroundColor: Color.black, 6 | backgroundColor: BackgroundColor.lightgray, 7 | spacing: 1, 8 | minWidth: 4 9 | } 10 | 11 | export class Label { 12 | public foregroundColor = LabelDefaults.foregroundColor; 13 | public backgroundColor = LabelDefaults.backgroundColor; 14 | 15 | constructor( 16 | public readonly label: string, 17 | public readonly width: number, 18 | public readonly height: number, 19 | public readonly boundary: number = 0, 20 | public readonly align: LabelPositionFlags = LabelDefaults.align, 21 | public readonly spacing = LabelDefaults.spacing, 22 | ) { 23 | } 24 | 25 | public draw(screen: string[][], xOffset: number, yOffset: number) { 26 | const maxWidth = this.width - xOffset; 27 | if (!this.label || maxWidth <= LabelDefaults.minWidth) return; 28 | 29 | let label = this._clipLabel(this.label, maxWidth, this.boundary); 30 | if (label.length < maxWidth) { 31 | const spacing = Math.min(this.spacing, Math.floor(maxWidth - label.length) / 2); 32 | 33 | if (spacing) { 34 | label = " ".repeat(spacing) + label + " ".repeat(spacing); 35 | } 36 | } 37 | 38 | let x; 39 | if (this.align & LabelPositionFlags.left) { 40 | x = 0 41 | } else if (this.align & LabelPositionFlags.right) { 42 | x = this.width - label.length - 1; 43 | } else { 44 | x = xOffset + Math.round(maxWidth / 2 - label.length / 2) 45 | } 46 | 47 | let y = yOffset; 48 | if (this.align & LabelPositionFlags.bottom) { 49 | y = this.height - 1 - yOffset; 50 | } 51 | 52 | for (let i = 0; i < label.length; i++) { 53 | screen[y][x + i] = this.backgroundColor + this.foregroundColor + label[i] + Color.reset; 54 | } 55 | } 56 | 57 | private _clipLabel(label: string, maxLength: number, boundary: number): string { 58 | if (label.length > maxLength) { 59 | return label.slice(0, maxLength - boundary - 1) + "…"; 60 | } 61 | 62 | return label 63 | } 64 | } -------------------------------------------------------------------------------- /src/multi-plot.ts: -------------------------------------------------------------------------------- 1 | import {BackgroundColor, Color, LabelPositionFlags} from "./enum"; 2 | import {Plot, PlotOptions, PlotSeriesConfig} from "./plot"; 3 | import {Label, LabelDefaults} from "./label"; 4 | 5 | type ChartPlotConfig = { 6 | xOffset: number, 7 | yOffset: number, 8 | width: number, 9 | height: number, 10 | }; 11 | 12 | type MultiPlotOptionsT = { 13 | title: string, 14 | titlePosition: LabelPositionFlags, 15 | titleForeground: Color, 16 | titleBackground: BackgroundColor, 17 | titleBoundary: number, 18 | titleSpacing: number, 19 | } 20 | 21 | const MultiPlotOptionsDefaults = { 22 | title: "", 23 | titlePosition: LabelDefaults.align, 24 | titleForeground: LabelDefaults.foregroundColor, 25 | titleBackground: LabelDefaults.backgroundColor, 26 | titleBoundary: 1, 27 | titleSpacing: LabelDefaults.spacing, 28 | } 29 | 30 | export class MultiPlotChart { 31 | get title(): string { 32 | return this._title; 33 | } 34 | 35 | set title(value: string) { 36 | const needDrawTitleChanged = !!value !== !!this._title; 37 | this._title = value; 38 | 39 | this._updateScreen(); 40 | } 41 | 42 | public width: number = 0; 43 | public height: number = 0; 44 | 45 | private _title: string; 46 | public titlePosition: LabelPositionFlags; 47 | public titleForeground: Color; 48 | public titleBackground: BackgroundColor; 49 | public titleBoundary: number; 50 | public titleSpacing: number; 51 | 52 | public readonly plots: Plot[] = []; 53 | private readonly configs = new Map(); 54 | 55 | public screen!: string[][]; 56 | 57 | constructor(options: Partial = {}) { 58 | const opts = {...MultiPlotOptionsDefaults, ...options}; 59 | 60 | this._title = opts.title; 61 | this.titlePosition = opts.titlePosition; 62 | this.titleForeground = opts.titleForeground; 63 | this.titleBackground = opts.titleBackground; 64 | this.titleBoundary = opts.titleBoundary; 65 | this.titleSpacing = opts.titleSpacing; 66 | } 67 | 68 | public addPlot(config: ChartPlotConfig, options?: Partial): number { 69 | const plot = new Plot(config.width, config.height, options); 70 | this.plots.push(plot); 71 | this.configs.set(plot, config); 72 | 73 | this._updateScreen(); 74 | 75 | return this.plots.length - 1; 76 | } 77 | 78 | public addPlotSeries(plotId: number, config: Partial): number { 79 | this._assertChartId(plotId); 80 | 81 | return this.plots[plotId].addSeries(config); 82 | } 83 | 84 | public addSeriesEntry(plotId: number, seriesId: number, entry: number) { 85 | this._assertChartId(plotId); 86 | 87 | this.plots[plotId].addSeriesEntry(seriesId, entry); 88 | } 89 | 90 | public redraw() { 91 | if (this.title) { 92 | const titleLabel = new Label( 93 | this.title, this.width, this.height, 0, this.titlePosition, this.titleSpacing 94 | ); 95 | 96 | titleLabel.foregroundColor = this.titleForeground; 97 | titleLabel.backgroundColor = this.titleBackground; 98 | titleLabel.draw(this.screen, 0, 0); 99 | } 100 | 101 | const xGlobalOffset = 0; 102 | const yGlobalOffset = this.title && this.titlePosition & LabelPositionFlags.top ? this.titleBoundary : 0; 103 | 104 | for (const plot of this.plots) { 105 | this._drawPlot(plot, xGlobalOffset, yGlobalOffset); 106 | } 107 | } 108 | 109 | public paint(): string { 110 | this.redraw(); 111 | 112 | return this.screen.map(row => row.join("")).join("\n") + Color.reset; 113 | } 114 | 115 | private _assertChartId(id: number) { 116 | if (id >= this.plots.length) { 117 | throw new Error("Wrong chart id"); 118 | } 119 | } 120 | 121 | private _updateScreen() { 122 | let width = 0, height = 0; 123 | for (const conf of this.configs.values()) { 124 | width = Math.max(width, conf.xOffset + conf.width); 125 | height = Math.max(height, conf.yOffset + conf.height); 126 | } 127 | 128 | if (this.title) { 129 | height += this.titleBoundary; 130 | } 131 | 132 | this.width = width; 133 | this.height = height; 134 | this.screen = new Array(height); 135 | for (let i = 0; i < height; i++) { 136 | this.screen[i] = new Array(width).fill(Plot.SpaceSymbol); 137 | } 138 | } 139 | 140 | private _drawPlot(plot: Plot, xGlobalOffset: number, yGlobalOffset: number) { 141 | const config = this.configs.get(plot)!; 142 | const {xOffset, yOffset} = config; 143 | 144 | plot.redraw(); 145 | for (let y = 0; y < plot.screen.length; y++) { 146 | const row = plot.screen[y]; 147 | for (let x = 0; x < row.length; x++) { 148 | this.screen[y + yOffset + yGlobalOffset][x + xOffset + xGlobalOffset] = row[x]; 149 | } 150 | } 151 | } 152 | } -------------------------------------------------------------------------------- /src/plot.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Color, 3 | PlotAxisScale, 4 | PlotSeriesAggregationFn, 5 | PlotSeriesOverflow, 6 | LabelPositionFlags, BackgroundColor 7 | } from "./enum"; 8 | import {Axis} from "./axis"; 9 | import * as Utils from "./utils" 10 | import {Label, LabelDefaults} from "./label"; 11 | 12 | enum States { 13 | straight = 0, 14 | up = 1, 15 | down = 2 16 | } 17 | 18 | 19 | export type PlotOptions = { 20 | showAxis: boolean, 21 | horizontalBoundary: number 22 | verticalBoundary: number 23 | title: string, 24 | titlePosition: LabelPositionFlags, 25 | titleForeground: Color, 26 | titleBackground: BackgroundColor, 27 | titleSpacing: number, 28 | axisScale: PlotAxisScale, 29 | aggregation: Utils.AggregationFn, 30 | axisLabelsFraction: number, 31 | zoom: boolean, 32 | } 33 | 34 | export type PlotStaticOptions = { 35 | width: number, 36 | height: number 37 | } & PlotOptions; 38 | 39 | export const PlotCtorDefaultOptions = { 40 | width: 80, 41 | height: 10, 42 | showAxis: true, 43 | axisScale: PlotAxisScale.linear, 44 | title: "", 45 | titlePosition: LabelDefaults.align, 46 | titleForeground: LabelDefaults.foregroundColor, 47 | titleBackground: LabelDefaults.backgroundColor, 48 | titleSpacing: LabelDefaults.spacing, 49 | horizontalBoundary: 0, 50 | axisLabelsFraction: 2, 51 | zoom: false 52 | } 53 | 54 | 55 | export type PlotSeriesConfig = { 56 | color: Color, 57 | overflow: PlotSeriesOverflow 58 | } 59 | 60 | const PlotSeriesDefaults: PlotSeriesConfig = { 61 | color: Color.default, 62 | overflow: PlotSeriesOverflow.linearScale 63 | } 64 | 65 | const PlotDefaultAggregation = { 66 | [PlotAxisScale.linear]: PlotSeriesAggregationFn.mean, 67 | [PlotAxisScale.log]: PlotSeriesAggregationFn.max, 68 | [PlotAxisScale.logInverted]: PlotSeriesAggregationFn.min, 69 | } as { [key in PlotAxisScale]: Utils.AggregationFn } 70 | 71 | export class Plot { 72 | static readonly AxisSymbol = "┼" 73 | static readonly SpaceSymbol = " "; 74 | 75 | static readonly ChartHorizontal = ["─", "╯", "╮",]; 76 | static readonly ChartVertical = ["│", "╭", "╰",]; 77 | 78 | public showAxis: boolean; 79 | public aggregationFn: Utils.AggregationFn; 80 | public axisScale: PlotAxisScale; 81 | public horizontalBoundary: number; 82 | public verticalBoundary: number; 83 | public axisLabelsFraction: number; 84 | public title: string; 85 | public titlePosition: LabelPositionFlags; 86 | public titleForeground: Color; 87 | public titleBackground: BackgroundColor; 88 | public titleSpacing: number; 89 | public zoom: boolean; 90 | 91 | public readonly width; 92 | public readonly height; 93 | 94 | public readonly screen!: string[][]; 95 | 96 | private readonly series: number[][] = []; 97 | readonly seriesConfigs: PlotSeriesConfig[] = []; 98 | 99 | constructor( 100 | width = PlotCtorDefaultOptions.width, height = PlotCtorDefaultOptions.height, { 101 | showAxis = PlotCtorDefaultOptions.showAxis, 102 | axisScale = PlotCtorDefaultOptions.axisScale, 103 | aggregation = PlotDefaultAggregation[axisScale] ?? PlotSeriesAggregationFn.skip, 104 | title = PlotCtorDefaultOptions.title, 105 | titlePosition = PlotCtorDefaultOptions.titlePosition, 106 | titleForeground = PlotCtorDefaultOptions.titleForeground, 107 | titleBackground = PlotCtorDefaultOptions.titleBackground, 108 | titleSpacing = PlotCtorDefaultOptions.titleSpacing, 109 | horizontalBoundary = PlotCtorDefaultOptions.horizontalBoundary, 110 | verticalBoundary = title ? 1 : 0, 111 | axisLabelsFraction = PlotCtorDefaultOptions.axisLabelsFraction, 112 | zoom = PlotCtorDefaultOptions.zoom, 113 | }: Partial = {} 114 | ) { 115 | this.width = width; 116 | this.height = height; 117 | 118 | this.showAxis = showAxis; 119 | this.axisScale = axisScale; 120 | this.aggregationFn = aggregation; 121 | this.zoom = zoom; 122 | 123 | this.title = title; 124 | this.titlePosition = titlePosition; 125 | this.titleForeground = titleForeground; 126 | this.titleBackground = titleBackground; 127 | this.titleSpacing = titleSpacing; 128 | 129 | this.horizontalBoundary = horizontalBoundary; 130 | this.verticalBoundary = verticalBoundary; 131 | this.axisLabelsFraction = axisLabelsFraction; 132 | 133 | this.screen = new Array(this.height); 134 | for (let i = 0; i < this.height; i++) { 135 | this.screen[i] = new Array(this.width).fill(Plot.SpaceSymbol); 136 | } 137 | } 138 | 139 | static plot( 140 | data: number[], plotOptions?: Partial, 141 | seriesOptions: Partial = {} 142 | ): string { 143 | const opts = {...PlotCtorDefaultOptions, ...plotOptions} 144 | const p = new Plot(opts.width, opts.height, opts); 145 | 146 | p.addSeries(seriesOptions); 147 | p.addSeriesRange(0, data); 148 | 149 | return p.paint(); 150 | } 151 | 152 | public addSeries(options: Partial = {}) { 153 | this.series.push([]) 154 | this.seriesConfigs.push({...PlotSeriesDefaults, ...options}); 155 | 156 | return this.series.length - 1; 157 | } 158 | 159 | public addSeriesEntry(seriesIndex: number, value: number) { 160 | if (seriesIndex >= this.series.length) throw new Error("Wrong series index"); 161 | this.series[seriesIndex].push(value); 162 | } 163 | 164 | public addSeriesRange(seriesIndex: number, data: number[]) { 165 | if (seriesIndex >= this.series.length) throw new Error("Wrong series index"); 166 | this.series[seriesIndex].push(...data); 167 | } 168 | 169 | public redraw() { 170 | this._clear(); 171 | 172 | const size = Math.max(2, this.height - this.verticalBoundary * 2); 173 | let [min, max] = Utils.minMax2d(this.series); 174 | const axis = new Axis(min, max, size, this.axisScale); 175 | 176 | const yOffset = (this.height - size) / 2; 177 | let xOffset = 0; 178 | if (this.showAxis) { 179 | const labelPadding = this._drawAxis(yOffset, axis.labels); 180 | xOffset = labelPadding + 2; 181 | } 182 | 183 | const maxSeriesLength = this.width - xOffset - this.horizontalBoundary * 2 + 1; 184 | for (let i = 0; i < this.series.length; i++) { 185 | if (this.series[i].length <= 1) continue; 186 | 187 | const {color, overflow} = this.seriesConfigs[i]; 188 | const seriesData = this.zoom ? Utils.zoomData(this.series[i], maxSeriesLength) : this.series[i]; 189 | const data = this._handleOverflow(seriesData, overflow, maxSeriesLength); 190 | 191 | let lastState = States.straight; 192 | let lastY = yOffset + axis.getPosition(data[0]); 193 | let x = xOffset + this.horizontalBoundary; 194 | 195 | for (let j = 1; j < data.length; j++) { 196 | if (!Number.isFinite(data[j])) break; 197 | 198 | const y = yOffset + axis.getPosition(data[j]); 199 | const state = y === lastY ? States.straight 200 | : y < lastY ? States.up : States.down; 201 | 202 | if (lastState === States.straight) { 203 | this.screen[lastY][x++] = color + Plot.ChartHorizontal[lastState]; 204 | this.screen[lastY][x] = color + Plot.ChartHorizontal[state]; 205 | } else { 206 | this.screen[lastY][x++] = color + Plot.ChartVertical[lastState]; 207 | 208 | if (state === States.straight) { 209 | this.screen[y][x] = color + Plot.ChartHorizontal[state]; 210 | } else { 211 | this.screen[lastY][x] = color + Plot.ChartHorizontal[state]; 212 | this.screen[y][x] = color + Plot.ChartVertical[state]; 213 | } 214 | } 215 | 216 | if (y !== lastY) { 217 | this._fillVertical(color, x, Math.min(y, lastY) + 1, Math.max(y, lastY) - 1); 218 | } 219 | 220 | lastY = y; 221 | lastState = state; 222 | } 223 | } 224 | 225 | const titleLabel = new Label( 226 | this.title, this.width, this.height, this.horizontalBoundary, this.titlePosition, this.titleSpacing 227 | ); 228 | titleLabel.foregroundColor = this.titleForeground; 229 | titleLabel.backgroundColor = this.titleBackground; 230 | titleLabel.draw(this.screen, xOffset, 0); 231 | } 232 | 233 | public paint(): string { 234 | this.redraw(); 235 | 236 | return this.screen.map(row => row.join("")).join("\n") + Color.reset; 237 | } 238 | 239 | private _drawAxis(yOffset: number, axisValues: number[]) { 240 | const size = axisValues.length; 241 | const labelPadding = Math.max( 242 | Math.abs(axisValues[0]).toFixed(this.axisLabelsFraction).length, 243 | Math.abs(axisValues[size - 1]).toFixed(this.axisLabelsFraction).length) + 1; 244 | 245 | for (let i = 0; i < this.height; i++) { 246 | const index = this.height - 1 - i; 247 | this.screen[index][labelPadding + 1] = Color.default + Plot.AxisSymbol; 248 | 249 | const labelIndex = i - yOffset; 250 | if (labelIndex >= 0 && labelIndex < size) { 251 | const axisValue = axisValues[labelIndex]; 252 | const label = Utils.toFixed(axisValue, this.axisLabelsFraction).padStart(labelPadding, " "); 253 | 254 | for (let j = 0; j < label.length; j++) { 255 | this.screen[index][j] = Color.default + label[j]; 256 | } 257 | } 258 | } 259 | 260 | return labelPadding; 261 | } 262 | 263 | private _clear() { 264 | for (let i = 0; i < this.height; i++) { 265 | this.screen[i].fill(Plot.SpaceSymbol); 266 | } 267 | } 268 | 269 | private _handleOverflow(data: number[], overflow: PlotSeriesOverflow, maxLength: number) { 270 | if (data.length <= maxLength) return data; 271 | 272 | switch (overflow) { 273 | case PlotSeriesOverflow.linearScale: 274 | return Utils.shrinkData(data, maxLength, Utils.linearDistribution, this.aggregationFn); 275 | 276 | case PlotSeriesOverflow.logScale: 277 | return Utils.shrinkData(data, maxLength, this._invertedLogDistribution.bind(this, data), this.aggregationFn); 278 | 279 | case PlotSeriesOverflow.clamp: 280 | return Utils.shrinkData(data, maxLength, this._skipDistribution.bind(this), this.aggregationFn); 281 | 282 | default: 283 | throw new Error(`Unsupported overflow function: ${overflow}`); 284 | } 285 | } 286 | 287 | private _skipDistribution(_: number, max: number, count: number): Iterable { 288 | return Utils.linearDistribution(max - count + 1, max, count); 289 | } 290 | 291 | private* _invertedLogDistribution(data: number[], min: number, max: number, count: number): Iterable { 292 | const overflowCount = data.length - count; 293 | const ratio = Math.min(1, overflowCount / 50); 294 | yield* Utils.invertedLogDistribution(min, max, count, ratio); 295 | } 296 | 297 | private _fillVertical(color: Color, x: number, fromY: number, toY: number) { 298 | for (let i = fromY; i <= toY; i++) { 299 | this.screen[i][x] = color + Plot.ChartVertical[0]; 300 | } 301 | } 302 | } -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export type DistributionFn = (min: number, max: number, count: number) => Iterable 2 | 3 | export type AggregationFn = (data: number[], from: number, to: number) => number; 4 | 5 | export function toFixed(value: number, maxFraction = 2) { 6 | let label = value.toFixed(maxFraction) 7 | const pointIndex = label.indexOf(".") 8 | let trimIndex = label.length; 9 | for (; trimIndex > pointIndex; trimIndex--) { 10 | if (label[trimIndex - 1] !== '0') break; 11 | } 12 | 13 | if (trimIndex > 0 && label[trimIndex - 1] === ".") { 14 | trimIndex--; 15 | } 16 | 17 | return label.slice(0, trimIndex); 18 | } 19 | 20 | export function minMax(values: number[]): [number, number] { 21 | let max = Number.NEGATIVE_INFINITY; 22 | let min = Number.POSITIVE_INFINITY; 23 | 24 | for (const value of values) { 25 | if (Number.isNaN(value)) continue; 26 | 27 | min = Math.min(min, value); 28 | max = Math.max(max, value); 29 | } 30 | 31 | return [min, max]; 32 | } 33 | 34 | export function minMax2d(values: number[][]): [number, number] { 35 | let max = Number.NEGATIVE_INFINITY; 36 | let min = Number.POSITIVE_INFINITY; 37 | 38 | for (const row of values) { 39 | const [localMin, localMax] = minMax(row); 40 | if (!Number.isFinite(localMin)) continue; 41 | 42 | min = Math.min(min, localMin); 43 | max = Math.max(max, localMax); 44 | } 45 | 46 | if (Number.isFinite(min)) { 47 | return [min, max]; 48 | } 49 | 50 | return [0, 0]; 51 | } 52 | 53 | export function* linearDistribution(min: number, max: number, count: number): Iterable { 54 | if (count < 2) throw new Error("Count should be greater or equals 2"); 55 | if (min > max) [min, max] = [max, min]; 56 | 57 | const step = (max - min) / (count - 1); 58 | for (let i = 0; i < count; i++) { 59 | yield min + i * step; 60 | } 61 | } 62 | 63 | export function* logDistribution(min: number, max: number, count: number, ratio: number = 1): Iterable { 64 | if (count < 2) throw new Error("Count should be greater or equals 2"); 65 | if (min > max) [min, max] = [max, min]; 66 | 67 | let offset = 0; 68 | if (min < 1) { 69 | offset = Math.abs(min) + 1; 70 | min += offset; 71 | max += offset; 72 | } 73 | 74 | ratio = Math.max(0, Math.min(1, ratio)); 75 | for (let i = 0; i < count; i++) { 76 | // Linear distribution value between 0 and 1 77 | const linearValue = i / (count - 1); 78 | 79 | // Logarithmic distribution value between 0 and 1 80 | // Special case is i=0, since 10^0 = 1, and so we get 0.1 and thus skip `min` border 81 | const logarithmicValue = i > 0 ? Math.pow(10, linearValue) / 10 : 0; 82 | 83 | // Applying ratio to interpolate between linear and logarithmic distributions 84 | const interpolatedValue = (1 - ratio) * linearValue + ratio * logarithmicValue; 85 | 86 | // Scaling the interpolated value to the desired range 87 | const scaledValue = min + interpolatedValue * (max - min); 88 | 89 | yield scaledValue - offset; 90 | } 91 | } 92 | 93 | export function* invertedLogDistribution(min: number, max: number, count: number, ratio: number = 1): Iterable { 94 | const values = Array.from(logDistribution(min, max, count, ratio)).reverse(); 95 | 96 | let prev = values[0]; 97 | let last = min; 98 | for (const value of values) { 99 | const delta = (prev - value); 100 | yield last + delta; 101 | 102 | prev = value; 103 | last += delta; 104 | } 105 | } 106 | 107 | export function aggregateAverage(data: number[], from: number, to: number): number { 108 | if (from >= to) return data[to]; 109 | 110 | const length = to - from + 1; 111 | let value = 0; 112 | for (let i = from; i <= to; i++) { 113 | value += data[i] / length; 114 | } 115 | 116 | return value; 117 | } 118 | 119 | export function aggregateMax(data: number[], from: number, to: number): number { 120 | if (from >= to) return data[to]; 121 | 122 | let value = data[from]; 123 | for (let i = from; i <= to; i++) { 124 | value = Math.max(value, data[i]); 125 | } 126 | 127 | return value; 128 | } 129 | 130 | export function aggregateMin(data: number[], from: number, to: number): number { 131 | if (from >= to) return data[to]; 132 | 133 | let value = data[from]; 134 | for (let i = from; i <= to; i++) { 135 | value = Math.min(value, data[i]); 136 | } 137 | 138 | return value; 139 | } 140 | 141 | export function aggregateSkip(data: number[], from: number, to: number) { 142 | return data[to]; 143 | } 144 | 145 | export function shrinkData(data: number[], maxLength: number, distributionFn: DistributionFn, aggregationFn: AggregationFn) { 146 | if (data.length <= maxLength) return data; 147 | const shrunk = new Array(maxLength); 148 | 149 | let i = 0; 150 | let prevIndex; 151 | for (let index of distributionFn(0, data.length - 1, maxLength)) { 152 | index = Math.round(index); 153 | if (prevIndex === undefined) prevIndex = index; 154 | 155 | shrunk[i++] = aggregationFn(data, prevIndex, index); 156 | prevIndex = index + 1; 157 | } 158 | 159 | return shrunk; 160 | } 161 | 162 | export function findClosestIndexSorted(data: number[], value: number): number { 163 | let index = 0; 164 | let left = 0; 165 | let right = data.length - 1; 166 | 167 | while (left <= right) { 168 | index = left + Math.floor((right - left) / 2); 169 | const current = data[index]; 170 | 171 | if (value < current) { 172 | right = index - 1; 173 | } else if (value > current) { 174 | left = index + 1; 175 | } else { 176 | return index; 177 | } 178 | } 179 | 180 | //value is outside [min; max] range 181 | if (left === 0 || left >= data.length) { 182 | return index; 183 | } 184 | 185 | const lowerDiff = Math.abs(data[left - 1] - value); 186 | const upperDiff = Math.abs(data[left] - value); 187 | return lowerDiff < upperDiff ? left - 1 : left; 188 | } 189 | 190 | export function zoomData(data: number[], maxLength: number): number[] { 191 | if (data.length === 0 && data.length >= maxLength) return data; 192 | 193 | const zoomed = new Array(maxLength); 194 | let outIndex = 0; 195 | for (const zoomedIndex of linearDistribution(0, data.length - 1, maxLength)) { 196 | zoomed[outIndex++] = data[Math.round(zoomedIndex)]; 197 | } 198 | 199 | return zoomed; 200 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2020", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "moduleResolution": "node", 10 | "rootDir": "src", 11 | "outDir": "lib", 12 | "esModuleInterop": true, 13 | "strict": true, 14 | "noImplicitAny": true, 15 | "skipLibCheck": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "declaration": true, 20 | "downlevelIteration": true, 21 | "importHelpers": true, 22 | }, 23 | "include": [ 24 | "./src/**/*.ts", 25 | "./examples/**/*.ts" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2020", 5 | "lib": [ 6 | "es2020" 7 | ], 8 | "allowJs": true, 9 | "moduleResolution": "node", 10 | "rootDir": "src", 11 | "outDir": "lib", 12 | "esModuleInterop": true, 13 | "strict": true, 14 | "noImplicitAny": true, 15 | "skipLibCheck": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "downlevelIteration": true, 20 | "importHelpers": true, 21 | "allowSyntheticDefaultImports": true, 22 | "sourceMap": false, 23 | "declaration": true, 24 | "emitDeclarationOnly": true 25 | }, 26 | "include": [ 27 | "./src/**/*.ts", 28 | ] 29 | } --------------------------------------------------------------------------------