From 110176499cd3ccff09ceea29391e4d99fcd45f1f Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sat, 6 Jul 2024 16:39:22 +0200 Subject: [PATCH 01/34] refactor: turned Activities into a function component --- src/components/Activities.jsx | 120 +++++++++++++++------------------- 1 file changed, 52 insertions(+), 68 deletions(-) diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index c14a71f..3d95afc 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -1,79 +1,33 @@ -import { Component } from 'react'; +import { useState, useEffect } from 'react'; import Activity from './Activity'; import Poster from './Poster'; import { KOALA_ACTIVITY_ENDPOINT } from '../helpers/env'; import PropTypes from 'prop-types'; -export default class Activities extends Component { - constructor(props) { - super(props); - this.state = { - activities: [], - }; +export default function Activities({ current, onChange }) { + const activities = useActivities(); - this.loadData(); - } - - //Utility function to change dates from activities to actual Date objects - setDate(activity) { - return Object.assign( - {}, - activity, - { has_start_time: activity.start_date.indexOf('T') > -1 }, - { - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - }, - { start_date: new Date(activity.start_date) }, - activity.end_date ? { end_date: new Date(activity.end_date) } : null - ); - } + if (activities.length > 0) { + if (current >= activities.length - 1) + onChange(true); - // Get activities - loadData() { - fetch(KOALA_ACTIVITY_ENDPOINT) - // Fix activity dates and sort them on start_date - .then((resp) => resp.json()) - .then((activities) => - activities.map(this.setDate).sort((a, b) => a.start_date - b.start_date) - ) - .then((activities) => { - this.setState({ activities: activities.filter((act) => act.poster) }); - }); - } - - componentDidMount() { - // Set up interval. - // Every this.props.loadInterval, new events are loaded from koala. - this.dataLoader = setInterval( - this.loadData.bind(this), - parseInt(import.meta.env.VITE_LOAD_INTERVAL) + const currentActivity = activities[current]; + return ( +
+ + +
); - } - - render() { - if (this.state.activities.length > 0) { - if (this.props.current >= this.state.activities.length - 1) - this.props.onChange(true); - - let currentActivity = this.state.activities[this.props.current]; - return ( -
- - -
- ); - } - return
; + } else { + return <>; } } @@ -82,3 +36,33 @@ Activities.propTypes = { current: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired, }; + +function setDate(activity) { + return Object.assign({ + ...activity, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, + start_date: new Date(activity.start_date) + }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); +} + +function useActivities() { + const [activities, setActivities] = useState([]); + + useEffect(() => { + const interval = setInterval(() => { + fetch(KOALA_ACTIVITY_ENDPOINT) + // Fix activity dates and sort them on start_date + .then(resp => resp.json()) + .then(activities => + setActivities(activities + .filter(act => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date))); + }, Number(import.meta.env.VITE_LOAD_INTERVAL)); + + return () => clearInterval(interval); + }); + + return activities; +} From bba137a25907d95e8e24cc7be213444ae7b56136 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sat, 6 Jul 2024 16:50:35 +0200 Subject: [PATCH 02/34] style: changed function definition for Activity --- src/components/Activity.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Activity.jsx b/src/components/Activity.jsx index 56ce743..c61c0a8 100644 --- a/src/components/Activity.jsx +++ b/src/components/Activity.jsx @@ -18,7 +18,7 @@ function createFormat(has_time, date, as = new Date()) { return format || '[]'; } -const Activity = ({ active, name, start_date, end_date, has_start_time, has_end_time, participant_counter }) => { +export default function Activity({ active, name, start_date, end_date, has_start_time, has_end_time, participant_counter }) { const activityRef = useRef(null); // Ensure that the current activity is visible @@ -58,5 +58,3 @@ Activity.propTypes = { has_end_time: PropTypes.bool.isRequired, participant_counter: PropTypes.string, }; - -export default Activity; From bbc80f552502699102ddc5513534daead50db290 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sat, 6 Jul 2024 17:02:36 +0200 Subject: [PATCH 03/34] fix: Activities does not halt state machine when there are no more activities --- src/components/Activities.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index 3d95afc..e23e76b 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -7,10 +7,10 @@ import PropTypes from 'prop-types'; export default function Activities({ current, onChange }) { const activities = useActivities(); - if (activities.length > 0) { - if (current >= activities.length - 1) - onChange(true); + if (current >= activities.length - 1) + onChange(true); + if (activities.length > 0) { const currentActivity = activities[current]; return (
@@ -62,7 +62,7 @@ function useActivities() { }, Number(import.meta.env.VITE_LOAD_INTERVAL)); return () => clearInterval(interval); - }); + }, []); return activities; } From ec60ff032eb60ba3c49f4867c6b9ad83a6984150 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sat, 6 Jul 2024 17:10:05 +0200 Subject: [PATCH 04/34] refactor: turned Ad into a function component --- src/components/Ad.jsx | 80 ++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index 32a955b..792519b 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -1,57 +1,53 @@ -import { Component } from 'react'; +import { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import Poster from './Poster'; import GetContent from '../helpers/contentful'; -export default class Ad extends Component { - constructor(props) { - super(props); - this.state = { - ads: [], - }; +export default function Ad({ current, onChange }) { + const ads = useAds(); - GetContent('ads', (entries) => { - this.setState({ - ads: entries !== null ? entries.map((entry) => entry.fields) : [], - }); - }); + if (ads.length > 0 && current >= ads.length - 1) + onChange(true); + + const currentAd = ads[current]; + if (ads.length <= 0) { + return ( +
+
    + +
    + ); + } else if (currentAd.fullscreen) { + return ( +
    + +
    + ); + } else { + return ( +
    +
      +

      {currentAd.title}

      +

      {currentAd.description}

      +
    + +
    + ); } +} - render() { - if (this.state.ads.length <= 0) - return ( -
    -
      - -
      - ); +function useAds() { + const [ads, setAds] = useState([]); - if (this.props.current >= this.state.ads.length - 1) - this.props.onChange(true); + useEffect(() => { + GetContent('ads', entries => setAds((entries ?? []).map(entry => entry.fields))); + }, []); - let currentAd = this.state.ads[this.props.current]; - if (currentAd.fullscreen) { - return ( -
      - -
      - ); - } else { - return ( -
      -
        -

        {currentAd.title}

        -

        {currentAd.description}

        -
      - -
      - ); - } - } + return ads; } // Explain expected types, for early error detection Ad.propTypes = { current: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired, -}; \ No newline at end of file +}; From 265deef279eb703e2c6fe84e8b0e827601e741ed Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sat, 6 Jul 2024 17:16:31 +0200 Subject: [PATCH 05/34] style: changed function definitions for Commits and Team --- src/App.jsx | 4 ++-- src/components/Commits.jsx | 4 ++-- src/components/Team.jsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 417787a..7119fca 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,9 +4,9 @@ import Clock from './components/Clock'; import BoardText from './components/BoardText'; import Quotes from './components/Quotes'; import Ad from './components/Ad'; -import { TeamPage } from './components/Team'; +import TeamPage from './components/Team'; import {GITHUB_REPOS, LOGO, NEXT_INTERVAL, NEXT_INTERVAL_COMMITS} from './helpers/env'; -import { CommitsPage } from './components/Commits'; +import CommitsPage from './components/Commits'; export default class App extends Component { constructor(props) { diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index 05315ea..bc8e30d 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -68,7 +68,7 @@ function formatDate(date) { return `${dd}-${mm}-${yyyy}`; } -export const CommitsPage = () => { +export default function CommitsPage() { const { data: commits, isLoading } = getAllCommits(); if (isLoading) return <> Loading... ; @@ -94,4 +94,4 @@ export const CommitsPage = () => {
      ); -}; +} diff --git a/src/components/Team.jsx b/src/components/Team.jsx index 33a70ce..a370b9c 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.jsx @@ -2,7 +2,7 @@ import { octokit } from '../helpers/github'; import { useQuery } from '../hooks/useQuery'; import Poster from './Poster'; -export const TeamPage = () => { +export default function TeamPage() { const { data: members, isLoading } = useQuery(async () => { const res = await octokit.rest.orgs.listMembers({ org: 'svsticky', @@ -39,4 +39,4 @@ export const TeamPage = () => { ); -}; +} From 83e6127b618b4d25a37ad4b64342244bb2141bcf Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Mon, 8 Jul 2024 19:21:50 +0200 Subject: [PATCH 06/34] refactor: added redux store and added api slices --- package-lock.json | 93 +++++++++++++++++++++++++++++++++-- package.json | 2 + src/components/Activities.jsx | 54 ++++++++++---------- src/components/Ad.jsx | 18 ++----- src/helpers/contentful.js | 12 ++--- src/main.jsx | 12 +++-- src/store.js | 17 +++++++ src/store/activities.js | 37 ++++++++++++++ src/store/ads.js | 22 +++++++++ 9 files changed, 210 insertions(+), 57 deletions(-) create mode 100644 src/store.js create mode 100644 src/store/activities.js create mode 100644 src/store/ads.js diff --git a/package-lock.json b/package-lock.json index 1bf9161..b5df2a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,13 @@ "name": "radio", "version": "0.0.0", "dependencies": { + "@reduxjs/toolkit": "^2.2.6", "contentful": "^10.6.1", "moment": "^2.29.4", "octokit": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^9.1.2", "scroll-into-view": "^1.16.2" }, "devDependencies": { @@ -3077,6 +3079,29 @@ "resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-7.4.0.tgz", "integrity": "sha512-FE2V+QZ2UYlh+9wWd5BPLNXG+J/XUD/PPq0ovS+nCcGX4+3qVbi3jYOmCTW48hg9SBBLtInx9+o7fFt4H5iP0Q==" }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", + "integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", @@ -3201,13 +3226,13 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3228,6 +3253,11 @@ "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -4191,7 +4221,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "devOptional": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -5585,6 +5615,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6834,6 +6873,28 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -6843,6 +6904,19 @@ "node": ">=0.10.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -6953,6 +7027,11 @@ "jsesc": "bin/jsesc" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -7645,6 +7724,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/vite": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", diff --git a/package.json b/package.json index 29c7df5..6051e9a 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,13 @@ "preview": "vite preview" }, "dependencies": { + "@reduxjs/toolkit": "^2.2.6", "contentful": "^10.6.1", "moment": "^2.29.4", "octokit": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^9.1.2", "scroll-into-view": "^1.16.2" }, "devDependencies": { diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index e23e76b..715afa2 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -1,11 +1,15 @@ -import { useState, useEffect } from 'react'; import Activity from './Activity'; import Poster from './Poster'; -import { KOALA_ACTIVITY_ENDPOINT } from '../helpers/env'; import PropTypes from 'prop-types'; +import { useGetActivitiesQuery } from '../store/activities'; export default function Activities({ current, onChange }) { - const activities = useActivities(); + const { data: activities, isSuccess } = useGetActivitiesQuery({ + pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL) + }); + + if (!isSuccess) + return <>; if (current >= activities.length - 1) onChange(true); @@ -14,7 +18,7 @@ export default function Activities({ current, onChange }) { const currentActivity = activities[current]; return (
      -
        +
          {activities.map((activity, i) => -1, - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - start_date: new Date(activity.start_date) - }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); -} -function useActivities() { - const [activities, setActivities] = useState([]); +// function useActivities() { +// const [activities, setActivities] = useState([]); - useEffect(() => { - const interval = setInterval(() => { - fetch(KOALA_ACTIVITY_ENDPOINT) - // Fix activity dates and sort them on start_date - .then(resp => resp.json()) - .then(activities => - setActivities(activities - .filter(act => act.poster) - .map(setDate) - .sort((a, b) => a.start_date - b.start_date))); - }, Number(import.meta.env.VITE_LOAD_INTERVAL)); +// useEffect(() => { +// const interval = setInterval(() => { +// fetch(KOALA_ACTIVITY_ENDPOINT) +// // Fix activity dates and sort them on start_date +// .then(resp => resp.json()) +// .then(activities => +// setActivities(activities +// .filter(act => act.poster) +// .map(setDate) +// .sort((a, b) => a.start_date - b.start_date))); +// }, Number(import.meta.env.VITE_LOAD_INTERVAL)); - return () => clearInterval(interval); - }, []); +// return () => clearInterval(interval); +// }, []); - return activities; -} +// return activities; +// } diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index 792519b..e99f319 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -1,10 +1,12 @@ -import { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import Poster from './Poster'; -import GetContent from '../helpers/contentful'; +import { useGetAdsQuery } from "../store/ads"; export default function Ad({ current, onChange }) { - const ads = useAds(); + const { data: ads, isSuccess } = useGetAdsQuery(); + + if (!isSuccess) + return <>; if (ads.length > 0 && current >= ads.length - 1) onChange(true); @@ -36,16 +38,6 @@ export default function Ad({ current, onChange }) { } } -function useAds() { - const [ads, setAds] = useState([]); - - useEffect(() => { - GetContent('ads', entries => setAds((entries ?? []).map(entry => entry.fields))); - }, []); - - return ads; -} - // Explain expected types, for early error detection Ad.propTypes = { current: PropTypes.number.isRequired, diff --git a/src/helpers/contentful.js b/src/helpers/contentful.js index 13abbcc..1a33bf1 100644 --- a/src/helpers/contentful.js +++ b/src/helpers/contentful.js @@ -7,13 +7,7 @@ const client = createClient({ }); // Get all entries from Contentful and return the data array -export default function GetContent(type, func) { - client - .getEntries({ - 'content_type': type - }) - .then(result => { - func(result.items) - }) - .catch(err => { throw err }); +export default async function getContentfulContent(type) { + const result = await client.getEntries({ 'content_type': type }); + return result.items; } diff --git a/src/main.jsx b/src/main.jsx index bc73550..a374a15 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,12 +1,18 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import App from './App.jsx'; + +import {Provider} from 'react-redux'; +import store from './store'; + import './index.css'; import './snow/snow.js'; import './snow/snow.css'; createRoot(document.getElementById('root')).render( - - - + + + + + ); diff --git a/src/store.js b/src/store.js new file mode 100644 index 0000000..b57e1ff --- /dev/null +++ b/src/store.js @@ -0,0 +1,17 @@ +import { configureStore } from "@reduxjs/toolkit"; +import activities from "./store/activities"; +import ads from "./store/ads"; + +const store = configureStore({ + reducer: { + [activities.reducerPath]: activities.reducer, + [ads.reducerPath]: ads.reducer + }, + middleware(getDefaultMiddleware) { + return getDefaultMiddleware() + .concat(activities.middleware) + .concat(ads.middleware); + } +}); + +export default store; diff --git a/src/store/activities.js b/src/store/activities.js new file mode 100644 index 0000000..7babb28 --- /dev/null +++ b/src/store/activities.js @@ -0,0 +1,37 @@ +import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; +import { KOALA_ACTIVITY_ENDPOINT } from '../helpers/env'; + +const activities = createApi({ + reducerPath: 'activities', + baseQuery: fakeBaseQuery(), + endpoints: build => ({ + getActivities: build.query({ + async queryFn() { + try { + const result = await fetch(KOALA_ACTIVITY_ENDPOINT) + .then(resp => resp.json()) + return { + data: result + .filter(act => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date) + }; + } catch (error) { + return { error: error.toString() }; + } + } + }) + }) +}); + +function setDate(activity) { + return Object.assign({ + ...activity, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, + start_date: new Date(activity.start_date) + }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); +} + +export const { useGetActivitiesQuery } = activities; +export default activities; diff --git a/src/store/ads.js b/src/store/ads.js new file mode 100644 index 0000000..461851e --- /dev/null +++ b/src/store/ads.js @@ -0,0 +1,22 @@ +import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react"; +import getContentfulContent from "../helpers/contentful"; + +const ads = createApi({ + reducerPath: "ads", + baseQuery: fakeBaseQuery(), + endpoints: build => ({ + getAds: build.query({ + async queryFn() { + try { + const res = await getContentfulContent('ads'); + return { data: res.map(entry => entry.fields) }; + } catch (error) { + return { error: error.toString() }; + } + } + }) + }) +}); + +export const { useGetAdsQuery } = ads; +export default ads; From 3bc93e0b1d78ca40de6fa0a1a1765838c002a3ef Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Mon, 8 Jul 2024 21:46:53 +0200 Subject: [PATCH 07/34] refactor: create board messages api slice --- src/store/boardMessages.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/store/boardMessages.js diff --git a/src/store/boardMessages.js b/src/store/boardMessages.js new file mode 100644 index 0000000..4b18927 --- /dev/null +++ b/src/store/boardMessages.js @@ -0,0 +1,22 @@ +import {createApi, fakeBaseQuery} from "@reduxjs/toolkit/query/react"; +import getContentfulContent from "../helpers/contentful"; + +const boardMessages = createApi({ + reducerPath: "boardMessages", + baseQuery: fakeBaseQuery(), + endpoints: build => ({ + getBoardMessages: build.query({ + async queryFn() { + try { + const results = await getContentfulContent('board-message'); + return { data: results.map(entry => entry.fields.message) }; + } catch (error) { + return { error: error.toString() }; + } + } + }) + }) +}); + +export const { useGetBoardMessagesQuery } = boardMessages; +export default boardMessages; From ffa21a245fe416b0fcf717f2bf61d63284a236ac Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Tue, 9 Jul 2024 22:29:43 +0200 Subject: [PATCH 08/34] refactor: create api slice for quotes --- src/store.js | 11 +++++++++-- src/store/quotes.js | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/store/quotes.js diff --git a/src/store.js b/src/store.js index b57e1ff..fe006c0 100644 --- a/src/store.js +++ b/src/store.js @@ -1,16 +1,23 @@ import { configureStore } from "@reduxjs/toolkit"; + import activities from "./store/activities"; import ads from "./store/ads"; +import boardMessages from "./store/boardMessages"; +import quotes from "./store/quotes"; const store = configureStore({ reducer: { [activities.reducerPath]: activities.reducer, - [ads.reducerPath]: ads.reducer + [ads.reducerPath]: ads.reducer, + [boardMessages.reducerPath]: boardMessages.reducer, + [quotes.reducerPath]: quotes.reducer }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() .concat(activities.middleware) - .concat(ads.middleware); + .concat(ads.middleware) + .concat(boardMessages.middleware) + .concat(quotes.middleware); } }); diff --git a/src/store/quotes.js b/src/store/quotes.js new file mode 100644 index 0000000..a71a323 --- /dev/null +++ b/src/store/quotes.js @@ -0,0 +1,23 @@ +import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react"; +import getContentfulContent from "../helpers/contentful"; + +const quotes = createApi({ + reducerPath: "quotes", + baseQuery: fakeBaseQuery(), + endpoints: build => ({ + getQuotes: build.query({ + async queryFn() { + try { + const res = await getContentfulContent('quotes'); + return { data: res.map(entry => entry.fields) }; + } catch (error) { + return { error: error.toString() }; + } + } + }) + }) +}); + +export const { useGetQuotesQuery } = quotes; +export default quotes; + From 5c3c59617a2a77f3dc35d879dcfe87446e81896c Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Tue, 9 Jul 2024 22:30:15 +0200 Subject: [PATCH 09/34] refactor: added slice for state machine variables --- src/store.js | 4 +++- src/store/state.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/store/state.js diff --git a/src/store.js b/src/store.js index fe006c0..b69c657 100644 --- a/src/store.js +++ b/src/store.js @@ -4,13 +4,15 @@ import activities from "./store/activities"; import ads from "./store/ads"; import boardMessages from "./store/boardMessages"; import quotes from "./store/quotes"; +import state from "./store/state"; const store = configureStore({ reducer: { [activities.reducerPath]: activities.reducer, [ads.reducerPath]: ads.reducer, [boardMessages.reducerPath]: boardMessages.reducer, - [quotes.reducerPath]: quotes.reducer + [quotes.reducerPath]: quotes.reducer, + state }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() diff --git a/src/store/state.js b/src/store/state.js new file mode 100644 index 0000000..2ab84b7 --- /dev/null +++ b/src/store/state.js @@ -0,0 +1,34 @@ +import {createSlice} from "@reduxjs/toolkit"; + +const state = createSlice({ + name: "state", + initialState: { + activityIndex: 0, + adIndex: 0, + boardMessageIndex: 0, + quotesIndices: [] + }, + reducers: { + incrementActivityIndex(state) { + state.activityIndex++; + }, + incrementAdIndex(state) { + state.adIndex++; + }, + incrementBoardMessageIndex(state) { + state.boardMessageIndex++; + }, + shiftQuote(state, action) { + if (state.quotesIndices.length === 1) { + state.quotesIndices = new Array(action.payload) + .fill(0) + .map((_, i) => i); + } else { + state.quotesIndices.shift(); + } + } + } +}); + +export const { incrementActivityIndex, incrementAdIndex, incrementBoardMessageIndex, shiftQuote } = state.actions; +export default state.reducer; From 00fb90255518e7625dd6e18cdfba599af2d1940d Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Wed, 10 Jul 2024 00:01:56 +0200 Subject: [PATCH 10/34] refactor: combined api slices based on api bases --- sample.env | 2 +- src/components/Activities.jsx | 4 ++-- src/components/Ad.jsx | 4 ++-- src/helpers/env.js | 6 ++---- src/store.js | 18 ++++++----------- src/store/activities.js | 37 ----------------------------------- src/store/ads.js | 22 --------------------- src/store/boardMessages.js | 22 --------------------- src/store/contentful.js | 28 ++++++++++++++++++++++++++ src/store/koala.js | 28 ++++++++++++++++++++++++++ src/store/quotes.js | 23 ---------------------- 11 files changed, 69 insertions(+), 125 deletions(-) delete mode 100644 src/store/activities.js delete mode 100644 src/store/ads.js delete mode 100644 src/store/boardMessages.js create mode 100644 src/store/contentful.js create mode 100644 src/store/koala.js delete mode 100644 src/store/quotes.js diff --git a/sample.env b/sample.env index 1df1eb8..4875f32 100644 --- a/sample.env +++ b/sample.env @@ -4,7 +4,7 @@ VITE_CONTENTFUL_ACCESS_TOKEN= # Endpoints VITE_LOGO=https://public.svsticky.nl/logos/logo_compact_outline_wit.svg -VITE_ACTIVITY_ENDPOINT=https://koala.svsticky.nl/api/activities +VITE_KOALA_API_BASE=https://koala.svsticky.nl/api/ # Timers VITE_LOAD_INTERVAL=900000 # 15 * 60 * 1000 diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index 715afa2..4c50afe 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -1,10 +1,10 @@ import Activity from './Activity'; import Poster from './Poster'; import PropTypes from 'prop-types'; -import { useGetActivitiesQuery } from '../store/activities'; +import { useActivitiesQuery } from '../store/koala'; export default function Activities({ current, onChange }) { - const { data: activities, isSuccess } = useGetActivitiesQuery({ + const { data: activities, isSuccess } = useActivitiesQuery({ pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL) }); diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index e99f319..c7fdc1f 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -1,9 +1,9 @@ import PropTypes from 'prop-types'; import Poster from './Poster'; -import { useGetAdsQuery } from "../store/ads"; +import { useAdsQuery } from '../store/contentful'; export default function Ad({ current, onChange }) { - const { data: ads, isSuccess } = useGetAdsQuery(); + const { data: ads, isSuccess } = useAdsQuery(); if (!isSuccess) return <>; diff --git a/src/helpers/env.js b/src/helpers/env.js index 88354bb..69f7d41 100644 --- a/src/helpers/env.js +++ b/src/helpers/env.js @@ -1,13 +1,11 @@ - - export const CONTENTFUL_SPACE_ID = import.meta.env.VITE_CONTENTFUL_SPACE_ID; export const CONTENTFUL_ACCESS_TOKEN = import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN; export const GITHUB_API_TOKEN = import.meta.env.VITE_GITHUB_API_TOKEN; export const GITHUB_REPOS = import.meta.env.VITE_GITHUB_REPOS; -export const KOALA_ACTIVITY_ENDPOINT = import.meta.env.VITE_ACTIVITY_ENDPOINT; +export const KOALA_API_BASE = import.meta.env.VITE_KOALA_API_BASE; export const LOGO = import.meta.env.VITE_LOGO; export const NEXT_INTERVAL = import.meta.env.VITE_NEXT_INTERVAL; -export const NEXT_INTERVAL_COMMITS = import.meta.env.VITE_NEXT_INTERVAL_COMMITS; \ No newline at end of file +export const NEXT_INTERVAL_COMMITS = import.meta.env.VITE_NEXT_INTERVAL_COMMITS; diff --git a/src/store.js b/src/store.js index b69c657..d1238d1 100644 --- a/src/store.js +++ b/src/store.js @@ -1,25 +1,19 @@ import { configureStore } from "@reduxjs/toolkit"; -import activities from "./store/activities"; -import ads from "./store/ads"; -import boardMessages from "./store/boardMessages"; -import quotes from "./store/quotes"; +import koala from "./store/koala"; +import contentful from "./store/contentful"; import state from "./store/state"; const store = configureStore({ reducer: { - [activities.reducerPath]: activities.reducer, - [ads.reducerPath]: ads.reducer, - [boardMessages.reducerPath]: boardMessages.reducer, - [quotes.reducerPath]: quotes.reducer, + [koala.reducerPath]: koala.reducer, + [contentful.reducerPath]: contentful.reducer, state }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() - .concat(activities.middleware) - .concat(ads.middleware) - .concat(boardMessages.middleware) - .concat(quotes.middleware); + .concat(koala.middleware) + .concat(contentful.middleware); } }); diff --git a/src/store/activities.js b/src/store/activities.js deleted file mode 100644 index 7babb28..0000000 --- a/src/store/activities.js +++ /dev/null @@ -1,37 +0,0 @@ -import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; -import { KOALA_ACTIVITY_ENDPOINT } from '../helpers/env'; - -const activities = createApi({ - reducerPath: 'activities', - baseQuery: fakeBaseQuery(), - endpoints: build => ({ - getActivities: build.query({ - async queryFn() { - try { - const result = await fetch(KOALA_ACTIVITY_ENDPOINT) - .then(resp => resp.json()) - return { - data: result - .filter(act => act.poster) - .map(setDate) - .sort((a, b) => a.start_date - b.start_date) - }; - } catch (error) { - return { error: error.toString() }; - } - } - }) - }) -}); - -function setDate(activity) { - return Object.assign({ - ...activity, - has_start_time: activity.start_date.indexOf('T') > -1, - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - start_date: new Date(activity.start_date) - }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); -} - -export const { useGetActivitiesQuery } = activities; -export default activities; diff --git a/src/store/ads.js b/src/store/ads.js deleted file mode 100644 index 461851e..0000000 --- a/src/store/ads.js +++ /dev/null @@ -1,22 +0,0 @@ -import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react"; -import getContentfulContent from "../helpers/contentful"; - -const ads = createApi({ - reducerPath: "ads", - baseQuery: fakeBaseQuery(), - endpoints: build => ({ - getAds: build.query({ - async queryFn() { - try { - const res = await getContentfulContent('ads'); - return { data: res.map(entry => entry.fields) }; - } catch (error) { - return { error: error.toString() }; - } - } - }) - }) -}); - -export const { useGetAdsQuery } = ads; -export default ads; diff --git a/src/store/boardMessages.js b/src/store/boardMessages.js deleted file mode 100644 index 4b18927..0000000 --- a/src/store/boardMessages.js +++ /dev/null @@ -1,22 +0,0 @@ -import {createApi, fakeBaseQuery} from "@reduxjs/toolkit/query/react"; -import getContentfulContent from "../helpers/contentful"; - -const boardMessages = createApi({ - reducerPath: "boardMessages", - baseQuery: fakeBaseQuery(), - endpoints: build => ({ - getBoardMessages: build.query({ - async queryFn() { - try { - const results = await getContentfulContent('board-message'); - return { data: results.map(entry => entry.fields.message) }; - } catch (error) { - return { error: error.toString() }; - } - } - }) - }) -}); - -export const { useGetBoardMessagesQuery } = boardMessages; -export default boardMessages; diff --git a/src/store/contentful.js b/src/store/contentful.js new file mode 100644 index 0000000..590c414 --- /dev/null +++ b/src/store/contentful.js @@ -0,0 +1,28 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; +import getContentfulContent from '../helpers/contentful'; + +async function contentfulBaseQuery(arg) { + try { + const res = await getContentfulContent(arg); + return { data: res.map(entry => entry.fields) }; + } catch (error) { + return { error: error.toString() }; + } +} + +const contentful = createApi({ + reducerPath: 'contentful', + baseQuery: contentfulBaseQuery, + endpoints: build => ({ + ads: build.query({ query: () => 'ads' }), + boardMessages: build.query({ query: () => 'board-message' }), + quotes: build.query({ query: () => 'quotes' }) + }) +}); + +export const { + useAdsQuery, + useBoardMessagesQuery, + useQuotesQuery +} = contentful; +export default contentful; diff --git a/src/store/koala.js b/src/store/koala.js new file mode 100644 index 0000000..7acdf51 --- /dev/null +++ b/src/store/koala.js @@ -0,0 +1,28 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; +import { KOALA_API_BASE } from '../helpers/env'; + +const koala = createApi({ + reducerPath: 'activities', + baseQuery: fetchBaseQuery({ baseUrl: KOALA_API_BASE }), + endpoints: build => ({ + activities: build.query({ + query: () => 'activities', + transformResponse: result => result + .filter(act => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date) + }) + }) +}); + +function setDate(activity) { + return Object.assign({ + ...activity, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, + start_date: new Date(activity.start_date) + }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); +} + +export const { useActivitiesQuery } = koala; +export default koala; diff --git a/src/store/quotes.js b/src/store/quotes.js deleted file mode 100644 index a71a323..0000000 --- a/src/store/quotes.js +++ /dev/null @@ -1,23 +0,0 @@ -import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react"; -import getContentfulContent from "../helpers/contentful"; - -const quotes = createApi({ - reducerPath: "quotes", - baseQuery: fakeBaseQuery(), - endpoints: build => ({ - getQuotes: build.query({ - async queryFn() { - try { - const res = await getContentfulContent('quotes'); - return { data: res.map(entry => entry.fields) }; - } catch (error) { - return { error: error.toString() }; - } - } - }) - }) -}); - -export const { useGetQuotesQuery } = quotes; -export default quotes; - From 1fe0ffb70e9c5579cf5bbe644dfee16c1b3d0f1c Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Wed, 10 Jul 2024 16:51:21 +0200 Subject: [PATCH 11/34] refactor: create api folder to replace previous store folder --- src/{store => api}/contentful.js | 15 +++++++++---- src/api/index.js | 5 +++++ src/{store => api}/koala.js | 0 src/components/Activities.jsx | 24 +------------------- src/components/Ad.jsx | 2 +- src/components/BoardText.jsx | 8 +++---- src/components/Quotes.jsx | 10 ++++----- src/helpers/contentful.js | 13 ----------- src/store.js | 38 ++++++++++++++++++++++++++++---- src/store/state.js | 34 ---------------------------- 10 files changed, 61 insertions(+), 88 deletions(-) rename src/{store => api}/contentful.js (57%) create mode 100644 src/api/index.js rename src/{store => api}/koala.js (100%) delete mode 100644 src/helpers/contentful.js delete mode 100644 src/store/state.js diff --git a/src/store/contentful.js b/src/api/contentful.js similarity index 57% rename from src/store/contentful.js rename to src/api/contentful.js index 590c414..994786e 100644 --- a/src/store/contentful.js +++ b/src/api/contentful.js @@ -1,10 +1,17 @@ +import { createClient } from 'contentful'; import { createApi } from '@reduxjs/toolkit/query/react'; -import getContentfulContent from '../helpers/contentful'; -async function contentfulBaseQuery(arg) { +import { CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_SPACE_ID } from '../helpers/env'; + +const client = createClient({ + space: CONTENTFUL_SPACE_ID, + accessToken: CONTENTFUL_ACCESS_TOKEN, +}); + +async function contentfulBaseQuery(content_type) { try { - const res = await getContentfulContent(arg); - return { data: res.map(entry => entry.fields) }; + const res = await client.getEntries({ content_type }); + return { data: res.items.map(entry => entry.fields) }; } catch (error) { return { error: error.toString() }; } diff --git a/src/api/index.js b/src/api/index.js new file mode 100644 index 0000000..7667578 --- /dev/null +++ b/src/api/index.js @@ -0,0 +1,5 @@ +export { default as contentful } from "./contentful"; +export * from "./contentful"; + +export { default as koala } from "./koala"; +export * from "./koala"; diff --git a/src/store/koala.js b/src/api/koala.js similarity index 100% rename from src/store/koala.js rename to src/api/koala.js diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index 4c50afe..0fbd477 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -1,7 +1,7 @@ import Activity from './Activity'; import Poster from './Poster'; import PropTypes from 'prop-types'; -import { useActivitiesQuery } from '../store/koala'; +import { useActivitiesQuery } from '../api/koala'; export default function Activities({ current, onChange }) { const { data: activities, isSuccess } = useActivitiesQuery({ @@ -40,25 +40,3 @@ Activities.propTypes = { current: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired, }; - - -// function useActivities() { -// const [activities, setActivities] = useState([]); - -// useEffect(() => { -// const interval = setInterval(() => { -// fetch(KOALA_ACTIVITY_ENDPOINT) -// // Fix activity dates and sort them on start_date -// .then(resp => resp.json()) -// .then(activities => -// setActivities(activities -// .filter(act => act.poster) -// .map(setDate) -// .sort((a, b) => a.start_date - b.start_date))); -// }, Number(import.meta.env.VITE_LOAD_INTERVAL)); - -// return () => clearInterval(interval); -// }, []); - -// return activities; -// } diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index c7fdc1f..b069f02 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import Poster from './Poster'; -import { useAdsQuery } from '../store/contentful'; +import { useAdsQuery } from '../api/contentful'; export default function Ad({ current, onChange }) { const { data: ads, isSuccess } = useAdsQuery(); diff --git a/src/components/BoardText.jsx b/src/components/BoardText.jsx index 17522c2..0930a4e 100644 --- a/src/components/BoardText.jsx +++ b/src/components/BoardText.jsx @@ -1,11 +1,11 @@ -import GetContent from '../helpers/contentful'; +// import GetContent from '../helpers/contentful'; let text = []; let index = -1; -GetContent('board-message', (entries) => { - text = entries !== null ? entries.map((entry) => entry.fields.message) : []; -}); +// GetContent('board-message', (entries) => { +// text = entries !== null ? entries.map((entry) => entry.fields.message) : []; +// }); // Get the next message from the array or start over if you have // reached the end. diff --git a/src/components/Quotes.jsx b/src/components/Quotes.jsx index d84d02b..0c99d79 100644 --- a/src/components/Quotes.jsx +++ b/src/components/Quotes.jsx @@ -1,9 +1,9 @@ -import GetContent from '../helpers/contentful'; +// import GetContent from '../helpers/contentful'; -GetContent('quotes', (entries) => { - const quotes = entries !== null ? entries.map((entry) => entry.fields) : []; - window.localStorage.setItem('AllQuotes', JSON.stringify(quotes)); -}); +// GetContent('quotes', (entries) => { +// const quotes = entries !== null ? entries.map((entry) => entry.fields) : []; +// window.localStorage.setItem('AllQuotes', JSON.stringify(quotes)); +// }); // Get a random quote function getRandomQuote(quotes) { diff --git a/src/helpers/contentful.js b/src/helpers/contentful.js deleted file mode 100644 index 1a33bf1..0000000 --- a/src/helpers/contentful.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createClient } from 'contentful'; -import { CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_SPACE_ID } from './env'; - -const client = createClient({ - space: CONTENTFUL_SPACE_ID, - accessToken: CONTENTFUL_ACCESS_TOKEN, -}); - -// Get all entries from Contentful and return the data array -export default async function getContentfulContent(type) { - const result = await client.getEntries({ 'content_type': type }); - return result.items; -} diff --git a/src/store.js b/src/store.js index d1238d1..4fe3d83 100644 --- a/src/store.js +++ b/src/store.js @@ -1,8 +1,38 @@ -import { configureStore } from "@reduxjs/toolkit"; +import { createSlice, configureStore } from '@reduxjs/toolkit'; -import koala from "./store/koala"; -import contentful from "./store/contentful"; -import state from "./store/state"; +import { koala, contentful } from './api'; + +const state = createSlice({ + name: 'state', + initialState: { + activityIndex: 0, + adIndex: 0, + boardMessageIndex: 0, + quotesIndices: [] + }, + reducers: { + incrementActivityIndex(state) { + state.activityIndex++; + }, + incrementAdIndex(state) { + state.adIndex++; + }, + incrementBoardMessageIndex(state) { + state.boardMessageIndex++; + }, + shiftQuote(state, action) { + if (state.quotesIndices.length === 1) { + state.quotesIndices = new Array(action.payload) + .fill(0) + .map((_, i) => i); + } else { + state.quotesIndices.shift(); + } + } + } +}); + +export const { incrementActivityIndex, incrementAdIndex, incrementBoardMessageIndex, shiftQuote } = state.actions; const store = configureStore({ reducer: { diff --git a/src/store/state.js b/src/store/state.js deleted file mode 100644 index 2ab84b7..0000000 --- a/src/store/state.js +++ /dev/null @@ -1,34 +0,0 @@ -import {createSlice} from "@reduxjs/toolkit"; - -const state = createSlice({ - name: "state", - initialState: { - activityIndex: 0, - adIndex: 0, - boardMessageIndex: 0, - quotesIndices: [] - }, - reducers: { - incrementActivityIndex(state) { - state.activityIndex++; - }, - incrementAdIndex(state) { - state.adIndex++; - }, - incrementBoardMessageIndex(state) { - state.boardMessageIndex++; - }, - shiftQuote(state, action) { - if (state.quotesIndices.length === 1) { - state.quotesIndices = new Array(action.payload) - .fill(0) - .map((_, i) => i); - } else { - state.quotesIndices.shift(); - } - } - } -}); - -export const { incrementActivityIndex, incrementAdIndex, incrementBoardMessageIndex, shiftQuote } = state.actions; -export default state.reducer; From a25c2de5256a874d2bc58e813b248ed221f5ef7f Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Wed, 10 Jul 2024 23:05:48 +0200 Subject: [PATCH 12/34] refactor: created github api slice --- src/api/github.js | 68 +++++++++++++++++++++++++++++++++++ src/api/index.js | 3 ++ src/components/Commits.jsx | 74 +++++++------------------------------- src/components/Team.jsx | 14 ++------ src/helpers/github.js | 5 --- src/hooks/useQuery.js | 22 ------------ src/store.js | 6 ++-- 7 files changed, 89 insertions(+), 103 deletions(-) create mode 100644 src/api/github.js delete mode 100644 src/helpers/github.js delete mode 100644 src/hooks/useQuery.js diff --git a/src/api/github.js b/src/api/github.js new file mode 100644 index 0000000..2689147 --- /dev/null +++ b/src/api/github.js @@ -0,0 +1,68 @@ +import { Octokit } from 'octokit'; +import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; + +import { GITHUB_API_TOKEN, GITHUB_REPOS } from '../helpers/env.js'; + +export const octokit = new Octokit({ auth: GITHUB_API_TOKEN }); + +async function listCommits(owner, repo) { + const res = await octokit.rest.repos.listCommits({ + owner, repo, per_page: 4, + }); + + return res.data.map(({ commit }) => ({ + message: commit.message, + author: commit.author.name ?? commit.author.login, + date: new Date(commit.committer.date), + repo, owner + })); +} + +const github = createApi({ + reducerPath: 'github', + baseQuery: fakeBaseQuery(), + endpoints: build => ({ + allCommits: build.query({ + queryFn: async () => { + try { + const commitsPerRepo = await Promise.allSettled( + GITHUB_REPOS + .split(' ') + .map(name => { + const [owner, repo] = name.split('/'); + return listCommits(owner, repo); + })); + + return { + data: commitsPerRepo + .flatMap(commits => commits.value) + .map(commit => ({ + ...commit, + date: commit.date.getTime(), + })) + .sort((a, b) => b - a) + }; + } catch (error) { + return { error: error.toString() }; + } + } + }), + members: build.query({ + queryFn: async () => { + try { + const res = await octokit.rest.orgs.listMembers({ + org: 'svsticky', + per_page: 100, + }); + + return res.data; + } catch (error) { + return { error: error.toString() }; + } + } + }) + }) +}); + +export const { useAllCommitsQuery, useMembersQuery } = github; +export default github; diff --git a/src/api/index.js b/src/api/index.js index 7667578..4a5777b 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -3,3 +3,6 @@ export * from "./contentful"; export { default as koala } from "./koala"; export * from "./koala"; + +export { default as github } from "./github"; +export * from "./github"; diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index bc8e30d..bb2b11d 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -1,51 +1,5 @@ -import {octokit} from '../helpers/github'; -import {useQuery} from '../hooks/useQuery'; import Poster from './Poster'; -import {GITHUB_REPOS} from '../helpers/env.js'; - -function useCommits(owner, repo) { - return useQuery(async () => { - const res = await octokit.rest.repos.listCommits({ - owner: owner, - repo: repo, - per_page: 4, - }); - - return res.data.map((commit, index) => { - return ({ - index: index, - message: commit.commit.message, - author: commit.commit.author.name ?? commit.commit.author.login, - repo: repo, - date: new Date(commit.commit.committer.date), - owner: owner - }) - }); - }); -} - -function getAllCommits() { - const v = GITHUB_REPOS - .split(' ') - .map(fIdent => { - const v = fIdent.split('/'); - return useCommits(v[0], v[1]); - }); - - let commits = v - .map(v => v.data) - .flat(); - commits.sort((a, b) => { - return b?.date?.getTime() - a?.date?.getTime(); - }); - - const isLoading = v.map(v => v.isLoading); - - return { - data: commits.slice(0, 5), - isLoading: isLoading.includes(true), - } -} +import {useAllCommitsQuery} from '../api/github'; function formatTime(date) { let hh = date.getHours(); @@ -69,27 +23,23 @@ function formatDate(date) { } export default function CommitsPage() { - const { data: commits, isLoading } = getAllCommits(); + const { data: commits, isLoading } = useAllCommitsQuery(); if (isLoading) return <> Loading... ; return (

          Recent commits

            - {commits?.map((commit) => { - return ( - <> -
          • -

            - {commit.message.split('\n')[0]} -

            -

            - On {commit.owner}/{commit.repo} by {commit.author} ({formatDate(commit.date)} {formatTime(commit.date)}) -

            -
          • - - ); - })} + {commits.map((commit, index) => +
          • +

            + {commit.message.split('\n')[0]} +

            +

            + On {commit.owner}/{commit.repo} by {commit.author} ({formatDate(new Date(commit.date))} {formatTime(new Date(commit.date))}) +

            +
          • + )}
          diff --git a/src/components/Team.jsx b/src/components/Team.jsx index a370b9c..fa314fc 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.jsx @@ -1,21 +1,11 @@ -import { octokit } from '../helpers/github'; -import { useQuery } from '../hooks/useQuery'; +import {useMembersQuery} from '../api/github'; import Poster from './Poster'; export default function TeamPage() { - const { data: members, isLoading } = useQuery(async () => { - const res = await octokit.rest.orgs.listMembers({ - org: 'svsticky', - per_page: 100, - }); - - return res.data; - }); + const { data: members, isLoading } = useMembersQuery(); if (isLoading) return <> Loading... ; - console.log(members); - return (
          diff --git a/src/helpers/github.js b/src/helpers/github.js deleted file mode 100644 index ee9e998..0000000 --- a/src/helpers/github.js +++ /dev/null @@ -1,5 +0,0 @@ -import { Octokit } from 'octokit'; -import { GITHUB_API_TOKEN } from './env.js' - - -export const octokit = new Octokit({ auth: GITHUB_API_TOKEN }); diff --git a/src/hooks/useQuery.js b/src/hooks/useQuery.js deleted file mode 100644 index 91bd772..0000000 --- a/src/hooks/useQuery.js +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect, useState } from 'react'; - -/** - * @description simple function to fetch data - * @example - * const { data: members, isLoading } = useQuery(async () => fetch(...)) - * */ -export function useQuery(func) { - const [isLoading, setLoading] = useState(true); - const [data, setData] = useState(null); - - useEffect(() => { - func().then((data) => { - setData(data); - setLoading(false); - }) - // Supress linter warning: - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return { data, isLoading }; -} \ No newline at end of file diff --git a/src/store.js b/src/store.js index 4fe3d83..5ce2b5d 100644 --- a/src/store.js +++ b/src/store.js @@ -1,6 +1,6 @@ import { createSlice, configureStore } from '@reduxjs/toolkit'; -import { koala, contentful } from './api'; +import { koala, contentful, github } from './api'; const state = createSlice({ name: 'state', @@ -38,12 +38,14 @@ const store = configureStore({ reducer: { [koala.reducerPath]: koala.reducer, [contentful.reducerPath]: contentful.reducer, + [github.reducerPath]: github.reducer, state }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() .concat(koala.middleware) - .concat(contentful.middleware); + .concat(contentful.middleware) + .concat(github.middleware); } }); From 34f2968df9efd6555d1d6f350aaa393c963d405a Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Wed, 10 Jul 2024 23:19:05 +0200 Subject: [PATCH 13/34] refactor: move env.js out of helpers --- src/App.jsx | 4 +++- src/api/contentful.js | 2 +- src/api/github.js | 2 +- src/api/koala.js | 3 ++- src/{helpers => }/env.js | 0 5 files changed, 7 insertions(+), 4 deletions(-) rename src/{helpers => }/env.js (100%) diff --git a/src/App.jsx b/src/App.jsx index 7119fca..508463d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,13 @@ import { Component } from 'react'; + +import {GITHUB_REPOS, LOGO, NEXT_INTERVAL, NEXT_INTERVAL_COMMITS} from './env'; + import Activities from './components/Activities'; import Clock from './components/Clock'; import BoardText from './components/BoardText'; import Quotes from './components/Quotes'; import Ad from './components/Ad'; import TeamPage from './components/Team'; -import {GITHUB_REPOS, LOGO, NEXT_INTERVAL, NEXT_INTERVAL_COMMITS} from './helpers/env'; import CommitsPage from './components/Commits'; export default class App extends Component { diff --git a/src/api/contentful.js b/src/api/contentful.js index 994786e..adcd972 100644 --- a/src/api/contentful.js +++ b/src/api/contentful.js @@ -1,7 +1,7 @@ import { createClient } from 'contentful'; import { createApi } from '@reduxjs/toolkit/query/react'; -import { CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_SPACE_ID } from '../helpers/env'; +import { CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_SPACE_ID } from '../env'; const client = createClient({ space: CONTENTFUL_SPACE_ID, diff --git a/src/api/github.js b/src/api/github.js index 2689147..a586026 100644 --- a/src/api/github.js +++ b/src/api/github.js @@ -1,7 +1,7 @@ import { Octokit } from 'octokit'; import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; -import { GITHUB_API_TOKEN, GITHUB_REPOS } from '../helpers/env.js'; +import { GITHUB_API_TOKEN, GITHUB_REPOS } from '../env.js'; export const octokit = new Octokit({ auth: GITHUB_API_TOKEN }); diff --git a/src/api/koala.js b/src/api/koala.js index 7acdf51..918b6c5 100644 --- a/src/api/koala.js +++ b/src/api/koala.js @@ -1,5 +1,6 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; -import { KOALA_API_BASE } from '../helpers/env'; + +import { KOALA_API_BASE } from '../env'; const koala = createApi({ reducerPath: 'activities', diff --git a/src/helpers/env.js b/src/env.js similarity index 100% rename from src/helpers/env.js rename to src/env.js From cdc8b6c6b385b39f051b49b0ffeea6415dd7a2d1 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Thu, 11 Jul 2024 16:40:26 +0200 Subject: [PATCH 14/34] refactor: create store folder and moved api into it --- src/App.jsx | 8 +++++--- src/components/Activities.jsx | 2 +- src/components/Ad.jsx | 2 +- src/components/Commits.jsx | 2 +- src/components/Team.jsx | 2 +- src/env.js | 11 ----------- src/{ => store}/api/contentful.js | 6 ++---- src/{ => store}/api/github.js | 8 ++++---- src/{ => store}/api/index.js | 0 src/{ => store}/api/koala.js | 6 +++--- src/store/index.js | 21 +++++++++++++++++++++ src/{store.js => store/state.js} | 22 ++-------------------- 12 files changed, 41 insertions(+), 49 deletions(-) delete mode 100644 src/env.js rename src/{ => store}/api/contentful.js (84%) rename src/{ => store}/api/github.js (91%) rename src/{ => store}/api/index.js (100%) rename src/{ => store}/api/koala.js (88%) create mode 100644 src/store/index.js rename src/{store.js => store/state.js} (59%) diff --git a/src/App.jsx b/src/App.jsx index 508463d..916cade 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,5 @@ import { Component } from 'react'; -import {GITHUB_REPOS, LOGO, NEXT_INTERVAL, NEXT_INTERVAL_COMMITS} from './env'; - import Activities from './components/Activities'; import Clock from './components/Clock'; import BoardText from './components/BoardText'; @@ -10,6 +8,10 @@ import Ad from './components/Ad'; import TeamPage from './components/Team'; import CommitsPage from './components/Commits'; +const LOGO = import.meta.env.VITE_LOGO; +const NEXT_INTERVAL = import.meta.env.VITE_NEXT_INTERVAL; +const NEXT_INTERVAL_COMMITS = import.meta.env.VITE_NEXT_INTERVAL_COMMITS; + export default class App extends Component { constructor(props) { super(props); @@ -67,7 +69,7 @@ export default class App extends Component { // }); // Dont go to commits page if no repositories are configured - if(GITHUB_REPOS === '') { + if (import.meta.env.VITE_GITHUB_REPOS === '') { this.setState({ current: 'activities', }); diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index 0fbd477..c64658b 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -1,7 +1,7 @@ import Activity from './Activity'; import Poster from './Poster'; import PropTypes from 'prop-types'; -import { useActivitiesQuery } from '../api/koala'; +import { useActivitiesQuery } from '../store/api'; export default function Activities({ current, onChange }) { const { data: activities, isSuccess } = useActivitiesQuery({ diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index b069f02..7f45bab 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import Poster from './Poster'; -import { useAdsQuery } from '../api/contentful'; +import { useAdsQuery } from '../store/api'; export default function Ad({ current, onChange }) { const { data: ads, isSuccess } = useAdsQuery(); diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index bb2b11d..acaef20 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -1,5 +1,5 @@ import Poster from './Poster'; -import {useAllCommitsQuery} from '../api/github'; +import {useAllCommitsQuery} from '../store/api'; function formatTime(date) { let hh = date.getHours(); diff --git a/src/components/Team.jsx b/src/components/Team.jsx index fa314fc..14b8044 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.jsx @@ -1,4 +1,4 @@ -import {useMembersQuery} from '../api/github'; +import {useMembersQuery} from '../store/api'; import Poster from './Poster'; export default function TeamPage() { diff --git a/src/env.js b/src/env.js deleted file mode 100644 index 69f7d41..0000000 --- a/src/env.js +++ /dev/null @@ -1,11 +0,0 @@ -export const CONTENTFUL_SPACE_ID = import.meta.env.VITE_CONTENTFUL_SPACE_ID; -export const CONTENTFUL_ACCESS_TOKEN = import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN; - -export const GITHUB_API_TOKEN = import.meta.env.VITE_GITHUB_API_TOKEN; -export const GITHUB_REPOS = import.meta.env.VITE_GITHUB_REPOS; - -export const KOALA_API_BASE = import.meta.env.VITE_KOALA_API_BASE; -export const LOGO = import.meta.env.VITE_LOGO; - -export const NEXT_INTERVAL = import.meta.env.VITE_NEXT_INTERVAL; -export const NEXT_INTERVAL_COMMITS = import.meta.env.VITE_NEXT_INTERVAL_COMMITS; diff --git a/src/api/contentful.js b/src/store/api/contentful.js similarity index 84% rename from src/api/contentful.js rename to src/store/api/contentful.js index adcd972..f1df484 100644 --- a/src/api/contentful.js +++ b/src/store/api/contentful.js @@ -1,11 +1,9 @@ import { createClient } from 'contentful'; import { createApi } from '@reduxjs/toolkit/query/react'; -import { CONTENTFUL_ACCESS_TOKEN, CONTENTFUL_SPACE_ID } from '../env'; - const client = createClient({ - space: CONTENTFUL_SPACE_ID, - accessToken: CONTENTFUL_ACCESS_TOKEN, + space: import.meta.env.VITE_CONTENTFUL_SPACE_ID, + accessToken: import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN, }); async function contentfulBaseQuery(content_type) { diff --git a/src/api/github.js b/src/store/api/github.js similarity index 91% rename from src/api/github.js rename to src/store/api/github.js index a586026..8b9adfd 100644 --- a/src/api/github.js +++ b/src/store/api/github.js @@ -1,9 +1,9 @@ import { Octokit } from 'octokit'; import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; -import { GITHUB_API_TOKEN, GITHUB_REPOS } from '../env.js'; - -export const octokit = new Octokit({ auth: GITHUB_API_TOKEN }); +export const octokit = new Octokit({ + auth: import.meta.env.VITE_GITHUB_API_TOKEN +}); async function listCommits(owner, repo) { const res = await octokit.rest.repos.listCommits({ @@ -26,7 +26,7 @@ const github = createApi({ queryFn: async () => { try { const commitsPerRepo = await Promise.allSettled( - GITHUB_REPOS + import.meta.env.VITE_GITHUB_REPOS .split(' ') .map(name => { const [owner, repo] = name.split('/'); diff --git a/src/api/index.js b/src/store/api/index.js similarity index 100% rename from src/api/index.js rename to src/store/api/index.js diff --git a/src/api/koala.js b/src/store/api/koala.js similarity index 88% rename from src/api/koala.js rename to src/store/api/koala.js index 918b6c5..0714e94 100644 --- a/src/api/koala.js +++ b/src/store/api/koala.js @@ -1,10 +1,10 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; -import { KOALA_API_BASE } from '../env'; - const koala = createApi({ reducerPath: 'activities', - baseQuery: fetchBaseQuery({ baseUrl: KOALA_API_BASE }), + baseQuery: fetchBaseQuery({ + baseUrl: import.meta.env.VITE_KOALA_API_BASE + }), endpoints: build => ({ activities: build.query({ query: () => 'activities', diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 0000000..537ea61 --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,21 @@ +import { configureStore } from '@reduxjs/toolkit'; + +import { koala, contentful, github } from './api'; +import state from './state'; + +const store = configureStore({ + reducer: { + [koala.reducerPath]: koala.reducer, + [contentful.reducerPath]: contentful.reducer, + [github.reducerPath]: github.reducer, + state + }, + middleware(getDefaultMiddleware) { + return getDefaultMiddleware() + .concat(koala.middleware) + .concat(contentful.middleware) + .concat(github.middleware); + } +}); + +export default store; diff --git a/src/store.js b/src/store/state.js similarity index 59% rename from src/store.js rename to src/store/state.js index 5ce2b5d..831b7c9 100644 --- a/src/store.js +++ b/src/store/state.js @@ -1,6 +1,4 @@ -import { createSlice, configureStore } from '@reduxjs/toolkit'; - -import { koala, contentful, github } from './api'; +import { createSlice } from "@reduxjs/toolkit"; const state = createSlice({ name: 'state', @@ -33,20 +31,4 @@ const state = createSlice({ }); export const { incrementActivityIndex, incrementAdIndex, incrementBoardMessageIndex, shiftQuote } = state.actions; - -const store = configureStore({ - reducer: { - [koala.reducerPath]: koala.reducer, - [contentful.reducerPath]: contentful.reducer, - [github.reducerPath]: github.reducer, - state - }, - middleware(getDefaultMiddleware) { - return getDefaultMiddleware() - .concat(koala.middleware) - .concat(contentful.middleware) - .concat(github.middleware); - } -}); - -export default store; +export default state.reducer; From d85dd1700e978aa59432ba971d3815a05fb45457 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 12 Jul 2024 13:51:19 +0200 Subject: [PATCH 15/34] refactor: moved state machine logic into thunk --- src/App.jsx | 187 +++++++++------------------------- src/components/Activities.jsx | 16 +-- src/components/Ad.jsx | 8 +- src/components/BoardText.jsx | 29 +++--- src/components/Quotes.jsx | 61 +++-------- src/store/api/koala.js | 2 +- src/store/index.js | 143 ++++++++++++++++++++++++++ src/store/state.js | 49 +++++++-- 8 files changed, 271 insertions(+), 224 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 916cade..18de829 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,159 +1,68 @@ -import { Component } from 'react'; +import {useEffect} from 'react'; +import {useDispatch, useSelector} from 'react-redux'; import Activities from './components/Activities'; import Clock from './components/Clock'; import BoardText from './components/BoardText'; import Quotes from './components/Quotes'; import Ad from './components/Ad'; -import TeamPage from './components/Team'; import CommitsPage from './components/Commits'; +import {nextState} from './store'; +import {contentful} from './store/api'; +import {resetQuotes} from './store/state'; + const LOGO = import.meta.env.VITE_LOGO; -const NEXT_INTERVAL = import.meta.env.VITE_NEXT_INTERVAL; -const NEXT_INTERVAL_COMMITS = import.meta.env.VITE_NEXT_INTERVAL_COMMITS; -export default class App extends Component { - constructor(props) { - super(props); +export default function App() { + return ( +
          +
          +
          + sticky logo +
          + +
          + +
          + ); +} - this.state = { - current: 'activities', - index: 0, - }; - } +function StateMachine() { + const dispatch = useDispatch(); - next() { - const params = new URLSearchParams(window.location.search); - const display_internal = params.get('internal') === 'true'; + useEffect(() => { + const result = dispatch(contentful.endpoints.quotes.initiate()); - switch (this.state.current) { - case 'activities': - if (this.finishedState) { - this.finishedState = false; - this.setState({ - current: 'advertisement', - index: 0, - }); - } else { - this.setState({ - index: this.state.index + 1, - }); - } - break; - case 'advertisement': - if (this.finishedState) { - this.finishedState = false; + result.then(({ data: quotes }) => { + dispatch(resetQuotes(quotes.length)); + }); - // skip boardText and quotes on the screen on the outside of the - // Sticky room - let new_state = display_internal ? 'boardText' : 'activities'; - this.setState({ - current: new_state, - index: 0, - }); - } else { - this.setState({ - index: this.state.index + 1, - }); - } - break; - case 'boardText': - this.setState({ - current: 'quotes', - }); - break; - case 'quotes': - // this.setState({ - // // current: 'team', REMOVED TEMPORARELY - // current: 'activities', - // }); + return result.unsubscribe; + }, []); - // Dont go to commits page if no repositories are configured - if (import.meta.env.VITE_GITHUB_REPOS === '') { - this.setState({ - current: 'activities', - }); - } else { - this.setState({ - current: 'commits', - }); - } + useEffect(() => { + const interval = setInterval(() => { + dispatch(nextState); + }, import.meta.env.VITE_NEXT_INTERVAL); - break; - case 'team': - // Temporarily disabled - break; - case 'commits': - setTimeout( - () => this.setState({ - current: 'activities', - }), - NEXT_INTERVAL_COMMITS - ) - break; - default: - return; - } - } + return () => clearInterval(interval); + }); - componentDidMount() { - // Set up interval. - // Every this.props.nextInterval, we switch to the next ad or activity to display - this.activityChanger = setInterval( - this.next.bind(this), - parseInt(NEXT_INTERVAL) - ); - } + const state = useSelector(state => state.state); - componentWillUnmount() { - clearInterval(this.dataLoader); - clearInterval(this.activityChanger); - } - - renderContent() { - switch (this.state.current) { - case 'activities': - return ( - { - this.finishedState = true; - }} - /> - ); - case 'advertisement': - return ( - { - this.finishedState = true; - }} - /> - ); - case 'boardText': - return ; - case 'quotes': - return ; - case 'team': - return ; - case 'commits': - return ; - default: - return; - } - } - - render() { - return ( -
          -
          -
          - sticky logo -
          - -
          - {this.renderContent()} -
          - ); + switch (state.current) { + case 'activities': + return ; + case 'advertisement': + return ; + case 'boardText': + return ; + case 'quotes': + return ; + case 'commits': + return ; + default: + return <>; } } diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index c64658b..8457462 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -3,17 +3,14 @@ import Poster from './Poster'; import PropTypes from 'prop-types'; import { useActivitiesQuery } from '../store/api'; -export default function Activities({ current, onChange }) { - const { data: activities, isSuccess } = useActivitiesQuery({ +export default function Activities({ current }) { + const { data: activities, isSuccess } = useActivitiesQuery(undefined, { pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL) }); if (!isSuccess) return <>; - if (current >= activities.length - 1) - onChange(true); - if (activities.length > 0) { const currentActivity = activities[current]; return ( @@ -31,12 +28,15 @@ export default function Activities({ current, onChange }) {
          ); } else { - return <>; + return ( +
          +

          There are no activities, wanbeleid!

          +
          + ); } } // Explain expected types, for early error detection Activities.propTypes = { - current: PropTypes.number.isRequired, - onChange: PropTypes.func.isRequired, + current: PropTypes.number.isRequired }; diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index 7f45bab..e780083 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -2,15 +2,12 @@ import PropTypes from 'prop-types'; import Poster from './Poster'; import { useAdsQuery } from '../store/api'; -export default function Ad({ current, onChange }) { +export default function Ad({ current }) { const { data: ads, isSuccess } = useAdsQuery(); if (!isSuccess) return <>; - if (ads.length > 0 && current >= ads.length - 1) - onChange(true); - const currentAd = ads[current]; if (ads.length <= 0) { return ( @@ -40,6 +37,5 @@ export default function Ad({ current, onChange }) { // Explain expected types, for early error detection Ad.propTypes = { - current: PropTypes.number.isRequired, - onChange: PropTypes.func.isRequired, + current: PropTypes.number.isRequired }; diff --git a/src/components/BoardText.jsx b/src/components/BoardText.jsx index 0930a4e..3f3f3b0 100644 --- a/src/components/BoardText.jsx +++ b/src/components/BoardText.jsx @@ -1,24 +1,21 @@ -// import GetContent from '../helpers/contentful'; +import PropTypes from 'prop-types'; +import {useBoardMessagesQuery} from '../store/api'; -let text = []; -let index = -1; +export default function BoardText({ current }) { + const { data: boardMessages, isSuccess } = useBoardMessagesQuery(); -// GetContent('board-message', (entries) => { -// text = entries !== null ? entries.map((entry) => entry.fields.message) : []; -// }); + if (!isSuccess) + return <>; -// Get the next message from the array or start over if you have -// reached the end. -function getCurrentText() { - index = index < text.length - 1 ? index + 1 : 0; + const { message } = boardMessages[current]; - return text[index]; -} - -export default function BoardText() { return ( -
          -

          {getCurrentText()}

          +
          +

          {message}

          ); } + +BoardText.propTypes = { + current: PropTypes.number.isRequired, +}; diff --git a/src/components/Quotes.jsx b/src/components/Quotes.jsx index 0c99d79..ed1a3d5 100644 --- a/src/components/Quotes.jsx +++ b/src/components/Quotes.jsx @@ -1,55 +1,24 @@ -// import GetContent from '../helpers/contentful'; +import PropTypes from 'prop-types'; +import {useQuotesQuery} from '../store/api'; -// GetContent('quotes', (entries) => { -// const quotes = entries !== null ? entries.map((entry) => entry.fields) : []; -// window.localStorage.setItem('AllQuotes', JSON.stringify(quotes)); -// }); +export default function Quotes({ current }) { + const { data: quotes, isSuccess } = useQuotesQuery(); -// Get a random quote -function getRandomQuote(quotes) { - let quote = { - text: '', - person: '', - }; + if (!isSuccess) + return <>; - let i = Math.floor(Math.random() * quotes.length); - if (quotes.length > 0) { - quote = { - text: quotes[i].text, - person: quotes[i].person, - }; - - // Delete quote after using it. - quotes = quotes.filter((quote) => quote !== quotes[i]); - window.localStorage.setItem('quotes', JSON.stringify(quotes)); - } - - return quote; -} - -export default function Quotes() { - let quotes = JSON.parse(localStorage.getItem('quotes') || '[]'); - - // If there are no quotes, retrieve them - if (!quotes || - // quotes === null || - // quotes === undefined || - // quotes === "" || - // quotes === false || - (Array.isArray(quotes) && quotes.length === 0) - ) { - quotes = JSON.parse(window.localStorage.getItem('AllQuotes')); - window.localStorage.setItem('quotes', JSON.stringify(quotes)); - } - - let quote = getRandomQuote(quotes); + const quote = quotes[current]; return ( -
          -
          -

          "{quote.text}"

          -

          -{quote.person}

          +
          +
          +

          "{quote.text}"

          +

          -{quote.person}

          ); } + +Quotes.propTypes = { + current: PropTypes.number.isRequired, +}; diff --git a/src/store/api/koala.js b/src/store/api/koala.js index 0714e94..8926e7d 100644 --- a/src/store/api/koala.js +++ b/src/store/api/koala.js @@ -1,7 +1,7 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const koala = createApi({ - reducerPath: 'activities', + reducerPath: 'koala', baseQuery: fetchBaseQuery({ baseUrl: import.meta.env.VITE_KOALA_API_BASE }), diff --git a/src/store/index.js b/src/store/index.js index 537ea61..5fd88c9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,8 +1,151 @@ import { configureStore } from '@reduxjs/toolkit'; import { koala, contentful, github } from './api'; +import * as actions from './state'; import state from './state'; +// next() { +// const params = new URLSearchParams(window.location.search); +// const display_internal = params.get('internal') === 'true'; + +// switch (this.state.current) { +// case 'activities': +// if (this.finishedState) { +// this.finishedState = false; +// this.setState({ +// current: 'advertisement', +// index: 0, +// }); +// } else { +// this.setState({ +// index: this.state.index + 1, +// }); +// } +// break; +// case 'advertisement': +// if (this.finishedState) { +// this.finishedState = false; + +// // skip boardText and quotes on the screen on the outside of the +// // Sticky room +// let new_state = display_internal ? 'boardText' : 'activities'; +// this.setState({ +// current: new_state, +// index: 0, +// }); +// } else { +// this.setState({ +// index: this.state.index + 1, +// }); +// } +// break; +// case 'boardText': +// this.setState({ +// current: 'quotes', +// }); +// break; +// case 'quotes': +// // this.setState({ +// // // current: 'team', REMOVED TEMPORARELY +// // current: 'activities', +// // }); + +// // Dont go to commits page if no repositories are configured +// if (import.meta.env.VITE_GITHUB_REPOS === '') { +// this.setState({ +// current: 'activities', +// }); +// } else { +// this.setState({ +// current: 'commits', +// }); +// } + +// break; +// case 'team': +// // Temporarily disabled +// break; +// case 'commits': +// setTimeout( +// () => this.setState({ +// current: 'activities', +// }), +// NEXT_INTERVAL_COMMITS +// ) +// break; +// default: +// return; +// } +// } + +export function nextState(dispatch, getState) { + const params = new URLSearchParams(window.location.search); + const displayInternal = params.get('internal') === 'true'; + + const state = getState(); + switch (state.state.current) { + case 'activities': { + const { data: activities } = koala.endpoints.activities.select()(state); + + if (state.state.activityIndex >= activities.length - 1) { + dispatch(actions.setCurrent('advertisement')); + dispatch(actions.resetActivityIndex()); + } else { + dispatch(actions.incrementActivityIndex()); + } + } break; + + case 'advertisement': { + const { data: ads } = contentful.endpoints.ads.select()(state); + + if (state.state.adIndex >= ads.length - 1) { + dispatch(actions.setCurrent( + displayInternal + ? 'boardText' + : 'activities' + )); + dispatch(actions.resetAdIndex()); + } else { + dispatch(actions.incrementAdIndex()); + } + } break; + + case 'boardText': { + const { data: messages } = contentful.endpoints.boardMessages.select()(state); + + if (state.state.boardMessageIndex >= messages.length - 1) { + dispatch(actions.resetBoardMessageIndex()); + } else { + dispatch(actions.incrementBoardMessageIndex()); + } + + dispatch(actions.setCurrent('quotes')); + } break; + + case 'quotes': + if (!state.state.availableQuotes.length) { + const { data: quotes } = contentful.endpoints.quotes.select()(state); + dispatch(actions.resetQuotes(quotes.length)); + } else { + dispatch(actions.nextQuote()); + } + + dispatch(actions.setCurrent( + import.meta.env.VITE_GITHUB_REPOS + ? 'commits' + : 'activities' + )); + break; + + case 'commits': + dispatch(actions.setCurrent('activities')); + break; + + default: + break; + } +} + const store = configureStore({ reducer: { [koala.reducerPath]: koala.reducer, diff --git a/src/store/state.js b/src/store/state.js index 831b7c9..394b363 100644 --- a/src/store/state.js +++ b/src/store/state.js @@ -6,29 +6,62 @@ const state = createSlice({ activityIndex: 0, adIndex: 0, boardMessageIndex: 0, - quotesIndices: [] + availableQuotes: [], + usedQuotes: [], + quoteIndex: 0, + current: 'activities' }, reducers: { incrementActivityIndex(state) { state.activityIndex++; }, + resetActivityIndex(state) { + state.activityIndex = 0; + }, + incrementAdIndex(state) { state.adIndex++; }, + resetAdIndex(state) { + state.adIndex = 0; + }, + incrementBoardMessageIndex(state) { state.boardMessageIndex++; }, - shiftQuote(state, action) { - if (state.quotesIndices.length === 1) { - state.quotesIndices = new Array(action.payload) + resetBoardMessageIndex(state) { + state.boardMessageIndex = 0; + }, + + nextQuote(state) { + state.usedQuotes.push(state.quoteIndex); + + const hi = state.availableQuotes.length - 1; + const availableQuoteIndex = Math.floor(Math.random() * hi); + + [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); + }, + resetQuotes(state, action) { + state.availableQuotes = new Array(action.payload) .fill(0) .map((_, i) => i); - } else { - state.quotesIndices.shift(); - } + state.usedQuotes = []; + + const availableQuoteIndex = Math.floor(Math.random() * (action.payload - 1)); + [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); + }, + + setCurrent(state, action) { + state.current = action.payload; } } }); -export const { incrementActivityIndex, incrementAdIndex, incrementBoardMessageIndex, shiftQuote } = state.actions; +export const { + incrementActivityIndex, resetActivityIndex, + incrementAdIndex, resetAdIndex, + incrementBoardMessageIndex, resetBoardMessageIndex, + nextQuote, resetQuotes, + setCurrent +} = state.actions; export default state.reducer; From 41fc0bdcba421ee110076f50fbf616c67da1588a Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 12 Jul 2024 14:05:41 +0200 Subject: [PATCH 16/34] refactor: create index.js for components + style fixes --- src/App.jsx | 16 ++++---- src/components/BoardText.jsx | 2 +- src/components/Commits.jsx | 8 ++-- src/components/Team.jsx | 7 ++-- src/components/index.js | 7 ++++ src/store/api/contentful.js | 5 ++- src/store/index.js | 77 +----------------------------------- 7 files changed, 31 insertions(+), 91 deletions(-) create mode 100644 src/components/index.js diff --git a/src/App.jsx b/src/App.jsx index 18de829..c9bcc4d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,12 +1,14 @@ import {useEffect} from 'react'; import {useDispatch, useSelector} from 'react-redux'; -import Activities from './components/Activities'; -import Clock from './components/Clock'; -import BoardText from './components/BoardText'; -import Quotes from './components/Quotes'; -import Ad from './components/Ad'; -import CommitsPage from './components/Commits'; +import { + Activities, + Clock, + BoardText, + Quotes, + Ad, + Commits +} from './components'; import {nextState} from './store'; import {contentful} from './store/api'; @@ -61,7 +63,7 @@ function StateMachine() { case 'quotes': return ; case 'commits': - return ; + return ; default: return <>; } diff --git a/src/components/BoardText.jsx b/src/components/BoardText.jsx index 3f3f3b0..ecee4c8 100644 --- a/src/components/BoardText.jsx +++ b/src/components/BoardText.jsx @@ -7,7 +7,7 @@ export default function BoardText({ current }) { if (!isSuccess) return <>; - const { message } = boardMessages[current]; + const message = boardMessages[current]; return (
          diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index acaef20..17f538c 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -22,9 +22,11 @@ function formatDate(date) { return `${dd}-${mm}-${yyyy}`; } -export default function CommitsPage() { - const { data: commits, isLoading } = useAllCommitsQuery(); - if (isLoading) return <> Loading... ; +export default function Commits() { + const { data: commits, isSuccess } = useAllCommitsQuery(); + + if (!isSuccess) + return <>; return (
          diff --git a/src/components/Team.jsx b/src/components/Team.jsx index 14b8044..66902b1 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.jsx @@ -1,10 +1,11 @@ import {useMembersQuery} from '../store/api'; import Poster from './Poster'; -export default function TeamPage() { - const { data: members, isLoading } = useMembersQuery(); +export default function Team() { + const { data: members, isSuccess } = useMembersQuery(); - if (isLoading) return <> Loading... ; + if (!isSuccess) + return <>; return (
          diff --git a/src/components/index.js b/src/components/index.js new file mode 100644 index 0000000..357a4ef --- /dev/null +++ b/src/components/index.js @@ -0,0 +1,7 @@ +export { default as Activities } from "./Activities"; +export { default as Ad } from "./Ad"; +export { default as BoardText } from "./BoardText"; +export { default as Clock } from "./Clock"; +export { default as Commits } from "./Commits"; +export { default as Quotes } from "./Quotes"; +export { default as Team } from "./Team"; diff --git a/src/store/api/contentful.js b/src/store/api/contentful.js index f1df484..84bf867 100644 --- a/src/store/api/contentful.js +++ b/src/store/api/contentful.js @@ -20,7 +20,10 @@ const contentful = createApi({ baseQuery: contentfulBaseQuery, endpoints: build => ({ ads: build.query({ query: () => 'ads' }), - boardMessages: build.query({ query: () => 'board-message' }), + boardMessages: build.query({ + query: () => 'board-message', + transformResponse: response => response.map(message => message.message) + }), quotes: build.query({ query: () => 'quotes' }) }) }); diff --git a/src/store/index.js b/src/store/index.js index 5fd88c9..53cecf4 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,82 +1,7 @@ import { configureStore } from '@reduxjs/toolkit'; import { koala, contentful, github } from './api'; -import * as actions from './state'; -import state from './state'; - -// next() { -// const params = new URLSearchParams(window.location.search); -// const display_internal = params.get('internal') === 'true'; - -// switch (this.state.current) { -// case 'activities': -// if (this.finishedState) { -// this.finishedState = false; -// this.setState({ -// current: 'advertisement', -// index: 0, -// }); -// } else { -// this.setState({ -// index: this.state.index + 1, -// }); -// } -// break; -// case 'advertisement': -// if (this.finishedState) { -// this.finishedState = false; - -// // skip boardText and quotes on the screen on the outside of the -// // Sticky room -// let new_state = display_internal ? 'boardText' : 'activities'; -// this.setState({ -// current: new_state, -// index: 0, -// }); -// } else { -// this.setState({ -// index: this.state.index + 1, -// }); -// } -// break; -// case 'boardText': -// this.setState({ -// current: 'quotes', -// }); -// break; -// case 'quotes': -// // this.setState({ -// // // current: 'team', REMOVED TEMPORARELY -// // current: 'activities', -// // }); - -// // Dont go to commits page if no repositories are configured -// if (import.meta.env.VITE_GITHUB_REPOS === '') { -// this.setState({ -// current: 'activities', -// }); -// } else { -// this.setState({ -// current: 'commits', -// }); -// } - -// break; -// case 'team': -// // Temporarily disabled -// break; -// case 'commits': -// setTimeout( -// () => this.setState({ -// current: 'activities', -// }), -// NEXT_INTERVAL_COMMITS -// ) -// break; -// default: -// return; -// } -// } +import state, * as actions from './state'; export function nextState(dispatch, getState) { const params = new URLSearchParams(window.location.search); From ddf8ec1edfe5c819b0b138fd5c5f305b51e5a4de Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 12 Jul 2024 14:38:54 +0200 Subject: [PATCH 17/34] docs: added little bit of docs to new functions --- src/App.jsx | 3 +++ src/store/api/contentful.js | 5 +++++ src/store/api/github.js | 12 +++++++++++- src/store/api/koala.js | 9 +++++++++ src/store/index.js | 13 +++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/App.jsx b/src/App.jsx index c9bcc4d..47c396f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -33,6 +33,7 @@ export default function App() { function StateMachine() { const dispatch = useDispatch(); + // Preload the quotes and initialise the store with the quote indices useEffect(() => { const result = dispatch(contentful.endpoints.quotes.initiate()); @@ -43,6 +44,7 @@ function StateMachine() { return result.unsubscribe; }, []); + // Create timer that ticks the state machine useEffect(() => { const interval = setInterval(() => { dispatch(nextState); @@ -51,6 +53,7 @@ function StateMachine() { return () => clearInterval(interval); }); + // Display the correct component based on state machine's state const state = useSelector(state => state.state); switch (state.current) { diff --git a/src/store/api/contentful.js b/src/store/api/contentful.js index 84bf867..d9bbe41 100644 --- a/src/store/api/contentful.js +++ b/src/store/api/contentful.js @@ -6,6 +6,11 @@ const client = createClient({ accessToken: import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN, }); +/** + * A base query function for contentful queries: each endpoint + * specifies the content_type of the thing it requests and these + * entries are searched via the contentful API. + */ async function contentfulBaseQuery(content_type) { try { const res = await client.getEntries({ content_type }); diff --git a/src/store/api/github.js b/src/store/api/github.js index 8b9adfd..5279804 100644 --- a/src/store/api/github.js +++ b/src/store/api/github.js @@ -5,6 +5,10 @@ export const octokit = new Octokit({ auth: import.meta.env.VITE_GITHUB_API_TOKEN }); +/** + * Return all commits from a Github repository + * identified by owner and name. + */ async function listCommits(owner, repo) { const res = await octokit.rest.repos.listCommits({ owner, repo, per_page: 4, @@ -18,6 +22,12 @@ async function listCommits(owner, repo) { })); } +/** + * The Github api slice + * + * It does not use a base query, since the octokit API + * does not allow for a nice abstraction in endpoint form + */ const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), @@ -40,7 +50,7 @@ const github = createApi({ ...commit, date: commit.date.getTime(), })) - .sort((a, b) => b - a) + .sort((a, b) => b.date - a.date) }; } catch (error) { return { error: error.toString() }; diff --git a/src/store/api/koala.js b/src/store/api/koala.js index 8926e7d..d136d12 100644 --- a/src/store/api/koala.js +++ b/src/store/api/koala.js @@ -1,5 +1,11 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; +/** + * The koala api slice + * + * Uses a fetch-based base query, the endpoint's query is appended to + * the base url and assumes the response is JSON, which is automatically decoded. + */ const koala = createApi({ reducerPath: 'koala', baseQuery: fetchBaseQuery({ @@ -16,6 +22,9 @@ const koala = createApi({ }) }); +/** + * Patch an activity + */ function setDate(activity) { return Object.assign({ ...activity, diff --git a/src/store/index.js b/src/store/index.js index 53cecf4..6cccdae 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3,6 +3,15 @@ import { configureStore } from '@reduxjs/toolkit'; import { koala, contentful, github } from './api'; import state, * as actions from './state'; +/** + * nextState is the transition function for the state machine. It + * updates the the state slice with new values based on the loaded + * activities, ads, etc. + * + * This function is implemented as a + * [synchronous thunk]{@link https://redux.js.org/usage/writing-logic-thunks#what-is-a-thunk} + * that is invoked at a fixed interval in the StateMachine component. + */ export function nextState(dispatch, getState) { const params = new URLSearchParams(window.location.search); const displayInternal = params.get('internal') === 'true'; @@ -71,6 +80,10 @@ export function nextState(dispatch, getState) { } } +/** + * The store consists of 4 slices: one for every api source we use + * and one for the state machine variables. + */ const store = configureStore({ reducer: { [koala.reducerPath]: koala.reducer, From db0a7c85ba168ae1bb8c723c9de8538c9fbc3166 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sun, 21 Jul 2024 22:25:22 +0200 Subject: [PATCH 18/34] chore: install typescript --- package-lock.json | 9 ++-- package.json | 4 +- tsconfig.json | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index b5df2a2..39163ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.5.3", "vite": "^4.4.5", "vite-plugin-eslint": "^1.8.1" } @@ -7598,11 +7599,11 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, - "peer": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 6051e9a..d53ca74 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "vite build", "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0", - "preview": "vite preview" + "preview": "vite preview", + "check": "tsc --noEmit" }, "dependencies": { "@reduxjs/toolkit": "^2.2.6", @@ -28,6 +29,7 @@ "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.5.3", "vite": "^4.4.5", "vite-plugin-eslint": "^1.8.1" } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e3638f6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,108 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "esnext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "bundler", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From 08718a1e8f2fd27b63659a51f1f71f82ffcda007 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sun, 21 Jul 2024 22:25:54 +0200 Subject: [PATCH 19/34] refactor: converted files to typescript - Removed vite-plugin-eslint because it is not maintained anymore and its typings are outdated - Added types to all files and made sure the project fully type checks --- index.html | 2 +- package-lock.json | 68 +--------- package.json | 3 +- src/{App.jsx => App.tsx} | 30 ++--- .../{Activities.jsx => Activities.tsx} | 16 +-- src/components/Activity.jsx | 60 --------- src/components/Activity.tsx | 52 ++++++++ src/components/{Ad.jsx => Ad.tsx} | 22 ++-- src/components/BoardText.jsx | 21 --- src/components/BoardText.tsx | 20 +++ src/components/{Clock.jsx => Clock.tsx} | 0 src/components/Commits.jsx | 49 ------- src/components/Commits.tsx | 32 +++++ src/components/Poster.jsx | 16 --- src/components/Poster.tsx | 7 + src/components/{Quotes.jsx => Quotes.tsx} | 13 +- src/components/{Team.jsx => Team.tsx} | 4 +- src/components/{index.js => index.ts} | 0 src/main.jsx | 18 --- src/main.tsx | 23 ++++ src/snow/{snow.js => snow.ts} | 10 +- src/store/api/contentful.js | 41 ------ src/store/api/contentful.ts | 81 ++++++++++++ src/store/api/{github.js => github.ts} | 45 ++++--- src/store/api/{index.js => index.ts} | 0 src/store/api/koala.js | 38 ------ src/store/api/koala.ts | 58 +++++++++ src/store/index.js | 102 --------------- src/store/index.ts | 120 ++++++++++++++++++ src/store/{state.js => state.ts} | 40 ++++-- src/vite-env.d.ts | 21 +++ tsconfig.json | 34 ++--- vite.config.js => vite.config.ts | 3 +- 33 files changed, 530 insertions(+), 519 deletions(-) rename src/{App.jsx => App.tsx} (64%) rename src/components/{Activities.jsx => Activities.tsx} (73%) delete mode 100644 src/components/Activity.jsx create mode 100644 src/components/Activity.tsx rename src/components/{Ad.jsx => Ad.tsx} (59%) delete mode 100644 src/components/BoardText.jsx create mode 100644 src/components/BoardText.tsx rename src/components/{Clock.jsx => Clock.tsx} (100%) delete mode 100644 src/components/Commits.jsx create mode 100644 src/components/Commits.tsx delete mode 100644 src/components/Poster.jsx create mode 100644 src/components/Poster.tsx rename src/components/{Quotes.jsx => Quotes.tsx} (66%) rename src/components/{Team.jsx => Team.tsx} (89%) rename src/components/{index.js => index.ts} (100%) delete mode 100644 src/main.jsx create mode 100644 src/main.tsx rename src/snow/{snow.js => snow.ts} (69%) delete mode 100644 src/store/api/contentful.js create mode 100644 src/store/api/contentful.ts rename src/store/api/{github.js => github.ts} (59%) rename src/store/api/{index.js => index.ts} (100%) delete mode 100644 src/store/api/koala.js create mode 100644 src/store/api/koala.ts delete mode 100644 src/store/index.js create mode 100644 src/store/index.ts rename src/store/{state.js => state.ts} (66%) create mode 100644 src/vite-env.d.ts rename vite.config.js => vite.config.ts (66%) diff --git a/index.html b/index.html index 042ee9f..8fa8f06 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@
          - + diff --git a/package-lock.json b/package-lock.json index 39163ec..bbb9894 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,8 +27,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "typescript": "^5.5.3", - "vite": "^4.4.5", - "vite-plugin-eslint": "^1.8.1" + "vite": "^4.4.5" } }, "node_modules/@ampproject/remapping": { @@ -3103,19 +3102,6 @@ } } }, - "node_modules/@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "dev": true, - "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/@rushstack/eslint-patch": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", @@ -3173,22 +3159,6 @@ "resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.2.tgz", "integrity": "sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==" }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -5161,12 +5131,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7788,36 +7752,6 @@ } } }, - "node_modules/vite-plugin-eslint": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz", - "integrity": "sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^4.2.1", - "@types/eslint": "^8.4.5", - "rollup": "^2.77.2" - }, - "peerDependencies": { - "eslint": ">=7", - "vite": ">=2" - } - }, - "node_modules/vite-plugin-eslint/node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index d53ca74..b4b1fd2 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "typescript": "^5.5.3", - "vite": "^4.4.5", - "vite-plugin-eslint": "^1.8.1" + "vite": "^4.4.5" } } diff --git a/src/App.jsx b/src/App.tsx similarity index 64% rename from src/App.jsx rename to src/App.tsx index 47c396f..c8ce975 100644 --- a/src/App.jsx +++ b/src/App.tsx @@ -1,5 +1,4 @@ -import {useEffect} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; +import { useEffect } from 'react'; import { Activities, @@ -10,9 +9,9 @@ import { Commits } from './components'; -import {nextState} from './store'; -import {contentful} from './store/api'; -import {resetQuotes} from './store/state'; +import { nextState, useAppDispatch, useAppSelector } from './store'; +import { contentful } from './store/api'; +import { actions, StateMachineState } from './store/state'; const LOGO = import.meta.env.VITE_LOGO; @@ -31,14 +30,15 @@ export default function App() { } function StateMachine() { - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); // Preload the quotes and initialise the store with the quote indices useEffect(() => { const result = dispatch(contentful.endpoints.quotes.initiate()); - result.then(({ data: quotes }) => { - dispatch(resetQuotes(quotes.length)); + result.then(({ data: quotes, isSuccess }) => { + if (isSuccess) + dispatch(actions.resetQuotes(quotes.length)); }); return result.unsubscribe; @@ -48,24 +48,24 @@ function StateMachine() { useEffect(() => { const interval = setInterval(() => { dispatch(nextState); - }, import.meta.env.VITE_NEXT_INTERVAL); + }, Number(import.meta.env.VITE_NEXT_INTERVAL)); return () => clearInterval(interval); }); // Display the correct component based on state machine's state - const state = useSelector(state => state.state); + const state = useAppSelector(state => state.state); switch (state.current) { - case 'activities': + case StateMachineState.Activities: return ; - case 'advertisement': + case StateMachineState.Advertisement: return ; - case 'boardText': + case StateMachineState.BoardText: return ; - case 'quotes': + case StateMachineState.Quotes: return ; - case 'commits': + case StateMachineState.Commits: return ; default: return <>; diff --git a/src/components/Activities.jsx b/src/components/Activities.tsx similarity index 73% rename from src/components/Activities.jsx rename to src/components/Activities.tsx index 8457462..2e9e4f4 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.tsx @@ -1,9 +1,12 @@ import Activity from './Activity'; import Poster from './Poster'; -import PropTypes from 'prop-types'; import { useActivitiesQuery } from '../store/api'; -export default function Activities({ current }) { +type ActivitiesProps = { + current: number +}; + +export default function Activities({ current }: ActivitiesProps) { const { data: activities, isSuccess } = useActivitiesQuery(undefined, { pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL) }); @@ -21,10 +24,10 @@ export default function Activities({ current }) { key={i} {...activity} active={activity === currentActivity} - /> + /> )}
        - +
      ); } else { @@ -35,8 +38,3 @@ export default function Activities({ current }) { ); } } - -// Explain expected types, for early error detection -Activities.propTypes = { - current: PropTypes.number.isRequired -}; diff --git a/src/components/Activity.jsx b/src/components/Activity.jsx deleted file mode 100644 index c61c0a8..0000000 --- a/src/components/Activity.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import { useEffect, useRef } from 'react'; -import moment from 'moment'; -import PropTypes from 'prop-types'; -import scrollIntoView from 'scroll-into-view'; - -function sameDay(d, t) { - return ( - d.getDate() === t.getDate() && // getDate returns day number in month... - d.getMonth() === t.getMonth() && - d.getYear() === t.getYear() - ); -} - -function createFormat(has_time, date, as = new Date()) { - const format = - (!sameDay(date, as) ? 'dddd DD-MM ' : '') - + (has_time ? 'HH:mm' : ''); - return format || '[]'; -} - -export default function Activity({ active, name, start_date, end_date, has_start_time, has_end_time, participant_counter }) { - const activityRef = useRef(null); - - // Ensure that the current activity is visible - useEffect(() => { - if (active && activityRef.current) { - scrollIntoView(activityRef.current, { - time: 500, - }); - } - }, [active]); - - const startDate = moment(start_date) - .format(createFormat(has_start_time, start_date)); - const endDate = moment(end_date) - .format(createFormat(has_end_time, end_date, start_date)); - const className = 'activity' + (active ? ' active' : ''); - - return ( -
    • -

      - {name} - {participant_counter && ` (${participant_counter})`} -

      - - {endDate && <> - } -
    • - ); -} - -// Define the the types of this component, for early error detection -Activity.propTypes = { - active: PropTypes.bool.isRequired, - name: PropTypes.string.isRequired, - start_date: PropTypes.instanceOf(Date).isRequired, - end_date: PropTypes.instanceOf(Date), - has_start_time: PropTypes.bool.isRequired, - has_end_time: PropTypes.bool.isRequired, - participant_counter: PropTypes.string, -}; diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx new file mode 100644 index 0000000..1eebd98 --- /dev/null +++ b/src/components/Activity.tsx @@ -0,0 +1,52 @@ +import { useEffect, useRef } from 'react'; +import moment from 'moment'; +import { type Activity } from '../store/api'; + +function sameDay(d: Date, t: Date): boolean { + return d.getDate() === t.getDate() // getDate returns day number in month... + && d.getMonth() === t.getMonth() + && d.getFullYear() === t.getFullYear(); +} + +function createFormat(has_time: boolean, date: Date, as = new Date()): string { + const format = + (!sameDay(date, as) ? 'dddd DD-MM ' : '') + + (has_time ? 'HH:mm' : ''); + return format || '[]'; +} + +type ActivityProps = Activity & { active: boolean }; + +export default function Activity({ + active, name, start_date, end_date, + has_start_time, has_end_time, participant_counter +}: ActivityProps) { + const activityRef = useRef(null); + + // Ensure that the current activity is visible + useEffect(() => { + if (active && activityRef.current) + activityRef.current.scrollIntoView({ + behavior: 'smooth' + }); + }, [active]); + + const startDate = moment(start_date) + .format(createFormat(has_start_time, new Date(start_date))); + const endDate = end_date + ? moment(end_date) + .format(createFormat(has_end_time, new Date(end_date), new Date(start_date))) + : null; + const className = 'activity' + (active ? ' active' : ''); + + return ( +
    • +

      + {name} + {participant_counter && ` (${participant_counter})`} +

      + + {endDate && <> - } +
    • + ); +} diff --git a/src/components/Ad.jsx b/src/components/Ad.tsx similarity index 59% rename from src/components/Ad.jsx rename to src/components/Ad.tsx index e780083..7758371 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.tsx @@ -1,25 +1,32 @@ -import PropTypes from 'prop-types'; import Poster from './Poster'; import { useAdsQuery } from '../store/api'; -export default function Ad({ current }) { +type AdProps = { + current: number; +}; + +export default function Ad({ current }: AdProps) { const { data: ads, isSuccess } = useAdsQuery(); if (!isSuccess) return <>; const currentAd = ads[current]; + + if (!currentAd.poster?.fields.file?.url) + throw new Error('Ad without poster'); + if (ads.length <= 0) { return (
        - +
        ); } else if (currentAd.fullscreen) { return (
        - +
        ); } else { @@ -29,13 +36,8 @@ export default function Ad({ current }) {

        {currentAd.title}

        {currentAd.description}

        - +
        ); } } - -// Explain expected types, for early error detection -Ad.propTypes = { - current: PropTypes.number.isRequired -}; diff --git a/src/components/BoardText.jsx b/src/components/BoardText.jsx deleted file mode 100644 index ecee4c8..0000000 --- a/src/components/BoardText.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import PropTypes from 'prop-types'; -import {useBoardMessagesQuery} from '../store/api'; - -export default function BoardText({ current }) { - const { data: boardMessages, isSuccess } = useBoardMessagesQuery(); - - if (!isSuccess) - return <>; - - const message = boardMessages[current]; - - return ( -
        -

        {message}

        -
        - ); -} - -BoardText.propTypes = { - current: PropTypes.number.isRequired, -}; diff --git a/src/components/BoardText.tsx b/src/components/BoardText.tsx new file mode 100644 index 0000000..55d12fb --- /dev/null +++ b/src/components/BoardText.tsx @@ -0,0 +1,20 @@ +import { useBoardMessagesQuery } from '../store/api'; + +type BoardTextProps = { + current: number +}; + +export default function BoardText({ current }: BoardTextProps) { + const { data: boardMessages, isSuccess } = useBoardMessagesQuery(); + + if (!isSuccess) + return <>; + + const { message } = boardMessages[current]; + + return ( +
        +

        {message}

        +
        + ); +} diff --git a/src/components/Clock.jsx b/src/components/Clock.tsx similarity index 100% rename from src/components/Clock.jsx rename to src/components/Clock.tsx diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx deleted file mode 100644 index 17f538c..0000000 --- a/src/components/Commits.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import Poster from './Poster'; -import {useAllCommitsQuery} from '../store/api'; - -function formatTime(date) { - let hh = date.getHours(); - let mm = date.getMinutes(); - - if (hh < 10) hh = '0' + hh; - if (mm < 10) mm = '0' + mm; - - return `${hh}:${mm}` -} - -function formatDate(date) { - let dd = date.getDate(); - let mm = date.getMonth() + 1; - const yyyy = date.getFullYear(); - - if (dd < 10) dd = '0' + dd; - if (mm < 10) mm = '0' + mm; - - return `${dd}-${mm}-${yyyy}`; -} - -export default function Commits() { - const { data: commits, isSuccess } = useAllCommitsQuery(); - - if (!isSuccess) - return <>; - - return ( -
        -

        Recent commits

        - - -
        - ); -} diff --git a/src/components/Commits.tsx b/src/components/Commits.tsx new file mode 100644 index 0000000..35435da --- /dev/null +++ b/src/components/Commits.tsx @@ -0,0 +1,32 @@ +import Poster from './Poster'; +import { useAllCommitsQuery } from '../store/api'; +import moment from 'moment'; + +export default function Commits() { + const { data: commits, isSuccess } = useAllCommitsQuery(); + + if (!isSuccess) + return <>; + + return ( +
        +

        Recent commits

        + + +
        + ); +} diff --git a/src/components/Poster.jsx b/src/components/Poster.jsx deleted file mode 100644 index 721b759..0000000 --- a/src/components/Poster.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * - * @param {Object} props - * @param {string} props.poster - * @returns - */ -export default function Poster(props) { - return poster; -} - -// Explain expected types, for early error detection -Poster.propTypes = { - poster: PropTypes.string.isRequired, -}; \ No newline at end of file diff --git a/src/components/Poster.tsx b/src/components/Poster.tsx new file mode 100644 index 0000000..ee20bfb --- /dev/null +++ b/src/components/Poster.tsx @@ -0,0 +1,7 @@ +type PosterProps = { + src: string +}; + +export default function Poster({ src }: PosterProps) { + return poster; +} diff --git a/src/components/Quotes.jsx b/src/components/Quotes.tsx similarity index 66% rename from src/components/Quotes.jsx rename to src/components/Quotes.tsx index ed1a3d5..afc0848 100644 --- a/src/components/Quotes.jsx +++ b/src/components/Quotes.tsx @@ -1,7 +1,10 @@ -import PropTypes from 'prop-types'; -import {useQuotesQuery} from '../store/api'; +import { useQuotesQuery } from '../store/api'; -export default function Quotes({ current }) { +type QuotesProps = { + current: number +}; + +export default function Quotes({ current }: QuotesProps) { const { data: quotes, isSuccess } = useQuotesQuery(); if (!isSuccess) @@ -18,7 +21,3 @@ export default function Quotes({ current }) { ); } - -Quotes.propTypes = { - current: PropTypes.number.isRequired, -}; diff --git a/src/components/Team.jsx b/src/components/Team.tsx similarity index 89% rename from src/components/Team.jsx rename to src/components/Team.tsx index 66902b1..bb428ca 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.tsx @@ -1,4 +1,4 @@ -import {useMembersQuery} from '../store/api'; +import { useMembersQuery } from '../store/api'; import Poster from './Poster'; export default function Team() { @@ -27,7 +27,7 @@ export default function Team() { ); })} - + ); } diff --git a/src/components/index.js b/src/components/index.ts similarity index 100% rename from src/components/index.js rename to src/components/index.ts diff --git a/src/main.jsx b/src/main.jsx deleted file mode 100644 index a374a15..0000000 --- a/src/main.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; -import App from './App.jsx'; - -import {Provider} from 'react-redux'; -import store from './store'; - -import './index.css'; -import './snow/snow.js'; -import './snow/snow.css'; - -createRoot(document.getElementById('root')).render( - - - - - -); diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..b6a23e3 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App.jsx'; + +import { Provider } from 'react-redux'; +import store from './store/index.js'; + +import './index.css'; +import './snow/snow.js'; +import './snow/snow.css'; + +const root = document.getElementById('root'); +if (root) { + createRoot(root).render( + + + + + + ); +} else { + throw new Error("Cannot find root element to bind to"); +} diff --git a/src/snow/snow.js b/src/snow/snow.ts similarity index 69% rename from src/snow/snow.js rename to src/snow/snow.ts index da75f4a..a90391c 100644 --- a/src/snow/snow.js +++ b/src/snow/snow.ts @@ -5,20 +5,20 @@ const isWinter = (mm >= 12 || mm < 3); if (isWinter) { // Add snow stylesheet - let link = document.createElement('link'); + const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'snow.css'; document.head.appendChild(link); - + // Prepend snow group - let snowGroup = document.createElement('div'); + const snowGroup = document.createElement('div'); snowGroup.id = 'snow-group'; document.body.prepend(snowGroup); // Create 200 snowflakes for (let i = 0; i < 200; i++) { - let snowflake = document.createElement('div'); + const snowflake = document.createElement('div'); snowflake.className = 'snowflake'; - document.getElementById('snow-group').appendChild(snowflake); + snowGroup.appendChild(snowflake); } } diff --git a/src/store/api/contentful.js b/src/store/api/contentful.js deleted file mode 100644 index d9bbe41..0000000 --- a/src/store/api/contentful.js +++ /dev/null @@ -1,41 +0,0 @@ -import { createClient } from 'contentful'; -import { createApi } from '@reduxjs/toolkit/query/react'; - -const client = createClient({ - space: import.meta.env.VITE_CONTENTFUL_SPACE_ID, - accessToken: import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN, -}); - -/** - * A base query function for contentful queries: each endpoint - * specifies the content_type of the thing it requests and these - * entries are searched via the contentful API. - */ -async function contentfulBaseQuery(content_type) { - try { - const res = await client.getEntries({ content_type }); - return { data: res.items.map(entry => entry.fields) }; - } catch (error) { - return { error: error.toString() }; - } -} - -const contentful = createApi({ - reducerPath: 'contentful', - baseQuery: contentfulBaseQuery, - endpoints: build => ({ - ads: build.query({ query: () => 'ads' }), - boardMessages: build.query({ - query: () => 'board-message', - transformResponse: response => response.map(message => message.message) - }), - quotes: build.query({ query: () => 'quotes' }) - }) -}); - -export const { - useAdsQuery, - useBoardMessagesQuery, - useQuotesQuery -} = contentful; -export default contentful; diff --git a/src/store/api/contentful.ts b/src/store/api/contentful.ts new file mode 100644 index 0000000..c430e87 --- /dev/null +++ b/src/store/api/contentful.ts @@ -0,0 +1,81 @@ +import { createClient, type EntryFieldTypes, type Entry } from 'contentful'; +import { createApi } from '@reduxjs/toolkit/query/react'; + +type FromSkeleton = Entry['fields']; + +type AdSkeleton = { + contentTypeId: 'ads', + fields: { + title: EntryFieldTypes.Text, + description: EntryFieldTypes.Text, + fullscreen: EntryFieldTypes.Boolean, + poster: EntryFieldTypes.AssetLink + } +}; +type Ad = FromSkeleton; + +type BoardMessageSkeleton = { + contentTypeId: 'board-message', + fields: { + message: EntryFieldTypes.Text + } +}; +type BoardMessage = FromSkeleton; + +type QuoteSkeleton = { + contentTypeId: 'quotes', + fields: { + person: EntryFieldTypes.Text, + text: EntryFieldTypes.Text + } +}; +type Quote = FromSkeleton; + +type ContentfulSkeletons = AdSkeleton | BoardMessageSkeleton | QuoteSkeleton; + +type ContentfulResponse = + Entry, 'WITHOUT_UNRESOLVABLE_LINKS'>[]; + +const client = createClient({ + space: import.meta.env.VITE_CONTENTFUL_SPACE_ID, + accessToken: import.meta.env.VITE_CONTENTFUL_ACCESS_TOKEN, +}); + +/** + * A base query function for contentful queries: each endpoint + * specifies the content_type of the thing it requests and these + * entries are searched via the contentful API. + */ +async function contentfulBaseQuery(content_type: ContentType): + Promise<{ data: ContentfulResponse } | { error: unknown }> { + try { + const res = await client.withoutUnresolvableLinks.getEntries({ content_type }); + return { data: res.items as ContentfulResponse }; + } catch (error) { + return { error }; + } +} + +function createQuery(content_type: ContentType) { + return { + query: () => content_type, + transformResponse: (response: ContentfulResponse) => response.map(entry => entry.fields) + }; +} + +const contentful = createApi({ + reducerPath: 'contentful', + baseQuery: contentfulBaseQuery, + endpoints: build => ({ + ads: build.query(createQuery('ads')), + boardMessages: build.query(createQuery('board-message')), + quotes: build.query(createQuery('quotes')) + }) +}); + +export const { + useAdsQuery, + useBoardMessagesQuery, + useQuotesQuery +} = contentful; +export default contentful; diff --git a/src/store/api/github.js b/src/store/api/github.ts similarity index 59% rename from src/store/api/github.js rename to src/store/api/github.ts index 5279804..40349e5 100644 --- a/src/store/api/github.js +++ b/src/store/api/github.ts @@ -1,23 +1,37 @@ import { Octokit } from 'octokit'; import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; -export const octokit = new Octokit({ +const octokit = new Octokit({ auth: import.meta.env.VITE_GITHUB_API_TOKEN }); +type Commit = { + message: string, + author: string, + date: number | null, + repo: string, + owner: string +}; + +type ArrayElement = + T extends readonly (infer U)[] ? U : never; +type Member = ArrayElement>['data']>; + /** * Return all commits from a Github repository * identified by owner and name. */ -async function listCommits(owner, repo) { +async function listCommits(owner: string, repo: string): Promise { const res = await octokit.rest.repos.listCommits({ owner, repo, per_page: 4, }); return res.data.map(({ commit }) => ({ message: commit.message, - author: commit.author.name ?? commit.author.login, - date: new Date(commit.committer.date), + author: commit.author?.name ?? commit.author?.email ?? "", + date: commit.committer?.date + ? new Date(commit.committer.date).getTime() + : null, repo, owner })); } @@ -32,7 +46,7 @@ const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), endpoints: build => ({ - allCommits: build.query({ + allCommits: build.query({ queryFn: async () => { try { const commitsPerRepo = await Promise.allSettled( @@ -45,19 +59,20 @@ const github = createApi({ return { data: commitsPerRepo - .flatMap(commits => commits.value) - .map(commit => ({ - ...commit, - date: commit.date.getTime(), - })) - .sort((a, b) => b.date - a.date) + .flatMap(commits => + commits.status === "fulfilled" + ? commits.value + : []) + .sort((a, b) => a.date && b.date + ? b.date - a.date + : -1) }; } catch (error) { - return { error: error.toString() }; + return { error }; } } }), - members: build.query({ + members: build.query({ queryFn: async () => { try { const res = await octokit.rest.orgs.listMembers({ @@ -65,9 +80,9 @@ const github = createApi({ per_page: 100, }); - return res.data; + return { data: res.data }; } catch (error) { - return { error: error.toString() }; + return { error }; } } }) diff --git a/src/store/api/index.js b/src/store/api/index.ts similarity index 100% rename from src/store/api/index.js rename to src/store/api/index.ts diff --git a/src/store/api/koala.js b/src/store/api/koala.js deleted file mode 100644 index d136d12..0000000 --- a/src/store/api/koala.js +++ /dev/null @@ -1,38 +0,0 @@ -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; - -/** - * The koala api slice - * - * Uses a fetch-based base query, the endpoint's query is appended to - * the base url and assumes the response is JSON, which is automatically decoded. - */ -const koala = createApi({ - reducerPath: 'koala', - baseQuery: fetchBaseQuery({ - baseUrl: import.meta.env.VITE_KOALA_API_BASE - }), - endpoints: build => ({ - activities: build.query({ - query: () => 'activities', - transformResponse: result => result - .filter(act => act.poster) - .map(setDate) - .sort((a, b) => a.start_date - b.start_date) - }) - }) -}); - -/** - * Patch an activity - */ -function setDate(activity) { - return Object.assign({ - ...activity, - has_start_time: activity.start_date.indexOf('T') > -1, - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - start_date: new Date(activity.start_date) - }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); -} - -export const { useActivitiesQuery } = koala; -export default koala; diff --git a/src/store/api/koala.ts b/src/store/api/koala.ts new file mode 100644 index 0000000..e119d5a --- /dev/null +++ b/src/store/api/koala.ts @@ -0,0 +1,58 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; + +type ResponseActivity = { + name: string, + start_date: string, + end_date: string | null, + poster: string, + participant_counter: number +}; + +export type Activity = Omit & { + start_date: number, + end_date: number | null, + has_start_time: boolean, + has_end_time: boolean +}; + +/** + * The koala api slice + * + * Uses a fetch-based base query, the endpoint's query is appended to + * the base url and assumes the response is JSON, which is automatically decoded. + */ +const koala = createApi({ + reducerPath: 'koala', + baseQuery: fetchBaseQuery({ + baseUrl: import.meta.env.VITE_KOALA_API_BASE + }), + endpoints: build => ({ + activities: build.query({ + query: () => 'activities', + transformResponse: (result: ResponseActivity[]): Activity[] => result + .filter(act => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date) + }) + }) +}); + +/** + * Patch an activity + */ +function setDate(activity: ResponseActivity): Activity { + return { + ...activity, + start_date: new Date(activity.start_date).getTime(), + end_date: activity.end_date + ? new Date(activity.end_date).getTime() + : null, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: activity.end_date + ? activity.end_date.indexOf('T') > -1 + : false + }; +} + +export const { useActivitiesQuery } = koala; +export default koala; diff --git a/src/store/index.js b/src/store/index.js deleted file mode 100644 index 6cccdae..0000000 --- a/src/store/index.js +++ /dev/null @@ -1,102 +0,0 @@ -import { configureStore } from '@reduxjs/toolkit'; - -import { koala, contentful, github } from './api'; -import state, * as actions from './state'; - -/** - * nextState is the transition function for the state machine. It - * updates the the state slice with new values based on the loaded - * activities, ads, etc. - * - * This function is implemented as a - * [synchronous thunk]{@link https://redux.js.org/usage/writing-logic-thunks#what-is-a-thunk} - * that is invoked at a fixed interval in the StateMachine component. - */ -export function nextState(dispatch, getState) { - const params = new URLSearchParams(window.location.search); - const displayInternal = params.get('internal') === 'true'; - - const state = getState(); - switch (state.state.current) { - case 'activities': { - const { data: activities } = koala.endpoints.activities.select()(state); - - if (state.state.activityIndex >= activities.length - 1) { - dispatch(actions.setCurrent('advertisement')); - dispatch(actions.resetActivityIndex()); - } else { - dispatch(actions.incrementActivityIndex()); - } - } break; - - case 'advertisement': { - const { data: ads } = contentful.endpoints.ads.select()(state); - - if (state.state.adIndex >= ads.length - 1) { - dispatch(actions.setCurrent( - displayInternal - ? 'boardText' - : 'activities' - )); - dispatch(actions.resetAdIndex()); - } else { - dispatch(actions.incrementAdIndex()); - } - } break; - - case 'boardText': { - const { data: messages } = contentful.endpoints.boardMessages.select()(state); - - if (state.state.boardMessageIndex >= messages.length - 1) { - dispatch(actions.resetBoardMessageIndex()); - } else { - dispatch(actions.incrementBoardMessageIndex()); - } - - dispatch(actions.setCurrent('quotes')); - } break; - - case 'quotes': - if (!state.state.availableQuotes.length) { - const { data: quotes } = contentful.endpoints.quotes.select()(state); - dispatch(actions.resetQuotes(quotes.length)); - } else { - dispatch(actions.nextQuote()); - } - - dispatch(actions.setCurrent( - import.meta.env.VITE_GITHUB_REPOS - ? 'commits' - : 'activities' - )); - break; - - case 'commits': - dispatch(actions.setCurrent('activities')); - break; - - default: - break; - } -} - -/** - * The store consists of 4 slices: one for every api source we use - * and one for the state machine variables. - */ -const store = configureStore({ - reducer: { - [koala.reducerPath]: koala.reducer, - [contentful.reducerPath]: contentful.reducer, - [github.reducerPath]: github.reducer, - state - }, - middleware(getDefaultMiddleware) { - return getDefaultMiddleware() - .concat(koala.middleware) - .concat(contentful.middleware) - .concat(github.middleware); - } -}); - -export default store; diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..2e0e9aa --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,120 @@ +import { configureStore, ThunkAction, UnknownAction } from '@reduxjs/toolkit'; + +import { koala, contentful, github } from './api'; +import state, { actions, StateMachineState } from './state'; +import { useDispatch, useSelector } from 'react-redux'; + +/** + * nextState is the transition function for the state machine. It + * updates the the state slice with new values based on the loaded + * activities, ads, etc. + * + * This function is implemented as a + * [synchronous thunk]{@link https://redux.js.org/usage/writing-logic-thunks#what-is-a-thunk} + * that is invoked at a fixed interval in the StateMachine component. + */ +export const nextState: ThunkAction = + (dispatch, getState) => { + const params = new URLSearchParams(window.location.search); + const displayInternal = params.get('internal') === 'true'; + + const state = getState(); + switch (state.state.current) { + case StateMachineState.Activities: { + const { data: activities, isSuccess } = koala.endpoints.activities.select()(state); + + if (!isSuccess) + throw new Error(''); + + if (state.state.activityIndex >= activities.length - 1) { + dispatch(actions.resetActivityIndex()); + dispatch(actions.setCurrent(StateMachineState.Advertisement)); + } else { + dispatch(actions.incrementActivityIndex()); + } + } break; + + case StateMachineState.Advertisement: { + const { data: ads, isSuccess } = contentful.endpoints.ads.select()(state); + + if (isSuccess) { + if (state.state.adIndex >= ads.length - 1) { + dispatch(actions.resetAdIndex()); + + dispatch(actions.setCurrent( + displayInternal + ? StateMachineState.BoardText + : StateMachineState.Activities + )); + } else { + dispatch(actions.incrementAdIndex()); + } + } + + } break; + + case StateMachineState.BoardText: { + const { data: messages, isSuccess } = contentful.endpoints.boardMessages.select()(state); + + if (isSuccess) { + if (state.state.boardMessageIndex >= messages.length - 1) { + dispatch(actions.resetBoardMessageIndex()); + } else { + dispatch(actions.incrementBoardMessageIndex()); + } + } + + dispatch(actions.setCurrent(StateMachineState.Quotes)); + } break; + + case StateMachineState.Quotes: + if (!state.state.availableQuotes.length) { + const { data: quotes, isSuccess } = contentful.endpoints.quotes.select()(state); + + if (isSuccess) + dispatch(actions.resetQuotes(quotes.length)); + } else { + dispatch(actions.nextQuote()); + } + + dispatch(actions.setCurrent( + import.meta.env.VITE_GITHUB_REPOS + ? StateMachineState.Commits + : StateMachineState.Activities + )); + break; + + case StateMachineState.Commits: + dispatch(actions.setCurrent(StateMachineState.Activities)); + break; + + default: + break; + } + } + +/** + * The store consists of 4 slices: one for every api source we use + * and one for the state machine variables. + */ +const store = configureStore({ + reducer: { + [koala.reducerPath]: koala.reducer, + [contentful.reducerPath]: contentful.reducer, + [github.reducerPath]: github.reducer, + state + }, + middleware(getDefaultMiddleware) { + return getDefaultMiddleware() + .concat(koala.middleware) + .concat(contentful.middleware) + .concat(github.middleware); + } +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; +export const useAppDispatch = useDispatch.withTypes(); +export const useAppSelector = useSelector.withTypes(); + +export default store; diff --git a/src/store/state.js b/src/store/state.ts similarity index 66% rename from src/store/state.js rename to src/store/state.ts index 394b363..1fa6fa8 100644 --- a/src/store/state.js +++ b/src/store/state.ts @@ -1,4 +1,22 @@ -import { createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +export enum StateMachineState { + Activities, + Advertisement, + BoardText, + Quotes, + Commits +} + +export type StateMachine = { + activityIndex: number, + adIndex: number, + boardMessageIndex: number, + availableQuotes: number[], + usedQuotes: number[], + quoteIndex: number, + current: StateMachineState +}; const state = createSlice({ name: 'state', @@ -9,8 +27,8 @@ const state = createSlice({ availableQuotes: [], usedQuotes: [], quoteIndex: 0, - current: 'activities' - }, + current: StateMachineState.Activities + } as StateMachine, reducers: { incrementActivityIndex(state) { state.activityIndex++; @@ -41,27 +59,21 @@ const state = createSlice({ [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); }, - resetQuotes(state, action) { + resetQuotes(state, action: PayloadAction) { state.availableQuotes = new Array(action.payload) - .fill(0) - .map((_, i) => i); + .fill(0) + .map((_, i) => i); state.usedQuotes = []; const availableQuoteIndex = Math.floor(Math.random() * (action.payload - 1)); [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); }, - setCurrent(state, action) { + setCurrent(state, action: PayloadAction) { state.current = action.payload; } } }); -export const { - incrementActivityIndex, resetActivityIndex, - incrementAdIndex, resetAdIndex, - incrementBoardMessageIndex, resetBoardMessageIndex, - nextQuote, resetQuotes, - setCurrent -} = state.actions; +export const actions = state.actions; export default state.reducer; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..df1faf1 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,21 @@ +/// + +interface ImportMetaEnv { + readonly VITE_CONTENTFUL_SPACE_ID: string; + readonly VITE_CONTENTFUL_ACCESS_TOKEN: string; + + readonly VITE_LOGO: string; + readonly VITE_KOALA_API_BASE: string; + + readonly VITE_LOAD_INTERVAL: string; + readonly VITE_NEXT_INTERVAL: string; + readonly VITE_NEXT_INTERVAL_COMMITS: string; + + readonly VITE_GITHUB_REPOS: string; + readonly VITE_GITHUB_API_TOKEN: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} + diff --git a/tsconfig.json b/tsconfig.json index e3638f6..fbe5ba4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,14 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - "jsx": "preserve", /* Specify what JSX code is generated. */ + "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ @@ -23,11 +18,10 @@ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "esnext", /* Specify what module code is generated. */ + "module": "esnext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "bundler", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "bundler", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -42,13 +36,9 @@ // "resolveJsonModule": true, /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ @@ -70,19 +60,15 @@ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - - /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ @@ -100,9 +86,7 @@ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } diff --git a/vite.config.js b/vite.config.ts similarity index 66% rename from vite.config.js rename to vite.config.ts index 29882e1..4a57ae5 100644 --- a/vite.config.js +++ b/vite.config.ts @@ -1,8 +1,7 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; -import eslint from 'vite-plugin-eslint'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react(), eslint()], + plugins: [react()], }) From ccd5d72db5c94f515925a4dbd8b8d668051b608b Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sun, 21 Jul 2024 22:37:55 +0200 Subject: [PATCH 20/34] chore: removed scroll-into-view dependency it was removed in the previous commit, since it is now provided by most browsers by default --- package-lock.json | 8 +------- package.json | 3 +-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index bbb9894..d519c83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,7 @@ "octokit": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^9.1.2", - "scroll-into-view": "^1.16.2" + "react-redux": "^9.1.2" }, "devDependencies": { "@types/react": "^18.2.15", @@ -7155,11 +7154,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/scroll-into-view": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/scroll-into-view/-/scroll-into-view-1.16.2.tgz", - "integrity": "sha512-vyTE0i27o6eldt9xinjHec41Dw05y+faoI+s2zNKJAVOdbA5M2XZrYq/obJ8E+QDQulJ2gDjgui9w9m9RZSRng==" - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/package.json b/package.json index b4b1fd2..7ee0924 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,7 @@ "octokit": "^3.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^9.1.2", - "scroll-into-view": "^1.16.2" + "react-redux": "^9.1.2" }, "devDependencies": { "@types/react": "^18.2.15", From 928ccedde30adb6daadecb904ca64c3431e54c5e Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Mon, 5 Aug 2024 16:13:09 +0200 Subject: [PATCH 21/34] refactor: moved reference to snow.ts from main.tsx to index.html --- index.html | 2 +- src/main.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/index.html b/index.html index 8fa8f06..2664d9e 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@
        - + diff --git a/src/main.tsx b/src/main.tsx index b6a23e3..43209d9 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,7 +6,6 @@ import { Provider } from 'react-redux'; import store from './store/index.js'; import './index.css'; -import './snow/snow.js'; import './snow/snow.css'; const root = document.getElementById('root'); From bc85a71282194dc16c71c9e713882c34bda5b9f4 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Mon, 5 Aug 2024 16:21:19 +0200 Subject: [PATCH 22/34] refactor: moved github endpoint logic into own functions --- src/store/api/github.js | 84 ++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/store/api/github.js b/src/store/api/github.js index 5279804..775ad54 100644 --- a/src/store/api/github.js +++ b/src/store/api/github.js @@ -22,6 +22,49 @@ async function listCommits(owner, repo) { })); } +/** + * Get all commits from all the configered repos in the environment + */ +async function allCommits() { + try { + const commitsPerRepo = await Promise.allSettled( + import.meta.env.VITE_GITHUB_REPOS + .split(' ') + .map(name => { + const [owner, repo] = name.split('/'); + return listCommits(owner, repo); + })); + + return { + data: commitsPerRepo + .flatMap(commits => commits.value) + .map(commit => ({ + ...commit, + date: commit.date.getTime(), + })) + .sort((a, b) => b.date - a.date) + }; + } catch (error) { + return { error: error.toString() }; + } +} + +/** + * Get all members in the github organisation + */ +async function allMembers() { + try { + const res = await octokit.rest.orgs.listMembers({ + org: 'svsticky', + per_page: 100, + }); + + return { data: res.data }; + } catch (error) { + return { error: error.toString() }; + } +} + /** * The Github api slice * @@ -32,45 +75,8 @@ const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), endpoints: build => ({ - allCommits: build.query({ - queryFn: async () => { - try { - const commitsPerRepo = await Promise.allSettled( - import.meta.env.VITE_GITHUB_REPOS - .split(' ') - .map(name => { - const [owner, repo] = name.split('/'); - return listCommits(owner, repo); - })); - - return { - data: commitsPerRepo - .flatMap(commits => commits.value) - .map(commit => ({ - ...commit, - date: commit.date.getTime(), - })) - .sort((a, b) => b.date - a.date) - }; - } catch (error) { - return { error: error.toString() }; - } - } - }), - members: build.query({ - queryFn: async () => { - try { - const res = await octokit.rest.orgs.listMembers({ - org: 'svsticky', - per_page: 100, - }); - - return res.data; - } catch (error) { - return { error: error.toString() }; - } - } - }) + allCommits: build.query({ queryFn: allCommits }), + members: build.query({ queryFn: allMembers }) }) }); From 7e38a67c1047635e873a8797858dd2455f73f71e Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Thu, 29 Aug 2024 17:09:06 +0200 Subject: [PATCH 23/34] refactor: reworked exports from api slices --- src/store/api/contentful.js | 3 +-- src/store/api/github.js | 3 +-- src/store/api/index.js | 5 ----- src/store/api/koala.js | 9 ++++----- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/store/api/contentful.js b/src/store/api/contentful.js index d9bbe41..bf3cbeb 100644 --- a/src/store/api/contentful.js +++ b/src/store/api/contentful.js @@ -20,7 +20,7 @@ async function contentfulBaseQuery(content_type) { } } -const contentful = createApi({ +export const contentful = createApi({ reducerPath: 'contentful', baseQuery: contentfulBaseQuery, endpoints: build => ({ @@ -38,4 +38,3 @@ export const { useBoardMessagesQuery, useQuotesQuery } = contentful; -export default contentful; diff --git a/src/store/api/github.js b/src/store/api/github.js index 775ad54..0b5d322 100644 --- a/src/store/api/github.js +++ b/src/store/api/github.js @@ -71,7 +71,7 @@ async function allMembers() { * It does not use a base query, since the octokit API * does not allow for a nice abstraction in endpoint form */ -const github = createApi({ +export const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), endpoints: build => ({ @@ -81,4 +81,3 @@ const github = createApi({ }); export const { useAllCommitsQuery, useMembersQuery } = github; -export default github; diff --git a/src/store/api/index.js b/src/store/api/index.js index 4a5777b..6eb9891 100644 --- a/src/store/api/index.js +++ b/src/store/api/index.js @@ -1,8 +1,3 @@ -export { default as contentful } from "./contentful"; export * from "./contentful"; - -export { default as koala } from "./koala"; export * from "./koala"; - -export { default as github } from "./github"; export * from "./github"; diff --git a/src/store/api/koala.js b/src/store/api/koala.js index d136d12..c6c60e8 100644 --- a/src/store/api/koala.js +++ b/src/store/api/koala.js @@ -6,7 +6,7 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; * Uses a fetch-based base query, the endpoint's query is appended to * the base url and assumes the response is JSON, which is automatically decoded. */ -const koala = createApi({ +export const koala = createApi({ reducerPath: 'koala', baseQuery: fetchBaseQuery({ baseUrl: import.meta.env.VITE_KOALA_API_BASE @@ -15,9 +15,9 @@ const koala = createApi({ activities: build.query({ query: () => 'activities', transformResponse: result => result - .filter(act => act.poster) - .map(setDate) - .sort((a, b) => a.start_date - b.start_date) + .filter(act => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date) }) }) }); @@ -35,4 +35,3 @@ function setDate(activity) { } export const { useActivitiesQuery } = koala; -export default koala; From 27eed9a9b910865e57e41897fbe52f631cb34d88 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 30 Aug 2024 16:40:13 +0200 Subject: [PATCH 24/34] refactor: split state slice into quotes and screen slice --- src/App.jsx | 14 ++++----- src/store/index.js | 51 ++++++++++++++++++------------- src/store/quotes.js | 33 ++++++++++++++++++++ src/store/{state.js => screen.js} | 30 +++--------------- 4 files changed, 73 insertions(+), 55 deletions(-) create mode 100644 src/store/quotes.js rename src/store/{state.js => screen.js} (51%) diff --git a/src/App.jsx b/src/App.jsx index 47c396f..623c808 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,5 @@ -import {useEffect} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; +import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { Activities, @@ -10,9 +10,9 @@ import { Commits } from './components'; -import {nextState} from './store'; -import {contentful} from './store/api'; -import {resetQuotes} from './store/state'; +import { nextState } from './store'; +import { contentful } from './store/api'; +import { resetQuotes } from './store/quotes'; const LOGO = import.meta.env.VITE_LOGO; @@ -42,7 +42,7 @@ function StateMachine() { }); return result.unsubscribe; - }, []); + }, [dispatch]); // Create timer that ticks the state machine useEffect(() => { @@ -51,7 +51,7 @@ function StateMachine() { }, import.meta.env.VITE_NEXT_INTERVAL); return () => clearInterval(interval); - }); + }, [dispatch]); // Display the correct component based on state machine's state const state = useSelector(state => state.state); diff --git a/src/store/index.js b/src/store/index.js index 6cccdae..047e215 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,7 +1,13 @@ import { configureStore } from '@reduxjs/toolkit'; import { koala, contentful, github } from './api'; -import state, * as actions from './state'; +import screen, { + incrementAdIndex, incrementActivityIndex, + resetAdIndex, resetActivityIndex, + incrementBoardMessageIndex, resetBoardMessageIndex, + setCurrent +} from './screen'; +import quotes, { resetQuotes, nextQuote } from './quotes'; /** * nextState is the transition function for the state machine. It @@ -17,62 +23,62 @@ export function nextState(dispatch, getState) { const displayInternal = params.get('internal') === 'true'; const state = getState(); - switch (state.state.current) { + switch (state.screen.current) { case 'activities': { const { data: activities } = koala.endpoints.activities.select()(state); - if (state.state.activityIndex >= activities.length - 1) { - dispatch(actions.setCurrent('advertisement')); - dispatch(actions.resetActivityIndex()); + if (state.screen.activityIndex >= activities.length - 1) { + dispatch(setCurrent('advertisement')); + dispatch(resetActivityIndex()); } else { - dispatch(actions.incrementActivityIndex()); + dispatch(incrementActivityIndex()); } } break; case 'advertisement': { const { data: ads } = contentful.endpoints.ads.select()(state); - if (state.state.adIndex >= ads.length - 1) { - dispatch(actions.setCurrent( + if (state.screen.adIndex >= ads.length - 1) { + dispatch(setCurrent( displayInternal ? 'boardText' : 'activities' )); - dispatch(actions.resetAdIndex()); + dispatch(resetAdIndex()); } else { - dispatch(actions.incrementAdIndex()); + dispatch(incrementAdIndex()); } } break; case 'boardText': { const { data: messages } = contentful.endpoints.boardMessages.select()(state); - if (state.state.boardMessageIndex >= messages.length - 1) { - dispatch(actions.resetBoardMessageIndex()); + if (state.screen.boardMessageIndex >= messages.length - 1) { + dispatch(resetBoardMessageIndex()); } else { - dispatch(actions.incrementBoardMessageIndex()); + dispatch(incrementBoardMessageIndex()); } - dispatch(actions.setCurrent('quotes')); + dispatch(setCurrent('quotes')); } break; case 'quotes': - if (!state.state.availableQuotes.length) { + if (!state.quotes.availableQuotes.length) { const { data: quotes } = contentful.endpoints.quotes.select()(state); - dispatch(actions.resetQuotes(quotes.length)); + dispatch(resetQuotes(quotes.length)); } else { - dispatch(actions.nextQuote()); + dispatch(nextQuote()); } - dispatch(actions.setCurrent( + dispatch(setCurrent( import.meta.env.VITE_GITHUB_REPOS - ? 'commits' - : 'activities' + ? 'commits' + : 'activities' )); break; case 'commits': - dispatch(actions.setCurrent('activities')); + dispatch(setCurrent('activities')); break; default: @@ -89,7 +95,8 @@ const store = configureStore({ [koala.reducerPath]: koala.reducer, [contentful.reducerPath]: contentful.reducer, [github.reducerPath]: github.reducer, - state + screen, + quotes }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() diff --git a/src/store/quotes.js b/src/store/quotes.js new file mode 100644 index 0000000..8e7d9fe --- /dev/null +++ b/src/store/quotes.js @@ -0,0 +1,33 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const quotes = createSlice({ + name: 'quotes', + initialState: { + availableQuotes: [], + quoteIndex: 0 + }, + reducers: { + nextQuote(state) { + const hi = state.availableQuotes.length - 1; + const availableQuoteIndex = Math.floor(Math.random() * hi); + + [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); + }, + resetQuotes(state, action) { + state.availableQuotes = new Array(action.payload) + .fill(0) + .map((_, i) => i); + } + } +}); + +export const { nextQuote } = quotes.actions; + +export function resetQuotes(payload) { + return (dispatch, _getState) => { + dispatch(quotes.actions.resetQuotes(payload)); + dispatch(quotes.actions.nextQuote()); + } +} + +export default quotes; diff --git a/src/store/state.js b/src/store/screen.js similarity index 51% rename from src/store/state.js rename to src/store/screen.js index 394b363..b2ff1d7 100644 --- a/src/store/state.js +++ b/src/store/screen.js @@ -1,14 +1,11 @@ import { createSlice } from "@reduxjs/toolkit"; -const state = createSlice({ - name: 'state', +const screen = createSlice({ + name: 'screen', initialState: { activityIndex: 0, adIndex: 0, boardMessageIndex: 0, - availableQuotes: [], - usedQuotes: [], - quoteIndex: 0, current: 'activities' }, reducers: { @@ -33,24 +30,6 @@ const state = createSlice({ state.boardMessageIndex = 0; }, - nextQuote(state) { - state.usedQuotes.push(state.quoteIndex); - - const hi = state.availableQuotes.length - 1; - const availableQuoteIndex = Math.floor(Math.random() * hi); - - [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); - }, - resetQuotes(state, action) { - state.availableQuotes = new Array(action.payload) - .fill(0) - .map((_, i) => i); - state.usedQuotes = []; - - const availableQuoteIndex = Math.floor(Math.random() * (action.payload - 1)); - [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); - }, - setCurrent(state, action) { state.current = action.payload; } @@ -61,7 +40,6 @@ export const { incrementActivityIndex, resetActivityIndex, incrementAdIndex, resetAdIndex, incrementBoardMessageIndex, resetBoardMessageIndex, - nextQuote, resetQuotes, setCurrent -} = state.actions; -export default state.reducer; +} = screen.actions; +export default screen.reducer; From 067fd404bb18170d5da331212b7221a84007ecc3 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 30 Aug 2024 20:18:45 +0200 Subject: [PATCH 25/34] refactor: list index based on id as opposed to index --- src/App.jsx | 2 +- src/components/Commits.jsx | 6 +++--- src/store/api/github.js | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 623c808..35415ce 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -54,7 +54,7 @@ function StateMachine() { }, [dispatch]); // Display the correct component based on state machine's state - const state = useSelector(state => state.state); + const state = useSelector(state => state.screen); switch (state.current) { case 'activities': diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index 17f538c..cfcb2a7 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -1,5 +1,5 @@ import Poster from './Poster'; -import {useAllCommitsQuery} from '../store/api'; +import { useAllCommitsQuery } from '../store/api'; function formatTime(date) { let hh = date.getHours(); @@ -32,8 +32,8 @@ export default function Commits() {

        Recent commits

          - {commits.map((commit, index) => -
        • + {commits.map(commit => +
        • {commit.message.split('\n')[0]}

          diff --git a/src/store/api/github.js b/src/store/api/github.js index 0b5d322..91a3209 100644 --- a/src/store/api/github.js +++ b/src/store/api/github.js @@ -15,6 +15,7 @@ async function listCommits(owner, repo) { }); return res.data.map(({ commit }) => ({ + id: commit.id, message: commit.message, author: commit.author.name ?? commit.author.login, date: new Date(commit.committer.date), From d2c0534316e36fe8dbd11f7aac10f3b6b04f302f Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 30 Aug 2024 23:24:40 +0200 Subject: [PATCH 26/34] fix: changed koala activity date to be stored as string in store --- src/components/Activities.jsx | 4 ++-- src/components/Activity.jsx | 32 +++++++++++++++++--------------- src/store/api/koala.js | 18 +++++------------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index 8457462..9f706c4 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -21,10 +21,10 @@ export default function Activities({ current }) { key={i} {...activity} active={activity === currentActivity} - /> + /> )}
        - +
        ); } else { diff --git a/src/components/Activity.jsx b/src/components/Activity.jsx index c61c0a8..b868740 100644 --- a/src/components/Activity.jsx +++ b/src/components/Activity.jsx @@ -5,17 +5,17 @@ import scrollIntoView from 'scroll-into-view'; function sameDay(d, t) { return ( - d.getDate() === t.getDate() && // getDate returns day number in month... - d.getMonth() === t.getMonth() && - d.getYear() === t.getYear() + d.date() === t.date() && + d.month() === t.month() && + d.year() === t.year() ); } -function createFormat(has_time, date, as = new Date()) { +function formatDate(has_time, date, as = moment()) { const format = (!sameDay(date, as) ? 'dddd DD-MM ' : '') + (has_time ? 'HH:mm' : ''); - return format || '[]'; + return date.format(format || '[]'); } export default function Activity({ active, name, start_date, end_date, has_start_time, has_end_time, participant_counter }) { @@ -30,20 +30,22 @@ export default function Activity({ active, name, start_date, end_date, has_start } }, [active]); - const startDate = moment(start_date) - .format(createFormat(has_start_time, start_date)); - const endDate = moment(end_date) - .format(createFormat(has_end_time, end_date, start_date)); - const className = 'activity' + (active ? ' active' : ''); + // TODO: Get rid of moment for formatting some time + start_date = moment(start_date); + + const formattedStartDate = formatDate(has_start_time, start_date); + const formattedEndDate = end_date + ? formatDate(has_end_time, moment(end_date), start_date) + : ''; return ( -
      • +
      • {name} {participant_counter && ` (${participant_counter})`}

        - - {endDate && <> - } + + {formattedEndDate && <> - }
      • ); } @@ -52,8 +54,8 @@ export default function Activity({ active, name, start_date, end_date, has_start Activity.propTypes = { active: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, - start_date: PropTypes.instanceOf(Date).isRequired, - end_date: PropTypes.instanceOf(Date), + start_date: PropTypes.string.isRequired, + end_date: PropTypes.string, has_start_time: PropTypes.bool.isRequired, has_end_time: PropTypes.bool.isRequired, participant_counter: PropTypes.string, diff --git a/src/store/api/koala.js b/src/store/api/koala.js index c6c60e8..b68cf20 100644 --- a/src/store/api/koala.js +++ b/src/store/api/koala.js @@ -16,22 +16,14 @@ export const koala = createApi({ query: () => 'activities', transformResponse: result => result .filter(act => act.poster) - .map(setDate) + .map(activity => ({ + ...activity, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, + })) .sort((a, b) => a.start_date - b.start_date) }) }) }); -/** - * Patch an activity - */ -function setDate(activity) { - return Object.assign({ - ...activity, - has_start_time: activity.start_date.indexOf('T') > -1, - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - start_date: new Date(activity.start_date) - }, activity.end_date ? { end_date: new Date(activity.end_date) } : null); -} - export const { useActivitiesQuery } = koala; From 289be9c5f12aabbbe25fff18aaf1366c39004fed Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sun, 1 Sep 2024 20:57:14 +0200 Subject: [PATCH 27/34] tooling: introduced prettier and git hooks - installed prettier - create simple prettier config - upgraded eslint to v9 - installed husky and lint-staged for pre-commit hook --- .eslintrc.json | 22 - .github/workflows/projects.yml | 1 - .husky/pre-commit | 1 + .lintstagedrc.json | 4 + .prettierignore | 3 + .prettierrc.json | 8 + CONTRIBUTING.md | 1 - README.md | 27 +- docs/instellen-raspberrypi.md | 30 +- eslint.config.js | 21 + index.html | 27 +- package-lock.json | 4363 ++++++++++---------------------- package.json | 20 +- src/App.tsx | 16 +- src/components/Activities.tsx | 15 +- src/components/Activity.tsx | 39 +- src/components/Ad.tsx | 6 +- src/components/BoardText.tsx | 9 +- src/components/Commits.tsx | 15 +- src/components/Poster.tsx | 2 +- src/components/Quotes.tsx | 13 +- src/components/Team.tsx | 3 +- src/components/index.ts | 14 +- src/index.css | 2 +- src/main.tsx | 4 +- src/store/api/contentful.ts | 75 +- src/store/api/github.ts | 62 +- src/store/api/index.ts | 12 +- src/store/api/koala.ts | 41 +- src/store/index.ts | 103 +- src/store/state.ts | 28 +- src/vite-env.d.ts | 3 +- tsconfig.json | 16 +- vite.config.ts | 2 +- 34 files changed, 1659 insertions(+), 3349 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .husky/pre-commit create mode 100644 .lintstagedrc.json create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 eslint.config.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index fa08210..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": [ // Inherit the following presets, from https://github.com/jsx-eslint/eslint-plugin-react/tree/master/configs - "react-app", - "eslint:recommended", - "plugin:react/recommended", - "plugin:react/jsx-runtime" - ], - "ignorePatterns" :["dist/*"], // At all times, ignore generated code. - "env": { - "browser": true // Indicate that browser globals are available - }, - "rules": { - "quotes": [1, "single"] // Enforce single quotes - }, - "parserOptions": { - "ecmaFeatures": { - "jsx": true, - "modules": true - } - } -} - diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml index e36685a..4d0b334 100644 --- a/.github/workflows/projects.yml +++ b/.github/workflows/projects.yml @@ -23,4 +23,3 @@ jobs: # labeled: # optional # The behavior of the labels filter, AND to match all labels, OR to match any label, NOT to exclude any listed label (default is OR) # label-operator: # optional - diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..baca7c7 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "**/*.{ts,tsx}": ["prettier . --write", "eslint . --fix", "eslint ."], + "**/*.{json,css,md}": ["prettier . --write"] +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b850a65 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +node_modules +package-lock.json +src/snow diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..3553493 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "bracketSpacing": true, + "endOfLine": "lf", + "printWidth": 80, + "semi": true, + "singleQuote": true, + "tabWidth": 2 +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8b0f141..b78e90d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,6 @@ To contribute to our projects, please follow these steps: git clone https://github.com/svsticky/radio.git ``` - 2. **Switch to a New Branch**: Create a new branch for your work and switch to it. ```shell diff --git a/README.md b/README.md index b4cbcd4..e48b28d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ and contains things like upcoming activities and peculiar quotes. Radio requires you to have some Node package manager installed on your device. This README assumes that you have NPM installed, but anything will work really. -See [the official documentation](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) +See [the official documentation](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/) on how to install NPM, if you would like to use that one. ### How to install @@ -21,17 +21,18 @@ on how to install NPM, if you would like to use that one. 1. Clone this repository to a location you prefer. 2. Then, enter the cloned repository with your terminal, or open visual studio code or some other IDE in there, as long as you have a command-line open in the folder of your clone of radio. -2. In that commandline, simply run `npm install`! -3. Finally, you need to provide your local installation of radio with some secrets. - 1. Copy `sample.env` to `.env`. - 2. Fill in all the missing secrets in `.env`. - - If you do not have access to them, feel free to ask for them! However, you might not need them. - The secrets are only required to fetch content for the 'internal' pages, meant only for inside - the Sticky room: those visible only when you add `?internal=true` to the URL. - - If, at the moment, you are not interested in those pages, you can just provide gibberish - secrets everywhere, and radio will work! +3. In that commandline, simply run `npm install`! +4. Finally, you need to provide your local installation of radio with some secrets. + + 1. Copy `sample.env` to `.env`. + 2. Fill in all the missing secrets in `.env`. + + If you do not have access to them, feel free to ask for them! However, you might not need them. + The secrets are only required to fetch content for the 'internal' pages, meant only for inside + the Sticky room: those visible only when you add `?internal=true` to the URL. + + If, at the moment, you are not interested in those pages, you can just provide gibberish + secrets everywhere, and radio will work! ## Usage @@ -81,7 +82,7 @@ npm run preview ### Distribution There are many ways one can replace the contents of the `dist` folder on the server -with your local `dist` folder's contents. For instance, you could travel to germany, +with your local `dist` folder's contents. For instance, you could travel to germany, ask the server maintainers kindly to plug in your USB stick and copy over your files. However, you could of course also do the following (on linux/WSL): diff --git a/docs/instellen-raspberrypi.md b/docs/instellen-raspberrypi.md index 2a9f416..f6f9037 100644 --- a/docs/instellen-raspberrypi.md +++ b/docs/instellen-raspberrypi.md @@ -7,27 +7,27 @@ 5. `sudo apt-get install iceweasel` 6. Zet het volgende in `/usr/share/xsessions/custom.desktop`: - ``` - [Desktop Entry] - Name=Xsession - Exec=/etc/X11/Xsession - ``` + ``` + [Desktop Entry] + Name=Xsession + Exec=/etc/X11/Xsession + ``` 7. Pas de volgende regel aan in `/etc/lightdm/lightdm.conf`: - ``` - autologin-session=custom - ``` + ``` + autologin-session=custom + ``` 8. Maak een `~/.xsession` bestand aan en zet er iets van het volgende in: - ``` - # Eventuele setup voordat je het volgende doet. Geen windowmanager betekent - # exec voor het programma zetten (X verwacht een fork() call) - exec firefox - # Of: - # exec firefox -url "radio.svsticky.nl" -fullscreen - ``` + ``` + # Eventuele setup voordat je het volgende doet. Geen windowmanager betekent + # exec voor het programma zetten (X verwacht een fork() call) + exec firefox + # Of: + # exec firefox -url "radio.svsticky.nl" -fullscreen + ``` 9. SSH keys naar keuze 10. Pre-assigned IP adres configureren in de router. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..effd87e --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,21 @@ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import pluginReact from 'eslint-plugin-react'; + +export default [ + { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] }, + { ignores: ['node_modules', 'dist'] }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + { + ...pluginReact.configs.flat.recommended, + settings: { + react: { + version: '18.3', + }, + }, + }, + pluginReact.configs.flat['jsx-runtime'], +]; diff --git a/index.html b/index.html index 2664d9e..329eee9 100644 --- a/index.html +++ b/index.html @@ -1,18 +1,15 @@ - - - - - - Radio - - - -
        - - - - + + + + + Radio + + + +
        + + + - diff --git a/package-lock.json b/package-lock.json index d519c83..ba6fc47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,15 +17,19 @@ "react-redux": "^9.1.2" }, "devDependencies": { + "@eslint/js": "^9.9.1", + "@types/eslint__js": "^8.42.3", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", - "eslint": "^8.57.0", - "eslint-config-react-app": "^7.0.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint": "^9.9.1", + "eslint-plugin-react": "^7.35.0", + "globals": "^15.9.0", + "husky": "^9.1.5", + "lint-staged": "^15.2.9", + "prettier": "^3.3.3", "typescript": "^5.5.3", + "typescript-eslint": "^8.3.0", "vite": "^4.4.5" } }, @@ -94,33 +98,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/eslint-parser": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.5.tgz", - "integrity": "sha512-gsUcqS/fPlgAw1kOtpss7uhY6E9SFFANQ6EFX5GTvzUwaV0+sGaZWk6xq22MOdeT9wfxyokW3ceCUvOiRtZciQ==", - "dev": true, - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/@babel/generator": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", @@ -136,30 +113,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.23.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", @@ -176,62 +129,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz", - "integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.24.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", @@ -266,18 +163,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz", - "integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { "version": "7.24.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", @@ -309,18 +194,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", @@ -330,40 +203,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", - "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/helper-simple-access": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", @@ -376,18 +215,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", @@ -427,20 +254,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz", - "integrity": "sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.23.0", - "@babel/template": "^7.24.0", - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helpers": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", @@ -482,1540 +295,13 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz", - "integrity": "sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", - "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", - "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", - "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz", - "integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-decorators": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "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-decorators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz", - "integrity": "sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", - "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", - "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", - "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "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", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "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-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "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.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", - "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", - "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", - "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-remap-async-to-generator": "^7.22.20", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", - "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-remap-async-to-generator": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", - "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz", - "integrity": "sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", - "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", - "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.4", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz", - "integrity": "sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-split-export-declaration": "^7.24.5", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", - "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/template": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz", - "integrity": "sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", - "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", - "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", - "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", - "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", - "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", - "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-flow": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", - "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", - "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", - "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", - "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", - "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", - "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", - "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", - "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-simple-access": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", - "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", - "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", - "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", - "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", - "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz", - "integrity": "sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", - "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", - "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz", - "integrity": "sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz", - "integrity": "sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", - "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz", - "integrity": "sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.5", - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", - "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", - "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", - "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", - "dev": true, - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { + "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.5.tgz", "integrity": "sha512-RtCJoUO2oYrYwFPtR1/jkoBEcFuI1ae9a9IMxeyAVa3a1Ap4AnxmyIKG2b2FaJKqkidw/0cxRbWN+HOs6ZWd1w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz", - "integrity": "sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", - "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", - "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", - "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", - "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.24.3", - "@babel/helper-plugin-utils": "^7.24.0", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.1", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", - "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", - "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", - "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", - "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz", - "integrity": "sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.5.tgz", - "integrity": "sha512-E0VWu/hk83BIFUWnsKZ4D81KXjN5L3MobvevOHErASk9IPwKHOkTgvqzvNo1yP/ePJWqqK2SpUR5z+KQbl6NVw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.5", - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/plugin-syntax-typescript": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", - "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", - "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", - "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", - "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.5.tgz", - "integrity": "sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.24.4", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.5", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.1", - "@babel/plugin-syntax-import-attributes": "^7.24.1", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@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-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.1", - "@babel/plugin-transform-async-generator-functions": "^7.24.3", - "@babel/plugin-transform-async-to-generator": "^7.24.1", - "@babel/plugin-transform-block-scoped-functions": "^7.24.1", - "@babel/plugin-transform-block-scoping": "^7.24.5", - "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.4", - "@babel/plugin-transform-classes": "^7.24.5", - "@babel/plugin-transform-computed-properties": "^7.24.1", - "@babel/plugin-transform-destructuring": "^7.24.5", - "@babel/plugin-transform-dotall-regex": "^7.24.1", - "@babel/plugin-transform-duplicate-keys": "^7.24.1", - "@babel/plugin-transform-dynamic-import": "^7.24.1", - "@babel/plugin-transform-exponentiation-operator": "^7.24.1", - "@babel/plugin-transform-export-namespace-from": "^7.24.1", - "@babel/plugin-transform-for-of": "^7.24.1", - "@babel/plugin-transform-function-name": "^7.24.1", - "@babel/plugin-transform-json-strings": "^7.24.1", - "@babel/plugin-transform-literals": "^7.24.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", - "@babel/plugin-transform-member-expression-literals": "^7.24.1", - "@babel/plugin-transform-modules-amd": "^7.24.1", - "@babel/plugin-transform-modules-commonjs": "^7.24.1", - "@babel/plugin-transform-modules-systemjs": "^7.24.1", - "@babel/plugin-transform-modules-umd": "^7.24.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.24.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", - "@babel/plugin-transform-numeric-separator": "^7.24.1", - "@babel/plugin-transform-object-rest-spread": "^7.24.5", - "@babel/plugin-transform-object-super": "^7.24.1", - "@babel/plugin-transform-optional-catch-binding": "^7.24.1", - "@babel/plugin-transform-optional-chaining": "^7.24.5", - "@babel/plugin-transform-parameters": "^7.24.5", - "@babel/plugin-transform-private-methods": "^7.24.1", - "@babel/plugin-transform-private-property-in-object": "^7.24.5", - "@babel/plugin-transform-property-literals": "^7.24.1", - "@babel/plugin-transform-regenerator": "^7.24.1", - "@babel/plugin-transform-reserved-words": "^7.24.1", - "@babel/plugin-transform-shorthand-properties": "^7.24.1", - "@babel/plugin-transform-spread": "^7.24.1", - "@babel/plugin-transform-sticky-regex": "^7.24.1", - "@babel/plugin-transform-template-literals": "^7.24.1", - "@babel/plugin-transform-typeof-symbol": "^7.24.5", - "@babel/plugin-transform-unicode-escapes": "^7.24.1", - "@babel/plugin-transform-unicode-property-regex": "^7.24.1", - "@babel/plugin-transform-unicode-regex": "^7.24.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", - "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-transform-react-display-name": "^7.24.1", - "@babel/plugin-transform-react-jsx": "^7.23.4", - "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@babel/plugin-transform-react-pure-annotations": "^7.24.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz", - "integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-syntax-jsx": "^7.24.1", - "@babel/plugin-transform-modules-commonjs": "^7.24.1", - "@babel/plugin-transform-typescript": "^7.24.1" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2024,22 +310,19 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, - "node_modules/@babel/runtime": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", - "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz", + "integrity": "sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.14.0" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/template": { @@ -2077,6 +360,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", @@ -2456,6 +749,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -2466,25 +760,55 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -2492,60 +816,43 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -2553,6 +860,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -2561,11 +869,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", @@ -2615,42 +931,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "dependencies": { - "eslint-scope": "5.1.1" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2664,6 +950,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -2673,6 +960,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -3101,12 +1389,6 @@ } } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", - "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", - "dev": true - }, "node_modules/@types/aws-lambda": { "version": "8.10.137", "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.137.tgz", @@ -3158,17 +1440,40 @@ "resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.2.tgz", "integrity": "sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==" }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint__js": { + "version": "8.42.3", + "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", + "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/jsonwebtoken": { "version": "9.0.6", @@ -3186,12 +1491,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", @@ -3217,44 +1516,38 @@ "@types/react": "*" } }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz", + "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/type-utils": "8.3.0", + "@typescript-eslint/utils": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -3262,57 +1555,28 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", - "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", - "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.62.0" - }, - "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" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz", + "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -3321,16 +1585,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -3338,26 +1603,24 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz", + "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/utils": "8.3.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "*" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -3365,12 +1628,13 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -3378,21 +1642,23 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -3404,11 +1670,38 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", - "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3417,88 +1710,59 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "@typescript-eslint/types": "8.3.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", - "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vitejs/plugin-react": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", @@ -3519,10 +1783,11 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3535,6 +1800,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3556,6 +1822,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3567,11 +1834,28 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3592,22 +1876,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } + "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -3624,6 +1901,7 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3639,40 +1917,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -3693,6 +1943,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3711,6 +1962,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3718,35 +1970,27 @@ "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/arraybuffer.prototype.slice": { @@ -3754,6 +1998,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -3771,12 +2016,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3787,6 +2026,7 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -3797,15 +2037,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axe-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", - "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", @@ -3816,104 +2047,12 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/axobject-query": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", - "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.2", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", - "dev": true - }, - "node_modules/babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/before-after-hook": { "version": "2.2.3", @@ -3930,18 +2069,20 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4012,6 +2153,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4058,6 +2200,39 @@ "node": ">=6" } }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4073,6 +2248,13 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4084,17 +2266,22 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/contentful": { "version": "10.9.3", @@ -4144,35 +2331,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/core-js-compat": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", - "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", - "dev": true, - "dependencies": { - "browserslist": "^4.23.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4193,17 +2351,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "devOptional": true }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -4221,6 +2374,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -4238,6 +2392,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -4251,10 +2406,11 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -4271,7 +2427,8 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/define-data-property": { "version": "1.1.4", @@ -4294,6 +2451,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -4319,37 +2477,17 @@ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/ecdsa-sig-formatter": { @@ -4366,19 +2504,17 @@ "integrity": "sha512-PIbxpiJGx6Bb8dQaonNc6CGTRlVntdLg/2nMa1YhnrwYOORY9a3ZgGN0UQYE6lAcj/lkyduJN7BPt/JiY+jAQQ==", "dev": true }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/es-abstract": { @@ -4386,6 +2522,7 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -4465,6 +2602,7 @@ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -4490,6 +2628,7 @@ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -4502,6 +2641,7 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4", "has-tostringtag": "^1.0.2", @@ -4516,6 +2656,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } @@ -4525,6 +2666,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -4579,393 +2721,137 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">=6" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8.0" } }, - "node_modules/eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "node_modules/eslint": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.1", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "jiti": "*" }, "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { + "jiti": { "optional": true } } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", - "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.23.2", - "aria-query": "^5.3.0", - "array-includes": "^3.1.7", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "=4.7.0", - "axobject-query": "^3.2.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.15", - "hasown": "^2.0.0", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "version": "7.35.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", + "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", + "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.7.tgz", - "integrity": "sha512-yrj+KInFmwuQS2UQcg1SF83ha1tuHC1jMQbRNyuWtlEzzKRDgAl7L4Yp4NlDUZTZNlWvHEzOtJhMi40R7JxcSw==", - "dev": true, - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "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/eslint-plugin-testing-library": { - "version": "5.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz", - "integrity": "sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^5.58.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0", - "npm": ">=6" - }, - "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -4976,6 +2862,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -4991,6 +2878,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5007,6 +2895,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -5018,13 +2907,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5032,26 +2923,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5061,6 +2938,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5068,40 +2946,30 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5114,6 +2982,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5126,6 +2995,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5135,10 +3005,42 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/fast-copy": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-2.1.7.tgz", @@ -5148,13 +3050,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -5171,6 +3075,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5182,40 +3087,45 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5228,6 +3138,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -5240,24 +3151,25 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -5283,6 +3195,7 @@ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } @@ -5300,12 +3213,6 @@ "node": ">= 6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5333,6 +3240,7 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5351,6 +3259,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5364,6 +3273,19 @@ "node": ">=6.9.0" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -5382,11 +3304,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -5399,31 +3335,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -5432,12 +3349,16 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -5445,6 +3366,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -5456,26 +3378,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "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/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -5491,13 +3393,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5549,6 +3453,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -5570,11 +3475,38 @@ "node": ">= 0.4" } }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -5593,6 +3525,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5609,6 +3542,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -5621,27 +3555,12 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -5656,6 +3575,7 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -5667,17 +3587,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5693,6 +3608,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -5705,6 +3621,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5721,6 +3638,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5729,12 +3647,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5745,6 +3667,7 @@ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "dependencies": { "is-typed-array": "^1.1.13" }, @@ -5760,6 +3683,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5775,6 +3699,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5784,6 +3709,7 @@ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -5791,11 +3717,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5811,6 +3751,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5823,6 +3764,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5835,6 +3777,7 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5847,6 +3790,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5856,6 +3800,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5871,6 +3816,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5880,6 +3826,7 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5896,6 +3843,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5908,6 +3856,7 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7" }, @@ -5915,7 +3864,20 @@ "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-string": { @@ -5923,6 +3885,7 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -5938,6 +3901,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -5953,6 +3917,7 @@ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "dependencies": { "which-typed-array": "^1.1.14" }, @@ -5968,6 +3933,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5980,6 +3946,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -5992,6 +3959,7 @@ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4" @@ -6003,6 +3971,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -6014,6 +3989,7 @@ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "get-intrinsic": "^1.2.1", @@ -6032,6 +4008,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6055,25 +4032,22 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -6129,6 +4103,7 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -6163,33 +4138,17 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6198,17 +4157,97 @@ "node": ">= 0.8.0" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -6219,18 +4258,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -6265,13 +4292,109 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6292,22 +4415,31 @@ "yallist": "^3.0.2" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -6333,11 +4465,38 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6345,15 +4504,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -6389,13 +4539,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.14", @@ -6403,11 +4548,41 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6425,6 +4600,7 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -6434,6 +4610,7 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -6452,6 +4629,7 @@ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6466,6 +4644,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6479,42 +4658,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6555,11 +4704,28 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -6577,6 +4743,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -6592,6 +4759,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -6618,6 +4786,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -6625,42 +4794,16 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "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/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -6674,16 +4817,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/picocolors": { "version": "1.0.0", @@ -6703,11 +4838,25 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -6745,15 +4894,33 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -6770,6 +4937,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6806,7 +4974,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/react": { "version": "18.3.1", @@ -6835,7 +5004,8 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/react-redux": { "version": "9.1.2", @@ -6886,6 +5056,7 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6902,44 +5073,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "define-properties": "^1.2.1", @@ -6953,54 +5092,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7018,34 +5120,61 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "MIT" }, "node_modules/rollup": { "version": "3.29.4", @@ -7082,6 +5211,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -7091,6 +5221,7 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -7104,12 +5235,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7134,6 +5259,7 @@ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -7184,6 +5310,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -7232,13 +5359,47 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/source-map-js": { @@ -7250,17 +5411,76 @@ "node": ">=0.10.0" } }, - "node_modules/string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } }, "node_modules/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7282,11 +5502,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7305,6 +5537,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7319,6 +5552,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7336,6 +5570,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7343,13 +5578,17 @@ "node": ">=8" } }, - "node_modules/strip-bom": { + "node_modules/strip-final-newline": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -7357,6 +5596,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -7381,6 +5621,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7392,7 +5633,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -7408,6 +5650,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7415,49 +5658,17 @@ "node": ">=8.0" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=16" }, "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" + "typescript": ">=4.2.0" } }, "node_modules/type-check": { @@ -7465,6 +5676,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -7488,6 +5700,7 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -7502,6 +5715,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -7521,6 +5735,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -7541,6 +5756,7 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -7570,11 +5786,36 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.3.0.tgz", + "integrity": "sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.3.0", + "@typescript-eslint/parser": "8.3.0", + "@typescript-eslint/utils": "8.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -7590,46 +5831,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/universal-github-app-jwt": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.1.2.tgz", @@ -7679,6 +5880,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -7766,6 +5968,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -7778,13 +5981,14 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, + "license": "MIT", "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -7793,8 +5997,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -7803,17 +6007,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -7832,6 +6031,7 @@ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -7851,10 +6051,71 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7866,20 +6127,12 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 7ee0924..d72d333 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,11 @@ "scripts": { "dev": "vite", "build": "vite build", - "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint . --report-unused-disable-directives --fix", "preview": "vite preview", - "check": "tsc --noEmit" + "check": "tsc --noEmit", + "format": "prettier . --write", + "prepare": "husky" }, "dependencies": { "@reduxjs/toolkit": "^2.2.6", @@ -20,15 +22,19 @@ "react-redux": "^9.1.2" }, "devDependencies": { + "@eslint/js": "^9.9.1", + "@types/eslint__js": "^8.42.3", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", - "eslint": "^8.57.0", - "eslint-config-react-app": "^7.0.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint": "^9.9.1", + "eslint-plugin-react": "^7.35.0", + "globals": "^15.9.0", + "husky": "^9.1.5", + "lint-staged": "^15.2.9", + "prettier": "^3.3.3", "typescript": "^5.5.3", + "typescript-eslint": "^8.3.0", "vite": "^4.4.5" } } diff --git a/src/App.tsx b/src/App.tsx index c8ce975..d856dc1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,7 +6,7 @@ import { BoardText, Quotes, Ad, - Commits + Commits, } from './components'; import { nextState, useAppDispatch, useAppSelector } from './store'; @@ -37,8 +37,7 @@ function StateMachine() { const result = dispatch(contentful.endpoints.quotes.initiate()); result.then(({ data: quotes, isSuccess }) => { - if (isSuccess) - dispatch(actions.resetQuotes(quotes.length)); + if (isSuccess) dispatch(actions.resetQuotes(quotes.length)); }); return result.unsubscribe; @@ -46,15 +45,18 @@ function StateMachine() { // Create timer that ticks the state machine useEffect(() => { - const interval = setInterval(() => { - dispatch(nextState); - }, Number(import.meta.env.VITE_NEXT_INTERVAL)); + const interval = setInterval( + () => { + dispatch(nextState); + }, + Number(import.meta.env.VITE_NEXT_INTERVAL), + ); return () => clearInterval(interval); }); // Display the correct component based on state machine's state - const state = useAppSelector(state => state.state); + const state = useAppSelector((state) => state.state); switch (state.current) { case StateMachineState.Activities: diff --git a/src/components/Activities.tsx b/src/components/Activities.tsx index 2e9e4f4..14cf7ad 100644 --- a/src/components/Activities.tsx +++ b/src/components/Activities.tsx @@ -3,36 +3,35 @@ import Poster from './Poster'; import { useActivitiesQuery } from '../store/api'; type ActivitiesProps = { - current: number + current: number; }; export default function Activities({ current }: ActivitiesProps) { const { data: activities, isSuccess } = useActivitiesQuery(undefined, { - pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL) + pollingInterval: Number(import.meta.env.VITE_LOAD_INTERVAL), }); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; if (activities.length > 0) { const currentActivity = activities[current]; return (
        -
          - {activities.map((activity, i) => +
            + {activities.map((activity, i) => ( - )} + ))}
        ); } else { return ( -
        +

        There are no activities, wanbeleid!

        ); diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx index 1eebd98..ce045b2 100644 --- a/src/components/Activity.tsx +++ b/src/components/Activity.tsx @@ -3,23 +3,29 @@ import moment from 'moment'; import { type Activity } from '../store/api'; function sameDay(d: Date, t: Date): boolean { - return d.getDate() === t.getDate() // getDate returns day number in month... - && d.getMonth() === t.getMonth() - && d.getFullYear() === t.getFullYear(); + return ( + d.getDate() === t.getDate() && // getDate returns day number in month... + d.getMonth() === t.getMonth() && + d.getFullYear() === t.getFullYear() + ); } function createFormat(has_time: boolean, date: Date, as = new Date()): string { const format = - (!sameDay(date, as) ? 'dddd DD-MM ' : '') - + (has_time ? 'HH:mm' : ''); + (!sameDay(date, as) ? 'dddd DD-MM ' : '') + (has_time ? 'HH:mm' : ''); return format || '[]'; } type ActivityProps = Activity & { active: boolean }; export default function Activity({ - active, name, start_date, end_date, - has_start_time, has_end_time, participant_counter + active, + name, + start_date, + end_date, + has_start_time, + has_end_time, + participant_counter, }: ActivityProps) { const activityRef = useRef(null); @@ -27,15 +33,17 @@ export default function Activity({ useEffect(() => { if (active && activityRef.current) activityRef.current.scrollIntoView({ - behavior: 'smooth' + behavior: 'smooth', }); }, [active]); - const startDate = moment(start_date) - .format(createFormat(has_start_time, new Date(start_date))); + const startDate = moment(start_date).format( + createFormat(has_start_time, new Date(start_date)), + ); const endDate = end_date - ? moment(end_date) - .format(createFormat(has_end_time, new Date(end_date), new Date(start_date))) + ? moment(end_date).format( + createFormat(has_end_time, new Date(end_date), new Date(start_date)), + ) : null; const className = 'activity' + (active ? ' active' : ''); @@ -46,7 +54,12 @@ export default function Activity({ {participant_counter && ` (${participant_counter})`} - {endDate && <> - } + {endDate && ( + <> + {' '} + - + + )} ); } diff --git a/src/components/Ad.tsx b/src/components/Ad.tsx index 7758371..d4653a1 100644 --- a/src/components/Ad.tsx +++ b/src/components/Ad.tsx @@ -8,13 +8,11 @@ type AdProps = { export default function Ad({ current }: AdProps) { const { data: ads, isSuccess } = useAdsQuery(); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; const currentAd = ads[current]; - if (!currentAd.poster?.fields.file?.url) - throw new Error('Ad without poster'); + if (!currentAd.poster?.fields.file?.url) throw new Error('Ad without poster'); if (ads.length <= 0) { return ( diff --git a/src/components/BoardText.tsx b/src/components/BoardText.tsx index 55d12fb..7355b86 100644 --- a/src/components/BoardText.tsx +++ b/src/components/BoardText.tsx @@ -1,20 +1,19 @@ import { useBoardMessagesQuery } from '../store/api'; type BoardTextProps = { - current: number + current: number; }; export default function BoardText({ current }: BoardTextProps) { const { data: boardMessages, isSuccess } = useBoardMessagesQuery(); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; const { message } = boardMessages[current]; return ( -
        -

        {message}

        +
        +

        {message}

        ); } diff --git a/src/components/Commits.tsx b/src/components/Commits.tsx index 35435da..fd8e87a 100644 --- a/src/components/Commits.tsx +++ b/src/components/Commits.tsx @@ -5,26 +5,27 @@ import moment from 'moment'; export default function Commits() { const { data: commits, isSuccess } = useAllCommitsQuery(); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; return (

        Recent commits

          - {commits.map((commit, index) => + {commits.map((commit, index) => (
        • {commit.message.split('\n')[0]}

          - On {commit.owner}/{commit.repo} + On{' '} + + {commit.owner}/{commit.repo} + {' by'} {commit.author} - {commit.date && - ` (${moment(commit.date).format('LLL')})`} + {commit.date && ` (${moment(commit.date).format('LLL')})`}

        • - )} + ))}
        diff --git a/src/components/Poster.tsx b/src/components/Poster.tsx index ee20bfb..2e16489 100644 --- a/src/components/Poster.tsx +++ b/src/components/Poster.tsx @@ -1,5 +1,5 @@ type PosterProps = { - src: string + src: string; }; export default function Poster({ src }: PosterProps) { diff --git a/src/components/Quotes.tsx b/src/components/Quotes.tsx index afc0848..382b071 100644 --- a/src/components/Quotes.tsx +++ b/src/components/Quotes.tsx @@ -1,22 +1,21 @@ import { useQuotesQuery } from '../store/api'; type QuotesProps = { - current: number + current: number; }; export default function Quotes({ current }: QuotesProps) { const { data: quotes, isSuccess } = useQuotesQuery(); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; const quote = quotes[current]; return ( -
        -
        -

        "{quote.text}"

        -

        -{quote.person}

        +
        +
        +

        "{quote.text}"

        +

        -{quote.person}

        ); diff --git a/src/components/Team.tsx b/src/components/Team.tsx index bb428ca..8456f8d 100644 --- a/src/components/Team.tsx +++ b/src/components/Team.tsx @@ -4,8 +4,7 @@ import Poster from './Poster'; export default function Team() { const { data: members, isSuccess } = useMembersQuery(); - if (!isSuccess) - return <>; + if (!isSuccess) return <>; return (
        diff --git a/src/components/index.ts b/src/components/index.ts index 357a4ef..30f8be1 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,7 +1,7 @@ -export { default as Activities } from "./Activities"; -export { default as Ad } from "./Ad"; -export { default as BoardText } from "./BoardText"; -export { default as Clock } from "./Clock"; -export { default as Commits } from "./Commits"; -export { default as Quotes } from "./Quotes"; -export { default as Team } from "./Team"; +export { default as Activities } from './Activities'; +export { default as Ad } from './Ad'; +export { default as BoardText } from './BoardText'; +export { default as Clock } from './Clock'; +export { default as Commits } from './Commits'; +export { default as Quotes } from './Quotes'; +export { default as Team } from './Team'; diff --git a/src/index.css b/src/index.css index 943d075..3ca4334 100644 --- a/src/index.css +++ b/src/index.css @@ -2,7 +2,7 @@ html { background: #262626; - font-family: "Work Sans", sans-serif; + font-family: 'Work Sans', sans-serif; max-height: 100%; width: 100%; position: fixed; diff --git a/src/main.tsx b/src/main.tsx index 43209d9..08a3197 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -15,8 +15,8 @@ if (root) { - + , ); } else { - throw new Error("Cannot find root element to bind to"); + throw new Error('Cannot find root element to bind to'); } diff --git a/src/store/api/contentful.ts b/src/store/api/contentful.ts index c430e87..c0e3d19 100644 --- a/src/store/api/contentful.ts +++ b/src/store/api/contentful.ts @@ -1,40 +1,47 @@ import { createClient, type EntryFieldTypes, type Entry } from 'contentful'; import { createApi } from '@reduxjs/toolkit/query/react'; -type FromSkeleton = Entry['fields']; +type FromSkeleton = Entry< + T, + 'WITHOUT_UNRESOLVABLE_LINKS' +>['fields']; type AdSkeleton = { - contentTypeId: 'ads', + contentTypeId: 'ads'; fields: { - title: EntryFieldTypes.Text, - description: EntryFieldTypes.Text, - fullscreen: EntryFieldTypes.Boolean, - poster: EntryFieldTypes.AssetLink - } + title: EntryFieldTypes.Text; + description: EntryFieldTypes.Text; + fullscreen: EntryFieldTypes.Boolean; + poster: EntryFieldTypes.AssetLink; + }; }; type Ad = FromSkeleton; type BoardMessageSkeleton = { - contentTypeId: 'board-message', + contentTypeId: 'board-message'; fields: { - message: EntryFieldTypes.Text - } + message: EntryFieldTypes.Text; + }; }; type BoardMessage = FromSkeleton; type QuoteSkeleton = { - contentTypeId: 'quotes', + contentTypeId: 'quotes'; fields: { - person: EntryFieldTypes.Text, - text: EntryFieldTypes.Text - } + person: EntryFieldTypes.Text; + text: EntryFieldTypes.Text; + }; }; type Quote = FromSkeleton; type ContentfulSkeletons = AdSkeleton | BoardMessageSkeleton | QuoteSkeleton; -type ContentfulResponse = - Entry, 'WITHOUT_UNRESOLVABLE_LINKS'>[]; +type ContentfulResponse< + ContentType extends ContentfulSkeletons['contentTypeId'], +> = Entry< + Extract, + 'WITHOUT_UNRESOLVABLE_LINKS' +>[]; const client = createClient({ space: import.meta.env.VITE_CONTENTFUL_SPACE_ID, @@ -46,36 +53,44 @@ const client = createClient({ * specifies the content_type of the thing it requests and these * entries are searched via the contentful API. */ -async function contentfulBaseQuery(content_type: ContentType): - Promise<{ data: ContentfulResponse } | { error: unknown }> { +async function contentfulBaseQuery< + ContentType extends ContentfulSkeletons['contentTypeId'], +>( + content_type: ContentType, +): Promise<{ data: ContentfulResponse } | { error: unknown }> { try { - const res = await client.withoutUnresolvableLinks.getEntries({ content_type }); + const res = + await client.withoutUnresolvableLinks.getEntries({ + content_type, + }); return { data: res.items as ContentfulResponse }; } catch (error) { return { error }; } } -function createQuery(content_type: ContentType) { +function createQuery( + content_type: ContentType, +) { return { query: () => content_type, - transformResponse: (response: ContentfulResponse) => response.map(entry => entry.fields) + transformResponse: (response: ContentfulResponse) => + response.map((entry) => entry.fields), }; } const contentful = createApi({ reducerPath: 'contentful', baseQuery: contentfulBaseQuery, - endpoints: build => ({ + endpoints: (build) => ({ ads: build.query(createQuery('ads')), - boardMessages: build.query(createQuery('board-message')), - quotes: build.query(createQuery('quotes')) - }) + boardMessages: build.query( + createQuery('board-message'), + ), + quotes: build.query(createQuery('quotes')), + }), }); -export const { - useAdsQuery, - useBoardMessagesQuery, - useQuotesQuery -} = contentful; +export const { useAdsQuery, useBoardMessagesQuery, useQuotesQuery } = + contentful; export default contentful; diff --git a/src/store/api/github.ts b/src/store/api/github.ts index 40349e5..eb051d4 100644 --- a/src/store/api/github.ts +++ b/src/store/api/github.ts @@ -2,20 +2,23 @@ import { Octokit } from 'octokit'; import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; const octokit = new Octokit({ - auth: import.meta.env.VITE_GITHUB_API_TOKEN + auth: import.meta.env.VITE_GITHUB_API_TOKEN, }); type Commit = { - message: string, - author: string, - date: number | null, - repo: string, - owner: string + message: string; + author: string; + date: number | null; + repo: string; + owner: string; }; -type ArrayElement = - T extends readonly (infer U)[] ? U : never; -type Member = ArrayElement>['data']>; +type ArrayElement = T extends readonly (infer U)[] + ? U + : never; +type Member = ArrayElement< + Awaited>['data'] +>; /** * Return all commits from a Github repository @@ -23,16 +26,19 @@ type Member = ArrayElement { const res = await octokit.rest.repos.listCommits({ - owner, repo, per_page: 4, + owner, + repo, + per_page: 4, }); return res.data.map(({ commit }) => ({ message: commit.message, - author: commit.author?.name ?? commit.author?.email ?? "", + author: commit.author?.name ?? commit.author?.email ?? '', date: commit.committer?.date ? new Date(commit.committer.date).getTime() : null, - repo, owner + repo, + owner, })); } @@ -45,32 +51,28 @@ async function listCommits(owner: string, repo: string): Promise { const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), - endpoints: build => ({ + endpoints: (build) => ({ allCommits: build.query({ queryFn: async () => { try { const commitsPerRepo = await Promise.allSettled( - import.meta.env.VITE_GITHUB_REPOS - .split(' ') - .map(name => { - const [owner, repo] = name.split('/'); - return listCommits(owner, repo); - })); + import.meta.env.VITE_GITHUB_REPOS.split(' ').map((name) => { + const [owner, repo] = name.split('/'); + return listCommits(owner, repo); + }), + ); return { data: commitsPerRepo - .flatMap(commits => - commits.status === "fulfilled" - ? commits.value - : []) - .sort((a, b) => a.date && b.date - ? b.date - a.date - : -1) + .flatMap((commits) => + commits.status === 'fulfilled' ? commits.value : [], + ) + .sort((a, b) => (a.date && b.date ? b.date - a.date : -1)), }; } catch (error) { return { error }; } - } + }, }), members: build.query({ queryFn: async () => { @@ -84,9 +86,9 @@ const github = createApi({ } catch (error) { return { error }; } - } - }) - }) + }, + }), + }), }); export const { useAllCommitsQuery, useMembersQuery } = github; diff --git a/src/store/api/index.ts b/src/store/api/index.ts index 4a5777b..42f715e 100644 --- a/src/store/api/index.ts +++ b/src/store/api/index.ts @@ -1,8 +1,8 @@ -export { default as contentful } from "./contentful"; -export * from "./contentful"; +export { default as contentful } from './contentful'; +export * from './contentful'; -export { default as koala } from "./koala"; -export * from "./koala"; +export { default as koala } from './koala'; +export * from './koala'; -export { default as github } from "./github"; -export * from "./github"; +export { default as github } from './github'; +export * from './github'; diff --git a/src/store/api/koala.ts b/src/store/api/koala.ts index e119d5a..e542af7 100644 --- a/src/store/api/koala.ts +++ b/src/store/api/koala.ts @@ -1,18 +1,18 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; type ResponseActivity = { - name: string, - start_date: string, - end_date: string | null, - poster: string, - participant_counter: number + name: string; + start_date: string; + end_date: string | null; + poster: string; + participant_counter: number; }; export type Activity = Omit & { - start_date: number, - end_date: number | null, - has_start_time: boolean, - has_end_time: boolean + start_date: number; + end_date: number | null; + has_start_time: boolean; + has_end_time: boolean; }; /** @@ -24,17 +24,18 @@ export type Activity = Omit & { const koala = createApi({ reducerPath: 'koala', baseQuery: fetchBaseQuery({ - baseUrl: import.meta.env.VITE_KOALA_API_BASE + baseUrl: import.meta.env.VITE_KOALA_API_BASE, }), - endpoints: build => ({ + endpoints: (build) => ({ activities: build.query({ query: () => 'activities', - transformResponse: (result: ResponseActivity[]): Activity[] => result - .filter(act => act.poster) - .map(setDate) - .sort((a, b) => a.start_date - b.start_date) - }) - }) + transformResponse: (result: ResponseActivity[]): Activity[] => + result + .filter((act) => act.poster) + .map(setDate) + .sort((a, b) => a.start_date - b.start_date), + }), + }), }); /** @@ -44,13 +45,11 @@ function setDate(activity: ResponseActivity): Activity { return { ...activity, start_date: new Date(activity.start_date).getTime(), - end_date: activity.end_date - ? new Date(activity.end_date).getTime() - : null, + end_date: activity.end_date ? new Date(activity.end_date).getTime() : null, has_start_time: activity.start_date.indexOf('T') > -1, has_end_time: activity.end_date ? activity.end_date.indexOf('T') > -1 - : false + : false, }; } diff --git a/src/store/index.ts b/src/store/index.ts index 2e0e9aa..f0a3d33 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -13,18 +13,21 @@ import { useDispatch, useSelector } from 'react-redux'; * [synchronous thunk]{@link https://redux.js.org/usage/writing-logic-thunks#what-is-a-thunk} * that is invoked at a fixed interval in the StateMachine component. */ -export const nextState: ThunkAction = - (dispatch, getState) => { - const params = new URLSearchParams(window.location.search); - const displayInternal = params.get('internal') === 'true'; - - const state = getState(); - switch (state.state.current) { - case StateMachineState.Activities: { - const { data: activities, isSuccess } = koala.endpoints.activities.select()(state); - - if (!isSuccess) - throw new Error(''); +export const nextState: ThunkAction = ( + dispatch, + getState, +) => { + const params = new URLSearchParams(window.location.search); + const displayInternal = params.get('internal') === 'true'; + + const state = getState(); + switch (state.state.current) { + case StateMachineState.Activities: + { + const { data: activities, isSuccess } = + koala.endpoints.activities.select()(state); + + if (!isSuccess) throw new Error(''); if (state.state.activityIndex >= activities.length - 1) { dispatch(actions.resetActivityIndex()); @@ -32,29 +35,36 @@ export const nextState: ThunkAction = } else { dispatch(actions.incrementActivityIndex()); } - } break; + } + break; - case StateMachineState.Advertisement: { - const { data: ads, isSuccess } = contentful.endpoints.ads.select()(state); + case StateMachineState.Advertisement: + { + const { data: ads, isSuccess } = + contentful.endpoints.ads.select()(state); if (isSuccess) { if (state.state.adIndex >= ads.length - 1) { dispatch(actions.resetAdIndex()); - dispatch(actions.setCurrent( - displayInternal - ? StateMachineState.BoardText - : StateMachineState.Activities - )); + dispatch( + actions.setCurrent( + displayInternal + ? StateMachineState.BoardText + : StateMachineState.Activities, + ), + ); } else { dispatch(actions.incrementAdIndex()); } } + } + break; - } break; - - case StateMachineState.BoardText: { - const { data: messages, isSuccess } = contentful.endpoints.boardMessages.select()(state); + case StateMachineState.BoardText: + { + const { data: messages, isSuccess } = + contentful.endpoints.boardMessages.select()(state); if (isSuccess) { if (state.state.boardMessageIndex >= messages.length - 1) { @@ -65,33 +75,36 @@ export const nextState: ThunkAction = } dispatch(actions.setCurrent(StateMachineState.Quotes)); - } break; + } + break; - case StateMachineState.Quotes: - if (!state.state.availableQuotes.length) { - const { data: quotes, isSuccess } = contentful.endpoints.quotes.select()(state); + case StateMachineState.Quotes: + if (!state.state.availableQuotes.length) { + const { data: quotes, isSuccess } = + contentful.endpoints.quotes.select()(state); - if (isSuccess) - dispatch(actions.resetQuotes(quotes.length)); - } else { - dispatch(actions.nextQuote()); - } + if (isSuccess) dispatch(actions.resetQuotes(quotes.length)); + } else { + dispatch(actions.nextQuote()); + } - dispatch(actions.setCurrent( + dispatch( + actions.setCurrent( import.meta.env.VITE_GITHUB_REPOS ? StateMachineState.Commits - : StateMachineState.Activities - )); - break; + : StateMachineState.Activities, + ), + ); + break; - case StateMachineState.Commits: - dispatch(actions.setCurrent(StateMachineState.Activities)); - break; + case StateMachineState.Commits: + dispatch(actions.setCurrent(StateMachineState.Activities)); + break; - default: - break; - } + default: + break; } +}; /** * The store consists of 4 slices: one for every api source we use @@ -102,14 +115,14 @@ const store = configureStore({ [koala.reducerPath]: koala.reducer, [contentful.reducerPath]: contentful.reducer, [github.reducerPath]: github.reducer, - state + state, }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() .concat(koala.middleware) .concat(contentful.middleware) .concat(github.middleware); - } + }, }); export type RootState = ReturnType; diff --git a/src/store/state.ts b/src/store/state.ts index 1fa6fa8..c9b7de7 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -1,21 +1,21 @@ -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; export enum StateMachineState { Activities, Advertisement, BoardText, Quotes, - Commits + Commits, } export type StateMachine = { - activityIndex: number, - adIndex: number, - boardMessageIndex: number, - availableQuotes: number[], - usedQuotes: number[], - quoteIndex: number, - current: StateMachineState + activityIndex: number; + adIndex: number; + boardMessageIndex: number; + availableQuotes: number[]; + usedQuotes: number[]; + quoteIndex: number; + current: StateMachineState; }; const state = createSlice({ @@ -27,7 +27,7 @@ const state = createSlice({ availableQuotes: [], usedQuotes: [], quoteIndex: 0, - current: StateMachineState.Activities + current: StateMachineState.Activities, } as StateMachine, reducers: { incrementActivityIndex(state) { @@ -65,14 +65,16 @@ const state = createSlice({ .map((_, i) => i); state.usedQuotes = []; - const availableQuoteIndex = Math.floor(Math.random() * (action.payload - 1)); + const availableQuoteIndex = Math.floor( + Math.random() * (action.payload - 1), + ); [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); }, setCurrent(state, action: PayloadAction) { state.current = action.payload; - } - } + }, + }, }); export const actions = state.actions; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index df1faf1..0775f4e 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -16,6 +16,5 @@ interface ImportMetaEnv { } interface ImportMeta { - readonly env: ImportMetaEnv + readonly env: ImportMetaEnv; } - diff --git a/tsconfig.json b/tsconfig.json index fbe5ba4..079bd74 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,9 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - "jsx": "preserve", /* Specify what JSX code is generated. */ + "jsx": "preserve" /* Specify what JSX code is generated. */, // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ @@ -19,9 +19,9 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "esnext", /* Specify what module code is generated. */ + "module": "esnext" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "bundler", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -64,11 +64,11 @@ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ diff --git a/vite.config.ts b/vite.config.ts index 4a57ae5..627a319 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,4 +4,4 @@ import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) +}); From 7b7f9b0fcc9b19d7ab7a057718abbe2371dd3406 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Sun, 1 Sep 2024 21:27:16 +0200 Subject: [PATCH 28/34] fix: add js files to lint-staged --- .lintstagedrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index baca7c7..40ac763 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,4 +1,4 @@ { - "**/*.{ts,tsx}": ["prettier . --write", "eslint . --fix", "eslint ."], + "**/*.{js,jsx,ts,tsx}": ["prettier . --write", "eslint . --fix", "eslint ."], "**/*.{json,css,md}": ["prettier . --write"] } From ae65c992b323f7682cd76c39700eb668706e072c Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Mon, 2 Sep 2024 22:18:36 +0200 Subject: [PATCH 29/34] refactor: combined adIndex and activityIndex in screen reducer --- src/App.jsx | 4 +- src/store/index.js | 100 +++++++++++++++++++++++--------------------- src/store/screen.js | 35 +++++++--------- 3 files changed, 68 insertions(+), 71 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 35415ce..2e1a629 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -58,9 +58,9 @@ function StateMachine() { switch (state.current) { case 'activities': - return ; + return ; case 'advertisement': - return ; + return ; case 'boardText': return ; case 'quotes': diff --git a/src/store/index.js b/src/store/index.js index 047e215..6e70a81 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,13 +1,14 @@ -import { configureStore } from '@reduxjs/toolkit'; +import { configureStore } from "@reduxjs/toolkit"; -import { koala, contentful, github } from './api'; +import { koala, contentful, github } from "./api"; import screen, { - incrementAdIndex, incrementActivityIndex, - resetAdIndex, resetActivityIndex, - incrementBoardMessageIndex, resetBoardMessageIndex, - setCurrent -} from './screen'; -import quotes, { resetQuotes, nextQuote } from './quotes'; + incrementCurrentIndex, + resetCurrentIndex, + incrementBoardMessageIndex, + resetBoardMessageIndex, + setCurrent, +} from "./screen"; +import quotes, { resetQuotes, nextQuote } from "./quotes"; /** * nextState is the transition function for the state machine. It @@ -20,49 +21,52 @@ import quotes, { resetQuotes, nextQuote } from './quotes'; */ export function nextState(dispatch, getState) { const params = new URLSearchParams(window.location.search); - const displayInternal = params.get('internal') === 'true'; + const displayInternal = params.get("internal") === "true"; const state = getState(); switch (state.screen.current) { - case 'activities': { - const { data: activities } = koala.endpoints.activities.select()(state); + case "activities": + { + const { data: activities } = koala.endpoints.activities.select()(state); - if (state.screen.activityIndex >= activities.length - 1) { - dispatch(setCurrent('advertisement')); - dispatch(resetActivityIndex()); - } else { - dispatch(incrementActivityIndex()); + if (state.screen.screenCurrentIndex >= activities.length - 1) { + dispatch(setCurrent("advertisement")); + dispatch(resetCurrentIndex()); + } else { + dispatch(incrementCurrentIndex()); + } } - } break; + break; - case 'advertisement': { - const { data: ads } = contentful.endpoints.ads.select()(state); + case "advertisement": + { + const { data: ads } = contentful.endpoints.ads.select()(state); - if (state.screen.adIndex >= ads.length - 1) { - dispatch(setCurrent( - displayInternal - ? 'boardText' - : 'activities' - )); - dispatch(resetAdIndex()); - } else { - dispatch(incrementAdIndex()); + if (state.screen.screenCurrentIndex >= ads.length - 1) { + dispatch(setCurrent(displayInternal ? "boardText" : "activities")); + dispatch(resetCurrentIndex()); + } else { + dispatch(incrementCurrentIndex()); + } } - } break; + break; - case 'boardText': { - const { data: messages } = contentful.endpoints.boardMessages.select()(state); + case "boardText": + { + const { data: messages } = + contentful.endpoints.boardMessages.select()(state); - if (state.screen.boardMessageIndex >= messages.length - 1) { - dispatch(resetBoardMessageIndex()); - } else { - dispatch(incrementBoardMessageIndex()); - } + if (state.screen.boardMessageIndex >= messages.length - 1) { + dispatch(resetBoardMessageIndex()); + } else { + dispatch(incrementBoardMessageIndex()); + } - dispatch(setCurrent('quotes')); - } break; + dispatch(setCurrent("quotes")); + } + break; - case 'quotes': + case "quotes": if (!state.quotes.availableQuotes.length) { const { data: quotes } = contentful.endpoints.quotes.select()(state); dispatch(resetQuotes(quotes.length)); @@ -70,15 +74,15 @@ export function nextState(dispatch, getState) { dispatch(nextQuote()); } - dispatch(setCurrent( - import.meta.env.VITE_GITHUB_REPOS - ? 'commits' - : 'activities' - )); + dispatch( + setCurrent( + import.meta.env.VITE_GITHUB_REPOS ? "commits" : "activities", + ), + ); break; - case 'commits': - dispatch(setCurrent('activities')); + case "commits": + dispatch(setCurrent("activities")); break; default: @@ -96,14 +100,14 @@ const store = configureStore({ [contentful.reducerPath]: contentful.reducer, [github.reducerPath]: github.reducer, screen, - quotes + quotes, }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() .concat(koala.middleware) .concat(contentful.middleware) .concat(github.middleware); - } + }, }); export default store; diff --git a/src/store/screen.js b/src/store/screen.js index b2ff1d7..b5bfd87 100644 --- a/src/store/screen.js +++ b/src/store/screen.js @@ -1,26 +1,18 @@ import { createSlice } from "@reduxjs/toolkit"; const screen = createSlice({ - name: 'screen', + name: "screen", initialState: { - activityIndex: 0, - adIndex: 0, + screenCurrentIndex: 0, boardMessageIndex: 0, - current: 'activities' + current: "activities", }, reducers: { - incrementActivityIndex(state) { - state.activityIndex++; + incrementCurrentIndex(state) { + state.screenCurrentIndex++; }, - resetActivityIndex(state) { - state.activityIndex = 0; - }, - - incrementAdIndex(state) { - state.adIndex++; - }, - resetAdIndex(state) { - state.adIndex = 0; + resetCurrentIndex(state) { + state.screenCurrentIndex = 0; }, incrementBoardMessageIndex(state) { @@ -32,14 +24,15 @@ const screen = createSlice({ setCurrent(state, action) { state.current = action.payload; - } - } + }, + }, }); export const { - incrementActivityIndex, resetActivityIndex, - incrementAdIndex, resetAdIndex, - incrementBoardMessageIndex, resetBoardMessageIndex, - setCurrent + incrementCurrentIndex, + resetCurrentIndex, + incrementBoardMessageIndex, + resetBoardMessageIndex, + setCurrent, } = screen.actions; export default screen.reducer; From 08a8b14703f0f405ea176425b603476481d929f0 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Thu, 5 Sep 2024 15:19:25 +0200 Subject: [PATCH 30/34] docs: added docs to quotes slice --- src/store/quotes.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/store/quotes.js b/src/store/quotes.js index 8e7d9fe..0b9b591 100644 --- a/src/store/quotes.js +++ b/src/store/quotes.js @@ -7,13 +7,20 @@ const quotes = createSlice({ quoteIndex: 0 }, reducers: { + /** + * Select a random quote from the list of available quotes and remove + * it, so that it cannot be reused again until all quotes are displayed. + */ nextQuote(state) { const hi = state.availableQuotes.length - 1; const availableQuoteIndex = Math.floor(Math.random() * hi); [state.quoteIndex] = state.availableQuotes.splice(availableQuoteIndex, 1); }, - resetQuotes(state, action) { + /** + * Reset the list of availabe quotes to a new list of indices from 0 to the number of quotes. + */ + resetAvailableQuotes(state, action) { state.availableQuotes = new Array(action.payload) .fill(0) .map((_, i) => i); @@ -23,9 +30,13 @@ const quotes = createSlice({ export const { nextQuote } = quotes.actions; +/** + * A synchronous thunk that resets the quotes state into an unused valid state. + * @param payload the total number of quotes + */ export function resetQuotes(payload) { return (dispatch, _getState) => { - dispatch(quotes.actions.resetQuotes(payload)); + dispatch(quotes.actions.resetAvailableQuotes(payload)); dispatch(quotes.actions.nextQuote()); } } From 773200a3eab361a3b2f475ab9800bbdd02a9e723 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Fri, 20 Sep 2024 13:06:23 +0200 Subject: [PATCH 31/34] refactor: changed if-else constructions into early returns --- src/components/Activities.jsx | 35 +++++++++++++++++------------------ src/components/Ad.jsx | 27 ++++++++++++++------------- src/components/Commits.jsx | 10 ++++++---- src/components/Team.jsx | 5 ++--- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/components/Activities.jsx b/src/components/Activities.jsx index e23e76b..1374e7d 100644 --- a/src/components/Activities.jsx +++ b/src/components/Activities.jsx @@ -10,25 +10,24 @@ export default function Activities({ current, onChange }) { if (current >= activities.length - 1) onChange(true); - if (activities.length > 0) { - const currentActivity = activities[current]; - return ( -
        -
          - {activities.map((activity, i) => - - )} -
        - -
        - ); - } else { + if (activities.length === 0) return <>; - } + + const currentActivity = activities[current]; + return ( +
        +
          + {activities.map((activity, i) => + + )} +
        + +
        + ); } // Explain expected types, for early error detection diff --git a/src/components/Ad.jsx b/src/components/Ad.jsx index 792519b..6623e84 100644 --- a/src/components/Ad.jsx +++ b/src/components/Ad.jsx @@ -10,30 +10,31 @@ export default function Ad({ current, onChange }) { onChange(true); const currentAd = ads[current]; - if (ads.length <= 0) { + + if (ads.length <= 0) return (
          ); - } else if (currentAd.fullscreen) { + + if (currentAd.fullscreen) return (
          ); - } else { - return ( -
          -
            -

            {currentAd.title}

            -

            {currentAd.description}

            -
          - -
          - ); - } + + return ( +
          +
            +

            {currentAd.title}

            +

            {currentAd.description}

            +
          + +
          + ); } function useAds() { diff --git a/src/components/Commits.jsx b/src/components/Commits.jsx index bc8e30d..5fa06ca 100644 --- a/src/components/Commits.jsx +++ b/src/components/Commits.jsx @@ -1,7 +1,7 @@ -import {octokit} from '../helpers/github'; -import {useQuery} from '../hooks/useQuery'; +import { octokit } from '../helpers/github'; +import { useQuery } from '../hooks/useQuery'; import Poster from './Poster'; -import {GITHUB_REPOS} from '../helpers/env.js'; +import { GITHUB_REPOS } from '../helpers/env.js'; function useCommits(owner, repo) { return useQuery(async () => { @@ -70,7 +70,9 @@ function formatDate(date) { export default function CommitsPage() { const { data: commits, isLoading } = getAllCommits(); - if (isLoading) return <> Loading... ; + + if (isLoading) + return <>Loading...; return (
          diff --git a/src/components/Team.jsx b/src/components/Team.jsx index a370b9c..ea2b2e8 100644 --- a/src/components/Team.jsx +++ b/src/components/Team.jsx @@ -12,9 +12,8 @@ export default function TeamPage() { return res.data; }); - if (isLoading) return <> Loading... ; - - console.log(members); + if (isLoading) + return <>Loading...; return (
          From 7429a986c5ef92f6a0821220ab5e5904489035fb Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Tue, 24 Sep 2024 18:52:47 +0200 Subject: [PATCH 32/34] fix: changed broken reference to quote index in StateMachine --- src/App.jsx | 3 ++- src/store/quotes.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 2e1a629..edefdaa 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -55,6 +55,7 @@ function StateMachine() { // Display the correct component based on state machine's state const state = useSelector(state => state.screen); + const quotes = useSelector(state => state.quotes); switch (state.current) { case 'activities': @@ -64,7 +65,7 @@ function StateMachine() { case 'boardText': return ; case 'quotes': - return ; + return ; case 'commits': return ; default: diff --git a/src/store/quotes.js b/src/store/quotes.js index 0b9b591..1d918cf 100644 --- a/src/store/quotes.js +++ b/src/store/quotes.js @@ -41,4 +41,4 @@ export function resetQuotes(payload) { } } -export default quotes; +export default quotes.reducer; From 94832405f144a4d8c56066f05b264551806a0df5 Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Tue, 1 Oct 2024 23:34:34 +0200 Subject: [PATCH 33/34] tooling: ran formatter --- eslint.config.js | 16 ++++++++ src/App.tsx | 9 ++--- src/components/Activities.tsx | 4 +- src/components/Activity.tsx | 14 +++---- src/components/Ad.tsx | 3 +- src/components/Commits.tsx | 4 +- src/components/Team.tsx | 4 +- src/store/api/contentful.ts | 75 ++++++++++++++++++++--------------- src/store/api/github.ts | 44 ++++++++++---------- src/store/api/index.ts | 6 +-- src/store/api/koala.ts | 34 ++++++++++------ src/store/index.ts | 58 +++++++++++++++------------ src/store/quotes.ts | 24 ++++++----- src/store/state.ts | 10 ++--- 14 files changed, 173 insertions(+), 132 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index effd87e..a7672a4 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -18,4 +18,20 @@ export default [ }, }, pluginReact.configs.flat['jsx-runtime'], + { + rules: { + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true, + }, + ], + }, + }, ]; diff --git a/src/App.tsx b/src/App.tsx index 86a84df..85047b5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,7 +31,7 @@ export default function App() { } export interface StateMachineSlideProps { - current: number + current: number; } function StateMachine() { @@ -42,8 +42,7 @@ function StateMachine() { const result = dispatch(contentful.endpoints.quotes.initiate()); result.then(({ data: quotes, isSuccess }) => { - if (isSuccess) - dispatch(resetQuotes(quotes.length)); + if (isSuccess) dispatch(resetQuotes(quotes.length)); }); return result.unsubscribe; @@ -62,8 +61,8 @@ function StateMachine() { }, [dispatch]); // Display the correct component based on state machine's state - const state = useAppSelector(state => state.screen); - const quotes = useAppSelector(state => state.quotes); + const state = useAppSelector((state) => state.screen); + const quotes = useAppSelector((state) => state.quotes); switch (state.current) { case StateMachineState.Activities: diff --git a/src/components/Activities.tsx b/src/components/Activities.tsx index 3047d78..8176db5 100644 --- a/src/components/Activities.tsx +++ b/src/components/Activities.tsx @@ -21,13 +21,13 @@ export default function Activities({ current }: StateMachineSlideProps) { return (
            - {activities.map((activity, i) => + {activities.map((activity, i) => ( - )} + ))}
          diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx index 06296a1..7f0bdca 100644 --- a/src/components/Activity.tsx +++ b/src/components/Activity.tsx @@ -11,12 +11,12 @@ function sameDay(d: Date, t: Date): boolean { } /** - * Create a format for the activity date - * - * If the date is today or the same same as the end date (supplied by the as parameter) - * then the day is not displayed. Additionally if the activity has a time, then it is - * displayed. - */ + * Create a format for the activity date + * + * If the date is today or the same same as the end date (supplied by the as parameter) + * then the day is not displayed. Additionally if the activity has a time, then it is + * displayed. + */ function createFormat(has_time: boolean, date: Date, as = new Date()): string { const format = (!sameDay(date, as) ? 'dddd DD-MM ' : '') + (has_time ? 'HH:mm' : ''); @@ -57,7 +57,7 @@ export default function Activity({
        • {name} - {participant_counter ? ` (${participant_counter})` : ""} + {participant_counter ? ` (${participant_counter})` : ''}

          {endDate && ( diff --git a/src/components/Ad.tsx b/src/components/Ad.tsx index 0ac6bc3..ec9cb66 100644 --- a/src/components/Ad.tsx +++ b/src/components/Ad.tsx @@ -18,8 +18,7 @@ export default function Ad({ current }: StateMachineSlideProps) { const currentAd = ads[current]; - if (!currentAd.poster?.fields.file?.url) - throw new Error('Ad without poster'); + if (!currentAd.poster?.fields.file?.url) throw new Error('Ad without poster'); if (currentAd.fullscreen) return ( diff --git a/src/components/Commits.tsx b/src/components/Commits.tsx index c755520..e8ddf8a 100644 --- a/src/components/Commits.tsx +++ b/src/components/Commits.tsx @@ -22,9 +22,7 @@ export default function Commits() { {commit.owner}/{commit.repo} {' by'} {commit.author} - {commit.date - ? ` (${moment(commit.date).format('LLL')})` - : ""} + {commit.date ? ` (${moment(commit.date).format('LLL')})` : ''}

        • ))} diff --git a/src/components/Team.tsx b/src/components/Team.tsx index 18ca8f0..3cf897a 100644 --- a/src/components/Team.tsx +++ b/src/components/Team.tsx @@ -18,9 +18,7 @@ export default function Team() { src={member.avatar_url} alt="member avatar" /> -
          - {member.name} -
          +
          {member.name}
          ); diff --git a/src/store/api/contentful.ts b/src/store/api/contentful.ts index e58202b..731e06c 100644 --- a/src/store/api/contentful.ts +++ b/src/store/api/contentful.ts @@ -1,4 +1,9 @@ -import { createClient, type EntryFieldTypes, type Entry, EntrySkeletonType } from 'contentful'; +import { + createClient, + type EntryFieldTypes, + type Entry, + EntrySkeletonType, +} from 'contentful'; import { createApi } from '@reduxjs/toolkit/query/react'; const client = createClient({ @@ -7,32 +12,35 @@ const client = createClient({ }); // Type aliases because the contentful types are quite verbose -type ToEntity = Entry; -type ContentTypeIdOf = T["sys"]["contentType"]["sys"]["id"]; +type ToEntity = Entry< + T, + 'WITHOUT_UNRESOLVABLE_LINKS' +>; +type ContentTypeIdOf = T['sys']['contentType']['sys']['id']; type Ad = ToEntity<{ - contentTypeId: "ads", + contentTypeId: 'ads'; fields: { - title: EntryFieldTypes.Text, - description: EntryFieldTypes.Text, - fullscreen: EntryFieldTypes.Boolean, - poster: EntryFieldTypes.AssetLink - } + title: EntryFieldTypes.Text; + description: EntryFieldTypes.Text; + fullscreen: EntryFieldTypes.Boolean; + poster: EntryFieldTypes.AssetLink; + }; }>; type BoardMessage = ToEntity<{ - contentTypeId: "board-message", + contentTypeId: 'board-message'; fields: { - message: EntryFieldTypes.Text - } + message: EntryFieldTypes.Text; + }; }>; type Quote = ToEntity<{ - contentTypeId: "quotes", + contentTypeId: 'quotes'; fields: { - person: EntryFieldTypes.Text, - text: EntryFieldTypes.Text - } + person: EntryFieldTypes.Text; + text: EntryFieldTypes.Text; + }; }>; type ContentfulEntity = Ad | BoardMessage | Quote; @@ -42,10 +50,14 @@ type ContentfulEntity = Ad | BoardMessage | Quote; * specifies the content_type of the thing it requests and these * entries are searched via the contentful API. */ -async function contentfulBaseQuery(content_type: ContentTypeIdOf) { +async function contentfulBaseQuery( + content_type: ContentTypeIdOf, +) { try { - const res = await client.withoutUnresolvableLinks.getEntries({ content_type }); - return { data: res.items.map(entry => entry.fields) }; + const res = await client.withoutUnresolvableLinks.getEntries({ + content_type, + }); + return { data: res.items.map((entry) => entry.fields) }; } catch (error) { return { error }; } @@ -54,21 +66,18 @@ async function contentfulBaseQuery(content_type: ContentTypeIdOf ({ - ads: build.query({ - query: () => "ads" + endpoints: (build) => ({ + ads: build.query({ + query: () => 'ads', + }), + boardMessages: build.query({ + query: () => 'board-message', }), - boardMessages: build.query({ - query: () => "board-message" + quotes: build.query({ + query: () => 'quotes', }), - quotes: build.query({ - query: () => "quotes" - }) - }) + }), }); -export const { - useAdsQuery, - useBoardMessagesQuery, - useQuotesQuery -} = contentful; +export const { useAdsQuery, useBoardMessagesQuery, useQuotesQuery } = + contentful; diff --git a/src/store/api/github.ts b/src/store/api/github.ts index 5e51bc9..bfa94e8 100644 --- a/src/store/api/github.ts +++ b/src/store/api/github.ts @@ -14,8 +14,8 @@ type Commit = { }; type Member = { - avatar_url: string, - name: string + avatar_url: string; + name: string; }; /** @@ -24,17 +24,20 @@ type Member = { */ async function listCommits(owner: string, repo: string): Promise { const { data: commits } = await octokit.rest.repos.listCommits({ - owner, repo, per_page: 4, + owner, + repo, + per_page: 4, }); return commits - .filter(commit => !!commit.commit.committer?.date) + .filter((commit) => !!commit.commit.committer?.date) .map(({ commit, sha }) => ({ id: sha, message: commit.message, - author: commit.author?.name ?? commit.author?.email ?? "", + author: commit.author?.name ?? commit.author?.email ?? '', date: new Date(commit.committer!.date!).getTime(), - repo, owner + repo, + owner, })); } @@ -44,18 +47,19 @@ async function listCommits(owner: string, repo: string): Promise { async function allCommits() { try { const commitsPerRepo = await Promise.allSettled( - import.meta.env.VITE_GITHUB_REPOS - .split(' ') - .map(name => { - const [owner, repo] = name.split('/'); - return listCommits(owner, repo); - })); + import.meta.env.VITE_GITHUB_REPOS.split(' ').map((name) => { + const [owner, repo] = name.split('/'); + return listCommits(owner, repo); + }), + ); return { data: commitsPerRepo - .flatMap(commits => commits.status === "fulfilled" ? commits.value : []) + .flatMap((commits) => + commits.status === 'fulfilled' ? commits.value : [], + ) .filter((commit): commit is Commit & { date: number } => !!commit.date) - .sort((a, b) => b.date - a.date) + .sort((a, b) => b.date - a.date), }; } catch (error) { return { error }; @@ -73,10 +77,10 @@ async function allMembers() { }); return { - data: res.data.map(member => ({ + data: res.data.map((member) => ({ name: member.name || member.login, - avatar_url: member.avatar_url - })) as Member[] + avatar_url: member.avatar_url, + })) as Member[], }; } catch (error) { return { error }; @@ -92,10 +96,10 @@ async function allMembers() { export const github = createApi({ reducerPath: 'github', baseQuery: fakeBaseQuery(), - endpoints: build => ({ + endpoints: (build) => ({ allCommits: build.query({ queryFn: allCommits }), - members: build.query({ queryFn: allMembers }) - }) + members: build.query({ queryFn: allMembers }), + }), }); export const { useAllCommitsQuery, useMembersQuery } = github; diff --git a/src/store/api/index.ts b/src/store/api/index.ts index 6eb9891..043e747 100644 --- a/src/store/api/index.ts +++ b/src/store/api/index.ts @@ -1,3 +1,3 @@ -export * from "./contentful"; -export * from "./koala"; -export * from "./github"; +export * from './contentful'; +export * from './koala'; +export * from './github'; diff --git a/src/store/api/koala.ts b/src/store/api/koala.ts index 8f9553b..f1e7f67 100644 --- a/src/store/api/koala.ts +++ b/src/store/api/koala.ts @@ -9,8 +9,8 @@ type ResponseActivity = { }; export type Activity = ResponseActivity & { - has_start_time: boolean, - has_end_time: boolean + has_start_time: boolean; + has_end_time: boolean; }; /** @@ -27,17 +27,25 @@ export const koala = createApi({ endpoints: (build) => ({ activities: build.query({ query: () => 'activities', - transformResponse: (result: ResponseActivity[]): Activity[] => result - .filter(act => act.poster) - .map(activity => ({ - ...activity, - has_start_time: activity.start_date.indexOf('T') > -1, - has_end_time: activity.end_date && activity.end_date.indexOf('T') > -1, - } as Activity)) - .sort((a, b) => - new Date(a.start_date).getTime() - new Date(b.start_date).getTime()) - }) - }) + transformResponse: (result: ResponseActivity[]): Activity[] => + result + .filter((act) => act.poster) + .map( + (activity) => + ({ + ...activity, + has_start_time: activity.start_date.indexOf('T') > -1, + has_end_time: + activity.end_date && activity.end_date.indexOf('T') > -1, + }) as Activity, + ) + .sort( + (a, b) => + new Date(a.start_date).getTime() - + new Date(b.start_date).getTime(), + ), + }), + }), }); export const { useActivitiesQuery } = koala; diff --git a/src/store/index.ts b/src/store/index.ts index 423e50d..5ef0852 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -7,10 +7,10 @@ import screen, { incrementCurrentIndex, resetBoardMessageIndex, incrementBoardMessageIndex, - setCurrent + setCurrent, } from './state'; import { useDispatch, useSelector } from 'react-redux'; -import quotes, { nextQuote, resetQuotes } from "./quotes"; +import quotes, { nextQuote, resetQuotes } from './quotes'; /** * nextState is the transition function for the state machine. It @@ -30,18 +30,20 @@ export const nextState: ThunkAction = ( const state = getState(); switch (state.screen.current) { - case StateMachineState.Activities: { - const { data: activities, isSuccess } = koala.endpoints.activities.select()(state); + case StateMachineState.Activities: + { + const { data: activities, isSuccess } = + koala.endpoints.activities.select()(state); - if (!isSuccess) throw new Error(''); + if (!isSuccess) throw new Error(''); - if (state.screen.screenCurrentIndex >= activities.length - 1) { - dispatch(resetCurrentIndex()); - dispatch(setCurrent(StateMachineState.Advertisement)); - } else { - dispatch(incrementCurrentIndex()); + if (state.screen.screenCurrentIndex >= activities.length - 1) { + dispatch(resetCurrentIndex()); + dispatch(setCurrent(StateMachineState.Advertisement)); + } else { + dispatch(incrementCurrentIndex()); + } } - } break; case StateMachineState.Advertisement: @@ -53,11 +55,13 @@ export const nextState: ThunkAction = ( if (state.screen.screenCurrentIndex >= ads.length - 1) { dispatch(resetCurrentIndex()); - dispatch(setCurrent( - displayInternal - ? StateMachineState.BoardText - : StateMachineState.Activities - )); + dispatch( + setCurrent( + displayInternal + ? StateMachineState.BoardText + : StateMachineState.Activities, + ), + ); } else { dispatch(incrementCurrentIndex()); } @@ -79,23 +83,25 @@ export const nextState: ThunkAction = ( } dispatch(setCurrent(StateMachineState.Quotes)); - } break; + } + break; case StateMachineState.Quotes: if (!state.quotes.availableQuotes.length) { - const { data: quotes, isSuccess } = contentful.endpoints.quotes.select()(state); + const { data: quotes, isSuccess } = + contentful.endpoints.quotes.select()(state); - if (isSuccess) - dispatch(resetQuotes(quotes.length)); + if (isSuccess) dispatch(resetQuotes(quotes.length)); } else { dispatch(nextQuote()); } - dispatch(setCurrent( - import.meta.env.VITE_GITHUB_REPOS - ? StateMachineState.Commits - : StateMachineState.Activities, - ), + dispatch( + setCurrent( + import.meta.env.VITE_GITHUB_REPOS + ? StateMachineState.Commits + : StateMachineState.Activities, + ), ); break; @@ -115,7 +121,7 @@ const store = configureStore({ [contentful.reducerPath]: contentful.reducer, [github.reducerPath]: github.reducer, screen, - quotes + quotes, }, middleware(getDefaultMiddleware) { return getDefaultMiddleware() diff --git a/src/store/quotes.ts b/src/store/quotes.ts index a05c17c..2a1f4d7 100644 --- a/src/store/quotes.ts +++ b/src/store/quotes.ts @@ -1,16 +1,21 @@ -import { PayloadAction, createSlice, ThunkAction, UnknownAction } from "@reduxjs/toolkit"; -import { type RootState } from "."; +import { + PayloadAction, + createSlice, + ThunkAction, + UnknownAction, +} from '@reduxjs/toolkit'; +import { type RootState } from '.'; type QuotesState = { - availableQuotes: number[], - quoteIndex: number + availableQuotes: number[]; + quoteIndex: number; }; const quotes = createSlice({ name: 'quotes', initialState: { availableQuotes: [], - quoteIndex: 0 + quoteIndex: 0, } as QuotesState, reducers: { /** @@ -30,8 +35,8 @@ const quotes = createSlice({ state.availableQuotes = new Array(action.payload) .fill(0) .map((_, i) => i); - } - } + }, + }, }); export const { nextQuote } = quotes.actions; @@ -40,12 +45,11 @@ export const { nextQuote } = quotes.actions; * A synchronous thunk that resets the quotes state into an unused valid state. * @param payload the total number of quotes */ -export const resetQuotes = (payload: number): ThunkAction => +export const resetQuotes = + (payload: number): ThunkAction => (dispatch, _getState) => { dispatch(quotes.actions.resetAvailableQuotes(payload)); dispatch(quotes.actions.nextQuote()); }; - export default quotes.reducer; - diff --git a/src/store/state.ts b/src/store/state.ts index 4150e05..6dc745b 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -9,17 +9,17 @@ export enum StateMachineState { } export type StateMachine = { - screenCurrentIndex: number, - boardMessageIndex: number, - current: StateMachineState + screenCurrentIndex: number; + boardMessageIndex: number; + current: StateMachineState; }; const screen = createSlice({ - name: "screen", + name: 'screen', initialState: { screenCurrentIndex: 0, boardMessageIndex: 0, - current: StateMachineState.Activities + current: StateMachineState.Activities, } as StateMachine, reducers: { incrementCurrentIndex(state) { From c409567fff53f3f08485e0b9de8bea072e6f951a Mon Sep 17 00:00:00 2001 From: Job Vonk Date: Wed, 9 Oct 2024 21:01:54 +0200 Subject: [PATCH 34/34] fix: change activities key into id --- src/components/Activities.tsx | 4 ++-- src/store/api/koala.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Activities.tsx b/src/components/Activities.tsx index 8176db5..56554d8 100644 --- a/src/components/Activities.tsx +++ b/src/components/Activities.tsx @@ -21,9 +21,9 @@ export default function Activities({ current }: StateMachineSlideProps) { return (
            - {activities.map((activity, i) => ( + {activities.map((activity) => ( diff --git a/src/store/api/koala.ts b/src/store/api/koala.ts index f1e7f67..d3ed5e7 100644 --- a/src/store/api/koala.ts +++ b/src/store/api/koala.ts @@ -1,6 +1,7 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; type ResponseActivity = { + id: string; name: string; start_date: string; end_date: string | null;