Replace react-vis with visx, add component testing infrastructure, and update Electron packages (#959)
This commit is contained in:
309
app/TESTING.md
Normal file
309
app/TESTING.md
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
# React Component Testing Guide
|
||||||
|
|
||||||
|
This guide explains how to write tests for React components in the MQTT-Explorer project using the generic testing utilities.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
We use the following testing stack:
|
||||||
|
- **Mocha** - Test framework
|
||||||
|
- **Chai** - Assertion library
|
||||||
|
- **React Testing Library** - React component testing utilities
|
||||||
|
- **JSDOM** - DOM implementation for Node.js
|
||||||
|
- **Custom Test Utilities** - Located in `src/utils/spec/testUtils.tsx`
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Create a Test File
|
||||||
|
|
||||||
|
Test files should be placed next to the component they test with the `.spec.tsx` extension:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/components/MyComponent/
|
||||||
|
├── MyComponent.tsx
|
||||||
|
└── MyComponent.spec.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Basic Test Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import React from 'react'
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import { describe, it } from 'mocha'
|
||||||
|
import MyComponent from './MyComponent'
|
||||||
|
import { renderWithProviders } from '../../utils/spec/testUtils'
|
||||||
|
|
||||||
|
describe('MyComponent', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent />)
|
||||||
|
expect(container).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Test Utilities
|
||||||
|
|
||||||
|
### `renderWithProviders`
|
||||||
|
|
||||||
|
This function wraps your component with necessary providers (Theme, Redux).
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { renderWithProviders } from '../../utils/spec/testUtils'
|
||||||
|
|
||||||
|
// Render with theme only (default)
|
||||||
|
const { container } = renderWithProviders(<MyComponent />, { withTheme: true })
|
||||||
|
|
||||||
|
// Render with both theme and Redux
|
||||||
|
const { container } = renderWithProviders(<MyComponent />, {
|
||||||
|
withTheme: true,
|
||||||
|
withRedux: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// Render with custom theme
|
||||||
|
import { createTheme } from '@mui/material/styles'
|
||||||
|
const darkTheme = createTheme({ palette: { mode: 'dark' } })
|
||||||
|
const { container } = renderWithProviders(<MyComponent />, {
|
||||||
|
theme: darkTheme
|
||||||
|
})
|
||||||
|
|
||||||
|
// Render with custom Redux store
|
||||||
|
import { configureStore } from '@reduxjs/toolkit'
|
||||||
|
const customStore = configureStore({ /* ... */ })
|
||||||
|
const { container } = renderWithProviders(<MyComponent />, {
|
||||||
|
store: customStore,
|
||||||
|
withRedux: true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### `createMockChartData`
|
||||||
|
|
||||||
|
Helper function to generate mock chart data:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createMockChartData } from '../../utils/spec/testUtils'
|
||||||
|
|
||||||
|
// Create 10 data points (default)
|
||||||
|
const data = createMockChartData()
|
||||||
|
|
||||||
|
// Create specific number of points
|
||||||
|
const data = createMockChartData(50)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Global Mocks
|
||||||
|
|
||||||
|
The test utilities automatically set up global mocks:
|
||||||
|
- **ResizeObserver** - Mocked for components using `react-resize-detector`
|
||||||
|
|
||||||
|
## Common Testing Patterns
|
||||||
|
|
||||||
|
### Testing Rendering
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
it('should render without crashing', () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent />)
|
||||||
|
expect(container).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render specific element', () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent />)
|
||||||
|
const element = container.querySelector('.my-class')
|
||||||
|
expect(element).to.exist
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Props
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
it('should accept all valid props', () => {
|
||||||
|
const props = {
|
||||||
|
title: 'Test',
|
||||||
|
value: 123,
|
||||||
|
onchange: () => {},
|
||||||
|
}
|
||||||
|
const { container } = renderWithProviders(<MyComponent {...props} />)
|
||||||
|
expect(container).to.exist
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing User Interactions
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { userEvent } from '../../utils/spec/testUtils'
|
||||||
|
|
||||||
|
it('should handle click events', async () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent />)
|
||||||
|
const button = container.querySelector('button')
|
||||||
|
|
||||||
|
if (button) {
|
||||||
|
await userEvent.click(button)
|
||||||
|
// Assert expected behavior
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Different States
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
it('should render empty state', () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent data={[]} />)
|
||||||
|
// Assert empty state
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render with data', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<MyComponent data={data} />)
|
||||||
|
// Assert data is rendered
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing SVG Components
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
it('should render SVG elements', () => {
|
||||||
|
const { container } = renderWithProviders(<ChartComponent />)
|
||||||
|
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
const paths = container.querySelectorAll('path')
|
||||||
|
expect(paths.length).to.be.greaterThan(0)
|
||||||
|
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(5)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Edge Cases
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
describe('Edge Cases', () => {
|
||||||
|
it('should handle negative values', () => {
|
||||||
|
const data = [{ x: 1, y: -10 }, { x: 2, y: -20 }]
|
||||||
|
const { container } = renderWithProviders(<MyComponent data={data} />)
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle empty arrays', () => {
|
||||||
|
const { container } = renderWithProviders(<MyComponent data={[]} />)
|
||||||
|
expect(container).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle very large numbers', () => {
|
||||||
|
const data = [{ x: 1, y: 1000000 }]
|
||||||
|
const { container } = renderWithProviders(<MyComponent data={data} />)
|
||||||
|
expect(container).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
### Run all tests
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run specific test file
|
||||||
|
```bash
|
||||||
|
npx mocha --require tsx --require source-map-support/register "src/components/MyComponent/MyComponent.spec.tsx"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run tests in watch mode
|
||||||
|
```bash
|
||||||
|
npx mocha --require tsx --require source-map-support/register --watch "src/**/*.spec.{ts,tsx}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Test Behavior, Not Implementation**
|
||||||
|
- Focus on what the component does, not how it does it
|
||||||
|
- Test user-facing behavior and output
|
||||||
|
|
||||||
|
2. **Use Descriptive Test Names**
|
||||||
|
```typescript
|
||||||
|
// Good
|
||||||
|
it('should render error message when validation fails')
|
||||||
|
|
||||||
|
// Bad
|
||||||
|
it('test1')
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Group Related Tests**
|
||||||
|
```typescript
|
||||||
|
describe('MyComponent', () => {
|
||||||
|
describe('Rendering', () => {
|
||||||
|
it('should render correctly')
|
||||||
|
it('should render with props')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Interactions', () => {
|
||||||
|
it('should handle clicks')
|
||||||
|
it('should handle keyboard input')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Keep Tests Independent**
|
||||||
|
- Each test should be able to run in isolation
|
||||||
|
- Don't rely on test execution order
|
||||||
|
- Clean up after each test if needed
|
||||||
|
|
||||||
|
5. **Test Edge Cases**
|
||||||
|
- Empty data
|
||||||
|
- Null/undefined values
|
||||||
|
- Very large/small numbers
|
||||||
|
- Negative values
|
||||||
|
- Single item arrays
|
||||||
|
|
||||||
|
6. **Use Chai Assertions**
|
||||||
|
```typescript
|
||||||
|
expect(value).to.exist
|
||||||
|
expect(value).to.be.true
|
||||||
|
expect(value).to.equal(expected)
|
||||||
|
expect(array).to.have.length(5)
|
||||||
|
expect(number).to.be.greaterThan(0)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: Complete Test Suite
|
||||||
|
|
||||||
|
See `src/components/Chart/Chart.spec.tsx` for a comprehensive example that demonstrates:
|
||||||
|
- Multiple test groups (Rendering, Data Visualization, Edge Cases, etc.)
|
||||||
|
- Testing with different props and configurations
|
||||||
|
- Testing SVG elements
|
||||||
|
- Testing theme integration
|
||||||
|
- Performance testing
|
||||||
|
- Edge case coverage
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "ResizeObserver is not defined"
|
||||||
|
This is automatically mocked by the test utilities. Make sure you're importing from `testUtils.tsx`.
|
||||||
|
|
||||||
|
### "Cannot find module"
|
||||||
|
Check your import paths. Remember to use relative paths from the test file.
|
||||||
|
|
||||||
|
### "Window is not defined"
|
||||||
|
Make sure `jsdom-global/register` is imported in testUtils.tsx.
|
||||||
|
|
||||||
|
### Tests timing out
|
||||||
|
Increase the timeout in your test:
|
||||||
|
```typescript
|
||||||
|
it('should complete async operation', function() {
|
||||||
|
this.timeout(5000) // 5 seconds
|
||||||
|
// test code
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding New Test Utilities
|
||||||
|
|
||||||
|
To add new helper functions, update `src/utils/spec/testUtils.tsx`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export function myNewHelper() {
|
||||||
|
// Helper implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then use it in your tests:
|
||||||
|
```typescript
|
||||||
|
import { myNewHelper } from '../../utils/spec/testUtils'
|
||||||
|
```
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
"dev": "node_modules/.bin/webpack-dev-server --mode development --progress",
|
"dev": "node_modules/.bin/webpack-dev-server --mode development --progress",
|
||||||
"test": "mocha --require tsx --require source-map-support/register --recursive src/*/**/*.spec.ts",
|
"test": "mocha --require tsx --require source-map-support/register --recursive 'src/*/**/*.spec.{ts,tsx}'",
|
||||||
"mochatest": "mocha --require tsx --require source-map-support/register --recursive src/*/**/*.spec.ts"
|
"mochatest": "mocha --require tsx --require source-map-support/register --recursive 'src/*/**/*.spec.{ts,tsx}'"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
@@ -21,7 +21,12 @@
|
|||||||
"@mui/lab": "^7.0.1-beta.20",
|
"@mui/lab": "^7.0.1-beta.20",
|
||||||
"@mui/material": "^7.3.6",
|
"@mui/material": "^7.3.6",
|
||||||
"@mui/styles": "^6.4.8",
|
"@mui/styles": "^6.4.8",
|
||||||
|
"@react-spring/web": "^9.7.5",
|
||||||
"@types/react-transition-group": "^4.4.11",
|
"@types/react-transition-group": "^4.4.11",
|
||||||
|
"@visx/axis": "^3.10.1",
|
||||||
|
"@visx/grid": "^3.5.0",
|
||||||
|
"@visx/tooltip": "^3.3.0",
|
||||||
|
"@visx/xychart": "^3.10.2",
|
||||||
"ace-builds": "^1.4.11",
|
"ace-builds": "^1.4.11",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"compare-versions": "^6.1.1",
|
"compare-versions": "^6.1.1",
|
||||||
@@ -51,7 +56,6 @@
|
|||||||
"react-resize-detector": "^11.0.1",
|
"react-resize-detector": "^11.0.1",
|
||||||
"react-split-pane": "^0.1.92",
|
"react-split-pane": "^0.1.92",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"react-vis": "^1.12.1",
|
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-batched-actions": "^0.5.0",
|
"redux-batched-actions": "^0.5.0",
|
||||||
"redux-thunk": "^3.1.0",
|
"redux-thunk": "^3.1.0",
|
||||||
@@ -62,6 +66,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime": "^7.28.4",
|
"@babel/runtime": "^7.28.4",
|
||||||
|
"@reduxjs/toolkit": "2.5.0",
|
||||||
|
"@testing-library/dom": "10.4.0",
|
||||||
|
"@testing-library/react": "16.1.0",
|
||||||
|
"@testing-library/user-event": "14.5.2",
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@types/diff": "^7.0.0",
|
"@types/diff": "^7.0.0",
|
||||||
"@types/get-value": "^3.0.5",
|
"@types/get-value": "^3.0.5",
|
||||||
@@ -81,6 +89,8 @@
|
|||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "^5.6.3",
|
"html-webpack-plugin": "^5.6.3",
|
||||||
|
"jsdom": "25.0.1",
|
||||||
|
"jsdom-global": "3.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mocha": "^10.8.2",
|
"mocha": "^10.8.2",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
|
|||||||
112
app/src/components/Chart/Chart.domain.spec.tsx
Normal file
112
app/src/components/Chart/Chart.domain.spec.tsx
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import { expect } from 'chai'
|
||||||
|
import { renderWithProviders } from '../../utils/spec/testUtils'
|
||||||
|
import Chart from './Chart'
|
||||||
|
|
||||||
|
describe('Chart X-Axis Domain Investigation', () => {
|
||||||
|
it('should spread points across X-axis with sequential timestamps', () => {
|
||||||
|
// Create 5 data points, 1 second (1000ms) apart
|
||||||
|
const now = Date.now()
|
||||||
|
const data = [
|
||||||
|
{ x: now - 4000, y: 20 },
|
||||||
|
{ x: now - 3000, y: 21 },
|
||||||
|
{ x: now - 2000, y: 22 },
|
||||||
|
{ x: now - 1000, y: 23 },
|
||||||
|
{ x: now, y: 24 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />)
|
||||||
|
|
||||||
|
// Find all circle elements (data points)
|
||||||
|
const circles = container.querySelectorAll('svg circle')
|
||||||
|
expect(circles).to.have.length(5)
|
||||||
|
|
||||||
|
// Extract cx (X-position) values
|
||||||
|
const cxValues: number[] = []
|
||||||
|
circles.forEach(circle => {
|
||||||
|
const cx = circle.getAttribute('cx')
|
||||||
|
if (cx) {
|
||||||
|
cxValues.push(parseFloat(cx))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Log for debugging
|
||||||
|
console.log('\n========== X-AXIS DOMAIN INVESTIGATION ==========')
|
||||||
|
console.log('Data X values (timestamps):')
|
||||||
|
data.forEach((d, i) => console.log(` Point ${i}: ${d.x} (${new Date(d.x).toISOString()})`))
|
||||||
|
console.log(`\nData X range: ${data[data.length - 1].x - data[0].x}ms (${(data[data.length - 1].x - data[0].x) / 1000}s)`)
|
||||||
|
|
||||||
|
console.log('\nRendered circle CX positions:')
|
||||||
|
cxValues.forEach((cx, i) => console.log(` Circle ${i}: cx=${cx.toFixed(2)}px`))
|
||||||
|
|
||||||
|
const minCx = Math.min(...cxValues)
|
||||||
|
const maxCx = Math.max(...cxValues)
|
||||||
|
const cxRange = maxCx - minCx
|
||||||
|
|
||||||
|
console.log(`\nCX position range: ${cxRange.toFixed(2)}px (from ${minCx.toFixed(2)} to ${maxCx.toFixed(2)})`)
|
||||||
|
console.log(`Points per pixel: ${(cxValues.length / cxRange).toFixed(4)}`)
|
||||||
|
|
||||||
|
// Calculate spacing between consecutive points
|
||||||
|
const spacings: number[] = []
|
||||||
|
for (let i = 1; i < cxValues.length; i++) {
|
||||||
|
spacings.push(cxValues[i] - cxValues[i - 1])
|
||||||
|
}
|
||||||
|
console.log('\nSpacing between consecutive points:')
|
||||||
|
spacings.forEach((s, i) => console.log(` ${i} to ${i+1}: ${s.toFixed(2)}px`))
|
||||||
|
|
||||||
|
const avgSpacing = spacings.reduce((a, b) => a + b, 0) / spacings.length
|
||||||
|
console.log(`Average spacing: ${avgSpacing.toFixed(2)}px`)
|
||||||
|
console.log('=================================================\n')
|
||||||
|
|
||||||
|
// Assertions:
|
||||||
|
// 1. Points should be spread out (CX range should be significant, not bunched)
|
||||||
|
expect(cxRange).to.be.greaterThan(50, 'Points should be spread across at least 50px')
|
||||||
|
|
||||||
|
// 2. Points should be in ascending order (left to right)
|
||||||
|
for (let i = 1; i < cxValues.length; i++) {
|
||||||
|
expect(cxValues[i]).to.be.greaterThan(cxValues[i - 1],
|
||||||
|
`Point ${i} (cx=${cxValues[i]}) should be to the right of point ${i-1} (cx=${cxValues[i-1]})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Spacing should be relatively uniform (since data points are equally spaced in time)
|
||||||
|
const spacingVariance = spacings.map(s => Math.abs(s - avgSpacing))
|
||||||
|
const maxVariance = Math.max(...spacingVariance)
|
||||||
|
expect(maxVariance).to.be.lessThan(avgSpacing * 0.5,
|
||||||
|
'Spacing between points should be relatively uniform')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle points bunched at far right correctly', () => {
|
||||||
|
// Simulate the "bunched up" scenario with very large timestamps
|
||||||
|
const largeTimestamp = 1703347200000 // Dec 23, 2023
|
||||||
|
const data = [
|
||||||
|
{ x: largeTimestamp, y: 20 },
|
||||||
|
{ x: largeTimestamp + 1000, y: 21 },
|
||||||
|
{ x: largeTimestamp + 2000, y: 22 },
|
||||||
|
{ x: largeTimestamp + 3000, y: 23 },
|
||||||
|
{ x: largeTimestamp + 4000, y: 24 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />)
|
||||||
|
|
||||||
|
const circles = container.querySelectorAll('svg circle')
|
||||||
|
const cxValues: number[] = []
|
||||||
|
circles.forEach(circle => {
|
||||||
|
const cx = circle.getAttribute('cx')
|
||||||
|
if (cx) {
|
||||||
|
cxValues.push(parseFloat(cx))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('\n========== LARGE TIMESTAMP TEST ==========')
|
||||||
|
console.log('Data X values:', data.map(d => d.x))
|
||||||
|
console.log('Rendered CX values:', cxValues.map(v => v.toFixed(2)))
|
||||||
|
|
||||||
|
const minCx = Math.min(...cxValues)
|
||||||
|
const maxCx = Math.max(...cxValues)
|
||||||
|
console.log(`CX range: ${(maxCx - minCx).toFixed(2)}px`)
|
||||||
|
console.log('==========================================\n')
|
||||||
|
|
||||||
|
// Points should still be spread out even with large timestamps
|
||||||
|
expect(maxCx - minCx).to.be.greaterThan(50,
|
||||||
|
'Points with large timestamps should still be spread across the chart')
|
||||||
|
})
|
||||||
|
})
|
||||||
514
app/src/components/Chart/Chart.spec.tsx
Normal file
514
app/src/components/Chart/Chart.spec.tsx
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
/**
|
||||||
|
* Chart Component Tests
|
||||||
|
*
|
||||||
|
* These tests verify the Chart component functionality including:
|
||||||
|
* - Rendering with various data configurations
|
||||||
|
* - Theme integration
|
||||||
|
* - Interactive features (tooltips, hover states)
|
||||||
|
* - Different curve interpolation types
|
||||||
|
* - Custom domains and ranges
|
||||||
|
* - Responsive behavior
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import { describe, it } from 'mocha'
|
||||||
|
import Chart, { Props as ChartProps } from './Chart'
|
||||||
|
import { renderWithProviders, createMockChartData, screen } from '../../utils/spec/testUtils'
|
||||||
|
import { PlotCurveTypes } from '../../reducers/Charts'
|
||||||
|
|
||||||
|
describe('Chart Component', () => {
|
||||||
|
describe('Basic Rendering', () => {
|
||||||
|
it('should render without crashing with valid data', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container).to.exist
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render NoData component when data is empty', () => {
|
||||||
|
const { container } = renderWithProviders(<Chart data={[]} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container).to.exist
|
||||||
|
// NoData component should be rendered
|
||||||
|
const noDataElement = container.querySelector('div')
|
||||||
|
expect(noDataElement).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render chart with correct height', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
const chartContainer = container.querySelector('[style*="height"]') as HTMLElement
|
||||||
|
expect(chartContainer).to.exist
|
||||||
|
expect(chartContainer.style.height).to.equal('150px')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render SVG chart elements', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Check for SVG element
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
// Check for chart elements (paths for line series)
|
||||||
|
const paths = container.querySelectorAll('path')
|
||||||
|
expect(paths.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Data Visualization', () => {
|
||||||
|
it('should render data points as glyphs', () => {
|
||||||
|
const data = createMockChartData(3)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Check for circles (glyphs representing data points)
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render exact number of data points matching data length', () => {
|
||||||
|
const dataLength = 5
|
||||||
|
const data = createMockChartData(dataLength)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Each data point should render as a circle
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(dataLength, `Expected ${dataLength} circles for ${dataLength} data points`)
|
||||||
|
|
||||||
|
// Verify each circle has proper attributes
|
||||||
|
circles.forEach((circle, index) => {
|
||||||
|
expect(circle.getAttribute('cx')).to.exist
|
||||||
|
expect(circle.getAttribute('cy')).to.exist
|
||||||
|
expect(circle.getAttribute('r')).to.equal('3')
|
||||||
|
expect(circle.getAttribute('fill')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should position data points with valid coordinates', () => {
|
||||||
|
const data = createMockChartData(3)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
circles.forEach((circle) => {
|
||||||
|
const cx = parseFloat(circle.getAttribute('cx') || '0')
|
||||||
|
const cy = parseFloat(circle.getAttribute('cy') || '0')
|
||||||
|
|
||||||
|
// Coordinates should be valid numbers
|
||||||
|
expect(cx).to.be.a('number')
|
||||||
|
expect(cy).to.be.a('number')
|
||||||
|
expect(isNaN(cx)).to.be.false
|
||||||
|
expect(isNaN(cy)).to.be.false
|
||||||
|
|
||||||
|
// Coordinates should be within chart bounds (positive values)
|
||||||
|
expect(cx).to.be.greaterThan(0)
|
||||||
|
expect(cy).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render line connecting data points', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Line series should create a path element
|
||||||
|
const paths = container.querySelectorAll('path')
|
||||||
|
expect(paths.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle single data point', () => {
|
||||||
|
const data = [{ x: Date.now(), y: 50 }]
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(1, 'Single data point should render as one circle')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle large datasets', () => {
|
||||||
|
const data = createMockChartData(100)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
const circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(100, '100 data points should render as 100 circles')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Curve Interpolation', () => {
|
||||||
|
const curveTypes: PlotCurveTypes[] = ['curve', 'linear', 'cubic_basis_spline', 'step_after', 'step_before']
|
||||||
|
|
||||||
|
curveTypes.forEach((interpolation) => {
|
||||||
|
it(`should render with ${interpolation} interpolation`, () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} interpolation={interpolation} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
const paths = container.querySelectorAll('path')
|
||||||
|
expect(paths.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Custom Styling', () => {
|
||||||
|
it('should apply custom color', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const customColor = '#ff0000'
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} color={customColor} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if custom color is applied to line or glyphs
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should use theme colors when no custom color provided', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Custom Domains and Ranges', () => {
|
||||||
|
it('should render with custom Y range', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const range: [number, number] = [0, 100]
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} range={range} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render with custom time range', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const timeRangeStart = 60000 // 1 minute
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} timeRangeStart={timeRangeStart} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render with partial Y range (only min)', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const range: [number?, number?] = [0, undefined]
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} range={range} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render with partial Y range (only max)', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const range: [number?, number?] = [undefined, 100]
|
||||||
|
const { container } = renderWithProviders(
|
||||||
|
<Chart data={data} range={range} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Chart Components', () => {
|
||||||
|
it('should render Y-axis', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Y-axis should be present (look for axis group or tick marks)
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
// Axis typically contains text elements for labels
|
||||||
|
const texts = container.querySelectorAll('text')
|
||||||
|
expect(texts.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render X-axis with time labels', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// X-axis should be present with text labels
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
// X-axis has text labels for timestamps
|
||||||
|
const texts = container.querySelectorAll('text')
|
||||||
|
expect(texts.length).to.be.greaterThan(0, 'X-axis and Y-axis should have text labels')
|
||||||
|
|
||||||
|
// At least one text element should contain time format (e.g., contains ":")
|
||||||
|
let hasTimeFormat = false
|
||||||
|
texts.forEach((text) => {
|
||||||
|
if (text.textContent && text.textContent.includes(':')) {
|
||||||
|
hasTimeFormat = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(hasTimeFormat).to.be.true
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render both X and Y axes', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
// Both axes should render tick marks (lines)
|
||||||
|
const lines = container.querySelectorAll('line')
|
||||||
|
expect(lines.length).to.be.greaterThan(0, 'Axes should render tick marks')
|
||||||
|
|
||||||
|
// Both axes should have labels (text)
|
||||||
|
const texts = container.querySelectorAll('text')
|
||||||
|
expect(texts.length).to.be.greaterThan(2, 'Both axes should have multiple labels')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render grid lines', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Grid lines are rendered as line elements
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should have proper chart margins', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
const svg = container.querySelector('svg')
|
||||||
|
expect(svg).to.exist
|
||||||
|
|
||||||
|
// SVG should have proper dimensions
|
||||||
|
expect(svg?.getAttribute('width')).to.exist
|
||||||
|
expect(svg?.getAttribute('height')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Edge Cases', () => {
|
||||||
|
it('should handle negative values', () => {
|
||||||
|
const data = [
|
||||||
|
{ x: Date.now() - 2000, y: -50 },
|
||||||
|
{ x: Date.now() - 1000, y: -25 },
|
||||||
|
{ x: Date.now(), y: -75 },
|
||||||
|
]
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle zero values', () => {
|
||||||
|
const data = [
|
||||||
|
{ x: Date.now() - 2000, y: 0 },
|
||||||
|
{ x: Date.now() - 1000, y: 0 },
|
||||||
|
{ x: Date.now(), y: 0 },
|
||||||
|
]
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle very large numbers', () => {
|
||||||
|
const data = [
|
||||||
|
{ x: Date.now() - 2000, y: 1000000 },
|
||||||
|
{ x: Date.now() - 1000, y: 2000000 },
|
||||||
|
{ x: Date.now(), y: 3000000 },
|
||||||
|
]
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
// Y-axis should abbreviate large numbers
|
||||||
|
const texts = container.querySelectorAll('text')
|
||||||
|
expect(texts.length).to.be.greaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle identical values', () => {
|
||||||
|
const data = [
|
||||||
|
{ x: Date.now() - 2000, y: 50 },
|
||||||
|
{ x: Date.now() - 1000, y: 50 },
|
||||||
|
{ x: Date.now(), y: 50 },
|
||||||
|
]
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Component Props', () => {
|
||||||
|
it('should accept all valid props without errors', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const props: ChartProps = {
|
||||||
|
data,
|
||||||
|
interpolation: 'curve',
|
||||||
|
range: [0, 100],
|
||||||
|
timeRangeStart: 60000,
|
||||||
|
color: '#00ff00',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { container } = renderWithProviders(<Chart {...props} />, { withTheme: true })
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work with minimal props', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Theme Integration', () => {
|
||||||
|
it('should render in light theme', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { container } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
|
||||||
|
// Note: Testing dark theme would require a custom theme provider
|
||||||
|
// This demonstrates how the test structure supports theme variations
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Performance', () => {
|
||||||
|
it('should memoize component with same props', () => {
|
||||||
|
const data = createMockChartData(5)
|
||||||
|
const { rerender } = renderWithProviders(<Chart data={data} />, { withTheme: true })
|
||||||
|
|
||||||
|
// Component should not re-render with same props due to React.memo
|
||||||
|
expect(() => {
|
||||||
|
rerender(<Chart data={data} />)
|
||||||
|
}).to.not.throw()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle rapid data updates', () => {
|
||||||
|
const { rerender, container } = renderWithProviders(
|
||||||
|
<Chart data={createMockChartData(5)} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Simulate rapid updates
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
rerender(<Chart data={createMockChartData(5)} />)
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Interactive Data Updates', () => {
|
||||||
|
it('should dynamically update when data points are added', () => {
|
||||||
|
// Start with 3 data points
|
||||||
|
const initialData = createMockChartData(3)
|
||||||
|
const { rerender, container } = renderWithProviders(
|
||||||
|
<Chart data={initialData} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify initial state: should have 3 data points
|
||||||
|
const initialCircles = container.querySelectorAll('circle')
|
||||||
|
expect(initialCircles.length).to.equal(3, 'Should initially render 3 data points')
|
||||||
|
|
||||||
|
// Verify each initial circle has valid attributes
|
||||||
|
initialCircles.forEach((circle, index) => {
|
||||||
|
const cx = circle.getAttribute('cx')
|
||||||
|
const cy = circle.getAttribute('cy')
|
||||||
|
const r = circle.getAttribute('r')
|
||||||
|
|
||||||
|
expect(cx).to.exist
|
||||||
|
expect(cy).to.exist
|
||||||
|
expect(r).to.equal('3')
|
||||||
|
expect(parseFloat(cx!)).to.be.a('number').and.not.NaN
|
||||||
|
expect(parseFloat(cy!)).to.be.a('number').and.not.NaN
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update state: add 2 more data points (total 5)
|
||||||
|
const updatedData = createMockChartData(5)
|
||||||
|
rerender(<Chart data={updatedData} />)
|
||||||
|
|
||||||
|
// Verify updated state: should now have 5 data points
|
||||||
|
const updatedCircles = container.querySelectorAll('circle')
|
||||||
|
expect(updatedCircles.length).to.equal(5, 'Should render 5 data points after update')
|
||||||
|
|
||||||
|
// Verify each updated circle has valid attributes
|
||||||
|
updatedCircles.forEach((circle, index) => {
|
||||||
|
const cx = circle.getAttribute('cx')
|
||||||
|
const cy = circle.getAttribute('cy')
|
||||||
|
const r = circle.getAttribute('r')
|
||||||
|
const fill = circle.getAttribute('fill')
|
||||||
|
|
||||||
|
expect(cx).to.exist
|
||||||
|
expect(cy).to.exist
|
||||||
|
expect(r).to.equal('3')
|
||||||
|
expect(fill).to.exist
|
||||||
|
expect(parseFloat(cx!)).to.be.a('number').and.not.NaN
|
||||||
|
expect(parseFloat(cy!)).to.be.a('number').and.not.NaN
|
||||||
|
expect(parseFloat(cy!)).to.be.greaterThan(0, 'Y coordinate should be positive')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Verify the line path is updated to connect all 5 points
|
||||||
|
const linePath = container.querySelector('path[stroke]')
|
||||||
|
expect(linePath).to.exist
|
||||||
|
expect(linePath!.getAttribute('d')).to.exist
|
||||||
|
|
||||||
|
// The path should start with MoveTo (M) command and contain curve/line commands
|
||||||
|
const pathData = linePath!.getAttribute('d')
|
||||||
|
expect(pathData).to.include('M') // MoveTo command for first point
|
||||||
|
// Path may contain 'L' (line) or 'C' (curve) commands depending on interpolation
|
||||||
|
expect(pathData!.length).to.be.greaterThan(10, 'Path should have substantial data for 5 points')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle data point removal', () => {
|
||||||
|
// Start with 5 data points
|
||||||
|
const initialData = createMockChartData(5)
|
||||||
|
const { rerender, container } = renderWithProviders(
|
||||||
|
<Chart data={initialData} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify initial state
|
||||||
|
let circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(5, 'Should initially render 5 data points')
|
||||||
|
|
||||||
|
// Remove 2 data points (now 3)
|
||||||
|
const reducedData = createMockChartData(3)
|
||||||
|
rerender(<Chart data={reducedData} />)
|
||||||
|
|
||||||
|
// Verify reduced state
|
||||||
|
circles = container.querySelectorAll('circle')
|
||||||
|
expect(circles.length).to.equal(3, 'Should render 3 data points after removal')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should maintain chart structure during data updates', () => {
|
||||||
|
const initialData = createMockChartData(3)
|
||||||
|
const { rerender, container } = renderWithProviders(
|
||||||
|
<Chart data={initialData} />,
|
||||||
|
{ withTheme: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify chart structure exists initially
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
expect(container.querySelectorAll('line').length).to.be.greaterThan(0, 'Should have axis/grid lines')
|
||||||
|
expect(container.querySelectorAll('text').length).to.be.greaterThan(0, 'Should have axis labels')
|
||||||
|
|
||||||
|
// Update data
|
||||||
|
const updatedData = createMockChartData(5)
|
||||||
|
rerender(<Chart data={updatedData} />)
|
||||||
|
|
||||||
|
// Verify chart structure is maintained after update
|
||||||
|
expect(container.querySelector('svg')).to.exist
|
||||||
|
expect(container.querySelectorAll('line').length).to.be.greaterThan(0, 'Should still have axis/grid lines')
|
||||||
|
expect(container.querySelectorAll('text').length).to.be.greaterThan(0, 'Should still have axis labels')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import '../../react-vis-compat' // React 19 compatibility shim for react-vis
|
|
||||||
import DateFormatter from '../helper/DateFormatter'
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
import NoData from './NoData'
|
import NoData from './NoData'
|
||||||
import NumberFormatter from '../helper/NumberFormatter'
|
import NumberFormatter from '../helper/NumberFormatter'
|
||||||
import React, { memo, useCallback, useRef, useEffect } from 'react'
|
import React, { memo, useCallback, useMemo } from 'react'
|
||||||
import TooltipComponent from './TooltipComponent'
|
import TooltipComponent from './TooltipComponent'
|
||||||
import { useResizeDetector } from 'react-resize-detector'
|
import { useResizeDetector } from 'react-resize-detector'
|
||||||
import { emphasize, useTheme } from '@mui/material/styles'
|
import { emphasize, useTheme } from '@mui/material/styles'
|
||||||
@@ -11,8 +10,7 @@ import { PlotCurveTypes } from '../../reducers/Charts'
|
|||||||
import { Point, Tooltip } from './Model'
|
import { Point, Tooltip } from './Model'
|
||||||
import { useCustomXDomain } from './effects/useCustomXDomain'
|
import { useCustomXDomain } from './effects/useCustomXDomain'
|
||||||
import { useCustomYDomain } from './effects/useCustomYDomain'
|
import { useCustomYDomain } from './effects/useCustomYDomain'
|
||||||
import 'react-vis/dist/style.css'
|
import { XYChart, Axis, Grid, LineSeries, GlyphSeries } from '@visx/xychart'
|
||||||
const { XYPlot, LineMarkSeries, YAxis, HorizontalGridLines, Hint } = require('react-vis')
|
|
||||||
const abbreviate = require('number-abbreviate')
|
const abbreviate = require('number-abbreviate')
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@@ -23,10 +21,14 @@ export interface Props {
|
|||||||
color?: string
|
color?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CHART_HEIGHT = 150
|
||||||
|
|
||||||
export default memo((props: Props) => {
|
export default memo((props: Props) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const [tooltip, setTooltip] = React.useState<Tooltip | undefined>()
|
const [tooltip, setTooltip] = React.useState<Tooltip | undefined>()
|
||||||
|
const [hoveredPoint, setHoveredPoint] = React.useState<Point | undefined>()
|
||||||
const { width = 300, ref } = useResizeDetector()
|
const { width = 300, ref } = useResizeDetector()
|
||||||
|
const chartContainerRef = React.useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const hintFormatter = React.useCallback(
|
const hintFormatter = React.useCallback(
|
||||||
(point: any) => [
|
(point: any) => [
|
||||||
@@ -39,14 +41,19 @@ export default memo((props: Props) => {
|
|||||||
|
|
||||||
const onMouseLeave = React.useCallback(() => {
|
const onMouseLeave = React.useCallback(() => {
|
||||||
setTooltip(undefined)
|
setTooltip(undefined)
|
||||||
|
setHoveredPoint(undefined)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const showTooltip = React.useCallback((point: Point, something: { event: MouseEvent }) => {
|
const showTooltip = React.useCallback(
|
||||||
if (!something) {
|
(point: Point) => {
|
||||||
|
if (!chartContainerRef.current) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setTooltip({ point, value: hintFormatter(point), element: something.event.target as any })
|
setHoveredPoint(point)
|
||||||
}, [])
|
setTooltip({ point, value: hintFormatter(point), element: chartContainerRef.current })
|
||||||
|
},
|
||||||
|
[hintFormatter]
|
||||||
|
)
|
||||||
|
|
||||||
const paletteColor =
|
const paletteColor =
|
||||||
theme.palette.mode === 'light' ? theme.palette.secondary.dark : theme.palette.primary.light
|
theme.palette.mode === 'light' ? theme.palette.secondary.dark : theme.palette.primary.light
|
||||||
@@ -54,47 +61,105 @@ export default memo((props: Props) => {
|
|||||||
|
|
||||||
const highlightSelectedPoint = useCallback(
|
const highlightSelectedPoint = useCallback(
|
||||||
(point: Point) => {
|
(point: Point) => {
|
||||||
const highlight = tooltip && tooltip.point.x === point.x && tooltip.point.y === point.y
|
const highlight = hoveredPoint && hoveredPoint.x === point.x && hoveredPoint.y === point.y
|
||||||
return highlight ? emphasize(color, 0.8) : color
|
return highlight ? emphasize(color, 0.8) : color
|
||||||
},
|
},
|
||||||
[tooltip, color]
|
[hoveredPoint, color]
|
||||||
)
|
)
|
||||||
|
|
||||||
const formatYAxis = useCallback((num: number) => abbreviate(num), [])
|
const formatYAxis = useCallback((num: number) => abbreviate(num), [])
|
||||||
|
|
||||||
|
const formatXAxis = useCallback((timestamp: number) => {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
const hours = date.getHours().toString().padStart(2, '0')
|
||||||
|
const minutes = date.getMinutes().toString().padStart(2, '0')
|
||||||
|
const seconds = date.getSeconds().toString().padStart(2, '0')
|
||||||
|
return `${hours}:${minutes}:${seconds}`
|
||||||
|
}, [])
|
||||||
|
|
||||||
const xDomain = useCustomXDomain(props)
|
const xDomain = useCustomXDomain(props)
|
||||||
const yDomain = useCustomYDomain(props)
|
const yDomain = useCustomYDomain(props)
|
||||||
|
|
||||||
const data = props.data
|
const data = props.data
|
||||||
const hasData = data.length > 0
|
const hasData = data.length > 0
|
||||||
const dummyDomain = [-1, 1]
|
const dummyDomain: [number, number] = [-1, 1]
|
||||||
const dummyData = [{ x: -2, y: -2 }]
|
const dummyData = [{ x: -2, y: -2 }]
|
||||||
|
|
||||||
|
const accessors = useMemo(
|
||||||
|
() => ({
|
||||||
|
xAccessor: (d: Point) => d.x,
|
||||||
|
yAccessor: (d: Point) => d.y,
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div ref={ref} style={{ height: '150px', width: '100%', position: 'relative' }}>
|
<div ref={ref} style={{ height: `${CHART_HEIGHT}px`, width: '100%', position: 'relative' }}>
|
||||||
{data.length === 0 ? <NoData /> : null}
|
{data.length === 0 ? <NoData /> : null}
|
||||||
<XYPlot
|
<div ref={chartContainerRef}>
|
||||||
|
<XYChart
|
||||||
width={width || 300}
|
width={width || 300}
|
||||||
height={180}
|
height={CHART_HEIGHT}
|
||||||
yDomain={hasData ? yDomain : dummyDomain}
|
margin={{ top: 10, right: 10, bottom: 30, left: 50 }}
|
||||||
xDomain={hasData ? xDomain : dummyDomain}
|
xScale={{ type: 'time', domain: xDomain || dummyDomain }}
|
||||||
onMouseLeave={onMouseLeave}
|
yScale={{ type: 'linear', domain: hasData ? yDomain : dummyDomain }}
|
||||||
|
onPointerOut={onMouseLeave}
|
||||||
>
|
>
|
||||||
<HorizontalGridLines />
|
<Grid rows={true} columns={false} stroke={theme.palette.divider} strokeOpacity={0.3} />
|
||||||
<YAxis width={45} tickFormat={formatYAxis} />
|
<Axis
|
||||||
<LineMarkSeries
|
orientation="left"
|
||||||
color={color}
|
numTicks={5}
|
||||||
colorType="literal"
|
tickFormat={formatYAxis}
|
||||||
getColor={highlightSelectedPoint}
|
stroke={theme.palette.text.secondary}
|
||||||
onValueMouseOver={showTooltip}
|
tickStroke={theme.palette.text.secondary}
|
||||||
size={3}
|
tickLabelProps={() => ({ fontSize: 11, fill: theme.palette.text.secondary })}
|
||||||
data={hasData ? data : dummyData}
|
|
||||||
curve={mapCurveType(props.interpolation)}
|
|
||||||
/>
|
/>
|
||||||
<Hint value={{ x: 0, y: 0 }} style={{ pointerEvents: 'none' }}>
|
<Axis
|
||||||
|
orientation="bottom"
|
||||||
|
numTicks={4}
|
||||||
|
tickFormat={formatXAxis}
|
||||||
|
stroke={theme.palette.text.secondary}
|
||||||
|
tickStroke={theme.palette.text.secondary}
|
||||||
|
tickLabelProps={() => ({ fontSize: 10, fill: theme.palette.text.secondary, textAnchor: 'middle' })}
|
||||||
|
/>
|
||||||
|
<LineSeries
|
||||||
|
dataKey="line"
|
||||||
|
data={hasData ? data : dummyData}
|
||||||
|
xAccessor={accessors.xAccessor}
|
||||||
|
yAccessor={accessors.yAccessor}
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth={2}
|
||||||
|
curve={mapCurveType(props.interpolation)}
|
||||||
|
onPointerMove={(datum) => {
|
||||||
|
if (datum && datum.datum) {
|
||||||
|
const point = datum.datum as Point
|
||||||
|
showTooltip(point)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<GlyphSeries
|
||||||
|
dataKey="points"
|
||||||
|
data={hasData ? data : dummyData}
|
||||||
|
xAccessor={accessors.xAccessor}
|
||||||
|
yAccessor={accessors.yAccessor}
|
||||||
|
renderGlyph={(glyphProps) => {
|
||||||
|
const point = glyphProps.datum as Point
|
||||||
|
const pointColor = highlightSelectedPoint(point)
|
||||||
|
return (
|
||||||
|
<circle
|
||||||
|
cx={glyphProps.x}
|
||||||
|
cy={glyphProps.y}
|
||||||
|
r={3}
|
||||||
|
fill={pointColor}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</XYChart>
|
||||||
|
</div>
|
||||||
|
{/* Custom tooltip outside of visx to maintain exact same appearance */}
|
||||||
<TooltipComponent tooltip={tooltip} />
|
<TooltipComponent tooltip={tooltip} />
|
||||||
</Hint>
|
|
||||||
</XYPlot>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,22 @@ import { Props } from '../Chart'
|
|||||||
|
|
||||||
export function useCustomXDomain(props: Props): [number, number] | undefined {
|
export function useCustomXDomain(props: Props): [number, number] | undefined {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
|
if (props.data.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
const lastDataPoint = [...props.data].sort((a, b) => b.x - a.x)[0]
|
const lastDataPoint = [...props.data].sort((a, b) => b.x - a.x)[0]
|
||||||
const lastDataDate = lastDataPoint ? lastDataPoint.x : Date.now()
|
const lastDataDate = lastDataPoint ? lastDataPoint.x : Date.now()
|
||||||
return props.timeRangeStart ? [Date.now() - props.timeRangeStart, lastDataDate] : undefined
|
|
||||||
|
if (props.timeRangeStart) {
|
||||||
|
// Custom time range mode
|
||||||
|
return [Date.now() - props.timeRangeStart, lastDataDate]
|
||||||
|
} else {
|
||||||
|
// Auto-calculate from data (like react-vis did)
|
||||||
|
const xValues = props.data.map(d => d.x)
|
||||||
|
const minX = Math.min(...xValues)
|
||||||
|
const maxX = Math.max(...xValues)
|
||||||
|
return [minX, maxX]
|
||||||
|
}
|
||||||
}, [props.data, props.timeRangeStart])
|
}, [props.data, props.timeRangeStart])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { PlotCurveTypes } from '../../reducers/Charts'
|
import { PlotCurveTypes } from '../../reducers/Charts'
|
||||||
|
import * as d3Shape from 'd3-shape'
|
||||||
|
|
||||||
export function mapCurveType(type: PlotCurveTypes | undefined) {
|
export function mapCurveType(type: PlotCurveTypes | undefined) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'curve':
|
case 'curve':
|
||||||
return 'curveMonotoneX'
|
return d3Shape.curveMonotoneX
|
||||||
case 'linear':
|
case 'linear':
|
||||||
return 'curveLinear'
|
return d3Shape.curveLinear
|
||||||
case 'cubic_basis_spline':
|
case 'cubic_basis_spline':
|
||||||
return 'curveBasis'
|
return d3Shape.curveBasis
|
||||||
case 'step_after':
|
case 'step_after':
|
||||||
return 'curveStepAfter'
|
return d3Shape.curveStepAfter
|
||||||
case 'step_before':
|
case 'step_before':
|
||||||
return 'curveStepBefore'
|
return d3Shape.curveStepBefore
|
||||||
default:
|
default:
|
||||||
return 'curveMonotoneX'
|
return d3Shape.curveMonotoneX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,15 @@ function mapWidth(width: 'big' | 'medium' | 'small' | undefined, calculatedSpaci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to generate unique keys for charts
|
||||||
|
const getChartKey = (chart: ChartParameters) => `${chart.topic}-${chart.dotPath || ''}`
|
||||||
|
|
||||||
function ChartPanel(props: Props) {
|
function ChartPanel(props: Props) {
|
||||||
const chartsInView = props.charts.count()
|
const chartsInView = props.charts.count()
|
||||||
|
|
||||||
const [spacing, setSpacing] = React.useState(spacingForChartCount(chartsInView))
|
const [spacing, setSpacing] = React.useState(spacingForChartCount(chartsInView))
|
||||||
|
const nodeRefsMap = React.useRef<Map<string, React.RefObject<HTMLDivElement>>>(new Map())
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
props.actions.chart.loadCharts()
|
props.actions.chart.loadCharts()
|
||||||
@@ -65,17 +70,42 @@ function ChartPanel(props: Props) {
|
|||||||
}
|
}
|
||||||
}, [chartsInView])
|
}, [chartsInView])
|
||||||
|
|
||||||
const charts = props.charts.map(chartParameters => (
|
// Clean up refs for removed charts
|
||||||
|
React.useEffect(() => {
|
||||||
|
const currentKeys = new Set(props.charts.map(getChartKey).toArray())
|
||||||
|
const refsToDelete: string[] = []
|
||||||
|
|
||||||
|
nodeRefsMap.current.forEach((_, key) => {
|
||||||
|
if (!currentKeys.has(key)) {
|
||||||
|
refsToDelete.push(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
refsToDelete.forEach(key => nodeRefsMap.current.delete(key))
|
||||||
|
}, [props.charts])
|
||||||
|
|
||||||
|
const charts = props.charts.map(chartParameters => {
|
||||||
|
const key = getChartKey(chartParameters)
|
||||||
|
|
||||||
|
// Get or create a ref for this specific chart
|
||||||
|
if (!nodeRefsMap.current.has(key)) {
|
||||||
|
nodeRefsMap.current.set(key, React.createRef<HTMLDivElement>())
|
||||||
|
}
|
||||||
|
const nodeRef = nodeRefsMap.current.get(key)!
|
||||||
|
|
||||||
|
return (
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
key={`${chartParameters.topic}-${chartParameters.dotPath || ''}`}
|
key={key}
|
||||||
timeout={{ enter: 500, exit: 500 }}
|
timeout={{ enter: 500, exit: 500 }}
|
||||||
classNames="example"
|
classNames="example"
|
||||||
|
nodeRef={nodeRef}
|
||||||
>
|
>
|
||||||
<Grid item xs={mapWidth(chartParameters.width, spacing)}>
|
<Grid item xs={mapWidth(chartParameters.width, spacing)} ref={nodeRef}>
|
||||||
<ChartWithTreeNode tree={props.tree} parameters={chartParameters} />
|
<ChartWithTreeNode tree={props.tree} parameters={chartParameters} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
))
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={props.classes.container}>
|
<div className={props.classes.container}>
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* React 19 compatibility shim for react-vis
|
|
||||||
*
|
|
||||||
* react-vis uses React internals that were removed in React 19.
|
|
||||||
* This shim adds back the missing internals to maintain compatibility.
|
|
||||||
*/
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
// Add missing React internals that react-vis expects
|
|
||||||
if (typeof React !== 'undefined') {
|
|
||||||
const internals = (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
||||||
|
|
||||||
if (internals) {
|
|
||||||
// ReactCurrentOwner was removed in React 19 but react-vis expects it
|
|
||||||
if (!internals.ReactCurrentOwner) {
|
|
||||||
internals.ReactCurrentOwner = {
|
|
||||||
current: null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReactCurrentDispatcher compatibility
|
|
||||||
if (!internals.ReactCurrentDispatcher) {
|
|
||||||
internals.ReactCurrentDispatcher = {
|
|
||||||
current: null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
166
app/src/utils/spec/testUtils.tsx
Normal file
166
app/src/utils/spec/testUtils.tsx
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* Generic test utilities for React component testing
|
||||||
|
*
|
||||||
|
* This file provides a reusable testing setup that can be used across all component tests.
|
||||||
|
* It includes:
|
||||||
|
* - Custom render function with theme and Redux providers
|
||||||
|
* - Common test utilities and matchers
|
||||||
|
* - Mock setup helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { render, RenderOptions, RenderResult } from '@testing-library/react'
|
||||||
|
import { ThemeProvider, createTheme } from '@mui/material/styles'
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
import { configureStore } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
|
// Setup JSDOM environment for tests
|
||||||
|
import 'jsdom-global/register'
|
||||||
|
|
||||||
|
// Setup global mocks
|
||||||
|
mockResizeObserver()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create a ResizeObserver mock
|
||||||
|
* This is set up globally for all tests
|
||||||
|
*/
|
||||||
|
export function mockResizeObserver() {
|
||||||
|
const MockResizeObserver = class ResizeObserver {
|
||||||
|
observe() {}
|
||||||
|
unobserve() {}
|
||||||
|
disconnect() {}
|
||||||
|
} as any
|
||||||
|
|
||||||
|
if (typeof global.ResizeObserver === 'undefined') {
|
||||||
|
global.ResizeObserver = MockResizeObserver
|
||||||
|
}
|
||||||
|
if (typeof window !== 'undefined' && typeof window.ResizeObserver === 'undefined') {
|
||||||
|
(window as any).ResizeObserver = MockResizeObserver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default theme for testing
|
||||||
|
*/
|
||||||
|
const defaultTheme = createTheme({
|
||||||
|
palette: {
|
||||||
|
mode: 'light',
|
||||||
|
primary: {
|
||||||
|
main: '#1976d2',
|
||||||
|
light: '#42a5f5',
|
||||||
|
dark: '#1565c0',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: '#9c27b0',
|
||||||
|
light: '#ba68c8',
|
||||||
|
dark: '#7b1fa2',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: 'rgba(0, 0, 0, 0.87)',
|
||||||
|
secondary: 'rgba(0, 0, 0, 0.6)',
|
||||||
|
},
|
||||||
|
divider: 'rgba(0, 0, 0, 0.12)',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Redux store for testing
|
||||||
|
*/
|
||||||
|
const createTestStore = (initialState = {}) => {
|
||||||
|
return configureStore({
|
||||||
|
reducer: {
|
||||||
|
// Add minimal reducers as needed
|
||||||
|
charts: (state = { charts: [] }) => state,
|
||||||
|
connection: (state = {}) => state,
|
||||||
|
},
|
||||||
|
preloadedState: initialState,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom render options
|
||||||
|
*/
|
||||||
|
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
||||||
|
theme?: typeof defaultTheme
|
||||||
|
store?: ReturnType<typeof createTestStore>
|
||||||
|
withTheme?: boolean
|
||||||
|
withRedux?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom render function that wraps components with necessary providers
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* import { renderWithProviders } from '../utils/spec/testUtils'
|
||||||
|
*
|
||||||
|
* describe('MyComponent', () => {
|
||||||
|
* it('renders correctly', () => {
|
||||||
|
* const { getByText } = renderWithProviders(<MyComponent />)
|
||||||
|
* expect(getByText('Hello')).toBeDefined()
|
||||||
|
* })
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function renderWithProviders(
|
||||||
|
ui: React.ReactElement,
|
||||||
|
{
|
||||||
|
theme = defaultTheme,
|
||||||
|
store = createTestStore(),
|
||||||
|
withTheme = true,
|
||||||
|
withRedux = false,
|
||||||
|
...renderOptions
|
||||||
|
}: CustomRenderOptions = {}
|
||||||
|
): RenderResult {
|
||||||
|
let Wrapper: React.FC<{ children: React.ReactNode }>
|
||||||
|
|
||||||
|
if (withRedux && withTheme) {
|
||||||
|
Wrapper = ({ children }) => (
|
||||||
|
<Provider store={store}>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
} else if (withRedux) {
|
||||||
|
Wrapper = ({ children }) => (
|
||||||
|
<Provider store={store}>
|
||||||
|
{children}
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
} else if (withTheme) {
|
||||||
|
Wrapper = ({ children }) => (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Wrapper = ({ children }) => <>{children}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(ui, { wrapper: Wrapper, ...renderOptions })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create mock chart data
|
||||||
|
*/
|
||||||
|
export function createMockChartData(count: number = 10): Array<{ x: number; y: number }> {
|
||||||
|
const now = Date.now()
|
||||||
|
return Array.from({ length: count }, (_, i) => ({
|
||||||
|
x: now - (count - i) * 1000,
|
||||||
|
y: Math.random() * 100,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to wait for async operations
|
||||||
|
*/
|
||||||
|
export const waitFor = async (ms: number = 100) => {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-export everything from @testing-library/react for convenience
|
||||||
|
*/
|
||||||
|
export * from '@testing-library/react'
|
||||||
|
export { default as userEvent } from '@testing-library/user-event'
|
||||||
1054
app/yarn.lock
1054
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -118,7 +118,7 @@
|
|||||||
"chai": "^4.5.0",
|
"chai": "^4.5.0",
|
||||||
"cspell": "^8.19.4",
|
"cspell": "^8.19.4",
|
||||||
"electron": "39.2.7",
|
"electron": "39.2.7",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.4.0",
|
||||||
"mocha": "^10.8.2",
|
"mocha": "^10.8.2",
|
||||||
"mustache": "^4.2.0",
|
"mustache": "^4.2.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"dot-prop": "^5.3.0",
|
"dot-prop": "^5.3.0",
|
||||||
"electron-log": "^5.4.3",
|
"electron-log": "^5.4.3",
|
||||||
"electron-updater": "^6.6.2",
|
"electron-updater": "^6.7.3",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"express-rate-limit": "^8.2.1",
|
"express-rate-limit": "^8.2.1",
|
||||||
"express-validator": "^7.3.1",
|
"express-validator": "^7.3.1",
|
||||||
|
|||||||
396
yarn.lock
396
yarn.lock
@@ -625,16 +625,7 @@
|
|||||||
ajv "^6.12.0"
|
ajv "^6.12.0"
|
||||||
ajv-keywords "^3.4.1"
|
ajv-keywords "^3.4.1"
|
||||||
|
|
||||||
"@electron/asar@3.2.18":
|
"@electron/asar@3.4.1", "@electron/asar@^3.3.1":
|
||||||
version "3.2.18"
|
|
||||||
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517"
|
|
||||||
integrity sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==
|
|
||||||
dependencies:
|
|
||||||
commander "^5.0.0"
|
|
||||||
glob "^7.1.6"
|
|
||||||
minimatch "^3.0.4"
|
|
||||||
|
|
||||||
"@electron/asar@^3.2.7":
|
|
||||||
version "3.4.1"
|
version "3.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065"
|
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065"
|
||||||
integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==
|
integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==
|
||||||
@@ -667,7 +658,7 @@
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
global-agent "^3.0.0"
|
global-agent "^3.0.0"
|
||||||
|
|
||||||
"@electron/node-gyp@10.2.0-electron.1", "@electron/node-gyp@https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2":
|
"@electron/node-gyp@10.2.0-electron.1":
|
||||||
version "10.2.0-electron.1"
|
version "10.2.0-electron.1"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/node-gyp/-/node-gyp-10.2.0-electron.1.tgz#ca5f125dcd0ffb275797c0c418c0d64005e0f815"
|
resolved "https://registry.yarnpkg.com/@electron/node-gyp/-/node-gyp-10.2.0-electron.1.tgz#ca5f125dcd0ffb275797c0c418c0d64005e0f815"
|
||||||
integrity sha512-YdpRE6qSNYyf7gBv1LBDc8OAs8f/mZthzM1k4pFzodNq8dBGf64MWC5Bq8VVlgdafjQXLpINHvtRAUC9uinoqw==
|
integrity sha512-YdpRE6qSNYyf7gBv1LBDc8OAs8f/mZthzM1k4pFzodNq8dBGf64MWC5Bq8VVlgdafjQXLpINHvtRAUC9uinoqw==
|
||||||
@@ -700,10 +691,10 @@
|
|||||||
debug "^4.4.0"
|
debug "^4.4.0"
|
||||||
promise-retry "^2.0.1"
|
promise-retry "^2.0.1"
|
||||||
|
|
||||||
"@electron/osx-sign@1.3.1":
|
"@electron/osx-sign@1.3.3":
|
||||||
version "1.3.1"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.3.1.tgz#faf7eeca7ca004a6be541dc4cf7a1bd59ec59b1c"
|
resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.3.3.tgz#af751510488318d9f7663694af85819690d75583"
|
||||||
integrity sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==
|
integrity sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==
|
||||||
dependencies:
|
dependencies:
|
||||||
compare-version "^0.1.2"
|
compare-version "^0.1.2"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
@@ -712,32 +703,32 @@
|
|||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
plist "^3.0.5"
|
plist "^3.0.5"
|
||||||
|
|
||||||
"@electron/rebuild@3.7.0":
|
"@electron/rebuild@4.0.1":
|
||||||
version "3.7.0"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-3.7.0.tgz#82e20c467ddedbb295d7f641592c52e68c141e9f"
|
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-4.0.1.tgz#0620d5bb71a0b8b09a86fb9fa979244e1fcc10bf"
|
||||||
integrity sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==
|
integrity sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/node-gyp" "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
|
|
||||||
"@malept/cross-spawn-promise" "^2.0.0"
|
"@malept/cross-spawn-promise" "^2.0.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
detect-libc "^2.0.1"
|
detect-libc "^2.0.1"
|
||||||
fs-extra "^10.0.0"
|
|
||||||
got "^11.7.0"
|
got "^11.7.0"
|
||||||
node-abi "^3.45.0"
|
graceful-fs "^4.2.11"
|
||||||
node-api-version "^0.2.0"
|
node-abi "^4.2.0"
|
||||||
|
node-api-version "^0.2.1"
|
||||||
|
node-gyp "^11.2.0"
|
||||||
ora "^5.1.0"
|
ora "^5.1.0"
|
||||||
read-binary-file-arch "^1.0.6"
|
read-binary-file-arch "^1.0.6"
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
tar "^6.0.5"
|
tar "^6.0.5"
|
||||||
yargs "^17.0.1"
|
yargs "^17.0.1"
|
||||||
|
|
||||||
"@electron/universal@2.0.1":
|
"@electron/universal@2.0.3":
|
||||||
version "2.0.1"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-2.0.1.tgz#7b070ab355e02957388f3dbd68e2c3cd08c448ae"
|
resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-2.0.3.tgz#1680df6ced8f128ca0ff24e29c2165d41d78b3ce"
|
||||||
integrity sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==
|
integrity sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/asar" "^3.2.7"
|
"@electron/asar" "^3.3.1"
|
||||||
"@malept/cross-spawn-promise" "^2.0.0"
|
"@malept/cross-spawn-promise" "^2.0.0"
|
||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
dir-compare "^4.2.0"
|
dir-compare "^4.2.0"
|
||||||
@@ -1034,6 +1025,17 @@
|
|||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
tmp-promise "^3.0.2"
|
tmp-promise "^3.0.2"
|
||||||
|
|
||||||
|
"@npmcli/agent@^3.0.0":
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-3.0.0.tgz#1685b1fbd4a1b7bb4f930cbb68ce801edfe7aa44"
|
||||||
|
integrity sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==
|
||||||
|
dependencies:
|
||||||
|
agent-base "^7.1.0"
|
||||||
|
http-proxy-agent "^7.0.0"
|
||||||
|
https-proxy-agent "^7.0.1"
|
||||||
|
lru-cache "^10.0.1"
|
||||||
|
socks-proxy-agent "^8.0.3"
|
||||||
|
|
||||||
"@npmcli/agent@^4.0.0":
|
"@npmcli/agent@^4.0.0":
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-4.0.0.tgz#2bb2b1c0a170940511554a7986ae2a8be9fedcce"
|
resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-4.0.0.tgz#2bb2b1c0a170940511554a7986ae2a8be9fedcce"
|
||||||
@@ -1106,6 +1108,13 @@
|
|||||||
"@gar/promisify" "^1.1.3"
|
"@gar/promisify" "^1.1.3"
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
|
|
||||||
|
"@npmcli/fs@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-4.0.0.tgz#a1eb1aeddefd2a4a347eca0fab30bc62c0e1c0f2"
|
||||||
|
integrity sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==
|
||||||
|
dependencies:
|
||||||
|
semver "^7.3.5"
|
||||||
|
|
||||||
"@npmcli/fs@^5.0.0":
|
"@npmcli/fs@^5.0.0":
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-5.0.0.tgz#674619771907342b3d1ac197aaf1deeb657e3539"
|
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-5.0.0.tgz#674619771907342b3d1ac197aaf1deeb657e3539"
|
||||||
@@ -1569,7 +1578,7 @@
|
|||||||
|
|
||||||
"@tootallnate/once@2":
|
"@tootallnate/once@2":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||||
|
|
||||||
"@tufjs/canonical-json@2.0.0":
|
"@tufjs/canonical-json@2.0.0":
|
||||||
@@ -1883,6 +1892,11 @@ abbrev@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||||
|
|
||||||
|
abbrev@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-3.0.1.tgz#8ac8b3b5024d31464fe2a5feeea9f4536bf44025"
|
||||||
|
integrity sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==
|
||||||
|
|
||||||
abbrev@^4.0.0:
|
abbrev@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-4.0.0.tgz#ec933f0e27b6cd60e89b5c6b2a304af42209bb05"
|
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-4.0.0.tgz#ec933f0e27b6cd60e89b5c6b2a304af42209bb05"
|
||||||
@@ -1918,7 +1932,7 @@ accepts@~1.3.4:
|
|||||||
|
|
||||||
agent-base@6, agent-base@^6.0.2:
|
agent-base@6, agent-base@^6.0.2:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||||
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "4"
|
debug "4"
|
||||||
@@ -2047,44 +2061,45 @@ app-builder-bin@5.0.0-alpha.12:
|
|||||||
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz#2daf82f8badc698e0adcc95ba36af4ff0650dc80"
|
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz#2daf82f8badc698e0adcc95ba36af4ff0650dc80"
|
||||||
integrity sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==
|
integrity sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==
|
||||||
|
|
||||||
app-builder-lib@26.0.12:
|
app-builder-lib@26.4.0:
|
||||||
version "26.0.12"
|
version "26.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.12.tgz#2e33df936e0f78d4266b058ece90308ea981eefb"
|
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.4.0.tgz#649b4a98b51a90141b73e4f12a74ac5bc0f2eff4"
|
||||||
integrity sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==
|
integrity sha512-Uas6hNe99KzP3xPWxh5LGlH8kWIVjZixzmMJHNB9+6hPyDpjc7NQMkVgi16rQDdpCFy22ZU5sp8ow7tvjeMgYQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@develar/schema-utils" "~2.6.5"
|
"@develar/schema-utils" "~2.6.5"
|
||||||
"@electron/asar" "3.2.18"
|
"@electron/asar" "3.4.1"
|
||||||
"@electron/fuses" "^1.8.0"
|
"@electron/fuses" "^1.8.0"
|
||||||
"@electron/notarize" "2.5.0"
|
"@electron/notarize" "2.5.0"
|
||||||
"@electron/osx-sign" "1.3.1"
|
"@electron/osx-sign" "1.3.3"
|
||||||
"@electron/rebuild" "3.7.0"
|
"@electron/rebuild" "4.0.1"
|
||||||
"@electron/universal" "2.0.1"
|
"@electron/universal" "2.0.3"
|
||||||
"@malept/flatpak-bundler" "^0.4.0"
|
"@malept/flatpak-bundler" "^0.4.0"
|
||||||
"@types/fs-extra" "9.0.13"
|
"@types/fs-extra" "9.0.13"
|
||||||
async-exit-hook "^2.0.1"
|
async-exit-hook "^2.0.1"
|
||||||
builder-util "26.0.11"
|
builder-util "26.3.4"
|
||||||
builder-util-runtime "9.3.1"
|
builder-util-runtime "9.5.1"
|
||||||
chromium-pickle-js "^0.2.0"
|
chromium-pickle-js "^0.2.0"
|
||||||
config-file-ts "0.2.8-rc1"
|
ci-info "4.3.1"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
dotenv "^16.4.5"
|
dotenv "^16.4.5"
|
||||||
dotenv-expand "^11.0.6"
|
dotenv-expand "^11.0.6"
|
||||||
ejs "^3.1.8"
|
ejs "^3.1.8"
|
||||||
electron-publish "26.0.11"
|
electron-publish "26.3.4"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
hosted-git-info "^4.1.0"
|
hosted-git-info "^4.1.0"
|
||||||
is-ci "^3.0.0"
|
|
||||||
isbinaryfile "^5.0.0"
|
isbinaryfile "^5.0.0"
|
||||||
|
jiti "^2.4.2"
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
json5 "^2.2.3"
|
json5 "^2.2.3"
|
||||||
lazy-val "^1.0.5"
|
lazy-val "^1.0.5"
|
||||||
minimatch "^10.0.0"
|
minimatch "^10.0.3"
|
||||||
plist "3.1.0"
|
plist "3.1.0"
|
||||||
resedit "^1.7.0"
|
resedit "^1.7.0"
|
||||||
semver "^7.3.8"
|
semver "~7.7.3"
|
||||||
tar "^6.1.12"
|
tar "^6.1.12"
|
||||||
temp-file "^3.4.0"
|
temp-file "^3.4.0"
|
||||||
tiny-async-pool "1.3.0"
|
tiny-async-pool "1.3.0"
|
||||||
|
which "^5.0.0"
|
||||||
|
|
||||||
append-transform@^2.0.0:
|
append-transform@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
@@ -2372,7 +2387,15 @@ buffer@^6.0.3:
|
|||||||
base64-js "^1.3.1"
|
base64-js "^1.3.1"
|
||||||
ieee754 "^1.2.1"
|
ieee754 "^1.2.1"
|
||||||
|
|
||||||
builder-util-runtime@9.3.1, builder-util-runtime@^9.3.1:
|
builder-util-runtime@9.5.1:
|
||||||
|
version "9.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz#74125fb374d1ecbf472ae1787485485ff7619702"
|
||||||
|
integrity sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.3.4"
|
||||||
|
sax "^1.2.4"
|
||||||
|
|
||||||
|
builder-util-runtime@^9.3.1:
|
||||||
version "9.3.1"
|
version "9.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
||||||
integrity sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==
|
integrity sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==
|
||||||
@@ -2380,22 +2403,21 @@ builder-util-runtime@9.3.1, builder-util-runtime@^9.3.1:
|
|||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
|
|
||||||
builder-util@26.0.11:
|
builder-util@26.3.4:
|
||||||
version "26.0.11"
|
version "26.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.11.tgz#ad85b92c93f2b976b973e1d87337e0c6813fcb8f"
|
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.3.4.tgz#eb20e2e2895fe360360eddded5d8cf12ad2aad60"
|
||||||
integrity sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==
|
integrity sha512-aRn88mYMktHxzdqDMF6Ayj0rKoX+ZogJ75Ck7RrIqbY/ad0HBvnS2xA4uHfzrGr5D2aLL3vU6OBEH4p0KMV2XQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"7zip-bin" "~5.2.0"
|
"7zip-bin" "~5.2.0"
|
||||||
"@types/debug" "^4.1.6"
|
"@types/debug" "^4.1.6"
|
||||||
app-builder-bin "5.0.0-alpha.12"
|
app-builder-bin "5.0.0-alpha.12"
|
||||||
builder-util-runtime "9.3.1"
|
builder-util-runtime "9.5.1"
|
||||||
chalk "^4.1.2"
|
chalk "^4.1.2"
|
||||||
cross-spawn "^7.0.6"
|
cross-spawn "^7.0.6"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
http-proxy-agent "^7.0.0"
|
http-proxy-agent "^7.0.0"
|
||||||
https-proxy-agent "^7.0.0"
|
https-proxy-agent "^7.0.0"
|
||||||
is-ci "^3.0.0"
|
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
sanitize-filename "^1.6.3"
|
sanitize-filename "^1.6.3"
|
||||||
source-map-support "^0.5.19"
|
source-map-support "^0.5.19"
|
||||||
@@ -2437,6 +2459,24 @@ cacache@^16.1.0:
|
|||||||
tar "^6.1.11"
|
tar "^6.1.11"
|
||||||
unique-filename "^2.0.0"
|
unique-filename "^2.0.0"
|
||||||
|
|
||||||
|
cacache@^19.0.1:
|
||||||
|
version "19.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/cacache/-/cacache-19.0.1.tgz#3370cc28a758434c85c2585008bd5bdcff17d6cd"
|
||||||
|
integrity sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==
|
||||||
|
dependencies:
|
||||||
|
"@npmcli/fs" "^4.0.0"
|
||||||
|
fs-minipass "^3.0.0"
|
||||||
|
glob "^10.2.2"
|
||||||
|
lru-cache "^10.0.1"
|
||||||
|
minipass "^7.0.3"
|
||||||
|
minipass-collect "^2.0.1"
|
||||||
|
minipass-flush "^1.0.5"
|
||||||
|
minipass-pipeline "^1.2.4"
|
||||||
|
p-map "^7.0.2"
|
||||||
|
ssri "^12.0.0"
|
||||||
|
tar "^7.4.3"
|
||||||
|
unique-filename "^4.0.0"
|
||||||
|
|
||||||
cacache@^20.0.0, cacache@^20.0.1, cacache@^20.0.3:
|
cacache@^20.0.0, cacache@^20.0.1, cacache@^20.0.3:
|
||||||
version "20.0.3"
|
version "20.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cacache/-/cacache-20.0.3.tgz#bd65205d5e6d86e02bbfaf8e4ce6008f1b81d119"
|
resolved "https://registry.yarnpkg.com/cacache/-/cacache-20.0.3.tgz#bd65205d5e6d86e02bbfaf8e4ce6008f1b81d119"
|
||||||
@@ -2634,21 +2674,16 @@ chromium-pickle-js@^0.2.0:
|
|||||||
resolved "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz"
|
resolved "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz"
|
||||||
integrity sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==
|
integrity sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==
|
||||||
|
|
||||||
ci-info@^3.2.0:
|
ci-info@4.3.1, ci-info@^4.2.0, ci-info@^4.3.1:
|
||||||
version "3.9.0"
|
version "4.3.1"
|
||||||
resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.1.tgz#355ad571920810b5623e11d40232f443f16f1daa"
|
||||||
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
|
integrity sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==
|
||||||
|
|
||||||
ci-info@^4.0.0:
|
ci-info@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2"
|
||||||
integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==
|
integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==
|
||||||
|
|
||||||
ci-info@^4.3.1:
|
|
||||||
version "4.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.1.tgz#355ad571920810b5623e11d40232f443f16f1daa"
|
|
||||||
integrity sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==
|
|
||||||
|
|
||||||
cidr-regex@5.0.1:
|
cidr-regex@5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-5.0.1.tgz#4b3972457b06445832929f6f268b477fe0372c1f"
|
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-5.0.1.tgz#4b3972457b06445832929f6f268b477fe0372c1f"
|
||||||
@@ -2897,14 +2932,6 @@ config-chain@^1.1.11:
|
|||||||
ini "^1.3.4"
|
ini "^1.3.4"
|
||||||
proto-list "~1.2.1"
|
proto-list "~1.2.1"
|
||||||
|
|
||||||
config-file-ts@0.2.8-rc1:
|
|
||||||
version "0.2.8-rc1"
|
|
||||||
resolved "https://registry.yarnpkg.com/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz#fb7fc6ccb2e313f69dbeb78f1db0b00038049de0"
|
|
||||||
integrity sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==
|
|
||||||
dependencies:
|
|
||||||
glob "^10.3.12"
|
|
||||||
typescript "^5.4.3"
|
|
||||||
|
|
||||||
content-disposition@^1.0.0:
|
content-disposition@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b"
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b"
|
||||||
@@ -3336,14 +3363,13 @@ dir-glob@^3.0.0, dir-glob@^3.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
|
|
||||||
dmg-builder@26.0.12:
|
dmg-builder@26.4.0:
|
||||||
version "26.0.12"
|
version "26.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.12.tgz#6996ad0bab80a861c9a7b33ee9734d4f60566b46"
|
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.4.0.tgz#dc7edec167b06b1542804e6e4220d1bcaf952b71"
|
||||||
integrity sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==
|
integrity sha512-ce4Ogns4VMeisIuCSK0C62umG0lFy012jd8LMZ6w/veHUeX4fqfDrGe+HTWALAEwK6JwKP+dhPvizhArSOsFbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib "26.0.12"
|
app-builder-lib "26.4.0"
|
||||||
builder-util "26.0.11"
|
builder-util "26.3.4"
|
||||||
builder-util-runtime "9.3.1"
|
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
iconv-lite "^0.6.2"
|
iconv-lite "^0.6.2"
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
@@ -3439,18 +3465,18 @@ ejs@^3.1.8:
|
|||||||
dependencies:
|
dependencies:
|
||||||
jake "^10.8.5"
|
jake "^10.8.5"
|
||||||
|
|
||||||
electron-builder@^26.0.12:
|
electron-builder@^26.4.0:
|
||||||
version "26.0.12"
|
version "26.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.12.tgz#797af2e70efdd96c9ea5d8a8164b8728c90d65ff"
|
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.4.0.tgz#f9a8598f045ded4cbaf41efb7bb18a89619c5dd2"
|
||||||
integrity sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==
|
integrity sha512-FCUqvdq2AULL+Db2SUGgjOYTbrgkPxZtCjqIZGnjH9p29pTWyesQqBIfvQBKa6ewqde87aWl49n/WyI/NyUBog==
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib "26.0.12"
|
app-builder-lib "26.4.0"
|
||||||
builder-util "26.0.11"
|
builder-util "26.3.4"
|
||||||
builder-util-runtime "9.3.1"
|
builder-util-runtime "9.5.1"
|
||||||
chalk "^4.1.2"
|
chalk "^4.1.2"
|
||||||
dmg-builder "26.0.12"
|
ci-info "^4.2.0"
|
||||||
|
dmg-builder "26.4.0"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
is-ci "^3.0.0"
|
|
||||||
lazy-val "^1.0.5"
|
lazy-val "^1.0.5"
|
||||||
simple-update-notifier "2.0.0"
|
simple-update-notifier "2.0.0"
|
||||||
yargs "^17.6.2"
|
yargs "^17.6.2"
|
||||||
@@ -3460,14 +3486,14 @@ electron-log@^5.4.3:
|
|||||||
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.3.tgz#02a90baf4256950ca416095db6e5745268584d20"
|
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.3.tgz#02a90baf4256950ca416095db6e5745268584d20"
|
||||||
integrity sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==
|
integrity sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==
|
||||||
|
|
||||||
electron-publish@26.0.11:
|
electron-publish@26.3.4:
|
||||||
version "26.0.11"
|
version "26.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.11.tgz#92c9329a101af2836d9d228c82966eca1eee9a7b"
|
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.3.4.tgz#ed05f1ccbb7ee1e53b4140d92735e26fa4bfefd7"
|
||||||
integrity sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==
|
integrity sha512-5/ouDPb73SkKuay2EXisPG60LTFTMNHWo2WLrK5GDphnWK9UC+yzYrzVeydj078Yk4WUXi0+TaaZsNd6Zt5k/A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/fs-extra" "^9.0.11"
|
"@types/fs-extra" "^9.0.11"
|
||||||
builder-util "26.0.11"
|
builder-util "26.3.4"
|
||||||
builder-util-runtime "9.3.1"
|
builder-util-runtime "9.5.1"
|
||||||
chalk "^4.1.2"
|
chalk "^4.1.2"
|
||||||
form-data "^4.0.0"
|
form-data "^4.0.0"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
@@ -3479,18 +3505,18 @@ electron-to-chromium@^1.5.263:
|
|||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7"
|
||||||
integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==
|
integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==
|
||||||
|
|
||||||
electron-updater@^6.6.2:
|
electron-updater@^6.7.3:
|
||||||
version "6.6.2"
|
version "6.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.2.tgz#3e65e044f1a99b00d61e200e24de8e709c69ce99"
|
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.7.3.tgz#c710b00cbce72f5fd2cc88f8c5f7535cae3097a3"
|
||||||
integrity sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==
|
integrity sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==
|
||||||
dependencies:
|
dependencies:
|
||||||
builder-util-runtime "9.3.1"
|
builder-util-runtime "9.5.1"
|
||||||
fs-extra "^10.1.0"
|
fs-extra "^10.1.0"
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
lazy-val "^1.0.5"
|
lazy-val "^1.0.5"
|
||||||
lodash.escaperegexp "^4.1.2"
|
lodash.escaperegexp "^4.1.2"
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
semver "^7.6.3"
|
semver "~7.7.3"
|
||||||
tiny-typed-emitter "^2.1.0"
|
tiny-typed-emitter "^2.1.0"
|
||||||
|
|
||||||
electron@39.2.7:
|
electron@39.2.7:
|
||||||
@@ -4411,16 +4437,17 @@ glob-parent@~5.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-glob "^4.0.1"
|
is-glob "^4.0.1"
|
||||||
|
|
||||||
glob@^10.3.12:
|
glob@^10.2.2:
|
||||||
version "10.3.14"
|
version "10.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.14.tgz#36501f871d373fe197fc5794588d0aa71e69ff68"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c"
|
||||||
integrity sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g==
|
integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==
|
||||||
dependencies:
|
dependencies:
|
||||||
foreground-child "^3.1.0"
|
foreground-child "^3.1.0"
|
||||||
jackspeak "^2.3.6"
|
jackspeak "^3.1.2"
|
||||||
minimatch "^9.0.1"
|
minimatch "^9.0.4"
|
||||||
minipass "^7.0.4"
|
minipass "^7.1.2"
|
||||||
path-scurry "^1.11.0"
|
package-json-from-dist "^1.0.0"
|
||||||
|
path-scurry "^1.11.1"
|
||||||
|
|
||||||
glob@^13.0.0:
|
glob@^13.0.0:
|
||||||
version "13.0.0"
|
version "13.0.0"
|
||||||
@@ -4689,7 +4716,7 @@ http-errors@^2.0.0, http-errors@^2.0.1, http-errors@~2.0.1:
|
|||||||
|
|
||||||
http-proxy-agent@^5.0.0:
|
http-proxy-agent@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz"
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43"
|
||||||
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
|
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tootallnate/once" "2"
|
"@tootallnate/once" "2"
|
||||||
@@ -4979,13 +5006,6 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
|
|||||||
resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz"
|
resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz"
|
||||||
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
|
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
|
||||||
|
|
||||||
is-ci@^3.0.0:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz"
|
|
||||||
integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==
|
|
||||||
dependencies:
|
|
||||||
ci-info "^3.2.0"
|
|
||||||
|
|
||||||
is-cidr@^6.0.1:
|
is-cidr@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-6.0.1.tgz#125e9dead938b6fa996aa500662a5e9f88f338f4"
|
resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-6.0.1.tgz#125e9dead938b6fa996aa500662a5e9f88f338f4"
|
||||||
@@ -5273,10 +5293,10 @@ istanbul-reports@^3.0.2:
|
|||||||
html-escaper "^2.0.0"
|
html-escaper "^2.0.0"
|
||||||
istanbul-lib-report "^3.0.0"
|
istanbul-lib-report "^3.0.0"
|
||||||
|
|
||||||
jackspeak@^2.3.6:
|
jackspeak@^3.1.2:
|
||||||
version "2.3.6"
|
version "3.4.3"
|
||||||
resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz"
|
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
|
||||||
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
|
integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@isaacs/cliui" "^8.0.2"
|
"@isaacs/cliui" "^8.0.2"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -5297,6 +5317,11 @@ java-properties@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211"
|
resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211"
|
||||||
integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==
|
integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==
|
||||||
|
|
||||||
|
jiti@^2.4.2:
|
||||||
|
version "2.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.6.1.tgz#178ef2fc9a1a594248c20627cd820187a4d78d92"
|
||||||
|
integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==
|
||||||
|
|
||||||
js-base64@^3.7.8:
|
js-base64@^3.7.8:
|
||||||
version "3.7.8"
|
version "3.7.8"
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4"
|
||||||
@@ -5755,6 +5780,23 @@ make-fetch-happen@^10.2.1:
|
|||||||
socks-proxy-agent "^7.0.0"
|
socks-proxy-agent "^7.0.0"
|
||||||
ssri "^9.0.0"
|
ssri "^9.0.0"
|
||||||
|
|
||||||
|
make-fetch-happen@^14.0.3:
|
||||||
|
version "14.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz#d74c3ecb0028f08ab604011e0bc6baed483fcdcd"
|
||||||
|
integrity sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==
|
||||||
|
dependencies:
|
||||||
|
"@npmcli/agent" "^3.0.0"
|
||||||
|
cacache "^19.0.1"
|
||||||
|
http-cache-semantics "^4.1.1"
|
||||||
|
minipass "^7.0.2"
|
||||||
|
minipass-fetch "^4.0.0"
|
||||||
|
minipass-flush "^1.0.5"
|
||||||
|
minipass-pipeline "^1.2.4"
|
||||||
|
negotiator "^1.0.0"
|
||||||
|
proc-log "^5.0.0"
|
||||||
|
promise-retry "^2.0.1"
|
||||||
|
ssri "^12.0.0"
|
||||||
|
|
||||||
make-fetch-happen@^15.0.0, make-fetch-happen@^15.0.1, make-fetch-happen@^15.0.3:
|
make-fetch-happen@^15.0.0, make-fetch-happen@^15.0.1, make-fetch-happen@^15.0.3:
|
||||||
version "15.0.3"
|
version "15.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz#1578d72885f2b3f9e5daa120b36a14fc31a84610"
|
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz#1578d72885f2b3f9e5daa120b36a14fc31a84610"
|
||||||
@@ -5899,7 +5941,7 @@ mimic-response@^3.1.0:
|
|||||||
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz"
|
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz"
|
||||||
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
|
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
|
||||||
|
|
||||||
minimatch@^10.0.0, minimatch@^10.0.3, minimatch@^10.1.1:
|
minimatch@^10.0.3, minimatch@^10.1.1:
|
||||||
version "10.1.1"
|
version "10.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55"
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55"
|
||||||
integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==
|
integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==
|
||||||
@@ -5920,14 +5962,7 @@ minimatch@^5.0.1, minimatch@^5.1.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^2.0.1"
|
brace-expansion "^2.0.1"
|
||||||
|
|
||||||
minimatch@^9.0.1:
|
minimatch@^9.0.3, minimatch@^9.0.4:
|
||||||
version "9.0.4"
|
|
||||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz"
|
|
||||||
integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
|
|
||||||
dependencies:
|
|
||||||
brace-expansion "^2.0.1"
|
|
||||||
|
|
||||||
minimatch@^9.0.3:
|
|
||||||
version "9.0.5"
|
version "9.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
|
||||||
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
|
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
|
||||||
@@ -5964,6 +5999,17 @@ minipass-fetch@^2.0.3:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
encoding "^0.1.13"
|
encoding "^0.1.13"
|
||||||
|
|
||||||
|
minipass-fetch@^4.0.0:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-4.0.1.tgz#f2d717d5a418ad0b1a7274f9b913515d3e78f9e5"
|
||||||
|
integrity sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==
|
||||||
|
dependencies:
|
||||||
|
minipass "^7.0.3"
|
||||||
|
minipass-sized "^1.0.3"
|
||||||
|
minizlib "^3.0.1"
|
||||||
|
optionalDependencies:
|
||||||
|
encoding "^0.1.13"
|
||||||
|
|
||||||
minipass-fetch@^5.0.0:
|
minipass-fetch@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-5.0.0.tgz#644ed3fa172d43b3163bb32f736540fc138c4afb"
|
resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-5.0.0.tgz#644ed3fa172d43b3163bb32f736540fc138c4afb"
|
||||||
@@ -6168,11 +6214,16 @@ mz@^2.4.0:
|
|||||||
object-assign "^4.0.1"
|
object-assign "^4.0.1"
|
||||||
thenify-all "^1.0.0"
|
thenify-all "^1.0.0"
|
||||||
|
|
||||||
negotiator@0.6.3, negotiator@^0.6.3:
|
negotiator@0.6.3:
|
||||||
version "0.6.3"
|
version "0.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||||
|
|
||||||
|
negotiator@^0.6.3:
|
||||||
|
version "0.6.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7"
|
||||||
|
integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
|
||||||
|
|
||||||
negotiator@^1.0.0:
|
negotiator@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
|
||||||
@@ -6193,19 +6244,19 @@ nice-try@^1.0.4:
|
|||||||
resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz"
|
resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz"
|
||||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||||
|
|
||||||
node-abi@^3.45.0:
|
node-abi@^4.2.0:
|
||||||
version "3.85.0"
|
version "4.24.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.85.0.tgz#b115d575e52b2495ef08372b058e13d202875a7d"
|
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-4.24.0.tgz#fcc1b4c645ffb4c0f39e2dbfb9c41698ba7e782e"
|
||||||
integrity sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==
|
integrity sha512-u2EC1CeNe25uVtX3EZbdQ275c74zdZmmpzrHEQh2aIYqoVjlglfUpOX9YY85x1nlBydEKDVaSmMNhR7N82Qj8A==
|
||||||
dependencies:
|
dependencies:
|
||||||
semver "^7.3.5"
|
semver "^7.6.3"
|
||||||
|
|
||||||
node-addon-api@^1.6.3:
|
node-addon-api@^1.6.3:
|
||||||
version "1.7.2"
|
version "1.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d"
|
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d"
|
||||||
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
|
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
|
||||||
|
|
||||||
node-api-version@^0.2.0:
|
node-api-version@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9"
|
resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9"
|
||||||
integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==
|
integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==
|
||||||
@@ -6222,6 +6273,22 @@ node-emoji@^2.2.0:
|
|||||||
emojilib "^2.4.0"
|
emojilib "^2.4.0"
|
||||||
skin-tone "^2.0.0"
|
skin-tone "^2.0.0"
|
||||||
|
|
||||||
|
node-gyp@^11.2.0:
|
||||||
|
version "11.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-11.5.0.tgz#82661b5f40647a7361efe918e3cea76d297fcc56"
|
||||||
|
integrity sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==
|
||||||
|
dependencies:
|
||||||
|
env-paths "^2.2.0"
|
||||||
|
exponential-backoff "^3.1.1"
|
||||||
|
graceful-fs "^4.2.6"
|
||||||
|
make-fetch-happen "^14.0.3"
|
||||||
|
nopt "^8.0.0"
|
||||||
|
proc-log "^5.0.0"
|
||||||
|
semver "^7.3.5"
|
||||||
|
tar "^7.4.3"
|
||||||
|
tinyglobby "^0.2.12"
|
||||||
|
which "^5.0.0"
|
||||||
|
|
||||||
node-gyp@^12.1.0:
|
node-gyp@^12.1.0:
|
||||||
version "12.1.0"
|
version "12.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-12.1.0.tgz#302fc2d3fec36975cfb8bfee7a6bf6b7f0be9553"
|
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-12.1.0.tgz#302fc2d3fec36975cfb8bfee7a6bf6b7f0be9553"
|
||||||
@@ -6257,6 +6324,13 @@ nopt@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
abbrev "^1.0.0"
|
abbrev "^1.0.0"
|
||||||
|
|
||||||
|
nopt@^8.0.0:
|
||||||
|
version "8.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/nopt/-/nopt-8.1.0.tgz#b11d38caf0f8643ce885818518064127f602eae3"
|
||||||
|
integrity sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==
|
||||||
|
dependencies:
|
||||||
|
abbrev "^3.0.0"
|
||||||
|
|
||||||
nopt@^9.0.0:
|
nopt@^9.0.0:
|
||||||
version "9.0.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-9.0.0.tgz#6bff0836b2964d24508b6b41b5a9a49c4f4a1f96"
|
resolved "https://registry.yarnpkg.com/nopt/-/nopt-9.0.0.tgz#6bff0836b2964d24508b6b41b5a9a49c4f4a1f96"
|
||||||
@@ -6720,6 +6794,11 @@ package-hash@^4.0.0:
|
|||||||
lodash.flattendeep "^4.4.0"
|
lodash.flattendeep "^4.4.0"
|
||||||
release-zalgo "^1.0.0"
|
release-zalgo "^1.0.0"
|
||||||
|
|
||||||
|
package-json-from-dist@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
|
||||||
|
integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
|
||||||
|
|
||||||
pacote@^21.0.0, pacote@^21.0.2, pacote@^21.0.4:
|
pacote@^21.0.0, pacote@^21.0.2, pacote@^21.0.4:
|
||||||
version "21.0.4"
|
version "21.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/pacote/-/pacote-21.0.4.tgz#59cd2a2b5a4c8c1b625f33991a96b136d1c05d95"
|
resolved "https://registry.yarnpkg.com/pacote/-/pacote-21.0.4.tgz#59cd2a2b5a4c8c1b625f33991a96b136d1c05d95"
|
||||||
@@ -6883,10 +6962,10 @@ path-parse@^1.0.7:
|
|||||||
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
|
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
|
||||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||||
|
|
||||||
path-scurry@^1.11.0:
|
path-scurry@^1.11.1:
|
||||||
version "1.11.0"
|
version "1.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.0.tgz#332d64e9726bf667fb348e5a1c71005c09ad741a"
|
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
|
||||||
integrity sha512-LNHTaVkzaYaLGlO+0u3rQTz7QrHTFOuKyba9JMTQutkmtNew8dw8wOD7mTU/5fCPZzCWpfW0XnQKzY61P0aTaw==
|
integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^10.2.0"
|
lru-cache "^10.2.0"
|
||||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||||
@@ -7062,6 +7141,11 @@ proc-log@^2.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685"
|
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685"
|
||||||
integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==
|
integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==
|
||||||
|
|
||||||
|
proc-log@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-5.0.0.tgz#e6c93cf37aef33f835c53485f314f50ea906a9d8"
|
||||||
|
integrity sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==
|
||||||
|
|
||||||
proc-log@^6.0.0, proc-log@^6.1.0:
|
proc-log@^6.0.0, proc-log@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-6.1.0.tgz#18519482a37d5198e231133a70144a50f21f0215"
|
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-6.1.0.tgz#18519482a37d5198e231133a70144a50f21f0215"
|
||||||
@@ -7641,14 +7725,14 @@ semver@^7.1.1, semver@^7.1.2, semver@^7.3.7, semver@^7.5.2:
|
|||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
|
||||||
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
|
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
|
||||||
|
|
||||||
semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3:
|
semver@^7.3.2, semver@^7.3.5, semver@^7.5.3:
|
||||||
version "7.6.0"
|
version "7.6.0"
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"
|
||||||
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
|
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
semver@^7.5.4, semver@^7.6.3, semver@^7.7.1, semver@^7.7.2, semver@^7.7.3:
|
semver@^7.5.4, semver@^7.6.3, semver@^7.7.1, semver@^7.7.2, semver@^7.7.3, semver@~7.7.3:
|
||||||
version "7.7.3"
|
version "7.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
||||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||||
@@ -8054,6 +8138,13 @@ sprintf-js@~1.0.2:
|
|||||||
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
||||||
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
||||||
|
|
||||||
|
ssri@^12.0.0:
|
||||||
|
version "12.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ssri/-/ssri-12.0.0.tgz#bcb4258417c702472f8191981d3c8a771fee6832"
|
||||||
|
integrity sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==
|
||||||
|
dependencies:
|
||||||
|
minipass "^7.0.3"
|
||||||
|
|
||||||
ssri@^13.0.0:
|
ssri@^13.0.0:
|
||||||
version "13.0.0"
|
version "13.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-13.0.0.tgz#4226b303dc474003d88905f9098cb03361106c74"
|
resolved "https://registry.yarnpkg.com/ssri/-/ssri-13.0.0.tgz#4226b303dc474003d88905f9098cb03361106c74"
|
||||||
@@ -8336,7 +8427,7 @@ tagged-tag@^1.0.0:
|
|||||||
|
|
||||||
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
|
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
|
||||||
version "6.2.1"
|
version "6.2.1"
|
||||||
resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz"
|
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
|
||||||
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
|
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
|
||||||
dependencies:
|
dependencies:
|
||||||
chownr "^2.0.0"
|
chownr "^2.0.0"
|
||||||
@@ -8747,7 +8838,7 @@ typedarray@^0.0.6:
|
|||||||
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
||||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||||
|
|
||||||
typescript@^5.4.3, typescript@^5.9.3:
|
typescript@^5.9.3:
|
||||||
version "5.9.3"
|
version "5.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
|
||||||
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
||||||
@@ -8816,6 +8907,13 @@ unique-filename@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
unique-slug "^3.0.0"
|
unique-slug "^3.0.0"
|
||||||
|
|
||||||
|
unique-filename@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-4.0.0.tgz#a06534d370e7c977a939cd1d11f7f0ab8f1fed13"
|
||||||
|
integrity sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==
|
||||||
|
dependencies:
|
||||||
|
unique-slug "^5.0.0"
|
||||||
|
|
||||||
unique-filename@^5.0.0:
|
unique-filename@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-5.0.0.tgz#8b17bbde1a7ca322dd1a1d23fe17c2b798c43f8f"
|
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-5.0.0.tgz#8b17bbde1a7ca322dd1a1d23fe17c2b798c43f8f"
|
||||||
@@ -8830,6 +8928,13 @@ unique-slug@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
imurmurhash "^0.1.4"
|
imurmurhash "^0.1.4"
|
||||||
|
|
||||||
|
unique-slug@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-5.0.0.tgz#ca72af03ad0dbab4dad8aa683f633878b1accda8"
|
||||||
|
integrity sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==
|
||||||
|
dependencies:
|
||||||
|
imurmurhash "^0.1.4"
|
||||||
|
|
||||||
unique-slug@^6.0.0:
|
unique-slug@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-6.0.0.tgz#f46fd688a9bd972fd356c23d95812a3a4862ed88"
|
resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-6.0.0.tgz#f46fd688a9bd972fd356c23d95812a3a4862ed88"
|
||||||
@@ -8994,11 +9099,18 @@ which@^1.2.9:
|
|||||||
|
|
||||||
which@^2.0.1, which@^2.0.2:
|
which@^2.0.1, which@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
|
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe "^2.0.0"
|
isexe "^2.0.0"
|
||||||
|
|
||||||
|
which@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/which/-/which-5.0.0.tgz#d93f2d93f79834d4363c7d0c23e00d07c466c8d6"
|
||||||
|
integrity sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==
|
||||||
|
dependencies:
|
||||||
|
isexe "^3.1.1"
|
||||||
|
|
||||||
which@^6.0.0:
|
which@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-6.0.0.tgz#a3a721a14cdd9b991a722e493c177eeff82ff32a"
|
resolved "https://registry.yarnpkg.com/which/-/which-6.0.0.tgz#a3a721a14cdd9b991a722e493c177eeff82ff32a"
|
||||||
|
|||||||
Reference in New Issue
Block a user