diff --git a/examples/accident-counter/index.html b/examples/accident-counter/index.html index 1352901..7c29042 100644 --- a/examples/accident-counter/index.html +++ b/examples/accident-counter/index.html @@ -3,7 +3,7 @@ Accident Counter - - -
+ +
diff --git a/examples/accident-counter/package.json b/examples/accident-counter/package.json index ecee833..af2089a 100644 --- a/examples/accident-counter/package.json +++ b/examples/accident-counter/package.json @@ -4,8 +4,9 @@ "main": "src/index.js", "type": "module", "scripts": { - "start": "vitest --ui", - "test": "vitest" + "start": "vite dev", + "test": "vitest", + "test:ui": "vitest --ui" }, "repository": { "type": "git", @@ -18,11 +19,12 @@ }, "homepage": "https://github.com/stevekinney/testing-javascript#readme", "devDependencies": { - "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e", "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^16.0.1", "@types/react": "^18.3.6", "@types/react-dom": "^18.3.0", + "@types/testing-library__jest-dom": "^5.14.9", "@vitejs/plugin-react": "^4.3.1", "@vitest/ui": "^2.1.1", "react": "^18.3.1", diff --git a/examples/accident-counter/postcss.config.js b/examples/accident-counter/postcss.config.js deleted file mode 100644 index a9abeeb..0000000 --- a/examples/accident-counter/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -export default { - plugins: { - '@tailwindcss/nesting': {}, - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/examples/accident-counter/src/counter.test.jsx b/examples/accident-counter/src/counter.test.jsx new file mode 100644 index 0000000..5392d94 --- /dev/null +++ b/examples/accident-counter/src/counter.test.jsx @@ -0,0 +1,85 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { Counter } from './counter'; + +import '@testing-library/jest-dom'; + +describe('Counter Component', () => { + beforeEach(() => { + render(); + }); + + it('renders with an initial count of 0', () => { + const countElement = screen.getByTestId('counter-count'); + expect(countElement).toHaveTextContent('0'); + }); + + it('displays "days" when the count is 0', () => { + const unitElement = screen.getByTestId('counter-unit'); + expect(unitElement).toHaveTextContent('days'); + }); + + it('increments the count when the "Increment" button is clicked', async () => { + const incrementButton = screen.getByText('Increment'); + await userEvent.click(incrementButton); // Using userEvent for a real click event + + const countElement = screen.getByTestId('counter-count'); + expect(countElement).toHaveTextContent('1'); + }); + + it('displays "day" when the count is 1', async () => { + const incrementButton = screen.getByText('Increment'); + await userEvent.click(incrementButton); // Increment the count + + const unitElement = screen.getByTestId('counter-unit'); + expect(unitElement).toHaveTextContent('day'); + }); + + it('decrements the count when the "Decrement" button is clicked', async () => { + const incrementButton = screen.getByText('Increment'); + const decrementButton = screen.getByText('Decrement'); + + await userEvent.click(incrementButton); // Increment first + await userEvent.click(decrementButton); // Then decrement + + const countElement = screen.getByTestId('counter-count'); + expect(countElement).toHaveTextContent('0'); + }); + + it('does not allow decrementing below 0', async () => { + const decrementButton = screen.getByText('Decrement'); + await userEvent.click(decrementButton); // Should not decrement below 0 + + const countElement = screen.getByTestId('counter-count'); + expect(countElement).toHaveTextContent('0'); + }); + + it('resets the count when the "Reset" button is clicked', async () => { + const incrementButton = screen.getByText('Increment'); + const resetButton = screen.getByText('Reset'); + + await userEvent.click(incrementButton); // Increment first + await userEvent.click(resetButton); // Then reset + + const countElement = screen.getByTestId('counter-count'); + expect(countElement).toHaveTextContent('0'); + }); + + it('disables the "Decrement" and "Reset" buttons when the count is 0', () => { + const decrementButton = screen.getByText('Decrement'); + const resetButton = screen.getByText('Reset'); + + expect(decrementButton).toBeDisabled(); + expect(resetButton).toBeDisabled(); + }); + + it('updates the document title based on the count', async () => { + const incrementButton = screen.getByText('Increment'); + await userEvent.click(incrementButton); + + expect(document.title).toBe('1 day'); + + await userEvent.click(incrementButton); + expect(document.title).toBe('2 days'); + }); +}); \ No newline at end of file diff --git a/examples/accident-counter/src/counter.tsx b/examples/accident-counter/src/counter.tsx index 1b7ff46..79351e8 100644 --- a/examples/accident-counter/src/counter.tsx +++ b/examples/accident-counter/src/counter.tsx @@ -1,4 +1,4 @@ -import React, { useReducer, useEffect } from 'react'; +import { useReducer, useEffect } from 'react'; import { reducer } from './reducer'; export const Counter = () => { @@ -12,12 +12,12 @@ export const Counter = () => { return (
-
+
{state.count}

- {unit} since the last - accident. + {unit} since the last + JavaScript-related accident.

diff --git a/examples/accident-counter/src/reducer.test.js b/examples/accident-counter/src/reducer.test.js index 40a9177..3505282 100644 --- a/examples/accident-counter/src/reducer.test.js +++ b/examples/accident-counter/src/reducer.test.js @@ -1,4 +1,3 @@ -import { describe, it, expect } from 'vitest'; import { reducer } from './reducer'; describe('reducer', () => { diff --git a/examples/accident-counter/tailwind.config.js b/examples/accident-counter/tailwind.config.js deleted file mode 100644 index e0133e3..0000000 --- a/examples/accident-counter/tailwind.config.js +++ /dev/null @@ -1,13 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./**/*.{html,js,jsx,ts,tsx}'], - theme: { - extend: { - container: { - center: true, - padding: '1rem', - }, - }, - }, - plugins: [], -}; diff --git a/examples/accident-counter/vite.config.ts b/examples/accident-counter/vite.config.ts index 0466183..571846b 100644 --- a/examples/accident-counter/vite.config.ts +++ b/examples/accident-counter/vite.config.ts @@ -1,6 +1,9 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +import { css } from 'css-configuration'; + export default defineConfig({ plugins: [react()], + css, }); diff --git a/examples/accident-counter/vitest.config.js b/examples/accident-counter/vitest.config.js index eca96b3..98845e1 100644 --- a/examples/accident-counter/vitest.config.js +++ b/examples/accident-counter/vitest.config.js @@ -4,5 +4,6 @@ import config from './vite.config'; export default mergeConfig(config, { test: { environment: 'happy-dom', + globals: true, }, }); diff --git a/examples/calculator-reducer/README.md b/examples/calculator-reducer/README.md deleted file mode 100644 index 39740c6..0000000 --- a/examples/calculator-reducer/README.md +++ /dev/null @@ -1,393 +0,0 @@ -# Calculator Reducer - -## Breakdown of the Code - -## 1. **JSDoc Type Imports** - -```javascript -/** - * @typedef {import('./types.js').CalculatorState} CalculatorState - * @typedef {import('./types.js').CalculatorAction} CalculatorAction - */ -``` - -- These lines use **JSDoc** to import types from `types.js`. -- `CalculatorState` represents the shape of the calculator's state, and `CalculatorAction` represents the shape of an action dispatched to the reducer. -- These types provide type checking and documentation within the IDE, even though the code is in plain JavaScript. - -## 2. **Initial State** - -```javascript -/** - * The initial state for the calculator. - * @type {CalculatorState} - */ -const initialState = { - currentValue: '0', // Current input or result - previousValue: null, // Previous value before an operation - operator: null, // The operator (+, -, *, /) - waitingForOperand: false, // Tracks if we're waiting for the next operand -}; -``` - -- `initialState` defines the starting values for the calculator. - - `currentValue`: Represents the value currently being input or the last calculated result. It starts as `'0'`. - - `previousValue`: Holds the value before an operator is pressed. Initially `null`. - - `operator`: Stores the operator (`+`, `-`, `*`, `/`) currently in use. It starts as `null`. - - `waitingForOperand`: A boolean flag that indicates if the calculator is waiting for the next operand after an operator is pressed. - -## 3. **Reducer Function** - -```javascript -/** - * A reducer function for the calculator state. - * @param {CalculatorState} state - * @param {CalculatorAction} action - * @returns {CalculatorState} - */ -export function calculatorReducer(state = initialState, action) { -``` - -- This is a **reducer function** that takes the current state and an action, and returns the new state based on the type of the action. -- **Default value**: If no state is provided (e.g., at initialization), it uses `initialState`. - -## 4. **Handling Action Types** - -```javascript -switch (action.type) { - case 'DIGIT': -``` - -- The `switch` statement handles different `action.type` values. - -### 4.1 **Handling `'DIGIT'` Action** - -```javascript -case 'DIGIT': - if (state.waitingForOperand) { - return { - ...state, - currentValue: action.payload, - waitingForOperand: false, - }; - } - return { - ...state, - currentValue: - state.currentValue === '0' - ? action.payload - : state.currentValue + action.payload, - }; -``` - -- **When a digit is pressed** (`'DIGIT'` action): - - If the calculator is waiting for the next operand (`waitingForOperand` is `true`), it replaces the `currentValue` with the digit and resets the `waitingForOperand` flag. - - Otherwise, it appends the digit to the `currentValue`. If `currentValue` is `'0'`, it replaces it with the new digit. - -### 4.2 **Handling `'OPERATOR'` Action** - -```javascript -case 'OPERATOR': - if (state.operator && state.previousValue !== null) { - const result = evaluate(state); - return { - ...state, - previousValue: result, - currentValue: '0', - operator: action.payload, - waitingForOperand: true, - }; - } - return { - ...state, - previousValue: state.currentValue, - operator: action.payload, - waitingForOperand: true, - }; -``` - -- **When an operator is pressed** (`'OPERATOR'` action): - - If there's already a `previousValue` and an operator is set, the function evaluates the current expression and stores the result as the `previousValue`. - - Otherwise, it sets the `currentValue` as the `previousValue` and assigns the operator from `action.payload`. - - It also sets `waitingForOperand` to `true` to signal that the calculator is waiting for the next number to be entered. - -### 4.3 **Handling `'EQUALS'` Action** - -```javascript -case 'EQUALS': - if (state.operator && state.previousValue !== null) { - const result = evaluate(state); - return { - ...state, - currentValue: result, - previousValue: null, - operator: null, - waitingForOperand: false, - }; - } - return state; -``` - -- **When the equals button is pressed** (`'EQUALS'` action): - - If an operator and a `previousValue` are set, it evaluates the current expression and updates `currentValue` with the result. It also clears the operator and `previousValue`. - - If the necessary data for evaluation is not present, it simply returns the current state unchanged. - -### 4.4 **Handling `'CLEAR'` Action** - -```javascript -case 'CLEAR': - return initialState; -``` - -- **When the clear button is pressed** (`'CLEAR'` action): - - It resets the calculator state to the `initialState`. - -### 4.5 **Default Case** - -```javascript -default: - return state; -``` - -- If an action type is not recognized, the reducer returns the current state without any changes. - -## 5. **Evaluate Function** - -```javascript -function evaluate({ currentValue, previousValue, operator }) { - const prev = parseFloat(previousValue); - const current = parseFloat(currentValue); - - switch (operator) { - case '+': - return (prev + current).toString(); - case '-': - return (prev - current).toString(); - case '*': - return (prev * current).toString(); - case '/': - return current !== 0 ? (prev / current).toString() : 'Error'; - default: - return currentValue; - } -} -``` - -- The `evaluate` function takes `currentValue`, `previousValue`, and `operator` to perform the calculation. -- **Steps**: - 1. It converts the `previousValue` and `currentValue` from strings to numbers using `parseFloat`. - 2. Based on the operator, it performs the corresponding arithmetic operation (`+`, `-`, `*`, `/`). - 3. **Divide by zero handling**: If the operation is division (`/`) and `currentValue` is `0`, it returns `'Error'` to avoid division by zero. - 4. The result of the operation is returned as a string. - -## Summary - -- The `calculatorReducer` function handles the state changes of a calculator by interpreting different actions (`'DIGIT'`, `'OPERATOR'`, `'EQUALS'`, `'CLEAR'`). -- The `evaluate` helper function performs the arithmetic operations when required. -- The state is updated incrementally as the user presses digits, operators, and other controls, making it suitable for a basic calculator UI. - -## Breakdown of the Tests - -### 1. **Imports and Initial Setup** - -```javascript -import { describe, it, expect } from 'vitest'; -import { calculatorReducer } from './calculator.js'; // Assume this is the path to the reducer -``` - -- **Vitest** is being imported for testing, using `describe` to group the test cases, `it` for individual test cases, and `expect` for assertions. -- The `calculatorReducer` is imported from a file called `calculator.js` for testing. -- The `CalculatorState` and `CalculatorAction` types are imported using **JSDoc** for static type checking. - -### 2. **Initial State** - -```javascript -const initialState = { - currentValue: '0', - previousValue: null, - operator: null, - waitingForOperand: false, -}; -``` - -- This defines the `initialState`, representing the calculator's default state when no input has been provided yet. - -### 3. **Test: Handling Digit Input** - -```javascript -it('should handle a digit input', () => { - const action = { type: 'DIGIT', payload: '5' }; - const newState = calculatorReducer(initialState, action); - expect(newState.currentValue).toBe('5'); -}); -``` - -- **What it does**: Tests that when the `'DIGIT'` action is dispatched with the digit `'5'`, the `currentValue` is updated to `'5'`. -- **Why**: To ensure the reducer correctly updates the state with the inputted digit. - -### 4. **Test: Appending Digits to Current Input** - -```javascript -it('should append digits to the current input', () => { - const firstAction = { type: 'DIGIT', payload: '5' }; - const secondAction = { type: 'DIGIT', payload: '3' }; - - let state = calculatorReducer(initialState, firstAction); - state = calculatorReducer(state, secondAction); - - expect(state.currentValue).toBe('53'); -}); -``` - -- **What it does**: Tests appending digits `'5'` and `'3'` to form `'53'`. -- **Why**: To verify that digits are appended to `currentValue` correctly and are not overwritten when a new digit is added. - -### 5. **Test: Handling Operator Input** - -```javascript -it('should handle operator input', () => { - const stateWithDigit = { ...initialState, currentValue: '10' }; - const action = { type: 'OPERATOR', payload: '+' }; - - const newState = calculatorReducer(stateWithDigit, action); - - expect(newState.previousValue).toBe('10'); - expect(newState.operator).toBe('+'); - expect(newState.waitingForOperand).toBe(true); -}); -``` - -- **What it does**: Tests pressing an operator (`'+'`), ensuring the state updates with the current value as `previousValue`, sets the operator, and sets `waitingForOperand` to `true`. -- **Why**: To confirm that when an operator is pressed, the reducer correctly prepares for the next operand. - -### 6. **Test: Performing Addition** - -```javascript -it('should perform addition when equals is pressed', () => { - const stateWithOperator = { - currentValue: '5', - previousValue: '10', - operator: '+', - waitingForOperand: false, - }; - - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('15'); -}); -``` - -- **What it does**: Tests the `'EQUALS'` action when the operator is `'+'`, and the values are `10` and `5`. The result should be `'15'`. -- **Why**: To verify that the addition is correctly performed when the equals button is pressed. - -### 7. **Test: Performing Subtraction** - -```javascript -it('should perform subtraction when equals is pressed', () => { - const stateWithOperator = { - currentValue: '3', - previousValue: '8', - operator: '-', - waitingForOperand: false, - }; - - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('5'); -}); -``` - -- **What it does**: Tests subtraction (`'8 - 3'`) when the equals button is pressed, with the result being `'5'`. -- **Why**: To confirm that subtraction works correctly with the equals action. - -### 8. **Test: Performing Multiplication** - -```javascript -it('should perform multiplication when equals is pressed', () => { - const stateWithOperator = { - currentValue: '4', - previousValue: '6', - operator: '*', - waitingForOperand: false, - }; - - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('24'); -}); -``` - -- **What it does**: Tests multiplication (`'6 * 4'`) when the equals button is pressed, expecting the result `'24'`. -- **Why**: To ensure the multiplication operation is working correctly. - -### 9. **Test: Performing Division** - -```javascript -it('should perform division when equals is pressed', () => { - const stateWithOperator = { - currentValue: '2', - previousValue: '10', - operator: '/', - waitingForOperand: false, - }; - - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('5'); -}); -``` - -- **What it does**: Tests division (`'10 / 2'`) with the expected result of `'5'`. -- **Why**: To confirm that division is handled properly. - -### 10. **Test: Division by Zero** - -```javascript -it('should return "Error" when dividing by zero', () => { - const stateWithOperator = { - currentValue: '0', - previousValue: '10', - operator: '/', - waitingForOperand: false, - }; - - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('Error'); -}); -``` - -- **What it does**: Tests dividing by zero (`'10 / 0'`) and expects the result to be `'Error'`. -- **Why**: To ensure the reducer correctly handles the edge case of division by zero, avoiding invalid arithmetic results. - -### 11. **Test: Clearing the Calculator State** - -```javascript -it('should reset the state when "CLEAR" action is dispatched', () => { - const stateWithValue = { - currentValue: '25', - previousValue: '5', - operator: '+', - waitingForOperand: true, - }; - - const action = { type: 'CLEAR' }; - const newState = calculatorReducer(stateWithValue, action); - - expect(newState).toEqual(initialState); -}); -``` - -- **What it does**: Tests that the `'CLEAR'` action resets the state back to its initial values (`initialState`). -- **Why**: To verify that pressing the clear button resets the entire calculator back to its default state. - -## Summary - -- Each test case ensures that the **calculatorReducer** handles individual actions correctly. -- The tests cover all possible scenarios, including handling digits, appending digits, performing operations, evaluating expressions, handling edge cases like division by zero, and resetting the state. -- This ensures that the calculator works as expected in all cases and prevents regressions when changes are made to the code. diff --git a/examples/calculator-reducer/src/calculator.js b/examples/calculator-reducer/src/calculator.js deleted file mode 100644 index 52b2b84..0000000 --- a/examples/calculator-reducer/src/calculator.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @typedef {import('./types.js').CalculatorState} CalculatorState - * @typedef {import('./types.js').CalculatorAction} CalculatorAction - */ - -/** - * The initial state for the calculator. - * @type {CalculatorState} - */ -const initialState = { - currentValue: '0', // Current input or result - previousValue: null, // Previous value before an operation - operator: null, // The operator (+, -, *, /) - waitingForOperand: false, // Tracks if we're waiting for the next operand -}; - -/** - * A reducer function for the calculator state. - * @param {CalculatorState} state - * @param {CalculatorAction} action - * @returns {CalculatorState} - */ -export function calculatorReducer(state = initialState, action) { - switch (action.type) { - case 'DIGIT': - if (state.waitingForOperand) { - return { - ...state, - currentValue: action.payload, // Start a new value for next operand - waitingForOperand: false, - }; - } - // Append the digit - return { - ...state, - currentValue: - state.currentValue === '0' - ? action.payload - : state.currentValue + action.payload, - }; - - case 'OPERATOR': - // When an operator is pressed, store the current value and operator - if (state.operator && state.previousValue !== null) { - // If there's an operator already, evaluate the expression - const result = evaluate(state); - return { - ...state, - previousValue: result, - currentValue: '0', - operator: action.payload, - waitingForOperand: true, - }; - } - return { - ...state, - previousValue: state.currentValue, - operator: action.payload, - waitingForOperand: true, - }; - - case 'EQUALS': - // Perform the operation when '=' is pressed - if (state.operator && state.previousValue !== null) { - const result = evaluate(state); - return { - ...state, - currentValue: result, - previousValue: null, - operator: null, - waitingForOperand: false, - }; - } - return state; - - case 'CLEAR': - // Clear the calculator state - return initialState; - - default: - return state; - } -} - -function evaluate({ currentValue, previousValue, operator }) { - const prev = parseFloat(previousValue); - const current = parseFloat(currentValue); - - switch (operator) { - case '+': - return (prev + current).toString(); - case '-': - return (prev - current).toString(); - case '*': - return (prev * current).toString(); - case '/': - return current !== 0 ? (prev / current).toString() : 'Error'; - default: - return currentValue; - } -} diff --git a/examples/calculator-reducer/src/calculator.test.js b/examples/calculator-reducer/src/calculator.test.js deleted file mode 100644 index 1db360b..0000000 --- a/examples/calculator-reducer/src/calculator.test.js +++ /dev/null @@ -1,146 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { calculatorReducer } from './calculator.js'; // Assume this is the path to the reducer - -/** - * @typedef {import('./types.js').CalculatorState} CalculatorState - * @typedef {import('./types.js').CalculatorAction} CalculatorAction - */ - -/** @type {import('./types.js').CalculatorState} */ -const initialState = { - currentValue: '0', - previousValue: null, - operator: null, - waitingForOperand: false, -}; - -describe('calculatorReducer', () => { - it('should handle a digit input', () => { - /** @type {CalculatorAction} */ - const action = { type: 'DIGIT', payload: '5' }; - - const newState = calculatorReducer(initialState, action); - - expect(newState.currentValue).toBe('5'); - }); - - it('should append digits to the current input', () => { - /** @type {CalculatorAction} */ - const firstAction = { type: 'DIGIT', payload: '5' }; - /** @type {CalculatorAction} */ - const secondAction = { type: 'DIGIT', payload: '3' }; - - let state = calculatorReducer(initialState, firstAction); - state = calculatorReducer(state, secondAction); - - expect(state.currentValue).toBe('53'); - }); - - it('should handle operator input', () => { - const stateWithDigit = { ...initialState, currentValue: '10' }; - /** @type {CalculatorAction} */ - const action = { type: 'OPERATOR', payload: '+' }; - - const newState = calculatorReducer(stateWithDigit, action); - - expect(newState.previousValue).toBe('10'); - expect(newState.operator).toBe('+'); - expect(newState.waitingForOperand).toBe(true); - }); - - it('should perform addition when equals is pressed', () => { - /** @type {CalculatorState} */ - const stateWithOperator = { - currentValue: '5', - previousValue: '10', - operator: '+', - waitingForOperand: false, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('15'); - }); - - it('should perform subtraction when equals is pressed', () => { - /** @type {CalculatorState} */ - const stateWithOperator = { - currentValue: '3', - previousValue: '8', - operator: '-', - waitingForOperand: false, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('5'); - }); - - it('should perform multiplication when equals is pressed', () => { - /** @type {CalculatorState} */ - const stateWithOperator = { - currentValue: '4', - previousValue: '6', - operator: '*', - waitingForOperand: false, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('24'); - }); - - it('should perform division when equals is pressed', () => { - /** @type {CalculatorState} */ - const stateWithOperator = { - currentValue: '2', - previousValue: '10', - operator: '/', - waitingForOperand: false, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('5'); - }); - - it('should return "Error" when dividing by zero', () => { - /** @type {CalculatorState} */ - const stateWithOperator = { - currentValue: '0', - previousValue: '10', - operator: '/', - waitingForOperand: false, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'EQUALS' }; - const newState = calculatorReducer(stateWithOperator, action); - - expect(newState.currentValue).toBe('Error'); - }); - - it('should reset the state when "CLEAR" action is dispatched', () => { - /** @type {CalculatorState} */ - const stateWithValue = { - currentValue: '25', - previousValue: '5', - operator: '+', - waitingForOperand: true, - }; - - /** @type {CalculatorAction} */ - const action = { type: 'CLEAR' }; - const newState = calculatorReducer(stateWithValue, action); - - expect(newState).toEqual(initialState); - }); -}); diff --git a/examples/calculator-reducer/src/types.ts b/examples/calculator-reducer/src/types.ts deleted file mode 100644 index e586c5e..0000000 --- a/examples/calculator-reducer/src/types.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type CalculatorState = { - currentValue: string; - previousValue: string | null; - operator: Operator | null; - waitingForOperand: boolean; -}; - -export type CalculatorAction = - | DigitAction - | OperatorAction - | EqualsAction - | ClearAction; - -export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; -export type Operator = '+' | '-' | '*' | '/'; - -export type ActionType = 'DIGIT' | 'OPERATOR' | 'EQUALS' | 'CLEAR'; - -type DigitAction = { - type: 'DIGIT'; - payload: Digit; -}; - -type OperatorAction = { - type: 'OPERATOR'; - payload: Operator; -}; - -type EqualsAction = { - type: 'EQUALS'; - payload?: never; -}; - -type ClearAction = { - type: 'CLEAR'; - payload?: never; -}; diff --git a/examples/calculator-reducer/vitest.config.js b/examples/calculator-reducer/vitest.config.js deleted file mode 100644 index 80d8ccf..0000000 --- a/examples/calculator-reducer/vitest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - environment: 'happy-dom', // Use jsdom environment for browser testing - }, -}); diff --git a/examples/calculator/postcss.config.js b/examples/calculator/postcss.config.js deleted file mode 100644 index a9abeeb..0000000 --- a/examples/calculator/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -export default { - plugins: { - '@tailwindcss/nesting': {}, - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/examples/calculator/setup-tests.js b/examples/calculator/setup-tests.js index da6ae0e..7b0828b 100644 --- a/examples/calculator/setup-tests.js +++ b/examples/calculator/setup-tests.js @@ -1 +1 @@ -import '@testing-library/jest-dom'; // Provides custom matchers +import '@testing-library/jest-dom'; diff --git a/examples/calculator/tailwind.config.js b/examples/calculator/tailwind.config.js deleted file mode 100644 index 30101cf..0000000 --- a/examples/calculator/tailwind.config.js +++ /dev/null @@ -1,13 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./**/*.{html,js}'], - theme: { - extend: { - container: { - center: true, - padding: '1rem', - }, - }, - }, - plugins: [], -}; diff --git a/examples/calculator/vite.config.js b/examples/calculator/vite.config.js index 1e15ea2..dd8de87 100644 --- a/examples/calculator/vite.config.js +++ b/examples/calculator/vite.config.js @@ -1,5 +1,7 @@ import { defineConfig } from 'vite'; +import { css } from 'css-configuration'; export default defineConfig({ assetsInclude: ['**/*.html'], + css, }); diff --git a/examples/calculator/vitest.config.js b/examples/calculator/vitest.config.js index e4ed480..eca96b3 100644 --- a/examples/calculator/vitest.config.js +++ b/examples/calculator/vitest.config.js @@ -1,7 +1,7 @@ -import { defineConfig } from 'vitest/config'; +import { mergeConfig } from 'vitest/config'; +import config from './vite.config'; -export default defineConfig({ - assetsInclude: ['**/*.html'], +export default mergeConfig(config, { test: { environment: 'happy-dom', }, diff --git a/examples/task-list/index.html b/examples/task-list/index.html new file mode 100644 index 0000000..7ae33e3 --- /dev/null +++ b/examples/task-list/index.html @@ -0,0 +1,13 @@ + + + + + + Task List + + + + +
+ + diff --git a/examples/task-list/package.json b/examples/task-list/package.json index 7b0bdb6..e6993fb 100644 --- a/examples/task-list/package.json +++ b/examples/task-list/package.json @@ -5,6 +5,9 @@ "main": "index.js", "type": "module", "scripts": { + "start": "concurrently \"npm run start:client\" \"npm run start:server\" --names \"client,server\" --kill-others -c blue,green", + "start:client": "vite dev", + "start:server": "node server/index.js", "test": "vitest" }, "repository": { @@ -18,8 +21,20 @@ }, "homepage": "https://github.com/stevekinney/testing-javascript#readme", "devDependencies": { + "@types/body-parser": "^1.19.5", + "@types/express": "^4.17.21", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react": "^4.3.1", "@vitest/ui": "^2.1.1", - "vite": "^5.4.5", + "chalk": "^5.3.0", + "concurrently": "^9.0.1", + "cors": "^2.8.5", + "uuid": "^10.0.0", + "vite": "^5.4.6", "vitest": "^2.1.1" + }, + "dependencies": { + "body-parser": "^1.20.3", + "express": "^4.21.0" } } diff --git a/examples/task-list/server/index.js b/examples/task-list/server/index.js new file mode 100644 index 0000000..6132537 --- /dev/null +++ b/examples/task-list/server/index.js @@ -0,0 +1,65 @@ +import express from 'express'; +import bodyParser from 'body-parser'; +import chalk from 'chalk'; + +import { + getTasks, + getTask, + createTask, + updateTask, + deleteTask, +} from './tasks.js'; + +const app = express(); +app.use(bodyParser.json()); + +app.get('/api/tasks', (req, res) => { + const tasks = getTasks(); + res.json(tasks); +}); + +app.post('/api/tasks', (req, res) => { + const { title } = req.body; + if (!title) { + return res.status(400).json({ message: 'A title is required' }); + } + const task = createTask(title); + res.status(201).json(task); +}); + +app.get('/api/tasks/:id', (req, res) => { + const task = getTask(req.params.id); + + if (!task) { + return res.status(404).json({ message: 'Task not found' }); + } + + res.json(task); +}); + +app.patch('/api/tasks/:id', (req, res) => { + const { title, completed } = req.body; + + const task = updateTask(req.params.id, { title, completed }); + + if (!task) { + return res.status(404).json({ message: 'Task not found' }); + } + + res.sendStatus(204); +}); + +app.delete('/api/tasks/:id', (req, res) => { + const task = deleteTask(req.params.id); + + if (!task) { + return res.status(404).json({ message: 'Task not found' }); + } + + res.status(204).send(); // No content to send back +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(chalk.magenta(`Server is running on port ${chalk.green(PORT)}…`)); +}); diff --git a/examples/task-list/server/tasks.js b/examples/task-list/server/tasks.js new file mode 100644 index 0000000..756512c --- /dev/null +++ b/examples/task-list/server/tasks.js @@ -0,0 +1,65 @@ +import { v4 as id } from 'uuid'; + +/** @typedef {import('../types').Task} Task */ + +/** @type {Task[]} tasks - An array to store tasks. */ +let tasks = []; + +/** + * Get all tasks. + * @returns {Task[]} An array of tasks. + */ +export const getTasks = () => tasks; + +/** + * Create a new task. + * @param {string} title - The title of the task. + * @returns {Task} The newly created task. + */ +export const createTask = (title) => { + /** @type {Task} */ + const task = { + id: id(), + title, + completed: false, + createdAt: new Date(), + lastModified: new Date(), + }; + tasks.push(task); + return task; +}; + +/** + * Find a task by ID. + * @param {string} id - The ID of the task to find. + * @returns {Task | undefined} The found task or undefined if not found. + */ +export const getTask = (id) => tasks.find((task) => task.id === id); + +/** + * Update a task by ID. + * @param {string} id - The ID of the task to update. + * @param {Partial>} updates - The updates to apply to the task. + * @returns {Task | undefined} The updated task or undefined if not found. + */ +export const updateTask = (id, updates) => { + const task = getTask(id); + + if (!task) return undefined; + + Object.assign(task, updates, { lastModified: new Date() }); + return task; +}; + +/** + * Delete a task by ID. + * @param {string} id - The ID of the task to delete. + * @returns {boolean} `true` if the task was deleted, `false` if not found. + */ +export const deleteTask = (id) => { + const index = tasks.findIndex((task) => task.id === id); + if (index === -1) return false; + + tasks.splice(index, 1); + return true; +}; diff --git a/examples/task-list/src/application.tsx b/examples/task-list/src/application.tsx new file mode 100644 index 0000000..3b444b4 --- /dev/null +++ b/examples/task-list/src/application.tsx @@ -0,0 +1,14 @@ +import { CreateTask } from './create-task'; +import { TaskProvider } from './task-context'; +import { Tasks } from './tasks'; + +export const Application = () => { + return ( + +
+ console.log(title)} /> + +
+
+ ); +}; diff --git a/examples/task-list/src/create-task.tsx b/examples/task-list/src/create-task.tsx new file mode 100644 index 0000000..977be37 --- /dev/null +++ b/examples/task-list/src/create-task.tsx @@ -0,0 +1,43 @@ +import { useState } from 'react'; +import { useTaskContext } from './task-context'; + +type CreateTaskProps = { + onSubmit: (title: string) => void; +}; + +export const CreateTask = ({ onSubmit }: CreateTaskProps) => { + const { addTask } = useTaskContext(); + const [title, setTitle] = useState(''); + + return ( +
{ + event.preventDefault(); + addTask(title); + setTitle(''); + }} + > +
+ +
+ setTitle(e.target.value)} + placeholder="What do you need to get done?" + required + /> + +
+
+
+ ); +}; diff --git a/examples/task-list/src/date-time.tsx b/examples/task-list/src/date-time.tsx new file mode 100644 index 0000000..cf5bf36 --- /dev/null +++ b/examples/task-list/src/date-time.tsx @@ -0,0 +1,15 @@ +export const DateTime = ({ date, title }: { date: Date; title: string }) => { + return ( +
+

+ {title} +

+

+ {date.toLocaleString(undefined, { + dateStyle: 'short', + timeStyle: 'short', + })} +

+
+ ); +}; diff --git a/examples/task-list/src/index.tsx b/examples/task-list/src/index.tsx new file mode 100644 index 0000000..3b207e6 --- /dev/null +++ b/examples/task-list/src/index.tsx @@ -0,0 +1,9 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { Application } from './application'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/examples/task-list/src/task-context.tsx b/examples/task-list/src/task-context.tsx new file mode 100644 index 0000000..6222470 --- /dev/null +++ b/examples/task-list/src/task-context.tsx @@ -0,0 +1,131 @@ +import { + createContext, + useReducer, + useEffect, + type ReactNode, + useContext, +} from 'react'; +import { TasksActions, taskReducer, initialState } from './task-reducer'; +import type { Task } from '../types'; + +interface TaskContextProps { + tasks: Task[]; + loading: boolean; + error: string | null; + addTask: (title: string) => void; + updateTask: (id: string, updatedTask: Partial) => void; + deleteTask: (id: string) => void; +} + +const TaskContext = createContext(undefined); + +interface TaskProviderProps { + children: ReactNode; +} + +const TaskProvider = ({ children }: TaskProviderProps) => { + const [state, dispatch] = useReducer(taskReducer, initialState); + + // Fetch all tasks + const fetchTasks = async () => { + dispatch({ type: TasksActions.SET_LOADING }); + try { + const response = await fetch('/api/tasks'); + const data = await response.json(); + dispatch({ type: TasksActions.FETCH_TASKS, payload: data }); + } catch (error) { + dispatch({ + type: TasksActions.SET_ERROR, + payload: 'Failed to fetch tasks', + }); + } + }; + + // Add a new task + const addTask = async (title: string) => { + dispatch({ type: TasksActions.SET_LOADING }); + try { + const response = await fetch('/api/tasks', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ title }), + }); + const data = await response.json(); + dispatch({ type: TasksActions.ADD_TASK, payload: data }); + } catch (error) { + dispatch({ type: TasksActions.SET_ERROR, payload: 'Failed to add task' }); + } + }; + + // Update a task + const updateTask = async (id: string, updatedTask: Partial) => { + dispatch({ type: TasksActions.SET_LOADING }); + + try { + const response = await fetch(`/api/tasks/${id}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(updatedTask), + }); + + if (!response.ok) { + throw new Error('Failed to update task'); + } + + dispatch({ + type: TasksActions.UPDATE_TASK, + payload: { id, ...updatedTask }, + }); + } catch (error) { + dispatch({ + type: TasksActions.SET_ERROR, + payload: 'Failed to update task', + }); + } + }; + + // Delete a task + const deleteTask = async (id: string) => { + dispatch({ type: TasksActions.SET_LOADING }); + try { + await fetch(`/api/tasks/${id}`, { + method: 'DELETE', + }); + dispatch({ type: TasksActions.DELETE_TASK, payload: id }); + } catch (error) { + dispatch({ + type: TasksActions.SET_ERROR, + payload: 'Failed to delete task', + }); + } + }; + + useEffect(() => { + fetchTasks(); + }, []); + + return ( + + {children} + + ); +}; + +const useTaskContext = () => { + const context = useContext(TaskContext); + if (!context) { + throw new Error('useTaskContext must be used within a TaskProvider'); + } + return context; +}; + +export { TaskContext, TaskProvider, useTaskContext }; diff --git a/examples/task-list/src/task-reducer.ts b/examples/task-list/src/task-reducer.ts new file mode 100644 index 0000000..9924547 --- /dev/null +++ b/examples/task-list/src/task-reducer.ts @@ -0,0 +1,60 @@ +import type { Task } from '../types'; + +export enum TasksActions { + FETCH_TASKS = 'fetch-tasks', + ADD_TASK = 'add-task', + UPDATE_TASK = 'update-task', + DELETE_TASK = 'delete-task', + SET_LOADING = 'set-loading', + SET_ERROR = 'set-error', +} + +export interface TaskState { + tasks: Task[]; + loading: boolean; + error: string | null; +} + +export interface Action { + type: TasksActions; + payload?: any; +} + +export const initialState: TaskState = { + tasks: [], + loading: false, + error: null, +}; + +export const taskReducer = (state: TaskState, action: Action): TaskState => { + switch (action.type) { + case TasksActions.FETCH_TASKS: + return { ...state, tasks: action.payload, loading: false }; + case TasksActions.ADD_TASK: + return { + ...state, + tasks: [...state.tasks, action.payload], + loading: false, + }; + case TasksActions.UPDATE_TASK: + return { + ...state, + tasks: state.tasks.map((task) => + task.id === action.payload.id ? { ...task, ...action.payload } : task, + ), + loading: false, + }; + case TasksActions.DELETE_TASK: + return { + ...state, + tasks: state.tasks.filter((task) => task.id !== action.payload), + loading: false, + }; + case TasksActions.SET_LOADING: + return { ...state, loading: true }; + case TasksActions.SET_ERROR: + return { ...state, error: action.payload, loading: false }; + default: + return state; + } +}; diff --git a/examples/task-list/src/task.tsx b/examples/task-list/src/task.tsx new file mode 100644 index 0000000..dea411c --- /dev/null +++ b/examples/task-list/src/task.tsx @@ -0,0 +1,40 @@ +import { DateTime } from './date-time'; +import { useTaskContext } from './task-context'; + +type TaskProps = { + task: import('../types').Task; +}; + +export const Task = ({ task }: TaskProps) => { + const { updateTask, deleteTask } = useTaskContext(); + + return ( +
  • +
    + + updateTask(task.id, { completed: !task.completed })} + /> +

    {task.title}

    + +
    +
    + + +
    +
  • + ); +}; diff --git a/examples/task-list/src/tasks.tsx b/examples/task-list/src/tasks.tsx new file mode 100644 index 0000000..f395806 --- /dev/null +++ b/examples/task-list/src/tasks.tsx @@ -0,0 +1,16 @@ +import { Task } from './task'; +import { useTaskContext } from './task-context'; + +export const Tasks = () => { + const { tasks } = useTaskContext(); + + return ( +
    +
      + {tasks.map((task) => ( + + ))} +
    +
    + ); +}; diff --git a/examples/task-list/styles.css b/examples/task-list/styles.css new file mode 100644 index 0000000..8608921 --- /dev/null +++ b/examples/task-list/styles.css @@ -0,0 +1,53 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + label { + @apply block text-sm font-medium leading-6; + &[for]:has(~ input[required]) { + @apply after:content-['*'] after:text-red-600; + } + } + + input[type='text'], + input[type='email'], + input[type='password'] { + @apply text-sm sm:text-base block w-full rounded-md border-0 py-1.5 px-2.5 text-slate-900 shadow-sm ring-1 ring-inset ring-primary-700/20 placeholder:text-slate-400 sm:text-sm sm:leading-6 placeholder:text-primary-600; + @apply focus:ring-2 focus:ring-primary-600 focus:outline-none; + &:has(+ button[type='submit']) { + @apply block w-full rounded-r-none; + } + } + + input[type='checkbox'] { + @apply h-4 w-4 rounded border-primary-500 accent-primary-600; + } + + button { + @apply button; + input + & { + @apply rounded-l-none -ml-px; + } + &[type='submit'] { + @apply button-primary; + } + } +} + +@layer components { + .button { + @apply relative inline-flex items-center justify-center gap-x-1.5 rounded-md px-3 py-2 text-sm font-semibold text-slate-900 ring-1 ring-inset ring-primary-300 hover:bg-slate-50 whitespace-pre disabled:cursor-not-allowed text-sm sm:text-base; + } + + .button-primary { + @apply bg-primary-600 text-white cursor-pointer ring-primary-700 transition duration-100 ease-in-out hover:bg-primary-700 active:bg-primary-800 disabled:bg-primary-600/50 disabled:hover:bg-primary-600/50 disabled:active:bg-primary-600/50 disabled:cursor-not-allowed disabled:ring-primary-700/20; + } + + .button-destructive { + @apply bg-red-600 text-white cursor-pointer ring-red-700 transition duration-100 ease-in-out hover:bg-red-700 active:bg-red-800 disabled:bg-red-600/50 disabled:hover:bg-red-600/50 disabled:active:bg-red-600/50 disabled:cursor-not-allowed disabled:ring-red-700/20; + &.button-ghost { + @apply bg-transparent text-red-600 ring-red-600 hover:bg-red-600/10; + } + } +} diff --git a/examples/task-list/types.ts b/examples/task-list/types.ts new file mode 100644 index 0000000..89759b2 --- /dev/null +++ b/examples/task-list/types.ts @@ -0,0 +1,7 @@ +export interface Task { + id: string; + title: string; + completed: boolean; + createdAt: Date; + lastModified: Date; +} diff --git a/examples/task-list/vite.config.ts b/examples/task-list/vite.config.ts new file mode 100644 index 0000000..747d49b --- /dev/null +++ b/examples/task-list/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import { css } from 'css-configuration'; + +export default defineConfig({ + plugins: [react()], + css, + server: { + proxy: { + '/api': { + target: 'http://localhost:3000', + changeOrigin: true, + secure: false, + }, + }, + }, +}); diff --git a/package-lock.json b/package-lock.json index 29cbc46..97640aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "examples/guess-the-number", "examples/basic-math", "examples/characters", - "examples/accident-counter" + "examples/accident-counter", + "packages/css-configuration" ], "devDependencies": { "prettier": "^3.3.3" @@ -26,11 +27,12 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e", "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^16.0.1", "@types/react": "^18.3.6", "@types/react-dom": "^18.3.0", + "@types/testing-library__jest-dom": "^5.14.9", "@vitejs/plugin-react": "^4.3.1", "@vitest/ui": "^2.1.1", "react": "^18.3.1", @@ -107,12 +109,37 @@ "examples/task-list": { "version": "1.0.0", "license": "MIT", + "dependencies": { + "body-parser": "^1.20.3", + "express": "^4.21.0" + }, "devDependencies": { + "@types/body-parser": "^1.19.5", + "@types/express": "^4.17.21", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react": "^4.3.1", "@vitest/ui": "^2.1.1", - "vite": "^5.4.5", + "chalk": "^5.3.0", + "concurrently": "^9.0.1", + "cors": "^2.8.5", + "uuid": "^10.0.0", + "vite": "^5.4.6", "vitest": "^2.1.1" } }, + "examples/task-list/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" + } + }, "examples/tic-tac-toe": { "version": "1.0.0", "license": "MIT", @@ -122,6 +149,13 @@ "vitest": "^2.1.1" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -951,6 +985,50 @@ "node": ">=12" } }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1297,6 +1375,13 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@tailwindcss/nesting": { "version": "0.0.0-insiders.565cd3e", "resolved": "https://registry.npmjs.org/@tailwindcss/nesting/-/nesting-0.0.0-insiders.565cd3e.tgz", @@ -1350,6 +1435,64 @@ "node": ">=18" } }, + "node_modules/@testing-library/jest-dom": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", + "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, "node_modules/@testing-library/react": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", @@ -1444,6 +1587,27 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -1451,6 +1615,129 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, "node_modules/@types/prop-types": { "version": "15.7.13", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", @@ -1458,6 +1745,20 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "18.3.6", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.6.tgz", @@ -1479,6 +1780,70 @@ "@types/react": "*" } }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", + "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jest": "*" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", @@ -1645,6 +2010,19 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/accident-counter": { "resolved": "examples/accident-counter", "link": true @@ -1756,6 +2134,12 @@ "dequal": "^2.0.3" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -1841,6 +2225,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1906,6 +2341,15 @@ "optional": true, "peer": true }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -1920,6 +2364,25 @@ "resolved": "examples/calculator", "link": true }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2053,6 +2516,116 @@ "node": ">= 6" } }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2098,6 +2671,69 @@ "node": ">= 6" } }, + "node_modules/concurrently": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.0.1.tgz", + "integrity": "sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2105,6 +2741,35 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2120,6 +2785,17 @@ "node": ">= 8" } }, + "node_modules/css-configuration": { + "resolved": "packages/css-configuration", + "link": true + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2208,6 +2884,23 @@ "node": ">=6" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2220,6 +2913,15 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2230,6 +2932,16 @@ "node": ">=6" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2237,6 +2949,16 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -2258,6 +2980,12 @@ "dev": true, "license": "MIT" }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.22", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.22.tgz", @@ -2272,6 +3000,15 @@ "dev": true, "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -2285,6 +3022,27 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -2334,6 +3092,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2354,6 +3118,89 @@ "@types/estree": "^1.0.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2429,6 +3276,39 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -2470,6 +3350,15 @@ "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -2484,6 +3373,15 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2503,7 +3401,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2519,6 +3416,16 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -2529,6 +3436,25 @@ "node": "*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -2573,6 +3499,25 @@ "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/guess-the-number": { "resolved": "examples/guess-the-number", "link": true @@ -2612,11 +3557,46 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2640,6 +3620,22 @@ "node": ">=18" } }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -2687,6 +3683,31 @@ "node": ">=0.10.0" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2791,6 +3812,205 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jiti": { "version": "1.21.6", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", @@ -2894,6 +4114,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2944,6 +4171,24 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2954,6 +4199,15 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2981,14 +4235,23 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.6" } @@ -2997,10 +4260,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -3008,6 +4268,16 @@ "node": ">= 0.6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -3048,7 +4318,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -3082,6 +4351,15 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -3138,6 +4416,30 @@ "node": ">= 6" } }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -3160,6 +4462,15 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3194,6 +4505,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -3468,6 +4785,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -3489,6 +4819,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -3519,6 +4864,42 @@ ], "license": "MIT" }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -3589,6 +4970,20 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -3596,6 +4991,16 @@ "dev": true, "license": "MIT" }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -3703,14 +5108,41 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", @@ -3747,6 +5179,92 @@ "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3770,6 +5288,34 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -3805,6 +5351,16 @@ "node": ">= 10" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3840,6 +5396,29 @@ "source-map": "^0.6.0" } }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -3847,6 +5426,15 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -3958,6 +5546,19 @@ "node": ">=8" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -4017,9 +5618,9 @@ "peer": true }, "node_modules/tailwindcss": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.11.tgz", - "integrity": "sha512-qhEuBcLemjSJk5ajccN9xJFtM/h0AVCPaA6C92jNP+M2J8kX+eMJHI7R2HFKUvvAsMpcfLILMCFYSeDwpMmlUg==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.12.tgz", + "integrity": "sha512-Htf/gHj2+soPb9UayUNci/Ja3d8pTmu9ONTfh4QY8r3MATTZOzmv6UYWF7ZwikEIC8okpfqmGqrmDehua8mF8w==", "dev": true, "license": "MIT", "dependencies": { @@ -4196,6 +5797,15 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -4239,6 +5849,16 @@ "node": ">=18" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -4246,6 +5866,47 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", @@ -4258,6 +5919,15 @@ "node": ">= 4.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", @@ -4309,6 +5979,15 @@ "dev": true, "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", @@ -4322,10 +6001,19 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.5.tgz", - "integrity": "sha512-pXqR0qtb2bTwLkev4SE3r4abCNioP3GkjvIDLlzziPpXtHgiJIjuKl+1GN6ESOT3wMjG3JTeARopj2SwYaHTOA==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4713,6 +6401,16 @@ "optional": true, "peer": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -4732,6 +6430,90 @@ "engines": { "node": ">= 14" } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "packages/css-configuration": { + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "autoprefixer": "^10.4.20", + "tailwindcss": "^3.4.12", + "typescript": "^5.6.2", + "vite": "^5.4.6" + } } } } diff --git a/package.json b/package.json index 3bc5565..8d30b74 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "examples/guess-the-number", "examples/basic-math", "examples/characters", - "examples/accident-counter" + "examples/accident-counter", + "packages/css-configuration" ], "devDependencies": { "prettier": "^3.3.3" diff --git a/packages/css-configuration/index.d.ts b/packages/css-configuration/index.d.ts new file mode 100644 index 0000000..33af660 --- /dev/null +++ b/packages/css-configuration/index.d.ts @@ -0,0 +1,4 @@ +/** + * @type import('vite').UserConfig['css'] + */ +export const css: import("vite").UserConfig["css"]; diff --git a/packages/css-configuration/index.js b/packages/css-configuration/index.js new file mode 100644 index 0000000..832ea97 --- /dev/null +++ b/packages/css-configuration/index.js @@ -0,0 +1,42 @@ +import nesting from 'tailwindcss/nesting/index.js'; +import tailwindcss from 'tailwindcss'; +import autoprefixer from 'autoprefixer'; + +/** + * @type import('vite').UserConfig['css'] + */ +export const css = { + postcss: { + plugins: [ + tailwindcss({ + content: ['./**/*.{html,js,jsx,ts,tsx}'], + theme: { + extend: { + container: { + center: true, + padding: '1rem', + }, + colors: { + primary: { + 50: '#f3faeb', + 100: '#e5f3d4', + 200: '#cde8ae', + 300: '#acd87e', + 400: '#8ec655', + 500: '#6ca635', + 600: '#558828', + 700: '#426823', + 800: '#375420', + 900: '#30481f', + 950: '#17270c', + }, + }, + }, + }, + plugins: [], + }), + nesting, + autoprefixer, + ], + }, +}; diff --git a/examples/calculator-reducer/package.json b/packages/css-configuration/package.json similarity index 57% rename from examples/calculator-reducer/package.json rename to packages/css-configuration/package.json index 34dda9f..131fa15 100644 --- a/examples/calculator-reducer/package.json +++ b/packages/css-configuration/package.json @@ -1,12 +1,11 @@ { - "name": "calculator-reducer", + "name": "css-configuration", "version": "1.0.0", - "description": "Yet another attempt at implementing a calculator, but this time with a reducer.", - "main": "src/index.js", + "description": "Some CSS settings for Vite/PostCSS that includes Tailwind", + "main": "index.js", "type": "module", "scripts": { - "start": "vitest --ui", - "test": "vitest" + "types": "tsc --emitDeclarationOnly --allowJs --declaration --skipLibCheck index.js" }, "repository": { "type": "git", @@ -19,7 +18,9 @@ }, "homepage": "https://github.com/stevekinney/testing-javascript#readme", "devDependencies": { - "@vitest/ui": "^2.1.1", - "vitest": "^2.1.1" + "autoprefixer": "^10.4.20", + "tailwindcss": "^3.4.12", + "typescript": "^5.6.2", + "vite": "^5.4.6" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..6f02403 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "paths": { + "*": ["node_modules/*"] + }, + "jsx": "react-jsx", + "forceConsistentCasingInFileNames": true + } +}