From b492826043574653f04de7435fb582c15a7a0bf9 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Mon, 27 Feb 2023 22:53:50 +0100 Subject: [PATCH] feat: Initial commit --- .eslintrc.ts | 13 + .github/workflows/test.yml | 21 + .gitignore | 2 + .prettierrc | 6 + LICENSE | 13 + README.md | 402 ++ assets/00-100.png | Bin 0 -> 70982 bytes assets/00-50.png | Bin 0 -> 67766 bytes assets/01-100.png | Bin 0 -> 72757 bytes assets/01-50.png | Bin 0 -> 75817 bytes assets/logo.svg | 46 + examples/index.html | 235 + jest.config.json | 12 + package-lock.json | 8297 +++++++++++++++++++++++ package.json | 62 + rollup.config.ts | 30 + src/charts/bar.ts | 222 + src/charts/bubble.ts | 161 + src/charts/pie.ts | 188 + src/charts/treemap.ts | 166 + src/charts/types.ts | 30 + src/charts/utils.ts | 16 + src/colors.ts | 51 + src/components/ColorLegend.module.scss | 8 + src/components/ColorLegend.ts | 255 + src/components/Datum.module.scss | 28 + src/components/Datum.ts | 178 + src/components/Group.module.scss | 20 + src/components/Group.ts | 245 + src/components/Step.ts | 382 ++ src/components/Svg.module.scss | 7 + src/components/Svg.ts | 49 + src/components/Text.module.scss | 4 + src/components/Text.spec.ts | 221 + src/components/Text.ts | 116 + src/components/Tick.module.scss | 15 + src/components/Tick.ts | 160 + src/components/Tooltip.module.scss | 21 + src/components/Tooltip.ts | 45 + src/components/VerticalAxis.module.scss | 14 + src/components/VerticalAxis.ts | 176 + src/components/index.ts | 8 + src/components/utils.ts | 66 + src/coords.ts | 371 + src/dims.ts | 86 + src/index.ts | 86 + src/scss.modules.d.ts | 4 + src/types.ts | 110 + src/utils.ts | 67 + src/variables.scss | 4 + tests/helpers.ts | 10 + tests/scssMock.ts | 1 + tsconfig.json | 20 + 53 files changed, 12750 insertions(+) create mode 100644 .eslintrc.ts create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/00-100.png create mode 100644 assets/00-50.png create mode 100644 assets/01-100.png create mode 100644 assets/01-50.png create mode 100644 assets/logo.svg create mode 100644 examples/index.html create mode 100644 jest.config.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 rollup.config.ts create mode 100644 src/charts/bar.ts create mode 100644 src/charts/bubble.ts create mode 100644 src/charts/pie.ts create mode 100644 src/charts/treemap.ts create mode 100644 src/charts/types.ts create mode 100644 src/charts/utils.ts create mode 100644 src/colors.ts create mode 100644 src/components/ColorLegend.module.scss create mode 100644 src/components/ColorLegend.ts create mode 100644 src/components/Datum.module.scss create mode 100644 src/components/Datum.ts create mode 100644 src/components/Group.module.scss create mode 100644 src/components/Group.ts create mode 100644 src/components/Step.ts create mode 100644 src/components/Svg.module.scss create mode 100644 src/components/Svg.ts create mode 100644 src/components/Text.module.scss create mode 100644 src/components/Text.spec.ts create mode 100644 src/components/Text.ts create mode 100644 src/components/Tick.module.scss create mode 100644 src/components/Tick.ts create mode 100644 src/components/Tooltip.module.scss create mode 100644 src/components/Tooltip.ts create mode 100644 src/components/VerticalAxis.module.scss create mode 100644 src/components/VerticalAxis.ts create mode 100644 src/components/index.ts create mode 100644 src/components/utils.ts create mode 100644 src/coords.ts create mode 100644 src/dims.ts create mode 100644 src/index.ts create mode 100644 src/scss.modules.d.ts create mode 100644 src/types.ts create mode 100644 src/utils.ts create mode 100644 src/variables.scss create mode 100644 tests/helpers.ts create mode 100644 tests/scssMock.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.ts b/.eslintrc.ts new file mode 100644 index 0000000..e78ad04 --- /dev/null +++ b/.eslintrc.ts @@ -0,0 +1,13 @@ +module.exports = { + env: { + node: true, + }, + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier", + ], +}; diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..04aeca3 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,21 @@ +name: Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 18.x + uses: actions/setup-node@v3 + with: + node-version: 18.x + - name: Install dependencies + run: npm install + - run: npm test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db4c6d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ac2549f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 80, + "semi": true, + "singleQuote": false, + "trailingComma": "es5" +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2e1a5cd --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2023 Bartosz Prusinowski + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ce57dc --- /dev/null +++ b/README.md @@ -0,0 +1,402 @@ +# Plotteus + + + +**Plotteus** is a JavaScript library designed for better storytelling. Plotteus is a powerful tool that allows you to create interactive visualizations for your story from scratch, starting with defining a chart type, through seamless transitions between states, to giving you full control over them. Bet you'll fall in love at first chart? + +## Installing + +To install Plotteus, run `npm install plotteus`. Plotteus uses ES modules, so it can be used both in the Node.js environment as well as directly in the browser with `type="module"`. + +**Node.js** + +```ts +import { makeStory } from "plotteus"; + +const story = makeStory(div, steps); +``` + +**Browser** + +```html + +``` + +## Getting started + +A core part of Plotteus is the `makeStory` function, which takes a `div` element and an array of `Steps` containing instructions on how to construct a story. + +When called, it returns an object that exposes a `render` method that takes `stepKey` as the first argument and `progress` (a value between `0` and `1`) as the second argument. + +Plotteus is based on transitions between consecutive steps. To animate things correctly, it uses key-matching between elements to determine whether they are entering, updating or exiting. + +```ts +import { makeStory } from "plotteus"; + +const div = document.querySelector("#story"); +const steps = [ + { + key: "intro", + chartType: "treemap", + title: "Plotteus", + titleAnchor: "middle", + subtitle: "A data storytelling library.", + subtitleAnchor: "middle", + showValues: true, + showDatumLabels: true, + groups: [ + { + key: "Alice", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 2 }, + { key: "C", value: 3 }, + ], + }, + { + key: "Bob", + data: [ + { key: "A", value: 3 }, + { key: "B", value: 4 }, + { key: "C", value: 2 }, + ], + }, + { + key: "Cecile", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 5 }, + { key: "C", value: 2 }, + ], + }, + ], + }, +]; +const story = makeStory(div, steps); + +story.render("intro", 1); +``` + + + +## Why should I use Plotteus? + +### 🕹ī¸ Fine-grained control + +One of the strengths of Plotteus is that it gives you complete control over how to present your data stories. Popular approaches to data storytelling focus on using a bunch of charts that remain blended in the text or a sticky chart connected to a set of _triggers_ that start an animation when activated, usually by scrolling. + +Plotteus gives you more freedom – it creates a set of interpolators that can be used to render a given part of a story at any progress. **This means that you can render your story incrementally as the user scrolls through the page, use a slider to control the progress or replicate the _trigger_ approach to completely render a step over a given duration.** + +You have the power to choose. + +### đŸŽŦ Smooth transitions + +Another behavior that is usually hard to achieve is the _smoothness_ of a story. Since some chart types may be better suited for a specific slice of the data better than others, it would be nice to be able to make a transition between them while keeping the data in context. + +For example, you might want to highlight several parts of a treemap and compare them using a bar chart. Normally, you would have to _exit_ the entire treemap and _enter_ a new bar chart with only the data you need (which could make it difficult to keep the track of the parts being compared and their position in the previous treemap). **In Plotteus, you can seamlessly animate any chart type into any other chart type.** + +Plotteus also makes it easy to do other _basic_ things that are also essential for data storytelling – like highlighting, sorting, or adding new data, all nicely animated. + +### 💃 Fun + +Limitless animations and a powerful mechanism to control them combined with a config-based approach, customizability, and responsiveness, make for a powerful combination that results in more enjoyable and memorable ways to tell your stories. + +## API Reference + +### 📊 Making a story + +```ts +const div = document.querySelector("#story"); +const groups: Group[] = [ + { + key: "Alice", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 2 }, + { key: "C", value: 3 }, + ], + }, + { + key: "Bob", + data: [ + { key: "A", value: 3 }, + { key: "B", value: 4 }, + { key: "C", value: 2 }, + ], + }, + { + key: "Cecile", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 5 }, + { key: "C", value: 2 }, + ], + }, +]; +const baseStep = { + title: "Plotteus", + titleAnchor: "middle", + subtitle: "A data storytelling library.", + subtitleAnchor: "middle", + showValues: true, + showDatumLabels: true, + groups, +}; +const steps: Step[] = [ + { + key: "zero", + chartType: "treemap", + ...baseStep, + }, + { + key: "one", + chartType: "bar", + ...baseStep, + }, +]; +const story = makeStory(div, steps); +``` + +After a story is created, it can be rendered by passing `stepKey` and `progress` arguments to the `render` function. The third, optional boolean argument indicates whether the progress of the step should be displayed (left border of the SVG, default: `true`). + +```ts +story.render("zero", 0.5); +``` + + + +```ts +story.render("zero", 1); // same as story.render("intro-2", 0) +``` + + + +```ts +story.render("one", 0.5); +``` + + + +```ts +story.render("one", 1); +``` + + + +And that's how it looks in action – animation is controlled by scrolling up or down. + +https://user-images.githubusercontent.com/52032047/221407756-3038fae9-84ed-4d77-bb81-da74678ca4e9.mov + +### ⚙ī¸ Step configuration + +```ts +type Step = { + // Unique identifier of a step. + // Passed as a first argument to the `render` method. + key: string; + chartType: "bar" | "bubble" | "pie" | "treemap"; + // Only applicable for bar chart. + chartSubtype?: "grouped" | "stacked"; + title?: string; + titleAnchor?: "start" | "middle" | "end"; + subtitle?: string; + subtitleAnchor?: "start" | "middle" | "end"; + // If true, shares the color domain between groups. + shareDomain?: boolean; + showLegend?: boolean; + legendAnchor?: "start" | "middle" | "end"; + showValues?: boolean; + // Artificial maximum value. + // Useful for fixing the value scale domain to show evolution of values. + maxValue?: number; + showDatumLabels?: boolean; + // Only applicable for bar chart. + verticalAxis?: { + show?: boolean; + title?: string; + }; + palette?: "default" | "pastel" | "vivid" | "oranges"; + // If true, enables hand-drawn look. + cartoonize?: boolean; + // Data used to render a chart. + groups: Array<{ + // Unique identifier of a group. + // Will be used to match and animate the groups between consecutive steps. + key: string; + opacity?: number; + data: Array<{ + // Unique identifier of a datum. + // Will be used to match and animate the data inside a given group between + // consecutive steps. + key: string; + value: number; + // Use when you want to move a given datum across groups. + // Should be defined as "groupKey:datumKey" for a datum from an exiting + // group you want to "teleport" it from. + teleportFrom?: string; + // HEX, e.g. "#CCCCCC" + fill?: string; + opacity?: number; + }>; + }>; +}; +``` + +### 🔠 Every group is a chart + +One of the principles that makes it possible to _animate anything_ is the approach to the data itself. In Plotteus, you pass the data to create a chart in an array of `Group` objects – each `Group` contains an array of `Datum` objects. + +You can think of each `Group` as a separate chart. Let's explain what this means on a chart-basis, assuming we want our chart to contain three elements: A, B, C, each with a numerical value assigned to it. + +#### Bar + +To make a bar chart, you need to pass three groups, each with one `Datum` attached. + +```ts +const groups = [ + { + key: "A", + data: [{ key: "value", value: 1 }], + }, + { + key: "B", + data: [{ key: "value", value: 2 }], + }, + { + key: "C", + data: [{ key: "value", value: 3 }], + }, +]; +``` + +While technically you could also make the same chart with just one `Group` and a `shareDomain = false`, the above approach makes it quite easy to make a proper grouped bar chart. + +```ts +const groups = [ + { + key: "A", + data: [ + { key: "value", value: 1 }, + { key: "otherValue", value: 2 }, + ], + }, + { + key: "B", + data: [ + { key: "value", value: 2 }, + { key: "otherValue", value: 3 }, + ], + }, + { + key: "C", + data: [ + { key: "value", value: 3 }, + { key: "otherValue", value: 4 }, + ], + }, +]; +``` + +#### Bubble, Pie, Treemap + +For other chart types, you'll want to have one chart that contains all three values. + +```ts +const groups = [ + { + key: "firstGroup", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 2 }, + { key: "C", value: 3 }, + ], + }, +]; +``` + +As with the bar chart, you could change the approach to using three `Groups` with one `Datum` each, if it better suits your needs. However, with the above approach, another group can easily be added. + +```ts +const groups = [ + { + key: "firstGroup", + data: [ + { key: "A", value: 1 }, + { key: "B", value: 2 }, + { key: "C", value: 3 }, + ], + }, + { + key: "secondGroup", + data: [ + { key: "A", value: 2 }, + { key: "B", value: 3 }, + { key: "C", value: 4 }, + ], + }, +]; +``` + +You can structure your `Steps` to be based on either more groups (as with the bar chart) or fewer groups (other charts). The main difference between them is that, by default, the color domain is shared at the `Datum` level for bar and pie charts and at the `Group` level for other charts. + +This decision comes from the experience that bar charts usually share the same domain within groups (so, _A_ in one group should have the same color as _A_ in all other groups). Pie charts, well, usually do not share the same color within the group, as you would end up with monochromatic slices. Bubble and treemap charts, on the other hand, usually have different "children" within groups. However, you can freely change this behavior by manually setting `shareDomain` to suit your needs, e.g. if you'd like to have a three-group bar chart with colors based on `Group` rather than `Datum`. + +While this design gives you a lot of freedom to manipulate the elements, it can also pose a problem if you want to make some specific animations. + +#### 🛸 Datum teleportation + +For complex animations such as _extracting_ some data from a grouped bubble / pie / treemap chart to show a single grouped bar chart based on it, Plotteus offers _datum teleportation_. + +To _teleport_ a `Datum` from a given **exiting** `Group`, you can add a `teleportFrom` property to it, in the form of a `previousGroupKey:previousDatumKey` string to intercept it from such a `Group` instead of showing a regular _entering_ animation. + +```ts +// Step 1, bar chart. +const barChartGroups = [ + { key: "A", data: [{ key: "value", value: 1 }] }, + { key: "B", data: [{ key: "value", value: 2 }] }, + { key: "C", data: [{ key: "value", value: 3 }] }, +]; + +// Step 2, pie chart. +const pieChartGroups = [ + { + key: "pieGroup", + data: [ + { key: "A", value: 1, teleportFrom: "A:value" }, + { key: "B", value: 2, teleportFrom: "A:value" }, + { key: "C", value: 3, teleportFrom: "A:value" }, + ], + }, +]; + +// Step 3 grouped bar chart. +const barChartGroups = [ + { + key: "A", + data: [ + { key: "value", value: 1, teleportFrom: "pieGroup:A" }, + { key: "otherValue", value: 2 }, + ], + }, + { + key: "B", + data: [ + { key: "value", value: 2, teleportFrom: "pieGroup:B" }, + { key: "otherValue", value: 3 }, + ], + }, + { + key: "C", + data: [ + { key: "value", value: 3, teleportFrom: "pieGroup:C" }, + { key: "otherValue", value: 4 }, + ], + }, +]; +``` + +Keep in mind that this is mostly needed for advanced use cases – for basic stuff, the default built-in key matching should be sufficient. diff --git a/assets/00-100.png b/assets/00-100.png new file mode 100644 index 0000000000000000000000000000000000000000..a34dd58abc9bcaab20045273028191c80f2dce6f GIT binary patch literal 70982 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 literal 0 HcmV?d00001 diff --git a/assets/00-50.png b/assets/00-50.png new file mode 100644 index 0000000000000000000000000000000000000000..1a233b8be6a3285edf771c1e8a009804daf3b363 GIT binary patch literal 67766 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 z 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 Rcl`#uj+q_*vB1&a(gj literal 0 HcmV?d00001 diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..db0cc54 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 0000000..32e9bcf --- /dev/null +++ b/examples/index.html @@ -0,0 +1,235 @@ + + + + + + Plotteus + + + + + + +

+
+
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/jest.config.json b/jest.config.json new file mode 100644 index 0000000..0b832a6 --- /dev/null +++ b/jest.config.json @@ -0,0 +1,12 @@ +{ + "preset": "ts-jest", + "testEnvironment": "jsdom", + "transform": { + "^.+\\.ts?$": "ts-jest" + }, + "moduleNameMapper": { + "^d3-(.*)$": "d3-$1/dist/d3-$1", + "\\.scss$": "/tests/scssMock.ts" + }, + "transformIgnorePatterns": ["/node_modules/"] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9a21cf8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8297 @@ +{ + "name": "plotteus", + "version": "1.0.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "plotteus", + "version": "1.0.2", + "license": "ISC", + "dependencies": { + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-path": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^13.1.3", + "@rollup/plugin-typescript": "^8.3.0", + "@types/d3-hierarchy": "^3.1.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-path": "^3.0.0", + "@types/d3-scale": "^4.0.2", + "@types/d3-selection": "^3.0.3", + "@types/d3-shape": "^3.1.0", + "@types/jest": "^27.5.2", + "@typescript-eslint/parser": "^5.12.0", + "autoprefixer": "^10.4.2", + "jest": "^27.5.1", + "prettier": "^2.5.1", + "rollup": "^2.67.3", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-terser": "^7.0.2", + "ts-jest": "^27.1.3", + "typescript": "^4.5.5", + "typescript-plugin-css-modules": "^3.4.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.17.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.3", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.3", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^2.42.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "8.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0", + "tslib": "*", + "typescript": ">=3.7.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.18", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.14.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/d3-color": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-selection": { + "version": "3.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "17.0.18", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prettier": { + "version": "2.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.12.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.12.0", + "@typescript-eslint/types": "5.12.0", + "@typescript-eslint/typescript-estree": "5.12.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.12.0", + "@typescript-eslint/visitor-keys": "5.12.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.12.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.12.0", + "@typescript-eslint/visitor-keys": "5.12.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.12.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abab": { + "version": "2.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.7.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0", + "peer": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/atob": { + "version": "2.1.2", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/big.js": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.19.1", + "dev": true, + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001312", + "dev": true, + "license": "CC-BY-4.0", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.2", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/concat-with-sourcemaps/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css": { + "version": "2.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.1.4", + "dev": true, + "license": "ISC", + "dependencies": { + "timsort": "^0.3.0" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-parse": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "css": "^2.0.0" + } + }, + "node_modules/css-select": { + "version": "4.2.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-selector-tokenizer": { + "version": "0.7.3", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "5.1.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.0.17", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^5.1.12", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "css-declaration-sorter": "^6.0.3", + "cssnano-utils": "^3.0.2", + "postcss-calc": "^8.2.0", + "postcss-colormin": "^5.2.5", + "postcss-convert-values": "^5.0.4", + "postcss-discard-comments": "^5.0.3", + "postcss-discard-duplicates": "^5.0.3", + "postcss-discard-empty": "^5.0.3", + "postcss-discard-overridden": "^5.0.4", + "postcss-merge-longhand": "^5.0.6", + "postcss-merge-rules": "^5.0.6", + "postcss-minify-font-values": "^5.0.4", + "postcss-minify-gradients": "^5.0.6", + "postcss-minify-params": "^5.0.5", + "postcss-minify-selectors": "^5.1.3", + "postcss-normalize-charset": "^5.0.3", + "postcss-normalize-display-values": "^5.0.3", + "postcss-normalize-positions": "^5.0.4", + "postcss-normalize-repeat-style": "^5.0.4", + "postcss-normalize-string": "^5.0.4", + "postcss-normalize-timing-functions": "^5.0.3", + "postcss-normalize-unicode": "^5.0.4", + "postcss-normalize-url": "^5.0.5", + "postcss-normalize-whitespace": "^5.0.4", + "postcss-ordered-values": "^5.0.5", + "postcss-reduce-initial": "^5.0.3", + "postcss-reduce-transforms": "^5.0.4", + "postcss-svgo": "^5.0.4", + "postcss-unique-selectors": "^5.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.1", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.0.0", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.71", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.9.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint/eslintrc": "^1.1.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastparse": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.13.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/form-data": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/generic-names": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^3.2.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "dev": true, + "license": "ISC" + }, + "node_modules/has": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/import-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "import-from": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/internmap": { + "version": "2.0.3", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/is-what": { + "version": "3.14.1", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.1.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-haste-map/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json5": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/less": { + "version": "4.1.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^2.5.2", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/loader-utils": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "dev": true, + "license": "MIT" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/needle": { + "version": "2.9.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.0.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.6", + "dev": true, + "license": "MIT", + "dependencies": { + "nanoid": "^3.2.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-filter-plugins": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss": "^6.0.14" + } + }, + "node_modules/postcss-filter-plugins/node_modules/postcss": { + "version": "6.0.23", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-filter-plugins/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-icss-keyframes": { + "version": "0.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^3.0.1", + "postcss": "^6.0.2", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/postcss-icss-keyframes/node_modules/icss-utils": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss": "^6.0.2" + } + }, + "node_modules/postcss-icss-keyframes/node_modules/postcss": { + "version": "6.0.23", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-icss-keyframes/node_modules/postcss-value-parser": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-icss-keyframes/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-icss-selectors": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "css-selector-tokenizer": "^0.7.0", + "generic-names": "^1.0.2", + "icss-utils": "^3.0.1", + "lodash": "^4.17.4", + "postcss": "^6.0.2" + } + }, + "node_modules/postcss-icss-selectors/node_modules/generic-names": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^0.2.16" + } + }, + "node_modules/postcss-icss-selectors/node_modules/icss-utils": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss": "^6.0.2" + } + }, + "node_modules/postcss-icss-selectors/node_modules/json5": { + "version": "0.5.1", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/postcss-icss-selectors/node_modules/loader-utils": { + "version": "0.2.17", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "node_modules/postcss-icss-selectors/node_modules/postcss": { + "version": "6.0.23", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-icss-selectors/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.4", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.0.3" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.0.2", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "cssnano-utils": "^3.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "generic-names": "^4.0.0", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-utils": "^3.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.5.1", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/promise.series": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/psl": { + "version": "1.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reserved-words": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.67.3", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-postcss": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "concat-with-sourcemaps": "^1.1.0", + "cssnano": "^5.0.1", + "import-cwd": "^3.0.0", + "p-queue": "^6.6.2", + "pify": "^5.0.0", + "postcss-load-config": "^3.0.0", + "postcss-modules": "^4.0.0", + "promise.series": "^0.2.0", + "resolve": "^1.19.0", + "rollup-pluginutils": "^2.8.2", + "safe-identifier": "^0.4.2", + "style-inject": "^0.3.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "8.x" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup-plugin-postcss/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "dev": true, + "license": "ISC" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.49.8", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "dev": true, + "license": "ISC" + }, + "node_modules/saxes": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.7.3", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stable": { + "version": "0.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/string-length": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-inject": { + "version": "0.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stylehacks": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.16.6", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/stylus": { + "version": "0.54.8", + "dev": true, + "license": "MIT", + "dependencies": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.6", + "mkdirp": "~1.0.4", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.3.0", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stylus/node_modules/debug": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stylus/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stylus/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svgo": { + "version": "2.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.10.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "acorn": "^8.5.0" + }, + "peerDependenciesMeta": { + "acorn": { + "optional": true + } + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/throat": { + "version": "6.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/timsort": { + "version": "0.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-jest": { + "version": "27.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "esbuild": "~0.14.0", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/json5": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.5.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typescript-plugin-css-modules": { + "version": "3.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dotenv": "^10.0.0", + "icss-utils": "^5.1.0", + "less": "^4.1.1", + "lodash.camelcase": "^4.3.0", + "postcss": "^8.3.0", + "postcss-filter-plugins": "^3.0.1", + "postcss-icss-keyframes": "^0.2.1", + "postcss-icss-selectors": "^2.0.3", + "postcss-load-config": "^3.0.1", + "reserved-words": "^0.1.2", + "sass": "^1.32.13", + "stylus": "^0.54.8", + "tsconfig-paths": "^3.9.0" + }, + "peerDependencies": { + "typescript": ">=3.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6cdf991 --- /dev/null +++ b/package.json @@ -0,0 +1,62 @@ +{ + "name": "plotteus", + "version": "1.0.2", + "description": "đŸĻ„ Plotteus is a JavaScript data visualization library designed to help you tell better stories.", + "homepage": "https://plotteus.dev", + "repository": "github:bprusinowski/plotteus", + "keywords": [ + "plotteus", + "visualization", + "svg", + "chart", + "charts", + "data-visualization", + "data-stories", + "data-storytelling" + ], + "license": "ISC", + "author": { + "name": "Bartosz Prusinowski", + "email": "bartoszprusinowski1@gmail.com" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "test": "jest -c", + "build": "rm -rf ./dist && rollup -c", + "lint": "eslint" + }, + "type": "module", + "files": [ + "dist/**/*" + ], + "dependencies": { + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-path": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^13.1.3", + "@rollup/plugin-typescript": "^8.3.0", + "@types/d3-hierarchy": "^3.1.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-path": "^3.0.0", + "@types/d3-scale": "^4.0.2", + "@types/d3-selection": "^3.0.3", + "@types/d3-shape": "^3.1.0", + "@types/jest": "^27.5.2", + "@typescript-eslint/parser": "^5.12.0", + "autoprefixer": "^10.4.2", + "jest": "^27.5.1", + "prettier": "^2.5.1", + "rollup": "^2.67.3", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-terser": "^7.0.2", + "ts-jest": "^27.1.3", + "typescript": "^4.5.5", + "typescript-plugin-css-modules": "^3.4.0" + } +} diff --git a/rollup.config.ts b/rollup.config.ts new file mode 100644 index 0000000..fa5d653 --- /dev/null +++ b/rollup.config.ts @@ -0,0 +1,30 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; +import autoprefixer from "autoprefixer"; +import postcss from "rollup-plugin-postcss"; +import { terser } from "rollup-plugin-terser"; + +export default [ + { + input: "src/index.ts", + output: { + dir: "dist", + format: "es", + }, + plugins: [ + nodeResolve(), + postcss({ + modules: true, + plugins: [autoprefixer()], + }), + terser({ + format: { + comments: false, + }, + }), + typescript({ + outDir: "dist", + }), + ], + }, +]; diff --git a/src/charts/bar.ts b/src/charts/bar.ts new file mode 100644 index 0000000..48c4496 --- /dev/null +++ b/src/charts/bar.ts @@ -0,0 +1,222 @@ +import { ScaleBand, scaleBand, ScaleLinear, scaleLinear } from "d3-scale"; +import { Datum, Group } from "../components"; +import { BAR, getPathData } from "../coords"; +import { BarChartSubtype, MaxValue } from "../types"; +import { FONT_SIZE, getTextColor } from "../utils"; +import { getGroupLabelStrokeWidth, getRotate, TEXT_MARGIN } from "./utils"; + +const PADDING_X0 = 0.1; +const PADDING_X1 = 0.05; + +export const getBarGetters = ( + subtype: BarChartSubtype, + { + groups, + groupsKeys, + dataKeys, + shareDomain, + maxValue, + showValues, + showDatumLabels, + svg, + dims: { width, height, margin, BASE_MARGIN }, + textDims, + colorMap, + cartoonize, + }: Group.GetterProps +): Group.Getter[] => { + const isGrouped = subtype === "grouped"; + const { x0Scale, x0bw, x1Scale, x1bw, yScale } = getScales({ + isGrouped, + groupsKeys, + dataKeys, + maxValue, + width, + height, + }); + const groupsGetters: Group.Getter[] = []; + + for (const group of groups) { + const { key } = group; + const groupX0 = x0Scale(key) as number; + const groupGetters: Group.Getter = { + key, + g: ({ s, _g }) => { + const d = BAR; + const x = margin.left + groupX0 + x0bw * 0.5; + const y = margin.top + height; + const labelX = 0; + const labelY = BASE_MARGIN; + const labelFontSize = s(0, shareDomain ? FONT_SIZE.groupLabel : 0); + const labelStrokeWidth = getGroupLabelStrokeWidth(labelFontSize); + const opacity = group.opacity ?? 1; + + return { + d, + x: s(x, null, _g?.x), + y: s(y, null, _g?.y), + labelX, + labelY, + labelFontSize, + labelStrokeWidth, + opacity, + }; + }, + data: [], + }; + + let accHeight = 0; + + for (const datum of group.data) { + const { key, value, fill } = datum; + + if (!shareDomain) { + x1Scale.domain(group.data.map((d) => d.key)); + } + + const datumX = x1Scale(key) as number; + const datumY = yScale(value); + const dHeight = height - datumY; + + const currentAccHeight = accHeight; + + if (!isGrouped) { + accHeight += dHeight; + } + + const datumFill = fill ?? colorMap.get(key, group.key, shareDomain); + const getD = (padding = 0): string => { + return getPathData({ + type: "bar", + width: x1bw, + height: dHeight + padding, + cartoonize, + }); + }; + const labelHeight = textDims.datumLabel.height; + const labelYShift = textDims.datumLabel.yShift; + const valueHeight = textDims.datumValue.height; + const valueYShift = textDims.datumValue.yShift; + + const datumGetters: Datum.Getter = { + key, + teleportKey: `${group.key}:${key}`, + teleportFrom: datum.teleportFrom, + value, + g: ({ s, _g }) => { + const d = s(BAR, getD()); + const clipPath = + isGrouped && showValues ? s(BAR, getD(valueHeight * 2)) : d; + const x = s(0, datumX + (x1bw - x0bw) * 0.5); + const y = s(0, (datumY - height) * 0.5 - currentAccHeight); + const rotate = getRotate(_g?.rotate); + const labelX = isGrouped + ? 0 + : s( + 0, + (svg.measureText(key, "datumLabel").width - x1bw) * 0.5 + + TEXT_MARGIN + ); + const labelY = isGrouped + ? s(0, dHeight * 0.5 - labelHeight - TEXT_MARGIN) + : s(0, -(dHeight * 0.5 + labelYShift)); + const labelFontSize = showDatumLabels ? FONT_SIZE.datumLabel : 0; + const labelFill = getTextColor(datumFill); + const valueX = isGrouped + ? 0 + : s( + 0, + (svg.measureText(value, "datumValue").width - x1bw) * 0.5 + + TEXT_MARGIN + ); + const valueY = isGrouped + ? s(0, -(dHeight * 0.5 + valueHeight)) + : s( + 0, + showDatumLabels + ? labelY + labelHeight + : -(dHeight * 0.5 + valueYShift) + ); + const valueFontSize = showValues ? s(0, FONT_SIZE.datumValue) : 0; + const valueFill = isGrouped ? "black" : labelFill; + const opacity = datum.opacity ?? 1; + + return { + d, + clipPath, + x, + y, + fill: datumFill, + rotate, + labelX, + labelY, + labelFontSize, + labelFill, + valueX, + valueY, + valueFontSize, + valueFill, + opacity, + }; + }, + }; + + groupGetters.data.push(datumGetters); + } + + groupsGetters.push(groupGetters); + } + + return groupsGetters; +}; + +const getScales = ({ + isGrouped, + groupsKeys, + dataKeys, + maxValue, + width, + height, +}: { + isGrouped: boolean; + groupsKeys: string[]; + dataKeys: string[]; + maxValue: MaxValue; + width: number; + height: number; +}): { + x0Scale: ScaleBand; + x0bw: number; + x1Scale: ScaleBand; + x1bw: number; + yScale: ScaleLinear; +} => { + const singleGroup = groupsKeys.length === 1; + const x0Scale = scaleBand() + .domain(groupsKeys) + .range([0, width]) + .paddingInner(singleGroup || dataKeys.length === 1 ? 0 : PADDING_X0); + const x0bw = x0Scale.bandwidth(); + const yScale = scaleLinear() + .domain([0, maxValue.actual]) + .range([height, maxValue.actual === 0 ? height : 0]); + + const x1Scale = scaleBand().domain(dataKeys).paddingInner(PADDING_X1); + let x1bw: number; + + if (isGrouped) { + x1Scale.range([0, x0bw]); + x1bw = x1Scale.bandwidth(); + } else { + x1Scale.range([0, 0]); + x1bw = x0bw; + } + + return { + x0Scale, + x0bw, + x1Scale, + x1bw, + yScale, + }; +}; diff --git a/src/charts/bubble.ts b/src/charts/bubble.ts new file mode 100644 index 0000000..fec9e22 --- /dev/null +++ b/src/charts/bubble.ts @@ -0,0 +1,161 @@ +import { hierarchy, pack } from "d3-hierarchy"; +import { Datum, Group } from "../components"; +import { BUBBLE, getPathData } from "../coords"; +import { InputGroup } from "../types"; +import { FONT_SIZE, getTextColor } from "../utils"; +import { HierarchyRoot } from "./types"; +import { getGroupLabelStrokeWidth, getRotate, PADDING } from "./utils"; + +export const getBubbleGetters = ({ + groups, + shareDomain, + maxValue, + showValues, + showDatumLabels, + dims: { width, height, size, margin }, + textDims, + colorMap, + cartoonize, +}: Group.GetterProps): Group.Getter[] => { + const root = getRoot({ groups, size: maxValue.k * size }); + const groupsGetters: Group.Getter[] = []; + // If a custom maxValue was provided, we need to shift the bubbles to the center. + const maxValueShift = maxValue.kc * size * 0.5; + const showDatumLabelsAndValues = showDatumLabels && showValues; + + for (const group of root.children || []) { + const { key } = group.data; + + // Skip groups with no data. + if ( + isNaN(group.r) || + group.children?.reduce((acc, d) => (acc += d.r), 0) === 0 + ) { + continue; + } + + const singleDatum = group.children?.length === 1; + const groupGetters: Group.Getter = { + key, + g: ({ s, _g }) => { + const d = s( + BUBBLE, + getPathData({ + type: "bubble", + r: group.r, + cartoonize, + }) + ); + const x = margin.left + group.x + maxValueShift + (width - size) * 0.5; + const y = margin.top + group.y + maxValueShift + (height - size) * 0.5; + const labelX = 0; + const labelY = textDims.groupLabel.yShift; + const labelFontSize = s(0, shareDomain ? FONT_SIZE.groupLabel : 0); + const labelStrokeWidth = getGroupLabelStrokeWidth(labelFontSize); + const opacity = group.data.opacity ?? 1; + + return { + d, + x: s(x, null, _g?.x), + y: s(y, null, _g?.y), + labelX, + labelY, + labelFontSize, + labelStrokeWidth, + opacity, + }; + }, + data: [], + }; + + for (const datum of group.children || []) { + const { key, value, fill } = datum.data; + const datumFill = fill ?? colorMap.get(key, group.data.key, shareDomain); + const datumGetters: Datum.Getter = { + key, + teleportKey: `${group.data.key}:${key}`, + teleportFrom: datum.data.teleportFrom, + value, + g: ({ s, _g }) => { + const d = s( + BUBBLE, + getPathData({ + type: "bubble", + r: datum.r, + cartoonize, + }) + ); + const clipPath = d; + const x = s(0, group.x - datum.x); + const y = s(0, group.y - datum.y); + const rotate = getRotate(_g?.rotate, cartoonize); + const labelX = 0; + const labelY = + textDims.datumLabel.yShift - + (showDatumLabelsAndValues ? textDims.datumLabel.height * 0.5 : 0); + const labelFontSize = showDatumLabels ? FONT_SIZE.datumLabel : 0; + const labelFill = getTextColor(datumFill); + const valueX = 0; + const valueY = s( + 0, + (singleDatum && key + ? datum.r * 0.5 + textDims.datumValue.yShift + : textDims.datumValue.yShift) + + (showDatumLabels ? textDims.datumLabel.height : 0) - + (showDatumLabelsAndValues ? textDims.datumLabel.height * 0.5 : 0) + ); + const valueFontSize = showValues ? s(0, FONT_SIZE.datumValue) : 0; + const valueFill = labelFill; + const opacity = datum.data.opacity ?? 1; + + return { + d, + clipPath, + x, + y, + fill: datumFill, + rotate, + labelX, + labelY, + labelFontSize, + labelFill, + valueX, + valueY, + valueFontSize, + valueFill, + opacity, + }; + }, + }; + + groupGetters.data.push(datumGetters); + } + + groupsGetters.push(groupGetters); + } + + return groupsGetters; +}; + +const getRoot = ({ + groups, + size, +}: { + groups: InputGroup[]; + size: number; +}): HierarchyRoot => { + const root = hierarchy({ + children: groups.map((d) => ({ + key: d.key, + opacity: d.opacity, + children: d.data, + })), + }).sum((d) => Math.max(0, (d as any).value)); + const descendants = root.descendants(); + const leaves = descendants.filter((d) => !d.children); + leaves.forEach((d: any, i) => (d.index = i)); + root.sort((a: any, b: any) => a.index - b.index); + pack().size([size, size]).padding(PADDING)(root); + + return root as any as HierarchyRoot; +}; diff --git a/src/charts/pie.ts b/src/charts/pie.ts new file mode 100644 index 0000000..12bdc17 --- /dev/null +++ b/src/charts/pie.ts @@ -0,0 +1,188 @@ +import { hierarchy, pack } from "d3-hierarchy"; +import { pie, PieArcDatum } from "d3-shape"; +import { Datum, Group } from "../components"; +import { BUBBLE, getPathData } from "../coords"; +import { InputDatum, InputGroup } from "../types"; +import { FONT_SIZE, getTextColor, radiansToDegrees } from "../utils"; +import { HierarchyRoot } from "./types"; +import { getGroupLabelStrokeWidth, PADDING } from "./utils"; + +export const getPieGetters = ({ + groups, + shareDomain, + maxValue, + showValues, + showDatumLabels, + dims: { width, height, size, margin }, + textDims, + colorMap, + cartoonize, +}: Group.GetterProps): Group.Getter[] => { + const root = getRoot({ groups, size: maxValue.k * size }); + const groupsGetters: Group.Getter[] = []; + const maxValueShift = maxValue.kc * size * 0.5; + const showDatumLabelsAndValues = showDatumLabels && showValues; + + for (const group of root.children || []) { + const { key } = group.data; + + // Skip groups with no data. + if ( + isNaN(group.r) || + group.children?.reduce((acc, d) => (acc += d.r), 0) === 0 + ) { + continue; + } + + const groupGetters: Group.Getter = { + key, + g: ({ s, _g }) => { + const d = BUBBLE; + const x = margin.left + group.x + maxValueShift + (width - size) * 0.5; + const y = margin.top + group.y + maxValueShift + (height - size) * 0.5; + const labelX = 0; + const labelY = textDims.groupLabel.yShift; + const labelFontSize = + groups.length > 1 ? s(0, shareDomain ? FONT_SIZE.groupLabel : 0) : 0; + const labelStrokeWidth = getGroupLabelStrokeWidth(labelFontSize); + const opacity = group.data.opacity ?? 1; + + return { + d, + x: s(x, null, _g?.x), + y: s(y, null, _g?.y), + labelX, + labelY, + labelFontSize, + labelStrokeWidth, + opacity, + }; + }, + data: [], + }; + + const data = pie().value((d: any) => d.value)( + group.children || ([] as any) + ) as unknown as PieArcDatum<{ data: InputDatum }>[]; + + data.map((datum, i) => { + const { key, value, fill } = datum.data.data; + const angleExtent = datum.endAngle - datum.startAngle; + let rotate = (angleExtent - Math.PI) * 0.5; + const _datum = data?.[i - 1]; + + if (_datum) { + data.slice(0, i).forEach((d) => { + rotate += d.endAngle - d.startAngle; + }); + } + + const datumX = Math.sin(rotate) * group.r * 0.5; + const datumY = -Math.cos(rotate) * group.r * 0.5; + const datumFill = fill ?? colorMap.get(key, group.data.key, shareDomain); + + const rotateDegrees = radiansToDegrees(rotate); + const singlePie = data.length === 1; + + const datumGetters: Datum.Getter = { + key, + teleportKey: `${group.data.key}:${key}`, + teleportFrom: datum.data.data.teleportFrom, + value, + g: ({ s, _g }) => { + const d = s( + BUBBLE, + singlePie + ? getPathData({ + type: "bubble", + r: group.r, + cartoonize, + }) + : getPathData({ + type: "pie", + startAngle: 0, + endAngle: angleExtent, + r: group.r, + cartoonize, + }) + ); + const clipPath = d; + const x = s(0, datumX - (singlePie ? group.r * 0.5 : 0)); + const y = s(0, datumY); + const labelX = s( + x, + -x + group.r * 0.5 * Math.sin(rotate + Math.PI * 0.5) + ); + const labelY = + s( + y, + -y - + group.r * 0.5 * Math.cos(rotate + Math.PI * 0.5) + + textDims.datumValue.yShift + ) + + textDims.datumLabel.yShift - + // TODO: move by cos / sin. + (showDatumLabelsAndValues ? textDims.datumLabel.height * 0.5 : 0); + const labelFontSize = showDatumLabels ? FONT_SIZE.datumLabel : 0; + const labelFill = getTextColor(datumFill); + const valueX = labelX; + const valueY = + labelY + (showDatumLabels ? textDims.datumLabel.height : 0); + const valueFontSize = showValues ? s(0, FONT_SIZE.datumValue) : 0; + const valueFill = labelFill; + const opacity = datum.data.data.opacity ?? 1; + + return { + d, + clipPath, + x, + y, + fill: datumFill, + labelX, + labelY, + labelFontSize, + labelFill, + valueX, + valueY, + valueFontSize, + rotate: + rotateDegrees - (_g?.rotate ?? 0) >= 180 + ? rotateDegrees - 360 + : rotateDegrees, + valueFill, + opacity, + }; + }, + }; + + groupGetters.data.push(datumGetters); + }); + + groupsGetters.push(groupGetters); + } + + return groupsGetters; +}; + +const getRoot = ({ + groups, + size, +}: { + groups: InputGroup[]; + size: number; +}): HierarchyRoot => { + const root = hierarchy({ + children: groups.map((d) => ({ + key: d.key, + opacity: d.opacity, + children: d.data, + })), + }).sum((d) => Math.max(0, (d as any).value)); + const descendants = root.descendants(); + const leaves = descendants.filter((d) => !d.children); + leaves.forEach((d: any, i) => (d.index = i)); + root.sort((a: any, b: any) => a.index - b.index); + pack().size([size, size]).padding(PADDING)(root); + + return root as any as HierarchyRoot; +}; diff --git a/src/charts/treemap.ts b/src/charts/treemap.ts new file mode 100644 index 0000000..59c0f15 --- /dev/null +++ b/src/charts/treemap.ts @@ -0,0 +1,166 @@ +import { hierarchy, treemap, treemapResquarify } from "d3-hierarchy"; +import { Datum, Group } from "../components"; +import { BAR, getPathData } from "../coords"; +import { InputGroup } from "../types"; +import { FONT_SIZE, getTextColor } from "../utils"; +import { TreemapHierarchyRoot } from "./types"; +import { getGroupLabelStrokeWidth, getRotate, TEXT_MARGIN } from "./utils"; + +const PADDING = 2; + +export const getTreemapGetters = ({ + groups, + shareDomain, + maxValue, + showValues, + showDatumLabels, + svg, + dims: { width, height, margin }, + textDims, + colorMap, + cartoonize, +}: Group.GetterProps): Group.Getter[] => { + const root = getRoot({ + groups, + width: maxValue.k * width, + height: maxValue.k * height, + }); + const groupsGetters: Group.Getter[] = []; + + for (const group of root.children || []) { + const { key } = group.data; + + // Skip groups with no data. + if ( + group.value === 0 || + group.children?.reduce((acc, d) => (acc += d.value), 0) === 0 + ) { + continue; + } + + const groupWidth = group.x1 - group.x0; + const groupHeight = group.y1 - group.y0; + + const groupGetters: Group.Getter = { + key, + g: ({ s, _g }) => { + const d = BAR; + const x = + margin.left + group.x0 + (maxValue.kc * width + groupWidth) * 0.5; + const y = + margin.top + group.y0 + (maxValue.kc * height + groupHeight) * 0.5; + const labelX = 0; + const labelY = textDims.groupLabel.yShift; + const labelFontSize = s(0, shareDomain ? FONT_SIZE.groupLabel : 0); + const labelStrokeWidth = getGroupLabelStrokeWidth(labelFontSize); + const opacity = group.data.opacity ?? 1; + + return { + d, + x: s(x, null, _g?.x), + y: s(y, null, _g?.y), + labelX, + labelY, + labelFontSize, + labelStrokeWidth, + opacity, + }; + }, + data: [], + }; + + for (const datum of group.children || []) { + const { key, value, fill } = datum.data; + const dWidth = datum.x1 - datum.x0; + const dHeight = datum.y1 - datum.y0; + const datumFill = fill ?? colorMap.get(key, group.data.key, shareDomain); + + const datumGetters: Datum.Getter = { + key, + teleportKey: `${group.data.key}:${key}`, + teleportFrom: datum.data.teleportFrom, + value, + g: ({ s, _g }) => { + const d = s( + BAR, + getPathData({ + type: "bar", + width: dWidth, + height: dHeight, + cartoonize, + }) + ); + const clipPath = d; + const x = s(0, datum.x0 - group.x0 - (groupWidth - dWidth) * 0.5); + const y = s(0, datum.y0 - group.y0 - (groupHeight - dHeight) * 0.5); + const rotate = getRotate(_g?.rotate); + const labelWidth = svg.measureText(key, "datumLabel").width; + const labelX = s(0, (labelWidth - dWidth) * 0.5 + TEXT_MARGIN); + const labelY = s(0, -(dHeight * 0.5 + textDims.datumLabel.yShift)); + const labelFontSize = showDatumLabels ? FONT_SIZE.datumLabel : 0; + const labelFill = getTextColor(datumFill); + const valueWidth = svg.measureText(value, "datumValue").width; + const valueX = s(0, (valueWidth - dWidth) * 0.5 + TEXT_MARGIN); + const valueY = + labelY + (showDatumLabels ? textDims.datumValue.height : 0); + const valueFontSize = showValues ? s(0, FONT_SIZE.datumValue) : 0; + const valueFill = labelFill; + const opacity = datum.data.opacity ?? 1; + + return { + d, + clipPath, + x, + y, + fill: datumFill, + rotate, + labelX, + labelY, + labelFontSize, + labelFill, + valueX, + valueY, + valueFontSize, + valueFill, + opacity, + }; + }, + }; + + groupGetters.data.push(datumGetters); + } + + groupsGetters.push(groupGetters); + } + + return groupsGetters; +}; + +const getRoot = ({ + groups, + width, + height, +}: { + groups: InputGroup[]; + width: number; + height: number; +}): TreemapHierarchyRoot => { + const root = hierarchy({ + children: groups.map((d) => ({ + key: d.key, + opacity: d.opacity, + children: d.data, + })), + }).sum((d) => Math.max(0, (d as any).value)); + const descendants = root.descendants(); + const leaves = descendants.filter((d) => !d.children); + leaves.forEach((d: any, i) => (d.index = i)); + root.sort((a: any, b: any) => a.index - b.index); + treemap() + .tile(treemapResquarify) + .size([width, height]) + .paddingInner(PADDING) + .paddingOuter(PADDING)(root); + + return root as any as TreemapHierarchyRoot; +}; diff --git a/src/charts/types.ts b/src/charts/types.ts new file mode 100644 index 0000000..e75c277 --- /dev/null +++ b/src/charts/types.ts @@ -0,0 +1,30 @@ +import { InputDatum, InputGroup } from "../types"; + +type Root = { + r: number; + x: number; + y: number; + value: number; + data: T; +}; + +export type HierarchyRoot = { + children?: (Root & { + children?: Root[]; + })[]; +}; + +type TreemapRoot = { + x0: number; + x1: number; + y0: number; + y1: number; + value: number; + data: T; +}; + +export type TreemapHierarchyRoot = { + children?: (TreemapRoot & { + children?: TreemapRoot[]; + })[]; +}; diff --git a/src/charts/utils.ts b/src/charts/utils.ts new file mode 100644 index 0000000..255190a --- /dev/null +++ b/src/charts/utils.ts @@ -0,0 +1,16 @@ +// 0.5 seems too much. +export const HALF_FONT_K = 0.42; + +export const TEXT_MARGIN = 8; + +export const PADDING = 4; + +export const getRotate = (_rotate = 0, cartoonize?: boolean): number => { + const rotate = _rotate <= -90 ? -180 : _rotate <= 90 ? 0 : 180; + + return rotate + (cartoonize ? Math.random() * 20 - 10 : 0); +}; + +export const getGroupLabelStrokeWidth = (labelFontSize: number): number => { + return labelFontSize ? 3 : 0; +}; diff --git a/src/colors.ts b/src/colors.ts new file mode 100644 index 0000000..8539ccb --- /dev/null +++ b/src/colors.ts @@ -0,0 +1,51 @@ +export type PaletteName = "default" | "pastel" | "vivid" | "oranges"; + +const defaultPalette = ["#333333", "#FD7F6F", "#A48CF2", "#6BA6FF", "#FA667E"]; + +const pastelPalette = [ + "#b3cde3", + "#fbb4ae", + "#ccebc5", + "#decbe4", + "#fed9a6", + "#ffffcc", + "#e5d8bd", + "#fddaec", + "#f2f2f2", +]; + +const vividPalette = ["#79A0FB", "#FCBB7E", "#F5A3CF", "#BB89F0", "#BBE773"]; + +const orangesPalette = ["#ff9191", "#ffa984", "#ffc680", "#fce389", "#e9ffa1"]; + +export const getPalette = (d: PaletteName): string[] => { + switch (d) { + case "default": + return defaultPalette; + case "pastel": + return pastelPalette; + case "vivid": + return vividPalette; + case "oranges": + return orangesPalette; + } +}; + +export class ColorMap { + private colorMap: Map; + + constructor(domain: string[], paletteName: PaletteName) { + const palette = getPalette(paletteName); + this.colorMap = new Map( + domain.map((d, i) => [d, palette[i % palette.length]]) + ); + } + + public get(datumKey: string, groupKey: string, shareDomain: boolean): string { + return this.colorMap.get(shareDomain ? datumKey : groupKey) as string; + } + + public [Symbol.iterator]() { + return this.colorMap[Symbol.iterator](); + } +} diff --git a/src/components/ColorLegend.module.scss b/src/components/ColorLegend.module.scss new file mode 100644 index 0000000..8f3062e --- /dev/null +++ b/src/components/ColorLegend.module.scss @@ -0,0 +1,8 @@ +.root { + .item { + pointer-events: none; + .itemLabel { + dominant-baseline: hanging; + } + } +} diff --git a/src/components/ColorLegend.ts b/src/components/ColorLegend.ts new file mode 100644 index 0000000..80bade0 --- /dev/null +++ b/src/components/ColorLegend.ts @@ -0,0 +1,255 @@ +import { ColorMap } from "../colors"; +import { ResolvedDimensions } from "../dims"; +import { Anchor, GenericInt, GProps, State } from "../types"; +import { FONT_SIZE, FONT_WEIGHT, max } from "../utils"; +import style from "./ColorLegend.module.scss"; +import { Svg } from "./Svg"; +import { prepareInts } from "./utils"; + +const R = FONT_SIZE.legendItem / 3; + +type G = { + x: number; + y: number; + labelX: number; + labelY: number; + fill: string; + opacity: number; +}; + +export type Getter = { + key: string; + rowIndex: number; + fontSize: number; + g: (props: GProps) => G; +}; + +export const getters = ({ + colorMap, + anchor, + itemHeight, + svg, + dims: { width, height, margin, BASE_MARGIN }, +}: { + colorMap: ColorMap; + anchor: Anchor; + itemHeight: number; + svg: Svg; + dims: ResolvedDimensions; +}): Getter[] => { + const getters: Getter[] = []; + const colorsWithCoords: { + key: string; + rowIndex: number; + color: string; + x: number; + y: number; + }[] = []; + const ITEM_MARGIN = BASE_MARGIN + R; + + let rowIndex = 0; + let rowWidth = 0; + + let x: number; + switch (anchor) { + case "start": + x = 0; + break; + case "middle": + x = width * 0.5; + break; + case "end": + x = width; + break; + } + + let y = -itemHeight * 0.5; + + for (const [key, color] of colorMap) { + const { width: itemWidth } = svg.measureText(key, "legendItem"); + + // Move to a next row. + if (rowWidth + itemWidth + ITEM_MARGIN > width) { + rowWidth = 0; + + switch (anchor) { + case "start": + x = 0; + break; + case "middle": + x = width * 0.5; + break; + case "end": + x = width; + break; + } + + // Move items up. + colorsWithCoords + .filter((d) => d.rowIndex <= rowIndex) + .forEach((d) => { + d.y -= itemHeight; + }); + + rowIndex++; + } + + let itemX: number; + switch (anchor) { + case "start": + itemX = x; + break; + case "middle": + itemX = x - itemWidth * 0.5; + + // Move row's items to the left. + colorsWithCoords + .filter((d) => d.rowIndex === rowIndex) + .forEach((d) => { + d.x -= (itemWidth + ITEM_MARGIN) * 0.5; + }); + + break; + case "end": + itemX = x - itemWidth; + + // Move row's items to the left. + colorsWithCoords + .filter((d) => d.rowIndex === rowIndex) + .forEach((d) => { + d.x -= itemWidth + ITEM_MARGIN; + }); + + break; + } + + colorsWithCoords.push({ + key, + rowIndex, + color, + x: itemX, + y, + }); + + switch (anchor) { + case "start": + x += itemWidth + ITEM_MARGIN; + break; + case "middle": + x += (itemWidth + ITEM_MARGIN) * 0.5; + break; + case "end": + break; + } + + rowWidth += itemWidth + ITEM_MARGIN; + } + + for (const { key, x, y, color } of colorsWithCoords) { + getters.push({ + key, + rowIndex, + fontSize: FONT_SIZE.legendItem, + g: ({ s, _g }) => { + return { + x: s(margin.left + x, null, _g?.x), + y: s(height + margin.top + y, null, _g?.y), + labelX: R * 2, + labelY: (-itemHeight + R) * 0.5, + fill: color, + opacity: s(0, 1), + }; + }, + }); + } + + return getters; +}; + +export type Int = { + key: string; + state: State; + fontSize: number; + i: GenericInt; +}; + +export const ints = ({ + colorLegends = [], + _colorLegends, + _colorLegendInts, +}: { + colorLegends: Getter[] | undefined; + _colorLegends: Getter[] | undefined; + _colorLegendInts: Int[] | undefined; +}): Int[] => { + const keys = colorLegends.map((d) => d.key); + const exitingColors = + _colorLegends?.filter((d) => !keys.includes(d.key)) ?? []; + const colorLegendInts: Int[] = colorLegends + .concat(exitingColors) + .map(({ key, fontSize, g }) => { + const exiting = !keys.includes(key); + const _int = _colorLegendInts?.find((d) => d.key === key); + const { state, i } = prepareInts({ _int, exiting, g }); + const colorLegendInt: Int = { key, fontSize, state, i }; + + return colorLegendInt; + }); + + return colorLegendInts; +}; + +export type Resolved = { + key: string; + fontSize: number; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ key, fontSize, i }) => ({ key, fontSize, ...i(t) })); +}; + +export const render = ({ + svg, + resolved, +}: { + svg: Svg; + resolved: Resolved[]; +}): void => { + svg.selection + .selectAll(`.${style.root}`) + .data([null]) + .join("g") + .attr("class", style.root) + .selectAll(`.${style.item}`) + .data(resolved, (d) => d.key) + .join("g") + .attr("class", style.item) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("opacity", (d) => d.opacity) + .call((g) => + g + .selectAll("circle") + .data((d) => [d]) + .join("circle") + .attr("r", R) + .style("fill", (d) => d.fill) + ) + .call((g) => + g + .selectAll(`.${style.itemLabel}`) + .data((d) => [d]) + .join("text") + .attr("class", style.itemLabel) + .attr("x", (d) => d.labelX) + .attr("y", (d) => d.labelY) + .style("font-size", (d) => d.fontSize) + .style("font-weight", FONT_WEIGHT.legendItem) + .text((d) => d.key) + ); +}; + +// --- UTILS + +export const getHeight = (getters: Getter[], itemHeight: number): number => { + return ((max(getters.map((d) => d.rowIndex)) ?? -1) + 1) * itemHeight; +}; diff --git a/src/components/Datum.module.scss b/src/components/Datum.module.scss new file mode 100644 index 0000000..14ab09f --- /dev/null +++ b/src/components/Datum.module.scss @@ -0,0 +1,28 @@ +.node { + .datum { + will-change: transform; + .path { + will-change: d; + stroke: white; + stroke-width: 2; + } + .clipPath { + will-change: d; + } + .labels { + .label { + dominant-baseline: hanging; + text-anchor: middle; + user-select: none; + letter-spacing: 1.5; + pointer-events: none; + } + .value { + dominant-baseline: hanging; + text-anchor: middle; + user-select: none; + pointer-events: none; + } + } + } +} diff --git a/src/components/Datum.ts b/src/components/Datum.ts new file mode 100644 index 0000000..64cf449 --- /dev/null +++ b/src/components/Datum.ts @@ -0,0 +1,178 @@ +import { interpolate } from "d3-interpolate"; +import { select, Selection } from "d3-selection"; +import { GenericInt, GProps, State } from "../types"; +import { FONT_WEIGHT } from "../utils"; +import style from "./Datum.module.scss"; +import * as Group from "./Group"; +import { prepareInts } from "./utils"; + +type G = { + d: string; + clipPath: string; + x: number; + y: number; + fill: string; + rotate: number; + labelX: number; + labelY: number; + labelFontSize: number; + labelFill: string; + valueX: number; + valueY: number; + valueFontSize: number; + valueFill: string; + opacity: number; +}; + +export type Getter = { + key: string; + teleportKey: string; + teleportFrom: string | undefined; + value: number; + g: (props: GProps) => G; +}; + +// Getters are defined per chart type in GroupsGetters. + +export type Int = { + key: string; + teleportKey: string; + state: State; + value: number; + _value: number; + i: GenericInt; +}; + +export const int = ({ + datum, + _int, + groupInt, + _groupTeleportInt, + exiting, + teleported, +}: { + datum: Getter; + _int: Int | undefined; + groupInt: Group.Int; + _groupTeleportInt: Group.Int | undefined; + exiting: boolean; + teleported: boolean; +}): Int => { + const { key, teleportKey, value, g } = datum; + // Update datum's x and y by their groups' coords when teleporting. + const _gAlter = + teleported && _groupTeleportInt && _int + ? (_g: G) => { + const g = groupInt.i(1); + const _gt = _groupTeleportInt.i(1); + _g.x += _gt.x - g.x; + _g.y += _gt.y - g.y; + } + : undefined; + const { state, i, _updateInt } = prepareInts({ _int, exiting, g, _gAlter }); + const _value = _updateInt?.value ?? value; + const datumInt: Int = { key, teleportKey, state, value, _value, i }; + + return datumInt; +}; + +export type Resolved = { + key: string; + value: number; + fill: string; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ key, value, _value, i }) => { + return { + key, + value: interpolate(_value, value)(Math.round(t)), + ...i(t), + }; + }); +}; + +export const render = ({ + dataSelection, +}: { + dataSelection: Selection; +}): void => { + const pathSelection = dataSelection + .selectAll(`.${style.path}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("path") + .attr("class", style.path) + .attr("d", (d) => d.d) + .style("fill", (d) => d.fill); + + const clipPathSelection = dataSelection + .selectAll(`.${style.clipPath}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("clipPath") + .attr("id", function (d) { + const parentEl = this.parentNode?.parentNode as SVGGElement; + const g = select(parentEl).datum() as Group.Resolved; + return `clip${g.key}${d.key}`.replace(/[^a-zA-Z0-9]/g, ""); + }) + .attr("class", style.clipPath) + .selectAll("path") + .data( + (d) => [d], + (d) => d.key + ) + .join("path") + .attr("d", (d) => d.clipPath); + + const labelsSelection = dataSelection + .selectAll(`.${style.labels}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("g") + .attr("class", style.labels) + .style("clip-path", function (d) { + const parentEl = this.parentNode?.parentNode as SVGGElement; + const g = select(parentEl).datum() as Group.Resolved; + const clipPathId = `clip${g.key}${d.key}`.replace(/[^a-zA-Z0-9]/g, ""); + return `url(#${clipPathId})`; + }); + + const labelSelection = labelsSelection + .selectAll(`.${style.label}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("text") + .attr("class", style.label) + .attr("x", (d) => d.labelX) + .attr("y", (d) => d.labelY) + .attr("transform", (d) => `rotate(${360 - d.rotate})`) + .style("font-size", (d) => d.labelFontSize) + .style("font-weight", FONT_WEIGHT.datumLabel) + .style("fill", (d) => d.labelFill) + .text((d) => d.key); + + const valueSelection = labelsSelection + .selectAll(`.${style.value}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("text") + .attr("class", style.value) + .attr("x", (d) => d.valueX) + .attr("y", (d) => d.valueY) + .attr("transform", (d) => `rotate(${360 - d.rotate})`) + .style("font-size", (d) => d.valueFontSize) + .style("font-weight", FONT_WEIGHT.datumValue) + .style("fill", (d) => d.valueFill) + .text((d) => d.value); +}; diff --git a/src/components/Group.module.scss b/src/components/Group.module.scss new file mode 100644 index 0000000..d357677 --- /dev/null +++ b/src/components/Group.module.scss @@ -0,0 +1,20 @@ +@import "../variables.scss"; + +.node { + .group { + .label { + dominant-baseline: hanging; + text-anchor: middle; + paint-order: stroke; + stroke: white; + stroke-linecap: round; + stroke-linejoin: round; + fill: $color-dark; + user-select: none; + pointer-events: none; + } + .background { + fill: $color-light; + } + } +} diff --git a/src/components/Group.ts b/src/components/Group.ts new file mode 100644 index 0000000..85e2d5f --- /dev/null +++ b/src/components/Group.ts @@ -0,0 +1,245 @@ +import { getBarGetters } from "../charts/bar"; +import { getBubbleGetters } from "../charts/bubble"; +import { getPieGetters } from "../charts/pie"; +import { getTreemapGetters } from "../charts/treemap"; +import { ColorMap } from "../colors"; +import { ResolvedDimensions } from "../dims"; +import { + BarChartSubtype, + ChartType, + GenericInt, + GProps, + InputGroup, + MaxValue, + State, + TextDims, +} from "../types"; +import { FONT_WEIGHT, stateOrderComparator } from "../utils"; +import * as Datum from "./Datum"; +import datumStyle from "./Datum.module.scss"; +import style from "./Group.module.scss"; +import { Svg } from "./Svg"; +import { Tooltip } from "./Tooltip"; +import { prepareInts } from "./utils"; + +type G = { + d: string; + x: number; + y: number; + labelX: number; + labelY: number; + labelFontSize: number; + labelStrokeWidth: number; + opacity: number; +}; + +export type Getter = { + key: string; + g: (props: GProps) => G; + data: Datum.Getter[]; +}; + +export type GetterProps = { + // Data. + groups: InputGroup[]; + groupsKeys: string[]; + dataKeys: string[]; + // Scales. + shareDomain: boolean; + maxValue: MaxValue; + // Labels. + showValues: boolean; + showDatumLabels: boolean; + // Dimensions. + svg: Svg; + dims: ResolvedDimensions; + textDims: TextDims; + // Appearance. + colorMap: ColorMap; + cartoonize: boolean; +}; + +export const getters = ( + chartType: ChartType, + chartSubtype: BarChartSubtype | undefined, + props: GetterProps +): Getter[] => { + switch (chartType) { + case "bar": + return getBarGetters(chartSubtype as BarChartSubtype, props); + case "bubble": + return getBubbleGetters(props); + case "pie": + return getPieGetters(props); + case "treemap": + return getTreemapGetters(props); + } +}; + +export type Int = { + key: string; + state: State; + i: GenericInt; + data: Datum.Int[]; +}; + +export const ints = ({ + groups = [], + _groups, + _groupInts, +}: { + groups: Getter[] | undefined; + _groups: Getter[] | undefined; + _groupInts: Int[] | undefined; +}): Int[] => { + const keys = groups.map((d) => d.key); + const exitingGroups = _groups?.filter((d) => !keys.includes(d.key)) ?? []; + const allGroups = groups.concat(exitingGroups); + const groupsInts: Int[] = allGroups.map(({ key, g, data }) => { + const exiting = !keys.includes(key); + const _int = _groupInts?.find((d) => d.key === key); + const { + state, + i, + _updateInt: _groupInt, + } = prepareInts({ _int, exiting, g }); + const groupInt: Int = { key, state, i, data: [] }; + const dataKeys = exiting ? [] : data.map((d) => d.key); + const _data = _groups?.find((d) => d.key === key)?.data; + const exitingData = _data?.filter((d) => !dataKeys.includes(d.key)) ?? []; + const allData = data.concat(exitingData); + groupInt.data = allData + .map((datum) => { + let _teleportInt: Datum.Int | undefined; + const _groupTeleportInt = _groupInts?.find((d) => { + return (_teleportInt = d.data.find( + (d) => d.teleportKey === datum.teleportFrom + )); + }); + const _int = + _teleportInt ?? _groupInt?.data?.find((d) => d.key === datum.key); + + return Datum.int({ + datum, + _int, + groupInt, + _groupTeleportInt, + exiting: !dataKeys.includes(datum.key), + teleported: _teleportInt !== undefined, + }); + }) + .sort(stateOrderComparator); + + return groupInt; + }); + + const allDataTeleportFrom = groups + .map((d) => d.data) + .flat() + .filter((d) => d.teleportFrom !== undefined) + .map((d) => d.teleportFrom) as string[]; + + // Remove teleported data from original groups. + groupsInts.forEach((groupInts) => { + groupInts.data = groupInts.data.filter((datumInts) => { + return !allDataTeleportFrom.includes(datumInts.teleportKey); + }); + }); + + return groupsInts; +}; + +export type Resolved = { + key: string; + data: Datum.Resolved[]; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ key, i, data }) => { + return { key, ...i(t), data: Datum.resolve(data, t) }; + }); +}; + +export const render = ({ + resolved, + svg, + tooltip, +}: { + resolved: Resolved[]; + svg: Svg; + tooltip?: Tooltip; +}): void => { + const groupsSelection = svg.selection + .selectAll(`.${style.node}`) + .data([null]) + .join("g") + .attr("class", style.node) + .selectAll(`.${style.group}`) + .data(resolved, (d) => d.key) + .join("g") + .attr("class", style.group) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("opacity", (d) => d.opacity); + + const backgroundsSelection = groupsSelection + .selectAll(`.${style.background}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("path") + .attr("class", style.background) + .attr("d", (d) => d.d); + + const dataSelection = groupsSelection + .selectAll(`.${datumStyle.node}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("g") + .attr("class", datumStyle.node) + .selectAll(`.${datumStyle.datum}`) + .data( + (d) => d.data, + (d) => d.key + ) + .join("g") + .attr("class", datumStyle.datum) + .attr("transform", (d) => `translate(${d.x}, ${d.y}) rotate(${d.rotate})`) + .style("opacity", (d) => d.opacity); + + if (tooltip) { + dataSelection + .on("mouseover mousemove", function (e: MouseEvent, d) { + tooltip.move(e.clientX, e.clientY); + tooltip.setText({ + label: d.key, + value: d.value, + }); + tooltip.show(); + }) + .on("mouseout", function () { + tooltip.hide(); + }); + } else { + dataSelection.on("mouseover mousemove mouseout", null); + } + + const labelsSelection = groupsSelection + .selectAll(`.${style.label}`) + .data( + (d) => [d], + (d) => d.key + ) + .join("text") + .attr("class", style.label) + .attr("x", (d) => d.labelX) + .attr("y", (d) => d.labelY) + .style("font-size", (d) => d.labelFontSize) + .style("font-weight", FONT_WEIGHT.groupLabel) + .style("stroke-width", (d) => d.labelStrokeWidth) + .text((d) => d.key); + + Datum.render({ dataSelection }); +}; diff --git a/src/components/Step.ts b/src/components/Step.ts new file mode 100644 index 0000000..090097a --- /dev/null +++ b/src/components/Step.ts @@ -0,0 +1,382 @@ +import { ColorLegend, Group, Svg, Text, Tooltip, VerticalAxis } from "."; +import { ColorMap } from "../colors"; +import { Dimensions } from "../dims"; +import { InputStep, MaxValue } from "../types"; +import { getTextDims, max, stateOrderComparator, unique } from "../utils"; +import { shouldShareDomain } from "./utils"; + +export type Getter = { + key: string; + title: Text.Getter | undefined; + subtitle: Text.Getter | undefined; + groups: Group.Getter[]; + colorLegends: ColorLegend.Getter[] | undefined; + verticalAxis: VerticalAxis.Getter | undefined; +}; + +export const getters = ({ + steps: inputSteps, + svg, + width, + height, +}: { + steps: InputStep[]; + svg: Svg; + width: number; + height: number; +}): Getter[] => { + const steps: Getter[] = []; + let _showVerticalAxis: boolean | undefined; + let _maxValue: number | undefined; + const textDims = getTextDims(svg); + + for (const step of inputSteps) { + const { + key, + chartType, + groups, + title, + titleAnchor = "start", + subtitle, + subtitleAnchor = "start", + shareDomain: inputShareDomain, + showLegend: inputShowLegend, + legendAnchor = "middle", + showValues = false, + maxValue: inputMaxValue, + showDatumLabels = false, + palette: paletteName = "default", + cartoonize = false, + } = step; + + const chartSubtype = + step.chartType === "bar" ? step.chartSubtype ?? "grouped" : undefined; + + // TODO: if bar is a preceding step to pie, it can already be pre-rotated, + // so animation will be smoother. + + const groupsKeys = groups.map((d) => d.key); + const dataKeys = unique(groups.map((d) => d.data.map((d) => d.key)).flat()); + + let dataMaxValue = 0; + + if (chartSubtype !== "stacked") { + dataMaxValue = + max(groups.map((d) => max(d.data.map((d) => d.value)) ?? 0)) ?? 0; + } else { + // Sum values by group for stacked bar chart. + for (const group of groups) { + const sum = group.data.map((d) => d.value).reduce((a, b) => a + b, 0); + + if (sum > dataMaxValue) { + dataMaxValue = sum; + } + } + } + + const k = inputMaxValue !== undefined ? dataMaxValue / inputMaxValue : 1; + const maxValue: MaxValue = { + data: dataMaxValue, + scale: inputMaxValue, + actual: inputMaxValue ?? dataMaxValue, + k, + kc: 1 - k, + }; + + const shareDomain = inputShareDomain ?? shouldShareDomain(chartType); + const domain = shareDomain ? dataKeys : groupsKeys; + + const showLegend = inputShowLegend ?? domain.length > 1; + + const dims = new Dimensions(width, height); + + let titleGetter: Text.Getter | undefined; + + if (title !== undefined) { + titleGetter = Text.getter({ + svg, + text: title, + textType: "title", + anchor: titleAnchor, + dims: dims.resolve(), + }); + const { height } = svg.measureText(title, "title"); + dims.addTop(height); + } + + let subtitleGetter: Text.Getter | undefined; + + if (subtitle !== undefined) { + subtitleGetter = Text.getter({ + svg, + text: subtitle, + textType: "subtitle", + anchor: subtitleAnchor, + dims: dims.resolve(), + }); + const { height } = svg.measureText(subtitle, "subtitle"); + dims.addTop(height); + } + + const colorMap = new ColorMap(domain, paletteName); + + let colorLegendsGetters: ColorLegend.Getter[] | undefined; + + if (showLegend) { + const legendItemHeight = textDims.legendItem.height; + colorLegendsGetters = ColorLegend.getters({ + colorMap, + anchor: legendAnchor, + itemHeight: legendItemHeight, + svg, + dims: dims.resolve(), + }); + + const colorLegendHeight = ColorLegend.getHeight( + colorLegendsGetters, + legendItemHeight + ); + + dims.addBottom(colorLegendHeight); + + if (chartType === "bar") { + dims.addBottom(dims.BASE_MARGIN * 2); + } else { + dims.addBottom(dims.BASE_MARGIN); + } + } else { + if (chartType === "bar") { + dims.addBottom(dims.BASE_MARGIN); + } + } + + if (title || subtitle) { + dims.addTop(dims.BASE_MARGIN); + } + + dims.addBottom(dims.BASE_MARGIN); + + let verticalAxisGetters: VerticalAxis.Getter | undefined; + + if (chartType === "bar") { + if (showValues) { + dims.addTop(dims.BASE_MARGIN); + } + + const { show = groups.length > 0, title = "" } = step.verticalAxis || {}; + + if (show) { + const width = VerticalAxis.getWidth({ + svg, + maxValue: maxValue.actual, + }); + const titleHeight = title + ? svg.measureText(title, "verticalAxisTitle").height + : 0; + const titleMargin = dims.BASE_MARGIN; + + dims.addTop(titleHeight + titleMargin).addLeft(width); + + verticalAxisGetters = VerticalAxis.getters({ + svg, + title, + maxValue: maxValue.actual, + // Only pass previous max value when vertical axis was present in previous step. + // Otherwise animate the ticks from bottom. + _maxValue: _showVerticalAxis ? _maxValue : undefined, + dims: dims.resolve(), + titleMargin: { + top: -( + titleHeight + + titleMargin + + (title && showValues ? dims.BASE_MARGIN : 0) + ), + right: 0, + bottom: 0, + left: -width, + }, + tickHeight: textDims.tick.height, + }); + } + + _showVerticalAxis = show; + } else { + _showVerticalAxis = false; + } + + const groupsGetters: Group.Getter[] = Group.getters( + chartType, + chartSubtype, + { + groups, + groupsKeys, + dataKeys, + shareDomain, + maxValue, + showValues, + showDatumLabels, + svg, + dims: dims.resolve(), + textDims, + colorMap, + cartoonize, + } + ); + + steps.push({ + key, + title: titleGetter, + subtitle: subtitleGetter, + colorLegends: colorLegendsGetters, + verticalAxis: verticalAxisGetters, + groups: groupsGetters, + }); + + _maxValue = maxValue.actual; + } + + return steps; +}; + +export type Int = { + titles: Text.Int[]; + subtitles: Text.Int[]; + groups: Group.Int[]; + colorLegends: ColorLegend.Int[]; + verticalAxes: VerticalAxis.Int[]; +}; + +export type IntsMap = Map; + +export const intsMap = ({ + steps, + svg, +}: { + steps: Getter[]; + svg: Svg; +}): IntsMap => { + const intsMap: IntsMap = new Map(); + let _titleInts: Text.Int[] | undefined; + let _subtitleInts: Text.Int[] | undefined; + let _groupInts: Group.Int[] | undefined; + let _colorLegendInts: ColorLegend.Int[] | undefined; + let _verticalAxisInts: VerticalAxis.Int[] | undefined; + + steps.forEach((step, i) => { + const { key, title, subtitle, groups, colorLegends, verticalAxis } = step; + const _stepGetters: Getter | undefined = steps[i - 1]; + + const titlesInts = Text.ints({ + text: title, + _text: _stepGetters?.title, + _textInts: _titleInts, + }); + + const subtitlesInts = Text.ints({ + text: subtitle, + _text: _stepGetters?.subtitle, + _textInts: _subtitleInts, + }); + + const colorLegendsInts = ColorLegend.ints({ + colorLegends, + _colorLegends: _stepGetters?.colorLegends, + _colorLegendInts, + }); + + const verticalAxesInts = VerticalAxis.ints({ + verticalAxis, + _verticalAxis: _stepGetters?.verticalAxis, + _verticalAxisInts, + }); + + const groupsInts = Group.ints({ + groups, + _groups: _stepGetters?.groups, + _groupInts, + }); + + intsMap.set(key, { + titles: (_titleInts = titlesInts), + subtitles: (_subtitleInts = subtitlesInts), + // Sort the groups so they are rendered in a correct order. + groups: (_groupInts = groupsInts.sort(stateOrderComparator)), + colorLegends: (_colorLegendInts = colorLegendsInts), + verticalAxes: (_verticalAxisInts = verticalAxesInts), + }); + }); + + return intsMap; +}; + +export type Resolved = { + titles: Text.Resolved[]; + subtitles: Text.Resolved[]; + groups: Group.Resolved[]; + colors: ColorLegend.Resolved[]; + verticalAxes: VerticalAxis.Resolved[]; +}; + +export const resolve = (ints: Int, t: number) => { + const { titles, subtitles, groups, colorLegends, verticalAxes } = ints; + + return { + titles: Text.resolve(titles, t), + subtitles: Text.resolve(subtitles, t), + groups: Group.resolve(groups, t), + colors: ColorLegend.resolve(colorLegends, t), + verticalAxes: VerticalAxis.resolve(verticalAxes, t), + }; +}; + +export const render = ({ + resolved, + svg, + tooltip, + finished, + indicateProgress, +}: { + resolved: Resolved; + svg: Svg; + tooltip: Tooltip; + finished: boolean; + indicateProgress: boolean; +}) => { + Text.render({ + resolved: resolved.titles, + svg, + key: "title", + }); + Text.render({ + resolved: resolved.subtitles, + svg, + key: "subtitle", + }); + ColorLegend.render({ + resolved: resolved.colors, + svg, + }); + VerticalAxis.render({ + resolved: resolved.verticalAxes, + svg, + }); + Group.render({ + resolved: resolved.groups, + svg, + tooltip: finished ? tooltip : undefined, + }); + + if (finished) { + tooltip.node.raise(); + + if (indicateProgress) { + svg.selection.style("border-left", "3px solid transparent"); + } + } else { + tooltip.hide(); + + if (indicateProgress) { + svg.selection.style("border-left", "3px solid #e9e9e9"); + } + } +}; diff --git a/src/components/Svg.module.scss b/src/components/Svg.module.scss new file mode 100644 index 0000000..6cd0147 --- /dev/null +++ b/src/components/Svg.module.scss @@ -0,0 +1,7 @@ +.node { + width: 100%; + height: 100%; + transform: translate3d(0, 0, 0); + border-left: 3px solid transparent; + transition: border-left 0.3s ease; +} diff --git a/src/components/Svg.ts b/src/components/Svg.ts new file mode 100644 index 0000000..08d9563 --- /dev/null +++ b/src/components/Svg.ts @@ -0,0 +1,49 @@ +import { select, Selection } from "d3-selection"; +import { TextType } from "../types"; +import { FONT_SIZE, FONT_WEIGHT } from "../utils"; +import style from "./Svg.module.scss"; + +export type Svg = { + selection: SVGSelection; + measure: () => DOMRect; + measureText: (text: string | number, textType: TextType) => DOMRect; +}; + +type SVGSelection = Selection< + SVGSVGElement, + unknown, + HTMLDivElement, + undefined +>; + +export const makeSvg = (div: HTMLDivElement): Svg => { + const selection = select(div) + .selectAll("svg") + .data([null]) + .join("svg") + .attr("class", style.node) as SVGSelection; + + const measure = (): DOMRect => { + return (selection.node() as SVGSVGElement).getBoundingClientRect(); + }; + + const measureText = (text: string | number, textType: TextType): DOMRect => { + const node = selection + .append("text") + .style("font-size", FONT_SIZE[textType]) + .style("font-weight", FONT_WEIGHT[textType]) + .text(text) + .node() as SVGTextElement; + + const rect = node.getBoundingClientRect(); + node.remove(); + + return rect; + }; + + return { + selection, + measure, + measureText, + }; +}; diff --git a/src/components/Text.module.scss b/src/components/Text.module.scss new file mode 100644 index 0000000..1a9bd95 --- /dev/null +++ b/src/components/Text.module.scss @@ -0,0 +1,4 @@ +.node { + dominant-baseline: hanging; + pointer-events: none; +} diff --git a/src/components/Text.spec.ts b/src/components/Text.spec.ts new file mode 100644 index 0000000..fa004ba --- /dev/null +++ b/src/components/Text.spec.ts @@ -0,0 +1,221 @@ +import { Text } from "."; +import { setup } from "../../tests/helpers"; +import { FONT_SIZE, FONT_WEIGHT } from "../utils"; + +describe("Text", () => { + const { svg, dims } = setup(); + const enterGetter = Text.getter({ + svg, + text: "Hello, Plotteus!", + textType: "title", + anchor: "middle", + dims: dims.resolve(), + }); + const enterInts = Text.ints({ + text: enterGetter, + _text: undefined, + _textInts: undefined, + }); + + describe("enter", () => { + describe("getter", () => { + test("key", () => { + expect(enterGetter.key).toBe("Hello, Plotteus!"); + }); + + test("enter", () => { + const g = enterGetter.g({ s: (enter) => enter }); + + expect(g.x).toEqual(400); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.title); + expect(g.opacity).toEqual(0); + }); + + test("update", () => { + const g = enterGetter.g({ s: (enter, update) => update ?? enter }); + + expect(g.x).toEqual(400); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.title); + expect(g.opacity).toEqual(1); + }); + + test("exit", () => { + const g = enterGetter.g({ s: (enter, _, exit) => exit ?? enter }); + + expect(g.x).toEqual(400); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.title); + expect(g.opacity).toEqual(0); + }); + }); + + describe("ints", () => { + test("general", () => { + expect(enterInts.length).toEqual(1); + expect(enterInts[0].key).toEqual("Hello, Plotteus!"); + expect(enterInts[0].state).toEqual("enter"); + }); + }); + + describe("resolve", () => { + test("0", () => { + const { key, ...r } = Text.resolve(enterInts, 0)[0]; + const g = enterGetter.g({ s: (enter) => enter }); + + expect(r).toEqual(g); + }); + + test("0.5", () => { + const { key, ...r } = Text.resolve(enterInts, 0.5)[0]; + + expect(r).toEqual({ + x: 400, + y: dims.margin.top, + fontSize: FONT_SIZE.title, + fontWeight: FONT_WEIGHT.title, + opacity: 0.5, + }); + }); + + test("1", () => { + const { key, ...r } = Text.resolve(enterInts, 1)[0]; + const g = enterGetter.g({ s: (enter, update) => update ?? enter }); + + expect(r).toEqual(g); + }); + }); + }); + + const updateGetter = Text.getter({ + svg, + text: "Hello, Plotteus!", + textType: "datumLabel", + anchor: "start", + dims: dims.resolve(), + }); + const updateInts = Text.ints({ + text: updateGetter, + _text: enterGetter, + _textInts: enterInts, + }); + + describe("update", () => { + describe("getter", () => { + test("key", () => { + expect(updateGetter.key).toBe("Hello, Plotteus!"); + }); + + test("enter", () => { + const g = updateGetter.g({ s: (enter) => enter }); + + expect(g.x).toEqual(16); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.datumLabel); + expect(g.opacity).toEqual(0); + }); + + test("update", () => { + const g = updateGetter.g({ s: (enter, update) => update ?? enter }); + + expect(g.x).toEqual(16); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.datumLabel); + expect(g.opacity).toEqual(1); + }); + + test("exit", () => { + const g = updateGetter.g({ s: (enter, _, exit) => exit ?? enter }); + + expect(g.x).toEqual(16); + expect(g.y).toEqual(dims.margin.top); + expect(g.fontSize).toEqual(FONT_SIZE.datumLabel); + expect(g.opacity).toEqual(0); + }); + }); + + describe("ints", () => { + test("general", () => { + expect(updateInts.length).toEqual(1); + expect(updateInts[0].key).toEqual("Hello, Plotteus!"); + expect(updateInts[0].state).toEqual("update"); + }); + }); + + describe("resolve", () => { + test("0", () => { + const { key, ...r } = Text.resolve(updateInts, 0)[0]; + const g = enterGetter.g({ s: (enter, update) => update ?? enter }); + + expect(r).toEqual(g); + }); + + test("0.5", () => { + const { key, ...r } = Text.resolve(updateInts, 0.5)[0]; + + expect(r).toEqual({ + x: 208, + y: dims.margin.top, + fontSize: + FONT_SIZE.title - (FONT_SIZE.title - FONT_SIZE.datumLabel) * 0.5, + fontWeight: + FONT_WEIGHT.title - + (FONT_WEIGHT.title - FONT_WEIGHT.datumLabel) * 0.5, + opacity: 1, + }); + }); + + test("1", () => { + const { key, ...r } = Text.resolve(updateInts, 1)[0]; + const g = updateGetter.g({ s: (enter, update) => update ?? enter }); + + expect(r).toEqual(g); + }); + }); + }); + + const exitInts = Text.ints({ + text: undefined, + _text: updateGetter, + _textInts: updateInts, + }); + + describe("exit", () => { + describe("ints", () => { + test("general", () => { + expect(exitInts.length).toEqual(1); + expect(exitInts[0].key).toEqual("Hello, Plotteus!"); + expect(exitInts[0].state).toEqual("exit"); + }); + }); + + describe("resolve", () => { + test("0", () => { + const { key, ...r } = Text.resolve(exitInts, 0)[0]; + const g = updateGetter.g({ s: (enter, update) => update ?? enter }); + + expect(r).toEqual(g); + }); + + test("0.5", () => { + const { key, ...r } = Text.resolve(exitInts, 0.5)[0]; + + expect(r).toEqual({ + x: 16, + y: dims.margin.top, + fontSize: FONT_SIZE.datumLabel, + fontWeight: FONT_WEIGHT.datumLabel, + opacity: 0.5, + }); + }); + + test("1", () => { + const { key, ...r } = Text.resolve(exitInts, 1)[0]; + const g = updateGetter.g({ s: (enter, _, exit) => exit ?? enter }); + + expect(r).toEqual(g); + }); + }); + }); +}); diff --git a/src/components/Text.ts b/src/components/Text.ts new file mode 100644 index 0000000..7852241 --- /dev/null +++ b/src/components/Text.ts @@ -0,0 +1,116 @@ +import { ResolvedDimensions } from "../dims"; +import { Anchor, GenericInt, GProps, State, TextType } from "../types"; +import { FONT_SIZE, FONT_WEIGHT } from "../utils"; +import { Svg } from "./Svg"; +import style from "./Text.module.scss"; +import { prepareInts } from "./utils"; + +type G = { + x: number; + y: number; + fontSize: number; + fontWeight: number; + opacity: number; +}; + +export type Getter = { + key: string; + g: (props: GProps) => G; +}; + +export const getter = ({ + svg, + text, + textType, + anchor, + dims: { fullWidth, margin }, +}: { + svg: Svg; + text: string; + textType: TextType; + anchor: Anchor; + dims: ResolvedDimensions; +}): Getter => { + const { width: textWidth } = svg.measureText(text, textType); + + return { + key: text, + g: ({ s, _g }) => { + const x = + anchor === "start" + ? margin.left + : anchor === "middle" + ? (fullWidth - textWidth) * 0.5 + : fullWidth - textWidth - margin.right; + + return { + x: s(x, null, _g?.x), + y: s(margin.top, null, _g?.y), + fontSize: FONT_SIZE[textType], + fontWeight: FONT_WEIGHT[textType], + opacity: s(0, 1), + }; + }, + }; +}; + +export type Int = { + key: string; + state: State; + i: GenericInt; +}; + +export const ints = ({ + text, + _text, + _textInts, +}: { + text: Getter | undefined; + _text: Getter | undefined; + _textInts: Int[] | undefined; +}): Int[] => { + const exitingText = + _text !== undefined && _text.key !== text?.key ? [_text] : []; + const texts = text !== undefined ? [text, ...exitingText] : exitingText; + const textInts: Int[] = texts.map(({ key, g }) => { + const exiting = text?.key !== key; + const _int = _textInts?.find((d) => d.key === key); + const { state, i } = prepareInts({ _int, exiting, g }); + const textInt: Int = { key, state, i }; + + return textInt; + }); + + return textInts; +}; + +export type Resolved = { + key: string; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ key, i }) => ({ key, ...i(t) })); +}; + +export const render = ({ + resolved, + svg, + key, +}: { + resolved: Resolved[]; + svg: Svg; + key: string; +}): void => { + const className = `${style.node} ${key}`; + + svg.selection + .selectAll(`.${style.node}.${key}`) + .data(resolved, (d) => d.key) + .join("text") + .attr("class", className) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("font-size", (d) => d.fontSize) + .style("font-weight", (d) => d.fontWeight) + .style("opacity", (d) => d.opacity) + .text((d) => d.key); +}; diff --git a/src/components/Tick.module.scss b/src/components/Tick.module.scss new file mode 100644 index 0000000..1504c58 --- /dev/null +++ b/src/components/Tick.module.scss @@ -0,0 +1,15 @@ +@import "../variables.scss"; + +.node { + .label { + dominant-baseline: hanging; + transform: translate(-2px, 0px); + text-anchor: end; + } + .boldLine { + stroke: $color-gray; + } + .lightLine { + stroke: $color-lightgray; + } +} diff --git a/src/components/Tick.ts b/src/components/Tick.ts new file mode 100644 index 0000000..35ec0f1 --- /dev/null +++ b/src/components/Tick.ts @@ -0,0 +1,160 @@ +import { scaleLinear } from "d3-scale"; +import { Selection } from "d3-selection"; +import { HALF_FONT_K } from "../charts/utils"; +import { ResolvedDimensions } from "../dims"; +import { GenericInt, GProps, State } from "../types"; +import { FONT_SIZE, FONT_WEIGHT, stateOrderComparator } from "../utils"; +import style from "./Tick.module.scss"; +import { prepareInts } from "./utils"; +import * as VerticalAxis from "./VerticalAxis"; + +export const WIDTH = 12; + +type G = { + x: number; + y: number; + width: number; + height: number; + fontSize: number; + opacity: number; +}; + +export type Getter = { + key: string; + g: (props: GProps) => G; +}; + +export const getters = ({ + ticks, + maxValue, + _maxValue, + dims: { width, height }, + tickHeight, +}: { + ticks: number[]; + maxValue: number; + _maxValue: number | undefined; + dims: ResolvedDimensions; + tickHeight: number; +}): Getter[] => { + const yScale = scaleLinear().domain([maxValue, 0]).range([0, height]); + let _yScale: (tick: number) => number = () => height; + + if (_maxValue !== undefined) { + _yScale = scaleLinear().domain([_maxValue, 0]).range([0, height]); + } + + return ticks.map((tick) => { + const getters: Getter = { + key: `${tick}`, + g: ({ s }) => { + const x = -WIDTH; + const y = s( + _yScale(tick), + (1 - tick / maxValue) * height, + yScale(tick) + ); + + return { + x, + y, + width, + height: tickHeight, + fontSize: FONT_SIZE.tick, + opacity: s(0, 1), + }; + }, + }; + + return getters; + }); +}; + +export type Int = { + key: string; + state: State; + i: GenericInt; +}; + +export const ints = ({ + ticks, + _ticks, + _tickInts, +}: { + ticks: Getter[]; + _ticks: Getter[] | undefined; + _tickInts: Int[] | undefined; +}): Int[] => { + const keys = ticks.map((d) => d.key); + const exitingTicks = _ticks?.filter((d) => !keys.includes(d.key)) ?? []; + const allTicks = ticks.concat(exitingTicks); + const tickInts: Int[] = allTicks + .map(({ key, g }) => { + const exiting = !keys.includes(key); + const _int = _tickInts?.find((d) => d.key === key); + const { state, i } = prepareInts({ _int, exiting, g }); + const tickInt: Int = { key, state, i }; + + return tickInt; + }) + .sort(stateOrderComparator); + + return tickInts; +}; + +export type Resolved = { + key: string; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ key, i }) => ({ key, ...i(t) })); +}; + +export const render = ( + verticalAxis: Selection< + SVGGElement, + VerticalAxis.Resolved, + SVGSVGElement, + unknown + > +): void => { + verticalAxis + .selectAll(`.${style.node}`) + .data( + (d) => d.ticks, + (d) => d.key + ) + .join("g") + .attr("class", style.node) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("opacity", (d) => d.opacity) + .call((g) => + g + .selectAll(`.${style.label}`) + .data((d) => [d]) + .join("text") + .attr("class", style.label) + .attr("dy", (d) => -d.height * HALF_FONT_K) + .style("font-size", (d) => d.fontSize) + .style("font-weight", FONT_WEIGHT.tick) + .text((d) => d.key) + ) + .call((g) => + g + .selectAll(`.${style.boldLine}`) + .data((d) => [d]) + .join("line") + .attr("class", style.boldLine) + .attr("x1", 2) + .attr("x2", 7) + ) + .call((g) => + g + .selectAll(`.${style.lightLine}`) + .data((d) => [d]) + .join("line") + .attr("class", style.lightLine) + .attr("x1", 7) + .attr("x2", (d) => d.width) + ); +}; diff --git a/src/components/Tooltip.module.scss b/src/components/Tooltip.module.scss new file mode 100644 index 0000000..2857a11 --- /dev/null +++ b/src/components/Tooltip.module.scss @@ -0,0 +1,21 @@ +.root { + position: fixed; + top: 0; + left: 0; + max-width: 250px; + padding: 8px; + background: #fcfcfcea; + font-size: 12px; + transform: translate(-50%, calc(-100% - 16px)); + pointer-events: none; + box-shadow: 0px 0px 48px 0px rgba(0, 0, 0, 0.15); + .content { + overflow-wrap: break-word; + .datumLabel { + opacity: 1; + } + .valueLabel { + font-weight: bold; + } + } +} diff --git a/src/components/Tooltip.ts b/src/components/Tooltip.ts new file mode 100644 index 0000000..0681e77 --- /dev/null +++ b/src/components/Tooltip.ts @@ -0,0 +1,45 @@ +import { select } from "d3-selection"; +import style from "./Tooltip.module.scss"; + +export type Tooltip = ReturnType; + +export const makeTooltip = (div: HTMLDivElement) => { + const root = select(div) + .append("div") + .attr("class", style.root) + .style("opacity", 0); + const content = root.append("div").attr("class", style.content); + const datumLabel = content.append("span").attr("class", style.datumLabel); + const valueLabel = content.append("span").attr("class", style.valueLabel); + + const show = (): void => { + root.style("opacity", 1); + }; + + const hide = (): void => { + root.style("opacity", 0); + }; + + const move = (x: number, y: number): void => { + root.style("left", `${x}px`).style("top", `${y}px`); + }; + + const setText = ({ + label, + value, + }: { + label: string; + value: number; + }): void => { + datumLabel.text(label ? `${label}:` : ""); + valueLabel.text(` ${value}`); + }; + + return { + node: root, + show, + move, + hide, + setText, + }; +}; diff --git a/src/components/VerticalAxis.module.scss b/src/components/VerticalAxis.module.scss new file mode 100644 index 0000000..a4d0f69 --- /dev/null +++ b/src/components/VerticalAxis.module.scss @@ -0,0 +1,14 @@ +@import "../variables.scss"; + +.node { + pointer-events: none; + .titleNode { + .title { + dominant-baseline: hanging; + fill: $color-dark; + } + } + .domain { + fill: $color-gray; + } +} diff --git a/src/components/VerticalAxis.ts b/src/components/VerticalAxis.ts new file mode 100644 index 0000000..2fcbab6 --- /dev/null +++ b/src/components/VerticalAxis.ts @@ -0,0 +1,176 @@ +import { scaleLinear } from "d3-scale"; +import { Text } from "."; +import { Margin, ResolvedDimensions } from "../dims"; +import { GenericInt, GProps, State } from "../types"; +import { FONT_WEIGHT, max } from "../utils"; +import { Svg } from "./Svg"; +import * as Tick from "./Tick"; +import { prepareInts } from "./utils"; +import style from "./VerticalAxis.module.scss"; + +type G = { + x: number; + y: number; + opacity: number; +}; + +export type Getter = { + title: Text.Getter; + g: (props: GProps) => G; + ticks: Tick.Getter[]; +}; + +export const getters = ({ + svg, + title, + maxValue, + _maxValue, + dims, + titleMargin, + tickHeight, +}: { + svg: Svg; + title: string; + maxValue: number; + _maxValue: number | undefined; + dims: ResolvedDimensions; + // As we are using Text to get title getter, we need to pass a custom margin + // relative to vertical axis. + titleMargin: Margin; + tickHeight: number; +}): Getter => { + const ticks = scaleLinear().domain([0, maxValue]).ticks(5); + + return { + title: Text.getter({ + svg, + text: title, + textType: "verticalAxisTitle", + anchor: "start", + dims: { ...dims, margin: titleMargin }, + }), + g: ({ s, _g }) => { + const x = dims.margin.left; + const y = dims.margin.top; + + return { + x: s(x, null, _g?.x), + y: s(y, null, _g?.y), + opacity: s(0, 1), + }; + }, + ticks: Tick.getters({ ticks, maxValue, _maxValue, dims, tickHeight }), + }; +}; + +export type Int = { + titles: Text.Int[]; + state: State; + i: GenericInt; + ticks: Tick.Int[]; +}; + +export const ints = ({ + verticalAxis, + _verticalAxis, + _verticalAxisInts, +}: { + verticalAxis: Getter | undefined; + _verticalAxis: Getter | undefined; + _verticalAxisInts: Int[] | undefined; +}): Int[] => { + const exitingVerticalAxis = _verticalAxis ? [_verticalAxis] : []; + const allVerticalAxes = verticalAxis ? [verticalAxis] : exitingVerticalAxis; + const verticalAxisInts: Int[] = allVerticalAxes.map(({ title, g, ticks }) => { + const exiting = verticalAxis === undefined; + const _int = _verticalAxisInts?.find((d) => d.state !== "exit"); + const { + state, + i, + _updateInt: _verticalAxisInt, + } = prepareInts({ _int, exiting, g }); + const verticalAxisInt: Int = { + titles: Text.ints({ + text: title, + _text: _verticalAxis?.title, + _textInts: _verticalAxisInt?.titles, + }), + state, + i, + ticks: Tick.ints({ + ticks, + _ticks: _verticalAxis?.ticks, + _tickInts: _verticalAxisInt?.ticks, + }), + }; + + return verticalAxisInt; + }); + + return verticalAxisInts; +}; + +export type Resolved = { + titles: Text.Resolved[]; + ticks: Tick.Resolved[]; +} & G; + +export const resolve = (ints: Int[], t: number): Resolved[] => { + return ints.map(({ titles, i, ticks }) => { + return { + titles: Text.resolve(titles, t), + ...i(t), + ticks: Tick.resolve(ticks, t), + }; + }); +}; + +export const render = ({ + resolved, + svg, +}: { + resolved: Resolved[]; + svg: Svg; +}): void => { + const verticalAxisSelection = svg.selection + .selectAll(`.${style.node}`) + .data(resolved) + .join("g") + .attr("class", style.node) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("opacity", (d) => d.opacity) + // Vertical axis needs to be the first element in SVG, so it doesn't overlap bars. + .lower(); + + const titlesSelection = verticalAxisSelection + .selectAll(`.${style.titleNode}`) + .data((d) => [d]) + .join("g") + .attr("class", style.titleNode) + .selectAll(`.${style.title}`) + .data((d) => d.titles) + .join("text") + .attr("class", style.title) + .attr("transform", (d) => `translate(${d.x}, ${d.y})`) + .style("font-size", (d) => d.fontSize) + .style("font-weight", FONT_WEIGHT.verticalAxisTitle) + .style("opacity", (d) => d.opacity) + .text((d) => d.key); + + Tick.render(verticalAxisSelection); +}; + +export const getWidth = ({ + svg, + maxValue, +}: { + svg: Svg; + maxValue: number; +}): number => { + const ticks = scaleLinear().domain([0, maxValue]).nice().ticks(5); + const ticksWidths = ticks.map((d) => { + return svg.measureText(d, "tick").width; + }); + + return (max(ticksWidths) as number) + Tick.WIDTH; +}; diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 0000000..9ff7bd9 --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,8 @@ +export * as ColorLegend from "./ColorLegend"; +export * as Datum from "./Datum"; +export * as Group from "./Group"; +export * as Step from "./Step"; +export * from "./Svg"; +export * as Text from "./Text"; +export * from "./Tooltip"; +export * as VerticalAxis from "./VerticalAxis"; diff --git a/src/components/utils.ts b/src/components/utils.ts new file mode 100644 index 0000000..a28c1f1 --- /dev/null +++ b/src/components/utils.ts @@ -0,0 +1,66 @@ +import { interpolate } from "d3-interpolate"; +import { ChartType, GenericInt, GProps, State } from "../types"; + +export const prepareInts = < + G extends object, + I extends { + state: State; + i: GenericInt; + } +>({ + exiting, + g, + _int, + _gAlter, +}: { + exiting: boolean; + g: (props: GProps) => G; + _int?: I; + _gAlter?: (_g: G) => void; +}) => { + // State. + const updating = _int !== undefined && _int.state !== "exit"; + const state: State = exiting ? "exit" : updating ? "update" : "enter"; + + const _updateInt = updating ? _int : undefined; + + const _g = _updateInt?.i(1); + + if (_gAlter && _g) { + _gAlter(_g); + } + + const from = _g ?? g({ s: (enter) => enter }); + const to = g({ + s: (enter, update, exit) => (exiting ? exit ?? enter : update ?? enter), + _g, + }); + const i = interpolate(from, to); + + return { state, i, _updateInt }; +}; + +export const stateValue = ( + state: State, + [enter, update, exit]: [T, T?, T?] +): T => { + switch (state) { + case "enter": + return enter; + case "update": + return update ?? enter; + case "exit": + return exit ?? enter; + } +}; + +export const shouldShareDomain = (type: ChartType): boolean => { + switch (type) { + case "bar": + case "pie": + return true; + case "bubble": + case "treemap": + return false; + } +}; diff --git a/src/coords.ts b/src/coords.ts new file mode 100644 index 0000000..bf3540d --- /dev/null +++ b/src/coords.ts @@ -0,0 +1,371 @@ +import { path } from "d3-path"; + +const TWO_PI = 2 * Math.PI; + +type Point = { + x: number; + y: number; +}; + +type BezierPoint = { + c1: Point; + c2: Point; + e: Point; +}; + +type PathProps = { + cartoonize: boolean; +} & ( + | { + type: "bar"; + width: number; + height: number; + } + | { + type: "bubble"; + r: number; + } + | { + type: "pie"; + startAngle: number; + endAngle: number; + r: number; + } +); + +const getRectangleCoords = ({ + width, + height, + cartoonize, +}: { + width: number; + height: number; + cartoonize: boolean; +}): BezierPoint[] => { + const [x0, x1] = [-width / 2, width / 2]; + const [y0, y1] = [-height / 2, height / 2]; + const k = cartoonize ? 2 : 0; + + const startEnd: BezierPoint = { + c1: { + x: x0 - k, + y: y0 + k, + }, + c2: { + x: x0 + k, + y: y0 - k, + }, + e: { + x: x0, + y: y0, + }, + }; + + return [ + startEnd, + { + c1: { + x: x1 - k, + y: y0 - k, + }, + c2: { + x: x1 + k, + y: y0 + k, + }, + e: { + x: x1, + y: y0, + }, + }, + { + c1: { + x: x1 + k, + y: y1 - k, + }, + c2: { + x: x1 - k, + y: y1 + k, + }, + e: { + x: x1, + y: y1, + }, + }, + { + c1: { + x: x0 + k, + y: y1 + k, + }, + c2: { + x: x0 - k, + y: y1 - k, + }, + e: { + x: x0, + y: y1, + }, + }, + startEnd, + ]; +}; + +const getCircleCoords = ({ + r, + cartoonize, +}: { + r: number; + cartoonize: boolean; +}): BezierPoint[] => { + const c = cartoonize ? 0.4 : 0.551915024494; + const cr = c * r; + const coords: BezierPoint[] = [ + { + c1: { + x: 0, + y: 0, + }, + c2: { + x: 0, + y: 0, + }, + e: { + x: -r, + y: 0, + }, + }, + { + c1: { + x: -r, + y: -cr, + }, + c2: { + x: -cr, + y: -r, + }, + e: { + x: 0, + y: -r, + }, + }, + { + c1: { + x: cr, + y: -r, + }, + c2: { + x: r, + y: -cr, + }, + e: { + x: r, + y: 0, + }, + }, + { + c1: { + x: r, + y: cr, + }, + c2: { + x: cr, + y: r, + }, + e: { + x: 0, + y: r, + }, + }, + { + c1: { + x: -cr, + y: r, + }, + c2: { + x: -r, + y: cr, + }, + e: { + x: -r, + y: 0, + }, + }, + ]; + + // Rotate coords, to get a nice shape tweening + // when rectangle is a preceding shape. + const rotateByRadians = 45 * (Math.PI / 180); + + return coords.map((d) => { + const { c1, c2, e } = d; + const sin = Math.sin(rotateByRadians); + const cos = Math.cos(rotateByRadians); + + return { + c1: { + x: c1.x * cos - c1.y * sin, + y: c1.y * cos + c1.x * sin, + }, + c2: { + x: c2.x * cos - c2.y * sin, + y: c2.y * cos + c2.x * sin, + }, + e: { + x: e.x * cos - e.y * sin, + y: e.y * cos + e.x * sin, + }, + }; + }); +}; + +const getPieCoords = ({ + startAngle, + endAngle, + r, + cartoonize, +}: { + startAngle: number; + endAngle: number; + r: number; + cartoonize: boolean; +}): BezierPoint[] => { + const k = cartoonize ? 8 : 0; + const cx = 0; + const cy = 0; + const angleExtent = endAngle - startAngle; + startAngle = startAngle - angleExtent * 0.5; + endAngle = endAngle - angleExtent * 0.5; + + const getBezierCoords = ( + startAngle: number, + stopAngle: number + ): BezierPoint => { + while (startAngle < 0) { + startAngle = startAngle + TWO_PI; + } + + while (stopAngle < 0) { + stopAngle = stopAngle + TWO_PI; + } + + startAngle = startAngle % TWO_PI; + stopAngle = stopAngle % TWO_PI; + + if (startAngle > stopAngle) { + stopAngle = stopAngle + TWO_PI; + } + + const alpha = (stopAngle - startAngle) / 2; + const cos = Math.cos(alpha); + const sin = Math.sin(alpha); + const cot = 1 / Math.tan(alpha); + + const phi = startAngle + alpha; + const cosPhi = Math.cos(phi); + const sinPhi = Math.sin(phi); + const lambda = (4 - cos) / 3; + + const mu = sin + (cos - lambda) * cot; + + const lambdaCosPhi = lambda * cosPhi; + const lambdaSinPhi = lambda * sinPhi; + const muCosPhi = mu * cosPhi; + const muSinPhi = mu * sinPhi; + + return { + // [cx + Math.cos(startAngle) * r, cy + Math.sin(startAngle) * r], + c1: { + x: (cx + lambdaCosPhi + muSinPhi) * r, + y: (cy + lambdaSinPhi - muCosPhi) * r - k, + }, + c2: { + x: (cx + lambdaCosPhi - muSinPhi) * r, + y: (cy + lambdaSinPhi + muCosPhi) * r + k, + }, + e: { + x: cx + Math.cos(stopAngle) * r, + y: cy + Math.sin(stopAngle) * r, + }, + }; + }; + + const startEnd: BezierPoint = { + c1: { + x: 0, + y: 0, + }, + c2: { + x: 0, + y: 0, + }, + e: { + x: cx + Math.cos(startAngle) * r, + y: cy + Math.sin(startAngle) * r, + }, + }; + + const coords = [ + startEnd, + getBezierCoords(startAngle, startAngle + angleExtent * 0.5), + getBezierCoords(startAngle + angleExtent * 0.5, startAngle + angleExtent), + { c1: { x: 0, y: 0 }, c2: { x: 0, y: 0 }, e: { x: 0, y: 0 } }, + startEnd, + ]; + + return coords.map(({ c1, c2, e }) => ({ + c1: { + x: c1.x, + y: c1.y + r * 0.5, + }, + c2: { + x: c2.x, + y: c2.y + r * 0.5, + }, + e: { + x: e.x, + y: e.y + r * 0.5, + }, + })); +}; + +const coordsToPathData = (coords: BezierPoint[]): string => { + const ctx = path(); + + ctx.moveTo(coords[0].e.x, coords[0].e.y); + coords.slice(1).forEach(({ c1, c2, e }) => { + ctx.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, e.x, e.y); + }); + ctx.closePath(); + + return ctx.toString(); +}; + +export function getPathData(props: PathProps): string { + let coords: BezierPoint[]; + + switch (props.type) { + case "bar": + coords = getRectangleCoords(props); + break; + case "bubble": + coords = getCircleCoords(props); + break; + case "pie": + coords = getPieCoords(props); + break; + } + + return coordsToPathData(coords); +} + +export const BAR = getPathData({ + type: "bar", + width: 0, + height: 0, + cartoonize: false, +}); + +export const BUBBLE = getPathData({ + type: "bubble", + r: 0, + cartoonize: false, +}); diff --git a/src/dims.ts b/src/dims.ts new file mode 100644 index 0000000..7d404e0 --- /dev/null +++ b/src/dims.ts @@ -0,0 +1,86 @@ +export type Margin = { + top: number; + right: number; + bottom: number; + left: number; +}; + +export type ResolvedDimensions = { + fullWidth: number; + width: number; + fullHeight: number; + height: number; + size: number; + margin: Margin; + BASE_MARGIN: number; +}; + +export class Dimensions { + public BASE_MARGIN = 16; + + public fullWidth: number; + public fullHeight: number; + public width: number; + public height: number; + + public top = this.BASE_MARGIN; + public right = this.BASE_MARGIN; + public bottom = this.BASE_MARGIN; + public left = this.BASE_MARGIN; + + constructor(width: number, height: number) { + this.fullWidth = width; + this.width = width - this.left - this.right; + this.fullHeight = height; + this.height = height - this.top - this.bottom; + } + + resolve(): ResolvedDimensions { + return { + fullWidth: this.fullWidth, + width: this.width, + fullHeight: this.fullHeight, + height: this.height, + size: Math.min(this.width, this.height), + margin: this.margin, + BASE_MARGIN: this.BASE_MARGIN, + }; + } + + get margin(): Margin { + return { + top: this.top, + right: this.right, + bottom: this.bottom, + left: this.left, + }; + } + + public addTop(top: number): this { + this.top += top; + this.height -= top; + + return this; + } + + public addRight(right: number): this { + this.right += right; + this.width -= right; + + return this; + } + + public addBottom(bottom: number): this { + this.bottom += bottom; + this.height -= bottom; + + return this; + } + + public addLeft(left: number): this { + this.left += left; + this.width -= left; + + return this; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..5e0e366 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,86 @@ +import { makeSvg, makeTooltip, Step } from "./components"; +import { InputStep } from "./types"; + +/** + * Creates a new `Story` object. + * + * @param div - `div` element that will be used as Story's container. + * @param steps - Array of step configs. + * + * @returns`Story` object. + */ +const makeStory = ( + div: HTMLDivElement, + steps: InputStep[] +): { + /** + * Renders a given step. + * + * @param stepKey - Step key. Refers to one of the steps passed to the `makeStory` function. + * @param t - Value between 0 and 1, indicating step's progress. + * @param indicateProgress - Whether to indicate step's progress. + */ + render: ( + stepKey: string | null | undefined, + t: number, + indicateProgress?: boolean + ) => void; +} => { + const svg = makeSvg(div); + const tooltip = makeTooltip(div); + + let loaded = false; + // Previous key. + let _key: string | null | undefined; + // Previous progress. + let _t = 0; + + let intsMap: Step.IntsMap; + + new ResizeObserver(() => { + const { width, height } = svg.measure(); + const recompute = () => { + prepareStepsIntsMap(width, height); + render(); + }; + + if (loaded) { + recompute(); + } else { + // Potentially wait for fonts to be loaded before the initial computation. + setTimeout(() => recompute(), 0); + loaded = true; + } + }).observe(div); + + const prepareStepsIntsMap = (width: number, height: number): void => { + const getters = Step.getters({ steps, svg, width, height }); + intsMap = Step.intsMap({ steps: getters, svg }); + }; + + const render = ( + stepKey: string | null | undefined = _key, + t: number = _t, + indicateProgress = true + ): void => { + // Save previous step & progress for the sake of window resizing. + _key = stepKey; + _t = t; + + if (stepKey !== null && stepKey !== undefined) { + const ints = intsMap.get(stepKey); + + if (ints) { + // Interactions with the story (e.g. hovering) are only allowed for the finished state. + const finished = t === 0 || t === 1; + const resolved = Step.resolve(ints, t); + + Step.render({ resolved, svg, tooltip, finished, indicateProgress }); + } + } + }; + + return { render }; +}; + +export { makeStory, InputStep }; diff --git a/src/scss.modules.d.ts b/src/scss.modules.d.ts new file mode 100644 index 0000000..aac6095 --- /dev/null +++ b/src/scss.modules.d.ts @@ -0,0 +1,4 @@ +declare module "*.scss" { + const styles: { [className: string]: string }; + export default styles; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..0af9965 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,110 @@ +import { PaletteName } from "./colors"; + +// External. +type BaseInputStep = { + key: string; + + /** Labels. */ + title?: string; + titleAnchor?: Anchor; + subtitle?: string; + subtitleAnchor?: Anchor; + + /** Legend. */ + shareDomain?: boolean; + showLegend?: boolean; + legendAnchor?: Anchor; + + /** Values & data labels. */ + showValues?: boolean; + maxValue?: number; + showDatumLabels?: boolean; + + /** Appearance. */ + palette?: PaletteName; + cartoonize?: boolean; + + /** Data. */ + groups: InputGroup[]; +}; + +export type InputStep = BaseInputStep & + ( + | { + chartType: "bar"; + chartSubtype?: BarChartSubtype; + verticalAxis?: { + show?: boolean; + title?: string; + }; + } + | { + chartType: Exclude; + } + ); + +export type InputGroup = { + key: string; + opacity?: number; + data: InputDatum[]; +}; + +export type InputDatum = { + key: string; + value: number; + // Used to teleport datum between groups. Formatted as "groupKey:datumKey". + teleportFrom?: string; + fill?: string; + opacity?: number; +}; + +export type Anchor = "start" | "middle" | "end"; + +// Charts. +export type ChartType = "bar" | "bubble" | "pie" | "treemap"; + +export type BarChartSubtype = "grouped" | "stacked"; + +export type TextType = + | "title" + | "subtitle" + | "legendItem" + | "verticalAxisTitle" + | "groupLabel" + | "datumLabel" + | "datumValue" + | "tick"; + +export type TextDims = { + [type in TextType]: { + height: number; + yShift: number; + }; +}; + +export type ColorMapEntry = { + ax: number; + ay: number; + color: string; +}; + +export type MaxValue = { + data: number; + scale: number | undefined; + actual: number; + // scale / data if defined + k: number; + // complement of k, 1 - k + kc: number; +}; + +// Getters. +export type GProps = { + s: (enter: Z, update?: Z | null, exit?: Z | null) => Z; + _g?: T; +}; + +// Interpolators. +export type State = "enter" | "update" | "exit"; + +export type GenericInt = (t: number) => T; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..80ef781 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,67 @@ +import { HALF_FONT_K } from "./charts/utils"; +import { Svg } from "./components"; +import { stateValue } from "./components/utils"; +import { State, TextDims, TextType } from "./types"; + +export const unique = (array: T[]): T[] => { + return Array.from(new Set(array)); +}; + +export const max = (array: number[]): number | undefined => { + return array.length === 0 ? undefined : Math.max(...array); +}; + +export const FONT_SIZE: Record = { + title: 24, + subtitle: 14, + legendItem: 12, + verticalAxisTitle: 12, + groupLabel: 14, + datumLabel: 11, + datumValue: 11, + tick: 11, +}; + +export const FONT_WEIGHT: Record = { + title: 700, + subtitle: 400, + legendItem: 400, + verticalAxisTitle: 400, + groupLabel: 400, + datumLabel: 600, + datumValue: 400, + tick: 400, +}; + +export const getTextDims = (svg: Svg): TextDims => { + return Object.fromEntries( + Object.entries(FONT_SIZE).map(([textType]) => { + const height = svg.measureText("Text", textType as TextType).height; + return [textType, { height, yShift: -height * HALF_FONT_K }]; + }) + ) as TextDims; +}; + +export const radiansToDegrees = (radians: number): number => { + return radians * (180 / Math.PI); +}; + +const getStateOrder = (state: State): 0 | 1 | 2 => { + return stateValue(state, [1, 2, 0]); +}; + +export const stateOrderComparator = ( + a: T, + b: T +): number => { + return getStateOrder(a.state) - getStateOrder(b.state); +}; + +export const getTextColor = (hex: string): "white" | "black" => { + const r = parseInt(hex.substring(1, 3), 16); + const g = parseInt(hex.substring(3, 5), 16); + const b = parseInt(hex.substring(5, 7), 16); + const yiq = (r * 299 + g * 587 + b * 114) / 1000; + + return yiq >= 128 ? "black" : "white"; +}; diff --git a/src/variables.scss b/src/variables.scss new file mode 100644 index 0000000..d65621f --- /dev/null +++ b/src/variables.scss @@ -0,0 +1,4 @@ +$color-light: #f5f5f5; +$color-lightgray: #ededed; +$color-gray: #696969; +$color-dark: #333333; diff --git a/tests/helpers.ts b/tests/helpers.ts new file mode 100644 index 0000000..32e6897 --- /dev/null +++ b/tests/helpers.ts @@ -0,0 +1,10 @@ +import { makeSvg } from "../src/components"; +import { Dimensions } from "../src/dims"; + +export const setup = () => { + const div = document.createElement("div"); + const svg = makeSvg(div); + const dims = new Dimensions(800, 550); + + return { svg, dims }; +}; diff --git a/tests/scssMock.ts b/tests/scssMock.ts new file mode 100644 index 0000000..ff8b4c5 --- /dev/null +++ b/tests/scssMock.ts @@ -0,0 +1 @@ +export default {}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d74d9e4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES6", + "lib": ["ES2020", "DOM"], + "module": "ESNEXT", + "moduleResolution": "node", + "declaration": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "plugins": [{ "name": "typescript-plugin-css-modules" }], + "typeRoots": ["./node_modules/@types", "./types"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "src/**/*.spec.ts"], + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Recommended" +}